diff --git a/api/src/main/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProvider.scala b/api/src/main/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProvider.scala index 97b7156..f25bd6e 100644 --- a/api/src/main/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProvider.scala +++ b/api/src/main/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProvider.scala @@ -59,12 +59,12 @@ class KerberosSPNEGOAuthenticationProvider(activeDirectoryLDAPConfig: ActiveDire provider } - private def sunJaasKerberosTicketValidator: SunJaasKerberosTicketValidator = + private[kerberos] def sunJaasKerberosTicketValidator: SunJaasKerberosTicketValidator = { val ticketValidator: SunJaasKerberosTicketValidator = new SunJaasKerberosTicketValidator() ticketValidator.setServicePrincipal(kerberos.spn) ticketValidator.setKeyTabLocation(new FileSystemResource(kerberos.keytabFileLocation)) - ticketValidator.setDebug(true) + ticketValidator.setDebug(kerberosDebug) ticketValidator.afterPropertiesSet() ticketValidator } diff --git a/api/src/test/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProviderTest.scala b/api/src/test/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProviderTest.scala new file mode 100644 index 0000000..d97fe56 --- /dev/null +++ b/api/src/test/scala/za/co/absa/loginsvc/rest/provider/kerberos/KerberosSPNEGOAuthenticationProviderTest.scala @@ -0,0 +1,155 @@ +/* + * Copyright 2023 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package za.co.absa.loginsvc.rest.provider.kerberos + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatest.BeforeAndAfterEach +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator +import za.co.absa.loginsvc.rest.config.auth.{ActiveDirectoryLDAPConfig, KerberosConfig, LdapUserCredentialsConfig, ServiceAccountConfig} + + +class KerberosSPNEGOAuthenticationProviderTest extends AnyFlatSpec with Matchers with BeforeAndAfterEach { + + private val serviceAccount = ServiceAccountConfig( + "CN=%s,OU=Users,DC=example,DC=com", + Option(LdapUserCredentialsConfig("svc_user", "svc_pass")), + None, + None + ) + + private def createLdapConfig(kerberosConfig: KerberosConfig): ActiveDirectoryLDAPConfig = { + ActiveDirectoryLDAPConfig( + domain = "example.com", + url = "ldaps://localhost:636", + searchFilter = "(sAMAccountName={0})", + order = 1, + serviceAccount = serviceAccount, + enableKerberos = Some(kerberosConfig), + ldapRetry = None, + attributes = None + ) + } + + private def clearKerberosProperties(): Unit = { + System.clearProperty("javax.net.debug") + System.clearProperty("sun.security.krb5.debug") + System.clearProperty("sun.security.krb5.rcache") + System.clearProperty("java.security.krb5.conf") + } + + override def beforeEach(): Unit = { + clearKerberosProperties() + } + + override def afterEach(): Unit = { + clearKerberosProperties() + } + + // initialization tests + "KerberosSPNEGOAuthenticationProvider" should + "set debug system properties to false when debug is None" + + " and set java.security.krb5.conf when krbFileLocation is non-empty" + + " and always set sun.security.krb5.rcache to none" in { + val kerberosConfig = KerberosConfig("/etc/krb5.conf", "test.keytab", "HTTP/host@REALM", debug = None) + val ldapConfig = createLdapConfig(kerberosConfig) + + new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + System.getProperty("javax.net.debug") shouldBe "false" + System.getProperty("sun.security.krb5.debug") shouldBe "false" + System.getProperty("java.security.krb5.conf") shouldBe "/etc/krb5.conf" + System.getProperty("sun.security.krb5.rcache") shouldBe "none" + } + + it should "set debug system properties to false when debug is explicitly false" + + " and set java.security.krb5.conf when krbFileLocation is non-empty" + + " and always set sun.security.krb5.rcache to none" in { + val kerberosConfig = KerberosConfig("/etc/krb5.conf", "test.keytab", "HTTP/host@REALM", debug = Some(false)) + val ldapConfig = createLdapConfig(kerberosConfig) + + new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + System.getProperty("javax.net.debug") shouldBe "false" + System.getProperty("sun.security.krb5.debug") shouldBe "false" + + System.getProperty("java.security.krb5.conf") shouldBe "/etc/krb5.conf" + System.getProperty("sun.security.krb5.rcache") shouldBe "none" + } + + it should "set debug system properties to true when debug is explicitly true" + + " and set java.security.krb5.conf when krbFileLocation is non-empty" + + " and always set sun.security.krb5.rcache to none" in { + val kerberosConfig = KerberosConfig("/etc/krb5.conf", "test.keytab", "HTTP/host@REALM", debug = Some(true)) + val ldapConfig = createLdapConfig(kerberosConfig) + + new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + System.getProperty("javax.net.debug") shouldBe "true" + System.getProperty("sun.security.krb5.debug") shouldBe "true" + + System.getProperty("java.security.krb5.conf") shouldBe "/etc/krb5.conf" + System.getProperty("sun.security.krb5.rcache") shouldBe "none" + } + + + it should "not set java.security.krb5.conf when krbFileLocation is empty" in { + val kerberosConfig = KerberosConfig("", "test.keytab", "HTTP/host@REALM", debug = None) + val ldapConfig = createLdapConfig(kerberosConfig) + + new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + System.getProperty("java.security.krb5.conf") shouldBe null + } + + /** + * Uses reflection to access the private `debug` field of the SunJaasKerberosTicketValidator instance + */ + private def getTicketValidatorDebug(validator: SunJaasKerberosTicketValidator): Boolean = { + val debugField = classOf[SunJaasKerberosTicketValidator].getDeclaredField("debug") + debugField.setAccessible(true) + debugField.getBoolean(validator) + } + + it should "have ticketValidator debug set to false even when ldapConfig.kerberos.debug is None (default)" in { + val kerberosConfig = KerberosConfig("krb5.conf", "test.keytab", "HTTP/host@REALM", debug = None) + val ldapConfig = createLdapConfig(kerberosConfig) + val provider = new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + val validator = provider.sunJaasKerberosTicketValidator + getTicketValidatorDebug(validator) shouldBe false + } + + it should "have ticketValidator debug set to false even when ldapConfig.kerberos.debug is explicitly false" in { + val kerberosConfig = KerberosConfig("krb5.conf", "test.keytab", "HTTP/host@REALM", debug = Some(false)) + val ldapConfig = createLdapConfig(kerberosConfig) + val provider = new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + val validator = provider.sunJaasKerberosTicketValidator + getTicketValidatorDebug(validator) shouldBe false + } + + it should "have ticketValidator debug set to true when ldapConfig.kerberos.debug is explicitly true" in { + val kerberosConfig = KerberosConfig("krb5.conf", "test.keytab", "HTTP/host@REALM", debug = Some(true)) + val ldapConfig = createLdapConfig(kerberosConfig) + val provider = new KerberosSPNEGOAuthenticationProvider(ldapConfig) + + val validator = provider.sunJaasKerberosTicketValidator + getTicketValidatorDebug(validator) shouldBe true + } +} +