diff --git a/permission-evaluator/README.adoc b/permission-evaluator/README.adoc index c06a1c5..7691bcd 100644 --- a/permission-evaluator/README.adoc +++ b/permission-evaluator/README.adoc @@ -56,7 +56,36 @@ We've provided an `CustomPermissionEvaluator` implementation to serve as an exam It first checks the target domain object type, before calling out to the appropriate permission store to check for access. The access rules here are modeled quite simply, but you can extend this as much as needed for your domain. -Lastly, the `@PreAuthorize` annotations need to be activated through `@EnableGlobalMethodSecurity(prePostEnabled = true)`, which is done in `PermissionEvaluatorConfiguration`. +=== Configure method security +Lastly, the `@PreAuthorize` annotations need to be activated, which we will do in `PermissionEvaluatorConfiguration`. + +At present, we could only annotate `PermissionEvaluatorConfiguration` with `@EnableGlobalMethodSecurity(prePostEnabled = true)` to protect our methods annotated with `@PreAuthorize`. +That works and we would be done, but there's a slight catch related to more https://docs.spring.io/spring-security/reference/5.7.2/servlet/authorization/method-security.html#_enablemethodsecurity[recent developments around `@EnableMethodSecurity`]. +The documentation lists some of the benefits of using `EnableMethodSecurity` over `EnableGlobalMethodSecurity`. + +We need to add the following configuration to wire up our custom permission evaluator. + +.PermissionEvaluatorConfiguration.java +[source,java] +---- +@Configuration +@EnableMethodSecurity(prePostEnabled = false) +class PermissionEvaluatorConfiguration { + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + Advisor preAuthorizeAuthorizationMethodInterceptor(CustomPermissionEvaluator customPermissionEvaluator) { + DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + expressionHandler.setPermissionEvaluator(customPermissionEvaluator); + + PreAuthorizeAuthorizationManager authorizationManager = new PreAuthorizeAuthorizationManager(); + authorizationManager.setExpressionHandler(expressionHandler); + + return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(authorizationManager); + } + +} +---- === Tests Our `CustomPermissionEvaluatorIT` tests use mock users _Alice_ and _Bob_, with a malicious third user _Eve_, all trying to read and write a single spreadsheet. diff --git a/permission-evaluator/src/main/java/com/jdriven/PermissionEvaluatorConfiguration.java b/permission-evaluator/src/main/java/com/jdriven/PermissionEvaluatorConfiguration.java index c90b879..ca53923 100644 --- a/permission-evaluator/src/main/java/com/jdriven/PermissionEvaluatorConfiguration.java +++ b/permission-evaluator/src/main/java/com/jdriven/PermissionEvaluatorConfiguration.java @@ -1,10 +1,31 @@ package com.jdriven; +import com.jdriven.permission.CustomPermissionEvaluator; + +import org.springframework.aop.Advisor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.context.annotation.Role; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; +import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; @Configuration -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class PermissionEvaluatorConfiguration { - // Annotations only +@EnableMethodSecurity(prePostEnabled = false) +class PermissionEvaluatorConfiguration { + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + Advisor preAuthorizeAuthorizationMethodInterceptor(CustomPermissionEvaluator customPermissionEvaluator) { + DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + expressionHandler.setPermissionEvaluator(customPermissionEvaluator); + + PreAuthorizeAuthorizationManager authorizationManager = new PreAuthorizeAuthorizationManager(); + authorizationManager.setExpressionHandler(expressionHandler); + + return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(authorizationManager); + } + }