mirror of
https://github.com/2martens/tsw-timetable.git
synced 2026-10-17 07:57:55 +02:00
fix: Check for subject not authorized party
This commit is contained in:
@@ -63,9 +63,8 @@ class UserController(
|
||||
)
|
||||
]) body: User
|
||||
): ResponseEntity<User> {
|
||||
val authentication = SecurityContextHolder.getContext().authentication
|
||||
val jwt = authentication as JwtAuthenticationToken
|
||||
val authorizedParty = jwt.token.getClaimAsString("azp")
|
||||
val authentication = SecurityContextHolder.getContext().authentication as JwtAuthenticationToken
|
||||
val subject = authentication.token.getClaimAsString("sub") ?: authentication.name
|
||||
var created = false
|
||||
|
||||
val userIdConverted = UserId.of(NonEmptyString(userId))
|
||||
@@ -73,7 +72,7 @@ class UserController(
|
||||
if (user == null) {
|
||||
created = true
|
||||
user = mapper.mapToDB(body)
|
||||
} else if (authorizedParty == userId) {
|
||||
} else if (subject == userId) {
|
||||
user.name = NonEmptyString(body.name)
|
||||
user.email = Email.of(NonEmptyString(body.email))
|
||||
} else {
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
package de.twomartens.timetable.configuration
|
||||
|
||||
import de.twomartens.timetable.configuration.roles.CheckParty
|
||||
import de.twomartens.timetable.configuration.roles.PartyAuthorizationManager
|
||||
import de.twomartens.timetable.configuration.roles.CheckSubject
|
||||
import de.twomartens.timetable.configuration.roles.SubjectAuthorizationManager
|
||||
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut
|
||||
import org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE
|
||||
import org.springframework.context.annotation.Bean
|
||||
@@ -16,8 +16,8 @@ class AuthorizationManagerConfiguration {
|
||||
@Bean
|
||||
@Role(ROLE_INFRASTRUCTURE)
|
||||
fun checkPartyInterceptor(): AuthorizationManagerBeforeMethodInterceptor {
|
||||
val pointcut = AnnotationMatchingPointcut(null, CheckParty::class.java, true)
|
||||
val interceptor = AuthorizationManagerBeforeMethodInterceptor(pointcut, PartyAuthorizationManager())
|
||||
val pointcut = AnnotationMatchingPointcut(null, CheckSubject::class.java, true)
|
||||
val interceptor = AuthorizationManagerBeforeMethodInterceptor(pointcut, SubjectAuthorizationManager())
|
||||
interceptor.order = AuthorizationInterceptorsOrder.PRE_AUTHORIZE.order
|
||||
return interceptor
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ import java.lang.annotation.Inherited
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Inherited
|
||||
@MustBeDocumented
|
||||
annotation class CheckParty(
|
||||
annotation class CheckSubject(
|
||||
val partyParamName: String // Name of method argument holding the party ID
|
||||
)
|
||||
+7
-6
@@ -7,20 +7,21 @@ import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorizationResult
|
||||
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
|
||||
import java.util.function.Supplier
|
||||
|
||||
class PartyAuthorizationManager : AuthorizationManager<MethodInvocation>, MethodAuthorizationDeniedHandler {
|
||||
class SubjectAuthorizationManager : AuthorizationManager<MethodInvocation>, MethodAuthorizationDeniedHandler {
|
||||
@Deprecated("Deprecated in Spring Security")
|
||||
override fun check(authentication: Supplier<Authentication?>?, invocation: MethodInvocation?): AuthorizationDecision {
|
||||
if (authentication == null || authentication.get() == null || !authentication.get()!!.isAuthenticated) {
|
||||
return AuthorizationDecision(false)
|
||||
}
|
||||
|
||||
val annotation = invocation!!.method.getAnnotation(CheckParty::class.java)
|
||||
?: invocation.method.declaringClass.getAnnotation(CheckParty::class.java)
|
||||
val annotation = invocation!!.method.getAnnotation(CheckSubject::class.java)
|
||||
?: invocation.method.declaringClass.getAnnotation(CheckSubject::class.java)
|
||||
?: return AuthorizationDecision(true) // No annotation, allow
|
||||
|
||||
val authentication = authentication.get()!!
|
||||
val authentication = authentication.get()!! as JwtAuthenticationToken
|
||||
val partyParamName = annotation.partyParamName
|
||||
|
||||
// 1. Authorized party check
|
||||
@@ -31,13 +32,13 @@ class PartyAuthorizationManager : AuthorizationManager<MethodInvocation>, Method
|
||||
}
|
||||
|
||||
val requestedPartyId = invocation.arguments[argIndex]?.toString()
|
||||
val tokenPartyId = (authentication.details as? Map<*, *>)?.get("azp")?.toString()
|
||||
val tokenPartyId = authentication.token.getClaimAsString("sub")
|
||||
?: authentication.name // fallback
|
||||
|
||||
return AuthorizationDecision(requestedPartyId == tokenPartyId)
|
||||
}
|
||||
|
||||
override fun handleDeniedInvocation(methodInvocation: MethodInvocation?, authorizationResult: AuthorizationResult?): Any? {
|
||||
throw AuthorizationDeniedException("The requested resources are not accessible to the authorized party")
|
||||
throw AuthorizationDeniedException("The requested resources are not accessible for the subject")
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
package de.twomartens.timetable.formation
|
||||
|
||||
import de.twomartens.timetable.auth.UserRepository
|
||||
import de.twomartens.timetable.configuration.roles.CheckParty
|
||||
import de.twomartens.timetable.configuration.roles.CheckSubject
|
||||
import de.twomartens.timetable.model.common.FormationId
|
||||
import de.twomartens.timetable.model.common.UserId
|
||||
import de.twomartens.timetable.model.dto.Formation
|
||||
@@ -45,7 +45,7 @@ class FormationController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@GetMapping("/{userId}/")
|
||||
fun getFormations(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -98,7 +98,7 @@ class FormationController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@GetMapping("/{userId}/{id}")
|
||||
fun getFormation(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -147,7 +147,7 @@ class FormationController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@PutMapping("/{userId}/{id}")
|
||||
fun putFormation(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -240,7 +240,7 @@ class FormationController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@DeleteMapping("/{userId}/{id}")
|
||||
fun deleteFormation(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package de.twomartens.timetable.route
|
||||
|
||||
import de.twomartens.timetable.auth.UserRepository
|
||||
import de.twomartens.timetable.configuration.roles.CheckParty
|
||||
import de.twomartens.timetable.configuration.roles.CheckSubject
|
||||
import de.twomartens.timetable.model.common.RouteId
|
||||
import de.twomartens.timetable.model.common.UserId
|
||||
import de.twomartens.timetable.model.dto.TswRoute
|
||||
@@ -44,7 +44,7 @@ class RouteController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@GetMapping("/{userId}/")
|
||||
fun getRoutes(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -89,7 +89,7 @@ class RouteController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@GetMapping("/{userId}/{id}")
|
||||
fun getRoute(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -133,7 +133,7 @@ class RouteController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@PutMapping("/{userId}/{id}")
|
||||
fun putRoute(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
@@ -199,7 +199,7 @@ class RouteController(
|
||||
)
|
||||
@SecurityRequirement(name = "bearer")
|
||||
@SecurityRequirement(name = "oauth2")
|
||||
@CheckParty(partyParamName = "userId")
|
||||
@CheckSubject(partyParamName = "userId")
|
||||
@DeleteMapping("/{userId}/{id}")
|
||||
fun deleteRoute(
|
||||
@PathVariable @Parameter(description = "The id of the user",
|
||||
|
||||
Reference in New Issue
Block a user