|
@@ -519,12 +519,8 @@ A security-conscious organization should be aware that the benefits of their dil
|
|
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.
|
|
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.
|
|
You can make it fully dynamic if you choose.
|
|
You can make it fully dynamic if you choose.
|
|
|
|
|
|
-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.
|
|
|
|
-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.
|
|
|
|
-
|
|
|
|
-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.
|
|
|
|
-You cannot use the namespace.
|
|
|
|
-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:
|
|
|
|
|
|
+Both method and web security are protected by implementations of `AuthorizationManager`.
|
|
|
|
+For web security, you can supply your own implementation of `AuthorizationManager<RequestAuthorizationContext>` and supply it to the filter chain DSL like so:
|
|
|
|
|
|
[tabs]
|
|
[tabs]
|
|
======
|
|
======
|
|
@@ -532,60 +528,100 @@ Java::
|
|
+
|
|
+
|
|
[source,java,role="primary"]
|
|
[source,java,role="primary"]
|
|
----
|
|
----
|
|
|
|
+@Component
|
|
|
|
+public class DynamicAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
|
|
|
|
+ private final MyExternalAuthorizationService authz;
|
|
|
|
|
|
- public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
|
|
|
|
|
|
+ // ...
|
|
|
|
|
|
- public List<ConfigAttribute> getAttributes(Object object) {
|
|
|
|
- FilterInvocation fi = (FilterInvocation) object;
|
|
|
|
- String url = fi.getRequestUrl();
|
|
|
|
- String httpMethod = fi.getRequest().getMethod();
|
|
|
|
- List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
|
|
|
|
|
|
+ @Override
|
|
|
|
+ public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
|
|
|
|
+ // query the external service
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- // Lookup your database (or other source) using this information and populate the
|
|
|
|
- // list of attributes
|
|
|
|
|
|
+// ...
|
|
|
|
|
|
- return attributes;
|
|
|
|
- }
|
|
|
|
|
|
+http
|
|
|
|
+ .authorizeHttpRequests((authorize) -> authorize.anyRequest().access(dynamicAuthorizationManager))
|
|
|
|
+----
|
|
|
|
|
|
- public Collection<ConfigAttribute> getAllConfigAttributes() {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
|
|
+Kotlin::
|
|
|
|
++
|
|
|
|
+[source,kotlin,role="secondary"]
|
|
|
|
+----
|
|
|
|
+@Component
|
|
|
|
+class DynamicAuthorizationManager : AuthorizationManager<RequestAuthorizationContext?> {
|
|
|
|
+ private val rules: MyAuthorizationRulesRepository? = null
|
|
|
|
|
|
- public boolean supports(Class<?> clazz) {
|
|
|
|
- return FilterInvocation.class.isAssignableFrom(clazz);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ // ...
|
|
|
|
+
|
|
|
|
+ override fun check(authentication: Supplier<Authentication?>?, context: RequestAuthorizationContext?): AuthorizationDecision {
|
|
|
|
+ // look up rules from the database
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ...
|
|
|
|
|
|
|
|
+http {
|
|
|
|
+ authorizeHttpRequests {
|
|
|
|
+ authorize(anyRequest, dynamicAuthorizationManager)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+======
|
|
|
|
+
|
|
|
|
+For method security, you can supply your own implementation of `AuthorizationManager<MethodInvocation>` and supply it to Spring AOP like so:
|
|
|
|
+
|
|
|
|
+[tabs]
|
|
|
|
+======
|
|
|
|
+Java::
|
|
|
|
++
|
|
|
|
+[source,java,role="primary"]
|
|
|
|
+----
|
|
|
|
+@Component
|
|
|
|
+public class DynamicAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
+ private final MyExternalAuthorizationService authz;
|
|
|
|
+
|
|
|
|
+ // ...
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
|
|
|
|
+ // query the external service
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ...
|
|
|
|
+
|
|
|
|
+@Bean
|
|
|
|
+static Advisor securedAuthorizationAdvisor(DynamicAuthorizationManager dynamicAuthorizationManager) {
|
|
|
|
+ return AuthorizationManagerBeforeMethodInterceptor.secured(dynamicAuthorizationManager)
|
|
|
|
+}
|
|
----
|
|
----
|
|
|
|
|
|
Kotlin::
|
|
Kotlin::
|
|
+
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
----
|
|
-class MyFilterSecurityMetadataSource : FilterInvocationSecurityMetadataSource {
|
|
|
|
- override fun getAttributes(securedObject: Any): List<ConfigAttribute> {
|
|
|
|
- val fi = securedObject as FilterInvocation
|
|
|
|
- val url = fi.requestUrl
|
|
|
|
- val httpMethod = fi.request.method
|
|
|
|
-
|
|
|
|
- // Lookup your database (or other source) using this information and populate the
|
|
|
|
- // list of attributes
|
|
|
|
- return ArrayList()
|
|
|
|
- }
|
|
|
|
|
|
+@Component
|
|
|
|
+class DynamicAuthorizationManager : AuthorizationManager<MethodInvocation?> {
|
|
|
|
+ private val authz: MyExternalAuthorizationService? = null
|
|
|
|
|
|
- override fun getAllConfigAttributes(): Collection<ConfigAttribute>? {
|
|
|
|
- return null
|
|
|
|
|
|
+ // ...
|
|
|
|
+ override fun check(authentication: Supplier<Authentication?>?, invocation: MethodInvocation?): AuthorizationDecision {
|
|
|
|
+ // query the external service
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- override fun supports(clazz: Class<*>): Boolean {
|
|
|
|
- return FilterInvocation::class.java.isAssignableFrom(clazz)
|
|
|
|
|
|
+companion object {
|
|
|
|
+ @Bean
|
|
|
|
+ fun securedAuthorizationAdvisor(dynamicAuthorizationManager: DynamicAuthorizationManager): Advisor {
|
|
|
|
+ return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(dynamicAuthorizationManager)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
----
|
|
----
|
|
======
|
|
======
|
|
|
|
|
|
-For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`.
|
|
|
|
-
|
|
|
|
|
|
|
|
[[appendix-faq-ldap-authorities]]
|
|
[[appendix-faq-ldap-authorities]]
|
|
=== How do I authenticate against LDAP but load user roles from a database?
|
|
=== How do I authenticate against LDAP but load user roles from a database?
|