Skip to content

Commit bb43857

Browse files
committed
Deprecate SecurityMetadataSource
- Updated FAQ to replace SecurityMetadataSource recommendation with AuthorizationManager Issue gh-16772
1 parent 8e9634d commit bb43857

File tree

1 file changed

+75
-39
lines changed
  • docs/modules/ROOT/pages/servlet/appendix

1 file changed

+75
-39
lines changed

docs/modules/ROOT/pages/servlet/appendix/faq.adoc

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -519,73 +519,109 @@ A security-conscious organization should be aware that the benefits of their dil
519519
If you have taken this into account (perhaps by using multiple layers of security within your application), Spring Security lets you fully customize the source of security metadata.
520520
You can make it fully dynamic if you choose.
521521

522-
Both method and web security are protected by subclasses of `AbstractSecurityInterceptor`, which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation.
523-
For web security, the interceptor class is `FilterSecurityInterceptor`, and it uses the `FilterInvocationSecurityMetadataSource` marker interface. The "`secured object`" type it operates on is a `FilterInvocation`. The default implementation (which is used both in the namespace `<http>` and when configuring the interceptor explicitly) stores the list of URL patterns and their corresponding list of "`configuration attributes`" (instances of `ConfigAttribute`) in an in-memory map.
524-
525-
To load the data from an alternative source, you must use an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) to customize the `FilterSecurityInterceptor` bean.
526-
You cannot use the namespace.
527-
You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation`. The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision, based on what the list of returned attributes contains. A basic outline would look something like the following example:
522+
Both method and web security are protected by implementations of `AuthorizationManager`.
523+
For web security, you can supply your own implementation of `AuthorizationManager<RequestAuthorizationContext>` and supply it to the filter chain DSL like so:
528524

529525
[tabs]
530526
======
531527
Java::
532528
+
533529
[source,java,role="primary"]
534530
----
531+
@Component
532+
public class DynamicAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
533+
private final MyExternalAuthorizationService authz;
535534
536-
public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
535+
// ...
537536
538-
public List<ConfigAttribute> getAttributes(Object object) {
539-
FilterInvocation fi = (FilterInvocation) object;
540-
String url = fi.getRequestUrl();
541-
String httpMethod = fi.getRequest().getMethod();
542-
List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
537+
@Override
538+
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
539+
// query the external service
540+
}
541+
}
543542
544-
// Lookup your database (or other source) using this information and populate the
545-
// list of attributes
543+
// ...
546544
547-
return attributes;
548-
}
545+
http
546+
.authorizeHttpRequests((authorize) -> authorize.anyRequest().access(dynamicAuthorizationManager))
547+
----
549548
550-
public Collection<ConfigAttribute> getAllConfigAttributes() {
551-
return null;
552-
}
549+
Kotlin::
550+
+
551+
[source,kotlin,role="secondary"]
552+
----
553+
@Component
554+
class DynamicAuthorizationManager : AuthorizationManager<RequestAuthorizationContext?> {
555+
private val rules: MyAuthorizationRulesRepository? = null
553556
554-
public boolean supports(Class<?> clazz) {
555-
return FilterInvocation.class.isAssignableFrom(clazz);
556-
}
557-
}
557+
// ...
558+
559+
override fun check(authentication: Supplier<Authentication?>?, context: RequestAuthorizationContext?): AuthorizationDecision {
560+
// look up rules from the database
561+
}
562+
}
563+
564+
// ...
558565
566+
http {
567+
authorizeHttpRequests {
568+
authorize(anyRequest, dynamicAuthorizationManager)
569+
}
570+
}
571+
----
572+
======
573+
574+
For method security, you can supply your own implementation of `AuthorizationManager<MethodInvocation>` and supply it to Spring AOP like so:
575+
576+
[tabs]
577+
======
578+
Java::
579+
+
580+
[source,java,role="primary"]
581+
----
582+
@Component
583+
public class DynamicAuthorizationManager implements AuthorizationManager<MethodInvocation> {
584+
private final MyExternalAuthorizationService authz;
585+
586+
// ...
587+
588+
@Override
589+
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
590+
// query the external service
591+
}
592+
}
593+
594+
// ...
595+
596+
@Bean
597+
static Advisor securedAuthorizationAdvisor(DynamicAuthorizationManager dynamicAuthorizationManager) {
598+
return AuthorizationManagerBeforeMethodInterceptor.secured(dynamicAuthorizationManager)
599+
}
559600
----
560601
561602
Kotlin::
562603
+
563604
[source,kotlin,role="secondary"]
564605
----
565-
class MyFilterSecurityMetadataSource : FilterInvocationSecurityMetadataSource {
566-
override fun getAttributes(securedObject: Any): List<ConfigAttribute> {
567-
val fi = securedObject as FilterInvocation
568-
val url = fi.requestUrl
569-
val httpMethod = fi.request.method
570-
571-
// Lookup your database (or other source) using this information and populate the
572-
// list of attributes
573-
return ArrayList()
574-
}
606+
@Component
607+
class DynamicAuthorizationManager : AuthorizationManager<MethodInvocation?> {
608+
private val authz: MyExternalAuthorizationService? = null
575609
576-
override fun getAllConfigAttributes(): Collection<ConfigAttribute>? {
577-
return null
610+
// ...
611+
override fun check(authentication: Supplier<Authentication?>?, invocation: MethodInvocation?): AuthorizationDecision {
612+
// query the external service
578613
}
614+
}
579615
580-
override fun supports(clazz: Class<*>): Boolean {
581-
return FilterInvocation::class.java.isAssignableFrom(clazz)
616+
companion object {
617+
@Bean
618+
fun securedAuthorizationAdvisor(dynamicAuthorizationManager: DynamicAuthorizationManager): Advisor {
619+
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(dynamicAuthorizationManager)
582620
}
583621
}
584622
----
585623
======
586624

587-
For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`.
588-
589625

590626
[[appendix-faq-ldap-authorities]]
591627
=== How do I authenticate against LDAP but load user roles from a database?

0 commit comments

Comments
 (0)