diff --git a/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClient.scala b/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClient.scala index 1a1e031e..f3211730 100644 --- a/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClient.scala +++ b/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClient.scala @@ -21,7 +21,7 @@ import org.slf4j.{Logger, LoggerFactory} import org.springframework.http.{HttpEntity, HttpHeaders, HttpMethod, MediaType, ResponseEntity} import org.springframework.security.kerberos.client.KerberosRestTemplate import org.springframework.web.client.RestTemplate -import za.co.absa.loginclient.tokenRetrieval.model.{AccessToken, RefreshToken} +import za.co.absa.loginclient.tokenRetrieval.model.{AccessToken, AuthMethod, BasicAuth, KerberosAuth, RefreshToken} import java.net.URLEncoder import java.util.{Collections, Properties} @@ -39,116 +39,50 @@ case class TokenRetrievalClient(host: String) { private val logger: Logger = LoggerFactory.getLogger(this.getClass) /** - * This method requests an access token (JWT) from the login service using the specified username and password. + * This method requests an access token (JWT) from the login service using the specified authentication method. * This Token is used to access resources which utilize the login Service for authentication. - * - * @param username The username used for authentication. - * @param password The password associated with the provided username. - * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. - * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. + * @param authMethod The authentication method to use. Either Basic Auth or Kerberos Auth. + * @param groups A list of group prefixes to include in the token. + * @param caseSensitiveGroups Whether the group prefixes are case sensitive. * @return An AccessToken object representing the retrieved access token (JWT) from the login service. */ - def fetchAccessToken( - username: String, - password: String, - groups: List[String], - caseSensitiveGroups: Boolean): AccessToken = { - fetchAccessAndRefreshToken(username, password, groups, caseSensitiveGroups)._1 - } - /** - * This method requests an access token (JWT) from the login service using SPNEGO. - * This Token is used to access resources which utilize the login Service for authentication. - * - * @param keytabLocation Optional location of the keytab file. - * @param userPrincipal Optional userPrincipal name included in the above keytab file. - * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. - * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. - * @return An AccessToken object representing the retrieved access token (JWT) from the login service. - */ def fetchAccessToken( - keytabLocation: Option[String], - userPrincipal: Option[String], - groups: List[String], - caseSensitiveGroups: Boolean): AccessToken = { - fetchAccessAndRefreshToken(keytabLocation, userPrincipal, groups, caseSensitiveGroups)._1 + authMethod: AuthMethod, + groups: List[String] = List.empty, + caseSensitiveGroups: Boolean = false + ): AccessToken = { + fetchAccessAndRefreshToken(authMethod, groups, caseSensitiveGroups)._1 } /** * This method requests a refresh token from the login service using SPNEGO. * This token may be used to acquire a new access token (JWT) when the current access token expires. - * - * @param keytabLocation Optional location of the keytab file. - * @param userPrincipal Optional userPrincipal name included in the above keytab file. + * @param authMethod The authentication method to use. Either Basic Auth or Kerberos Auth. * @return A RefreshToken object representing the retrieved refresh token from the login service. */ - def fetchRefreshToken(keytabLocation: Option[String], userPrincipal: Option[String]): RefreshToken = { - fetchAccessAndRefreshToken(keytabLocation, userPrincipal, List.empty, false)._2 - } - /** - * This method requests a refresh token from the login service using the specified username and password. - * This token may be used to acquire a new access token (JWT) when the current access token expires. - * - * @param username The username used for authentication. - * @param password The password associated with the provided username. - * @return A RefreshToken object representing the retrieved refresh token from the login service. - */ - def fetchRefreshToken(username: String, password: String): RefreshToken = { - fetchAccessAndRefreshToken(username, password, List.empty, false)._2 + def fetchRefreshToken(authMethod: AuthMethod): RefreshToken = { + fetchAccessAndRefreshToken(authMethod)._2 } /** * Fetches both an access token and a refresh token from the login service using the provided username, password, and optional groups. * This method requests both an access token and a refresh token (JWTs) from the login service using the specified username and password. - * Additionally, it allows specifying optional groups that act as filters for the JWT, returning only the JWTs associated with the provided groups if the user belongs to them. - * - * @param username The username used for authentication. - * @param password The password associated with the provided username. - * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. - * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. - * @return A tuple containing the AccessToken and RefreshToken objects representing the retrieved access and refresh tokens (JWTs) from the login service. + * Additionally, it allows specifying optional groups (and their case sensitivity) that act as filters for the JWT, + * returning only the JWTs associated with the provided groups if the user belongs to them. + * @param authMethod The authentication method to use. + * @param groups A list of group prefixes to include in the token. + * @param caseSensitiveGroups Whether the group prefixes are case sensitive. + * @return A tuple containing the access token and the refresh token. */ - def fetchAccessAndRefreshToken( - username: String, - password: String, - groups: List[String], - caseSensitiveGroups: Boolean - ): (AccessToken, RefreshToken) = { - val issuerUri = if(groups.nonEmpty) { - val commaSeparatedString = groups.mkString(",") - val urlEncodedGroups = URLEncoder.encode(commaSeparatedString, "UTF-8") - var uri = s"$host/token/generate?group-prefixes=$urlEncodedGroups" - if(caseSensitiveGroups) { - uri += "&case-sensitive=true" - } - uri - } else s"$host/token/generate" - val jsonString = fetchToken(issuerUri, username, password) - val jsonObject = JsonParser.parseString(jsonString).getAsJsonObject - val accessToken = jsonObject.get("token").getAsString - val refreshToken = jsonObject.get("refresh").getAsString - (AccessToken(accessToken), RefreshToken(refreshToken)) - } - - /** - * Fetches both an access token and a refresh token from the login service using SPNEGO. - * This method requests both an access token and a refresh token (JWTs) from the login service using kerberos, either with a keytab or the users cached ticket. - * Additionally, it allows specifying optional groups that act as filters for the JWT, returning only the JWTs associated with the provided groups if the user belongs to them. - * - * @param keytabLocation Optional location of the keytab file. - * @param userPrincipal Optional userPrincipal name included in the above keytab file. - * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. - * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. - * @return A tuple containing the AccessToken and RefreshToken objects representing the retrieved access and refresh tokens (JWTs) from the login service. - */ def fetchAccessAndRefreshToken( - keytabLocation: Option[String], - userPrincipal: Option[String], - groups: List[String], - caseSensitiveGroups: Boolean + authMethod: AuthMethod, + groups: List[String] = List.empty, + caseSensitiveGroups: Boolean = false ): (AccessToken, RefreshToken) = { + val issuerUri = if(groups.nonEmpty) { val commaSeparatedString = groups.mkString(",") val urlEncodedGroups = URLEncoder.encode(commaSeparatedString, "UTF-8") @@ -159,13 +93,27 @@ case class TokenRetrievalClient(host: String) { uri } else s"$host/token/generate" - val jsonString = fetchToken(issuerUri, keytabLocation, userPrincipal) + val jsonString = authMethod match { + case BasicAuth(username, password) => + fetchToken(issuerUri, username, password) + case KerberosAuth(keytabLocation, userPrincipal) => + fetchToken(issuerUri, keytabLocation, userPrincipal) + } + val jsonObject = JsonParser.parseString(jsonString).getAsJsonObject val accessToken = jsonObject.get("token").getAsString val refreshToken = jsonObject.get("refresh").getAsString (AccessToken(accessToken), RefreshToken(refreshToken)) } + /** + * Refreshes an access token using a refresh token. + * + * @param accessToken The access token to refresh. + * @param refreshToken The refresh token to use. + * @return A tuple containing the new access token and the existing refresh token. + */ + def refreshAccessToken(accessToken: AccessToken, refreshToken: RefreshToken): (AccessToken, RefreshToken) = { val issuerUri = s"$host/token/refresh" @@ -204,6 +152,14 @@ case class TokenRetrievalClient(host: String) { } } + /** + * Sets the Kerberos properties for the JVM. + * + * @param jaasFileLocation The location of the JAAS file. + * @param krb5FileLocation The location of the krb5 file. + * @param debug Whether to enable Kerberos debugging. + */ + def setKerberosProperties(jaasFileLocation: String, krb5FileLocation: Option[String], debug: Option[Boolean]): Unit = { val properties: Properties = new Properties() properties.setProperty("java.security.auth.login.config", jaasFileLocation) @@ -276,4 +232,127 @@ case class TokenRetrievalClient(host: String) { throw e } } + + //Deprecated methods + + /** + * This method requests an access token (JWT) from the login service using the specified username and password. + * This Token is used to access resources which utilize the login Service for authentication. + * This Method is Deprecated. Use fetchAccessToken with AuthMethod instead. + * + * @param username The username used for authentication. + * @param password The password associated with the provided username. + * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. + * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. + * @return An AccessToken object representing the retrieved access token (JWT) from the login service. + */ + + @deprecated("This method is deprecated. Use fetchAccessToken with AuthMethod instead") + def fetchAccessToken( + username: String, + password: String, + groups: List[String], + caseSensitiveGroups: Boolean): AccessToken = { + val authMethod = BasicAuth(username, password) + fetchAccessAndRefreshToken(authMethod, groups, caseSensitiveGroups)._1 + } + + /** + * This method requests an access token (JWT) from the login service using SPNEGO. + * This Token is used to access resources which utilize the login Service for authentication. + * This Method is Deprecated. Use fetchAccessToken with AuthMethod instead. + * + * @param keytabLocation Optional location of the keytab file. + * @param userPrincipal Optional userPrincipal name included in the above keytab file. + * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. + * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. + * @return An AccessToken object representing the retrieved access token (JWT) from the login service. + */ + @deprecated("This method is deprecated. Use fetchAccessToken with AuthMethod instead") + def fetchAccessToken( + keytabLocation: Option[String], + userPrincipal: Option[String], + groups: List[String], + caseSensitiveGroups: Boolean): AccessToken = { + val authMethod = KerberosAuth(keytabLocation, userPrincipal) + fetchAccessAndRefreshToken(authMethod, groups, caseSensitiveGroups)._1 + } + + /** + * This method requests a refresh token from the login service using the specified username and password. + * This token may be used to acquire a new access token (JWT) when the current access token expires. + * This Method is Deprecated. Use fetchRefreshToken with AuthMethod instead. + * + * @param username The username used for authentication. + * @param password The password associated with the provided username. + * @return A RefreshToken object representing the retrieved refresh token from the login service. + */ + @deprecated("This method is deprecated. Use fetchRefreshToken with AuthMethod instead") + def fetchRefreshToken(username: String, password: String): RefreshToken = { + val authMethod = BasicAuth(username, password) + fetchAccessAndRefreshToken(authMethod)._2 + } + + /** + * This method requests a refresh token from the login service using SPNEGO. + * This token may be used to acquire a new access token (JWT) when the current access token expires. + * This Method is Deprecated. Use fetchRefreshToken with AuthMethod instead. + * + * @param keytabLocation Optional location of the keytab file. + * @param userPrincipal Optional userPrincipal name included in the above keytab file. + * @return A RefreshToken object representing the retrieved refresh token from the login service. + */ + + @deprecated("This method is deprecated. Use fetchRefreshToken with AuthMethod instead") + def fetchRefreshToken( + keytabLocation: Option[String], + userPrincipal: Option[String]): RefreshToken = { + val authMethod = KerberosAuth(keytabLocation, userPrincipal) + fetchAccessAndRefreshToken(authMethod)._2 + } + + /** + * This method requests both an access token and a refresh token from the login service using the specified username and password. + * Additionally, it allows specifying optional groups (and their case sensitivity) that act as filters for the JWT, + * returning only the JWTs associated with the provided groups if the user belongs to them. + * This Method is Deprecated. Use fetchAccessAndRefreshToken with AuthMethod instead. + * + * @param username The username used for authentication. + * @param password The password associated with the provided username. + * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. + * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. + * @return A tuple containing the access token and the refresh token. + */ + + @deprecated("This method is deprecated. Use fetchAccessAndRefreshToken with AuthMethod instead") + def fetchAccessAndRefreshToken( + username: String, + password: String, + groups: List[String], + caseSensitiveGroups: Boolean): (AccessToken, RefreshToken) = { + val authMethod = BasicAuth(username, password) + fetchAccessAndRefreshToken(authMethod, groups, caseSensitiveGroups) + } + + /** + * This method requests both an access token and a refresh token from the login service using SPNEGO. + * Additionally, it allows specifying optional groups (and their case sensitivity) that act as filters for the JWT, + * returning only the JWTs associated with the provided groups if the user belongs to them. + * This Method is Deprecated. Use fetchAccessAndRefreshToken with AuthMethod instead. + * + * @param keytabLocation Optional location of the keytab file. + * @param userPrincipal Optional userPrincipal name included in the above keytab file. + * @param groups An optional list of PAM groups. If provided, only JWTs associated with these groups are returned if the user belongs to them. + * @param caseSensitiveGroups A boolean indicating whether the group prefixes should be treated as case sensitive. + * @return A tuple containing the access token and the refresh token. + */ + @deprecated("This method is deprecated. Use fetchAccessAndRefreshToken with AuthMethod instead") + def fetchAccessAndRefreshToken( + keytabLocation: Option[String], + userPrincipal: Option[String], + groups: List[String], + caseSensitiveGroups: Boolean): (AccessToken, RefreshToken) = { + val authMethod = KerberosAuth(keytabLocation, userPrincipal) + fetchAccessAndRefreshToken(authMethod, groups, caseSensitiveGroups) + } } diff --git a/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/model/AuthMethod.scala b/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/model/AuthMethod.scala new file mode 100644 index 00000000..601402d9 --- /dev/null +++ b/clientLibrary/src/main/scala/za/co/absa/loginclient/tokenRetrieval/model/AuthMethod.scala @@ -0,0 +1,21 @@ +/* + * 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.loginclient.tokenRetrieval.model + +sealed trait AuthMethod +case class BasicAuth(username: String, password: String) extends AuthMethod +case class KerberosAuth(keytabLocation: Option[String], userPrincipal: Option[String]) extends AuthMethod diff --git a/clientLibrary/src/test/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClientTest.scala b/clientLibrary/src/test/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClientTest.scala index f7ddbbf7..6ed8a22e 100644 --- a/clientLibrary/src/test/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClientTest.scala +++ b/clientLibrary/src/test/scala/za/co/absa/loginclient/tokenRetrieval/client/TokenRetrievalClientTest.scala @@ -1,51 +1,189 @@ -/* - * 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.loginclient.tokenRetrieval.client +import org.mockito.ArgumentMatchers.{any, anyString} +import org.mockito.Mockito.{mock, when} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import za.co.absa.loginclient.tokenRetrieval.model.{AccessToken, RefreshToken} +import org.springframework.http.{HttpEntity, HttpHeaders, HttpMethod, HttpStatus, MediaType, ResponseEntity} +import org.springframework.security.kerberos.client.KerberosRestTemplate +import org.springframework.web.client.RestTemplate +import za.co.absa.loginclient.tokenRetrieval.model.{AccessToken, BasicAuth, KerberosAuth, RefreshToken} +import com.google.gson.{JsonObject, JsonParser} + +import java.util.Collections -class TokenRetrievalClientTest extends AnyFlatSpec with Matchers{ +class TokenRetrievalClientTest extends AnyFlatSpec with Matchers { private val dummyUri = "https://example.com" private val dummyUser = "exampleUser" private val dummyPassword = "examplePassword" - private val dummyGroups = List() - private val dummyCaseSensitive = false - - class testTokenRetrievalClient extends TokenRetrievalClient(dummyUri) { - override private[client] def fetchToken(issuerUri: String, username: String, password: String) = - """{ - | "token": "mock-access-token", - | "refresh": "mock-refresh-token" - |}""".stripMargin + private val dummyGroups = List("group1", "group2") + private val dummyCaseSensitive = true + + class MockableTokenRetrievalClient( + host: String, + restTemplate: RestTemplate, + kerberosRestTemplate: KerberosRestTemplate) extends TokenRetrievalClient(host) { + + override private[client] def fetchToken(issuerUri: String, username: String, password: String): String = { + val response: ResponseEntity[String] = restTemplate.exchange( + issuerUri, + HttpMethod.POST, + null, + classOf[String]) + response.getBody + } + + override private[client] def fetchToken( + issuerUri: String, + keyTabLocation: Option[String], + userPrincipal: Option[String]): String = { + val response: ResponseEntity[String] = kerberosRestTemplate.exchange( + issuerUri, + HttpMethod.POST, + null, + classOf[String]) + response.getBody + } + + override def refreshAccessToken( + accessToken: AccessToken, + refreshToken: RefreshToken): (AccessToken, RefreshToken) = { + val issuerUri = s"$host/token/refresh" + val jsonPayload: JsonObject = new JsonObject() + jsonPayload.addProperty("token", accessToken.token) + jsonPayload.addProperty("refresh", refreshToken.token) + + val headers = new HttpHeaders() + headers.setContentType(MediaType.APPLICATION_JSON) + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)) + + val requestEntity = new HttpEntity[String](jsonPayload.toString, headers) + + val response: ResponseEntity[String] = restTemplate.exchange( + issuerUri, + HttpMethod.POST, + requestEntity, + classOf[String] + ) + val jsonObject = JsonParser.parseString(response.getBody).getAsJsonObject + ( + AccessToken(jsonObject.get("token").getAsString), + RefreshToken(jsonObject.get("refresh").getAsString) + ) + } } - "fetchAccessAndRefreshToken" should "return expected tokens" in { + "fetchAccessToken with BasicAuth" should "return access token" in { + val mockRestTemplate = mock(classOf[RestTemplate]) + val mockKerberosTemplate = mock(classOf[KerberosRestTemplate]) + val tokenResponse = """{"token": "mock-access-token", "refresh": "mock-refresh-token"}""" + + when(mockRestTemplate.exchange( + anyString(), + any[HttpMethod], + any[HttpEntity[String]], + any[Class[String]] + )).thenReturn(new ResponseEntity(tokenResponse, HttpStatus.OK)) - val testClient = new testTokenRetrievalClient + val testClient = new MockableTokenRetrievalClient(dummyUri, mockRestTemplate, mockKerberosTemplate) + val authMethod = BasicAuth(dummyUser, dummyPassword) + + val result = testClient.fetchAccessToken(authMethod) + + result shouldBe AccessToken("mock-access-token") + } + + "fetchRefreshToken with BasicAuth" should "return refresh token" in { + val mockRestTemplate = mock(classOf[RestTemplate]) + val mockKerberosTemplate = mock(classOf[KerberosRestTemplate]) + val tokenResponse = """{"token": "mock-access-token", "refresh": "mock-refresh-token"}""" + + when(mockRestTemplate.exchange( + anyString(), + any[HttpMethod], + any[HttpEntity[String]], + any[Class[String]] + )).thenReturn(new ResponseEntity(tokenResponse, HttpStatus.OK)) + + val testClient = new MockableTokenRetrievalClient(dummyUri, mockRestTemplate, mockKerberosTemplate) + val authMethod = BasicAuth(dummyUser, dummyPassword) + + val result = testClient.fetchRefreshToken(authMethod) + + result shouldBe RefreshToken("mock-refresh-token") + } + + "fetchAccessAndRefreshToken with BasicAuth and groups" should "return both tokens with group parameters" in { + val mockRestTemplate = mock(classOf[RestTemplate]) + val mockKerberosTemplate = mock(classOf[KerberosRestTemplate]) + val tokenResponse = """{"token": "mock-access-token", "refresh": "mock-refresh-token"}""" + + when(mockRestTemplate.exchange( + anyString(), + any[HttpMethod], + any[HttpEntity[String]], + any[Class[String]] + )).thenReturn(new ResponseEntity(tokenResponse, HttpStatus.OK)) + + val testClient = new MockableTokenRetrievalClient(dummyUri, mockRestTemplate, mockKerberosTemplate) + val authMethod = BasicAuth(dummyUser, dummyPassword) val (accessResult, refreshResult) = testClient.fetchAccessAndRefreshToken( - dummyUser, - dummyPassword, + authMethod, dummyGroups, - dummyCaseSensitive) + dummyCaseSensitive + ) + accessResult shouldBe AccessToken("mock-access-token") refreshResult shouldBe RefreshToken("mock-refresh-token") } -} + + "fetchAccessAndRefreshToken with KerberosAuth" should "return access and refresh tokens" in { + val mockRestTemplate = mock(classOf[RestTemplate]) + val mockKerberosTemplate = mock(classOf[KerberosRestTemplate]) + val tokenResponse = """{"token": "kerberos-access-token", "refresh": "kerberos-refresh-token"}""" + + when(mockKerberosTemplate.exchange( + anyString(), + any[HttpMethod], + any[HttpEntity[String]], + any[Class[String]] + )).thenReturn(new ResponseEntity(tokenResponse, HttpStatus.OK)) + + val testClient = new MockableTokenRetrievalClient(dummyUri, mockRestTemplate, mockKerberosTemplate) + val authMethod = KerberosAuth(Some("/path/to/keytab"), Some("user@REALM")) + + val (accessResult, refreshResult) = testClient.fetchAccessAndRefreshToken( + authMethod, + dummyGroups, + dummyCaseSensitive + ) + + accessResult shouldBe AccessToken("kerberos-access-token") + refreshResult shouldBe RefreshToken("kerberos-refresh-token") + } + + "refreshAccessToken" should "return new tokens" in { + val mockRestTemplate = mock(classOf[RestTemplate]) + val mockKerberosTemplate = mock(classOf[KerberosRestTemplate]) + val tokenResponse = """{"token": "refreshed-token", "refresh": "old-refresh-token"}""" + + when(mockRestTemplate.exchange( + anyString(), + any[HttpMethod], + any[HttpEntity[String]], + any[Class[String]] + )).thenReturn(new ResponseEntity(tokenResponse, HttpStatus.OK)) + + val testClient = new MockableTokenRetrievalClient(dummyUri, mockRestTemplate, mockKerberosTemplate) + + val (newAccess, newRefresh) = testClient.refreshAccessToken( + AccessToken("old-token"), + RefreshToken("old-refresh") + ) + + newAccess shouldBe AccessToken("refreshed-token") + newRefresh shouldBe RefreshToken("old-refresh-token") + } +} \ No newline at end of file diff --git a/examples/src/main/scala/za/co/absa/clientexample/Application.scala b/examples/src/main/scala/za/co/absa/clientexample/Application.scala index e535bdc8..ad9065e5 100644 --- a/examples/src/main/scala/za/co/absa/clientexample/Application.scala +++ b/examples/src/main/scala/za/co/absa/clientexample/Application.scala @@ -20,6 +20,7 @@ import za.co.absa.clientexample.config.ConfigProvider import za.co.absa.loginclient.exceptions.LsJwtException import za.co.absa.loginclient.authorization.{AccessTokenClaimsParser, AccessTokenVerificator, JwtDecoderProvider} import za.co.absa.loginclient.tokenRetrieval.client.TokenRetrievalClient +import za.co.absa.loginclient.tokenRetrieval.model.{BasicAuth, KerberosAuth} import java.nio.file.{Files, Paths} import java.util.Scanner @@ -91,9 +92,11 @@ object Application { try { val (accessToken, refreshToken) = authMethod match { case "1" => - tokenRetriever.fetchAccessAndRefreshToken(username, password, List.empty, false) + val basicAuth = BasicAuth(username, password) + tokenRetriever.fetchAccessAndRefreshToken(basicAuth) case "2" => - tokenRetriever.fetchAccessAndRefreshToken(None, None, List.empty, false) + val kerberosAuth = KerberosAuth(None, None) + tokenRetriever.fetchAccessAndRefreshToken(kerberosAuth) } val decodedAtJwt = accessVerificator.decodeAndVerifyAccessToken(accessToken) // throw Exception on verification fail loggedIn = true