Class MethodSecurityConfig
- All Implemented Interfaces:
org.springframework.beans.factory.Aware, org.springframework.beans.factory.BeanFactoryAware, org.springframework.beans.factory.SmartInitializingSingleton, org.springframework.context.annotation.ImportAware
<s:global-method-security> block in applicationContext-security.xml.
Despite the user-facing renaming to @EnableMethodSecurity, Spring Security 6 still ships
the legacy EnableGlobalMethodSecurity / GlobalMethodSecurityConfiguration stack
that uses AccessDecisionManager, AfterInvocationManager, and RunAsManager.
The new @EnableMethodSecurity annotation is an
AuthorizationManager-based replacement that
has no AfterInvocationManager concept — porting Gemma's after-invocation providers to
the new model would require a full re-architecture (custom AuthorizationManager + a
post-invocation MethodInterceptor). We deliberately stay on the legacy stack via
@EnableGlobalMethodSecurity so the existing after-invocation provider beans, the existing
accessDecisionManager (UnanimousBased + voter list), and the existing runAsManager
keep working without modification. AfterInvocationProviderManager and friends are marked
deprecated in Spring 6 but remain fully functional through the 6.x line.
Why this migration. The deprecated XML <s:global-method-security> namespace was
suspected (Phase 2) of not reliably wiring the configured DefaultMethodSecurityExpressionHandler into the SpEL evaluation path used by
@PreAuthorize("hasPermission(...)"), and a hasAuthority('GROUP_ADMIN') or ...
workaround was kept in UserService.removeUserFromGroup. Re-testing under the Java config
showed the suspicion was wrong: GlobalMethodSecurityConfiguration.setMethodSecurityExpressionHandler(List) is autowired by Spring and
— when the context contains a single MethodSecurityExpressionHandler bean (gsec's
securityExpressionHandler) — that bean is injected and the SpEL voter calls the correct
handler with the correct PermissionEvaluator/RoleHierarchy. The
hasPermission failure on the admin test path is a separate ACL-evaluation issue (likely a Sid /
permission-mask / cache mismatch in the AclPermissionEvaluator → AclImpl.isGranted
chain) and is tracked as a Phase-3 follow-up; the workaround stays for now. This migration still
delivers (1) deprecated-XML removal, (2) explicit Java-config control over the method-security
chain so any future SpEL wiring needs are obvious, and (3) a survivable path for follow-up work
on the underlying ACL bug without having to touch the XML namespace again.
Bean references. All of the collaborators (permissionEvaluator,
roleHierarchy, accessDecisionManager, runAsManager, and the 14 after-invocation
provider beans) are defined elsewhere (gsec's applicationContext-gsec.xml and Gemma's
applicationContext-security.xml) and only referenced here — never duplicated.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected org.springframework.security.access.AccessDecisionManagerReturn the existingaccessDecisionManagerbean (UnanimousBased with all the securable read/edit + collection + map voters wired in gsec XML).protected org.springframework.security.access.intercept.AfterInvocationManagerAggregate the after-invocation providers fromAFTER_INVOCATION_PROVIDER_BEAN_NAMESinto anAfterInvocationProviderManager.protected org.springframework.security.access.expression.method.MethodSecurityExpressionHandlerBuild aMethodSecurityExpressionHandlerwired with the lab's permission evaluator (gsec'sAclPermissionEvaluator) and the role hierarchy.org.springframework.security.access.PermissionEvaluatorpermissionEvaluator(org.springframework.security.acls.model.AclService aclService, org.springframework.beans.factory.ObjectProvider<org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy> oirsProvider, org.springframework.beans.factory.ObjectProvider<org.springframework.security.acls.model.SidRetrievalStrategy> srsProvider) TheAclPermissionEvaluatorthat backs@PreAuthorize("hasPermission(...)")and@PostAuthorize("hasPermission(...)")SpEL.protected org.springframework.security.access.intercept.RunAsManagerReturn the existingrunAsManagerbean (RunAsManagerImplwith theGROUP_role prefix and the configured run-as key).Methods inherited from class org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration
afterSingletonsInstantiated, authenticationManager, configure, customMethodSecurityMetadataSource, getExpressionHandler, methodSecurityInterceptor, methodSecurityMetadataSource, preInvocationAuthorizationAdvice, setBeanFactory, setImportMetadata, setMethodSecurityExpressionHandler, setObjectPostProcessor, setObjectPostProcessor
-
Constructor Details
-
MethodSecurityConfig
public MethodSecurityConfig()
-
-
Method Details
-
permissionEvaluator
@Bean(name="permissionEvaluator") public org.springframework.security.access.PermissionEvaluator permissionEvaluator(org.springframework.security.acls.model.AclService aclService, org.springframework.beans.factory.ObjectProvider<org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy> oirsProvider, org.springframework.beans.factory.ObjectProvider<org.springframework.security.acls.model.SidRetrievalStrategy> srsProvider) TheAclPermissionEvaluatorthat backs@PreAuthorize("hasPermission(...)")and@PostAuthorize("hasPermission(...)")SpEL. Declared here (rather than left in gsec'sapplicationContext-gsec.xml) so the SpEL evaluator bean owns its evaluator dependency directly — per the gsec absorption roadmap, which routes the lab'spermissionEvaluator+securityExpressionHandlerto this class.Constructor-wired with
AclServiceonly; theObjectIdentityRetrievalStrategyandSidRetrievalStrategyare applied via setters when those beans are present in the context (they're defined in gsec XML /GemmaAclConfiguration). The fallback to Spring Security's stock strategies (used when the optional beans are absent) is what lets minimal IT contexts that don't import the full gsec stack still load cleanly. -
createExpressionHandler
protected org.springframework.security.access.expression.method.MethodSecurityExpressionHandler createExpressionHandler()Build aMethodSecurityExpressionHandlerwired with the lab's permission evaluator (gsec'sAclPermissionEvaluator) and the role hierarchy.Note:
GlobalMethodSecurityConfiguration.setMethodSecurityExpressionHandler(List)is autowired by Spring and, when the application context contains exactly oneMethodSecurityExpressionHandlerbean (thesecurityExpressionHandlerfrom gsec'sapplicationContext-gsec.xml), that bean is injected into the framework'sexpressionHandlerfield at startup andcreateExpressionHandler()is never invoked. The handler the SpEL voter ends up using is therefore the gsec one — already wired with the samepermissionEvaluatorandroleHierarchywe'd attach here. This override exists so the legacy XML bean could be retired in a follow-up without losing the SpEL wiring (it becomes the active definition the moment the XML bean is removed).- Overrides:
createExpressionHandlerin classorg.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration
-
accessDecisionManager
protected org.springframework.security.access.AccessDecisionManager accessDecisionManager()Return the existingaccessDecisionManagerbean (UnanimousBased with all the securable read/edit + collection + map voters wired in gsec XML). Falls back to the superclass default if the bean isn't present — that shouldn't happen in Gemma, but the defensive lookup keeps test contexts that don't import the gsec XML from blowing up at startup.- Overrides:
accessDecisionManagerin classorg.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration
-
afterInvocationManager
protected org.springframework.security.access.intercept.AfterInvocationManager afterInvocationManager()Aggregate the after-invocation providers fromAFTER_INVOCATION_PROVIDER_BEAN_NAMESinto anAfterInvocationProviderManager. This preserves the post-invocation filtering chain (ACL_READ filters, value-object filters,@PostAuthorize/@PostFilteradvice) that the XML<s:after-invocation-provider>elements used to wire.AfterInvocationProviderManageris deprecated in Spring 6 but still functional; this is the documented bridge for code that hasn't yet migrated to the AuthorizationManager model. Removing the bridge would require rewriting all 14 providers, which is out of scope.- Overrides:
afterInvocationManagerin classorg.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration
-
runAsManager
protected org.springframework.security.access.intercept.RunAsManager runAsManager()Return the existingrunAsManagerbean (RunAsManagerImplwith theGROUP_role prefix and the configured run-as key). This is what@Secured("RUN_AS_ADMIN")needs to elevate authentications for signup / user-management flows.- Overrides:
runAsManagerin classorg.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration
-