I have security configuration via xml. I've added an extra provider. So it looks like this:
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="first" />
<sec:authentication-provider ref="second">
</sec:authentication-provider>
</sec:authentication-manager>
I would like to either use both providers or just one, based on an entry in an app.properties file. Is it even possible ?
Probably the easiest way is to have each AuthenticationProvider answer for itself. There is a supports method that you can implement or there is the option of returning null from authenticate, which indicates that this AuthenticationProvider is abstaining.
Overriding supports
public class FirstAuthenticationProvider implements AuthenticationProvider {
#Value("${myapp.security.usefirst}") boolean useFirst;
#Override
public boolean supports(Class<?> authentication) {
return useFirst && anyOtherTestingNecessary;
}
}
AuthenticationProvider abstains
public class SecondAuthenticationProvider implements AuthenticationProvider {
#Value("${myapp.security.usefirst}") boolean useFirst;
#Override
public Authentication authenticate(Authentication authentication) {
if ( useFirst ) {
return null; // abstain
}
// ... rest of authentication strategy
}
}
If you are using Spring 4 or higher, then you can use the #Conditional annotation to wire each provider conditionally based on your property, though based on your question, I'll forgo that example.
You can, of course, as suggested in a comment, create a wrapper AuthenticationProvider, though this can cause some heartburn depending on your wiring strategy. Also, it is duplicating a little bit of the work that ProviderManager is already intended to do.
Related
I have in a given project the circumstance that I need to extend or overwrite the default AccessDeniedHandler of spring.security. The reason is not important, but I need this to be able to implement custom behaviour whenever a MissingCsrfTokenException or InvalidCsrfTokenException is thrown.
My question is: How to override the org.springframework.security.web.access.AccessDeniedHandler class properly?
Meanwhile I figured out 3 ways which seem to be promising:
Set my custom version of AccessDeniedHandlerImpl when configuring spring.security as instance of my class
Set my custom accessDeniedHandler when configuring spring.security and get it as a bean
Override AccessDeniedHandlerImpl with #Component named AccessDeniedHandler and set it as #Primary
I am new to spring framework and unsure how to solve this the best way.
From my understanding as a technician, I would prefer setting my custom AccessDeniedHandler through spring.security configuration (independent of the way I configure it there). Because using a component will require any other developer to look up for the annotations (but maybe I am wrong with this).
Implementing it through spring security configuration
// in the spring security configuration class
protected void configure(final HttpSecurity http) throws Exception {
http
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());
}
or
// in the spring security configuration class
#Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
protected void configure(final HttpSecurity http) throws Exception {
http
.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
}
As a component override
// in custom AccessDeniedHandler class
#Component
#Primary
public CustomAccessDeniedHandler implements AccessDeniedHandler {
// custom implementation
}
Which will automatically fetch my custom AccessDeniedHandler instead of the default AccessDeniedHandlerImpl defined in org.springframework.security.
Finally the point for me is to figure out, what is the better way to implement this, through configuration or #Component and #Primary.
I want to tag methods in a class with a custom annotation that will control authorization decisions using spring security. For example:
#Role("ADMIN")
public void accessControlledMethod(){}
I understand that this means I somehow need to register my custom annotation "Role" so that it can result in ConfigAttributes being present when an authorization decision is made by the AccessDecisionManager. However, I do not understand how to register my custom annotation with spring security so that it will be recognized.
I see one potential solution in the framework code. There is a class called SecuredAnnotationSecurityMetadataSource whose documentation says "inject AnnotationMetadataExtractor for custom annotations". If that is the preferred method, I'm not sure how to configure the SecuredAnnotationSecurityMetadataSource or how to inject the AnnotationMetadataExtractor into it.
You can extend GlobalMethodSecurityConfiguration in your configuration :
#EnableGlobalMethodSecurity
#Configuration
public class MyMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return SecuredAnnotationSecurityMetadataSource(...);
}
}
In xml, you can do :
<global-method-security metadata-source-ref="customMethodSecurityMetadataSource">
...
</global-method-security>
<bean id="customMethodSecurityMetadataSource" class="org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource">
...
</bean>
customMethodSecurityMetadataSource can be any instanceof MethodSecurityMetadataSource
This is not working in Spring 5 becuase default bean overriding is disabled by default. It works only with spring.main.allow-bean-definition-overriding property set to true.
If anyone have some idea how to add custom MethodSecurityMetadataSource to GlobalMethodSecurityConfiguration without bean override enabling, it will be helpful for newer Spring version
In Spring Boot you can add custom MethodSecurityMetadataSources and AccessDecisionVoters by overriding the corresponding methods in GlobalMethodSecurityConfiguration and adding/modifying the values form the superclass.
#Configuration
#AutoConfigureAfter(SecurityConfiguration.class)
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Override
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
var source = (DelegatingMethodSecurityMetadataSource) super.methodSecurityMetadataSource();
source.getMethodSecurityMetadataSources().add(new FooSecurityMetadataSource());
return source;
}
#Override
protected AccessDecisionManager accessDecisionManager() {
var manager = (AffirmativeBased) super.accessDecisionManager();
manager.getDecisionVoters().add(new FooVoter());
return manager;
}
}
In a web project we have a simple file browser. For security we need some kind of mapping what user roles can read (R) or read+write (RW) in which directories (including their subdirectories).
examples:
UserA with roleA can view files in folderA/
roleA, "folderA/", R
UserB with roleB view and edit files in folderA/ and also view folderB/
roleB, "folderA/", RW
roleB, "folderB/", R
Some of the used technologies in the project so far:
Tapestry
Hibernate
Spring security (only used for users and roles so far)
I've been looking further into Spring Security, but am not sure if I can use a GrantedAuthority implementation (permissions) for my use case.
So my question is if anybody has experience with Spring Security and can point me in the right way. If it's not possible with Spring Security, other library proposals are also appreciated, but I ofcourse prefer using a library that is already being used.
It is possible with Spring Security with some custom code. Annotate your service layer to something like:
#PostAuthorize("hasPermission(returnObject, 'READ')")
public FileObject readFileObject(String path) {
// return the file object from DAO
}
#PreAuthorize("hasPermission(#fileObj, 'WRITE')")
public void writeFileObject(FileObject fileObj) {
// write the file object, security check made at this point
}
Implement the PermissionEvaluator interface, make it a Spring bean. Then enable it in security config with:
#Autowired
private PermissionEvaluator permissionEvaluator;
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
And:
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
I have a custom AuthenticationProvider that simply returns the Authentication object for the authenticate method. What I want to do is add a role to the user when they log in. This is for demo purposes, so all I want is the user to enter a username and let them in. I need to assign them the admin role.
There are, of course, several ways to achieve that.
My preferred one is do this in a custom UserDetailsService. The only method is loadUserByUsername, that will return an instance of UserDetails. When you are constructing your UserDetails, you can add whatever GrantedAuthority you want.
So first, you'll declare your custom UserDetailsService in your application context configuration file:
<bean id="myCustomUDS" class="com.myapp.AppUDS" />
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider user-service-ref="myCustomUDS">
</sec:authentication-provider>
</sec:authentication-manager>
Then you write the class itself:
public class AppUDS implements UserDetailsService {
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
//create your concrete UserDetails
//add your custom role (i.e. GrantedAuthority) to that object (that will be added to all users)
//return it
}
}
Typically, when you declare different "<authentication-provider>" for your application (webapp in my case), Spring Security takes care of invoking providers one after another, incase of failure. So, say I have DatabaseAuthenticationProvider and LDAPAuthenticationProvider with DatabaseAuthenticationProvider declared first in the config file, at runtime, DatabaseAuthenticationProvider is invoked first and if authentication fails, LDAPAuthentication is tried. This is cool - However, what I need is a runtime switch.
I would like to have an option of chosing between these two approaches (database based authentication / ldap based authentication) and somehow swith the implementation based on thsi global setting.
How do I do it? Is it even possible with Spring-Security?
I will leave how to inject your own custom authentication provider to the other myriad of examples from Googleland and here on StackOverflow. It looks like it has to do with marking a particular bean with the xml. But hopefully I can fill in some of the other details for you.
So you've defined the class somewhat like above and I'll add more of the details that you'll need for Spring (i.e. merge the stuff from above as well.
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
....
public List<AuthenticationProvider> getProviders() { return delegateList; }
public void setProviders(List<AuthenticationProvider> providers) {
this.delegateList = providers;
}
....
}
This will allow you to inject a host of providers using spring:
<bean id="customAuthProvider1" class=".....CustomProvider1"> ... </bean>
<bean id="customAuthProvider2" class=".....CustomProvider2"> ... </bean>
...
<bean id="customAuthProviderX" class=".....CustomProviderX"> ... </bean>
<bean id="authenticationProvider" class="....SwitchingAuthenticationProvider">
<security:custom-authentication-provider/>
<!-- using property injection (get/setProviders) in the bean class -->
<property name="providers">
<list>
<ref local="customAuthProvider1"/> <!-- Ref of 1st authenticator -->
<ref local="customAuthProvider2"/> <!-- Ref of 2nd authenticator -->
...
<ref local="customAuthProviderX"/> <!-- and so on for more -->
</list>
</property>
</bean>
In the end how you populate the providers could be any means of getting the delegator a collection of providers. How they map up to which one to use is up to you. The collection could be a named mapped, based on the current state of the delegator. It could be a list of more than one to try. It could be two properties, "get/setPrimary" and "get/setSecondary" for fail-over like functionality. Once you have the delegator injected the possibilities are up to you.
Let me know if this isn't answering your question.
How about writing a delegating AuthenticationProvider that knows how to access your runtime switch and the actual instances of Database/LDAP AuthenticationProvider.
I'm thinking of something like:
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
private List<AuthenticationProvider> delegateList;
private int selectedProvider;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException
{
AuthenticationProvider delegateTo = delegateList.get(selectedProvider);
return delegateTo.authenticate(authentication);
}
....
}