Skip to content

Commit

Permalink
Merge branch 'master' into feature/68-ldap-logging
Browse files Browse the repository at this point in the history
  • Loading branch information
dk1844 authored Aug 25, 2023
2 parents a7131cd + 5eef9ba commit d312d31
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,23 @@
package za.co.absa.loginsvc.rest.controller

import com.fasterxml.jackson.annotation.JsonProperty
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.{ArraySchema, Content, ExampleObject, Schema}
import io.swagger.v3.oas.annotations.enums.ParameterIn
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode
import io.swagger.v3.oas.annotations.responses.{ApiResponse, ApiResponses}
import io.swagger.v3.oas.annotations.media.{Content, ExampleObject, Schema}
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.security.SecurityRequirement
import io.swagger.v3.oas.annotations.tags.{Tag, Tags}
import io.swagger.v3.oas.annotations.{Operation, Parameter}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.{HttpStatus, MediaType}
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation._
import za.co.absa.loginsvc.model.User
import za.co.absa.loginsvc.rest.service.JWTService
import za.co.absa.loginsvc.utils.OptionExt.ImplicitOptionExt

import java.util.Base64
import java.util.concurrent.CompletableFuture
import java.util.{Base64, Optional}
import scala.concurrent.Future


Expand Down Expand Up @@ -70,15 +72,24 @@ class TokenController @Autowired()(jwtService: JWTService) {
))
)
)
@Parameter(in = ParameterIn.QUERY, name = "groups-prefix", schema = new Schema(implementation = classOf[String]), example = "pam-",
description = "Prefix of groups only to be returned in JWT user object")
@PostMapping(
path = Array("/generate"),
produces = Array(MediaType.APPLICATION_JSON_VALUE)
)
@ResponseStatus(HttpStatus.OK)
@SecurityRequirement(name = "basicAuth")
def generateToken(authentication: Authentication): CompletableFuture[TokenWrapper] = {
val principal = authentication.getPrincipal.asInstanceOf[User]
val jwt = jwtService.generateToken(principal)
def generateToken(authentication: Authentication, @RequestParam("groups-prefix") optionalGroupsPrefix: Optional[String]): CompletableFuture[TokenWrapper] = {
val user = authentication.getPrincipal.asInstanceOf[User]
val groupsPrefix = optionalGroupsPrefix.toScalaOption

val filteredGroupsUser = groupsPrefix.applyIfDefined(user, { (user: User, prefix) =>
val filteredGroups = user.groups.filter(_.startsWith(prefix))
user.copy(groups = filteredGroups)
})

val jwt = jwtService.generateToken(filteredGroupsUser)
Future.successful(TokenWrapper(jwt))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ object OptionExt {
}
}

implicit class ImplicitOptionExt[OptType](val opt: Option[OptType]) extends AnyVal {
def applyIfDefined[TargetType](target: TargetType, fn: (TargetType, OptType) => TargetType): TargetType = {
OptionExt.applyIfDefined(target, opt, fn)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import java.util

object FakeAuthentication {

val fakeUser: User = User("fakeUser", Some("[email protected]"), Some("Fake Name"), Seq.empty)
val fakeUser: User = User("fakeUser", Some("[email protected]"), Some("Fake Name"), Seq("fake-group1", "second-fake-group"))

val fakeUserAuthentication: Authentication = new UsernamePasswordAuthenticationToken(
fakeUser, "fakePassword", new util.ArrayList[GrantedAuthority]()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ class TokenControllerTest extends AnyFlatSpec with ControllerIntegrationTestBase
)(FakeAuthentication.fakeUserAuthentication)
}

it should "return token generated by mocked JWTService for the authenticated user with groups-prefix" in {
val fakeJWT = "abc.fakeJWTToken.abc"

// `groups-prefix` fill change the groups in user object passed to the jwtService.generateToken
val fakeUserFilteredGroups = FakeAuthentication.fakeUser.copy(groups = Seq("fake-group1"))
when(jwtService.generateToken(fakeUserFilteredGroups)).thenReturn(fakeJWT)

assertOkAndResultBodyJsonEquals(
"/token/generate?groups-prefix=fake",
Post(),
s"""{"token": "$fakeJWT"}"""
)(FakeAuthentication.fakeUserAuthentication)
}

it should "fail for anonymous (not authenticated) user" in {
val fakeJWT = "abc.fakeJWTToken.abc"
when(jwtService.generateToken(any[User]())).thenReturn(fakeJWT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ class OptionExtTest extends AnyFlatSpec with Matchers {
OptionExt.applyIfDefined(1, Some(2), (a:Int, b: Int) => a + b) shouldBe 3
}

"OptionExt.applyIfDefined" should "not apply fn if empty" in {
it should "not apply fn if empty" in {
OptionExt.applyIfDefined(1, None, (a: Int, b: Int) => a + b) shouldBe 1
}

import OptionExt.ImplicitOptionExt

"OptionExt.ImplicitOptionExt" should "apply fn correctly if defined" in {
Some(2).applyIfDefined(1, (a: Int, b: Int) => a + b) shouldBe 3
}

it should "not apply fn if empty" in {
None.applyIfDefined(1, (a: Int, b: Int) => a + b) shouldBe 1
}

}

0 comments on commit d312d31

Please sign in to comment.