I would like to add salt like:
PasswordEncoder encoder = new ShaPasswordEncoder();
userDetails.setPassword(encoder.encodePassword(userDetails.getPassword(),saltSource.getSalt(userDetails));
as far userDetails is instance of my custom UserDetail class,i obliged to cast it to this spring class:UserDetails
,but as it's logically expected i got in Runtime:
java.lang.ClassCastException: model.UserDetails cannot be cast to org.springframework.security.core.userdetails.UserDetails
config:
<beans:bean id="saultSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<beans:property name="userPropertyToUse" value="username"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<password-encoder hash="sha">
<salt-source user-property="username"/>
</password-encoder>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
How can I configure salt correctly in this case?
ReflectionSaltSource only works with a UserDetails object (I'm assuming that's where you get the class-cast exception?), so you would have to either implement UserDetails or create your own SaltSource implementation which works with your object.
However, I wouldn't use a property of the user as the salt unless you are working with a legacy system which already does this. The username is not a very good salt value. It's much better to use a random salt which is stored with the password. A good example is the BCrypt algorithm. See my answer to this question for an example of using it with Spring Security 3.1. As explained there, BCrypt automatically generates a random salt which it stores in the same string as the hashed password.
Note that there is actually a new PasswordEncoder interface in the Spring Security 3.1 "crypto" package (in org.springframework.security.crypto.password). This doesn't include a salt in the API methods, since it assumes the salt is internally generated (as it is with the BCrypt implementation). The framework will generally accept one of these or the legacy org.springframework.security.authentication.encoding.PasswordEncoder.
Your model.UserDetails class must implement the interface org.springframework.security.core.userdetails.UserDetails - it does not need to be a class org.springframework.security.core.userdetails.User.
You can also have a look at this answer to see how to set up a ReflectionSaltSource for both encoding and decoding passwords, or help You get the bigger picture to follow Luke's great tip on BCryptPasswordEncoder.
I've written a blog post about some of these details here: http://rtimothy.tumblr.com/post/26527448708/spring-3-1-security-and-salting-passwords
Luke wrote the code so he certainly knows what he's talking about, but I see a number of people including myself having a hard time groking this information, hopefully that like will help.
Related
I am working with Spring Websocket (4.1.4 release) and using #SendToUser for sending messages to the current user. But I've a problem. Ours is a multi-tenant platform where username is not unique, instead a combination of username and tenant id is unique. The DefaultUserSessionRegistry keeps a map from username to a list of session ids:
private final ConcurrentMap<String, Set<String>> userSessionIds = new ConcurrentHashMap<String, Set<String>>();
which would not work in my scenario. So is there a way I can plugin my custom UserSessionRegistry implementation?
After a code search, the issue seems related to this line.
I found that this class is extended by WebSocketMessageBrokerConfigurationSupport, which is extended by a #Configuration class (DelegatingWebSocketMessageBrokerConfiguration), so you could try to extend it by yourself, like in this example:
https://github.com/arawn/overview-of-spring4/blob/master/src/main/java/jco/conference/oxquiz/WebSocketConfig.java
I had no time to verify this, but if your problem is only the UserSessionRegistry implementation, this could be the way of overriding that #Bean method.
Update:
After digging a bit more, I found the real entry point to the whole flow: search for the DefaultHandshakeHandler class, having the determineUser method (I cannot add more links because of my low score)
I'm using spring-security 3.1.
I have to implement session concurrency strategy in a way that the maximum number of sessions is specified by user. Here is what I did :
Coded a class extending
org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy and overrode the method
protected int getMaximumSessionsForThisUser(Authentication authentication)
I configured it using namespace configuration :
<security:http>
...
<security:session-management session-authentication-strategy-ref="mySessionAuthenticationStrategy"/>
...
</security:http>
<bean id="mySessionAuthenticationStrategy" class="foo.bar.MySessionAuthenticationStrategy">
<constructor-arg ref="sessionRegistry"/>
</bean>
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
The problem is that "MySessionAuthenticationStrategy" is never called :(
I digged in spring api to see that the following line(70) in SessionManagementFilter is false (preventing any SessionAuthenticationStrategy to be invoked) :
if (!securityContextRepository.containsContext(request))
Why is that ?
I read the documentation where they suggest to set the session authentication strategy in the UsernamePasswordAuthenticationFilter, but it's not an option for me since I'm combining form login with SAML login plus a PreAuthentication mechanism validating authentication token (3 different authentication mechanisms).
Any of you can help ?
Short answer (which is a guess): The problem could be that your pre-auth filter (or other non-form login filter) creates a session without itself invoking the SessionAuthenticationStrategy first.
Long explanation: The line you mentioned is basically checking whether the request has just been authenticated in the current execution of the filter chain without the auth-filter creating a new session. The check inspects if there is a session, and if an auth object has already been saved to the session.
If it finds the session and the saved auth object, that means nothing has to be done: everything has already been arranged regarding authentication and session management either by some other filter, or by the same SessionManagementFilter during processing a previous request earlier in the same session.
The other case is when no session has been created or the (non-anonymous) auth object has not yet been saved in the existing session. Only in this case is it the SessionManagementFilter's responsibility to actully perform session management by invoking the SessionAuthenticationStrategy.
According to your description, this second case never occurs, which means that the session is already created, and the auth object is already saved at this point of execution. That should mean your custom auth filter must have created a session, which is not a problem in itself. The general rule however is that anyone creating a session must first consult the SessionAuthenticationStrategy itself. If your auth filter chooses to ignore it, nothing can be done by the SessionManagementFilter (it cannot undone the session creation, even if the SessionAuthenticationStrategy had raised a veto against the user's authenticatation).
Doublecheck if this is the case, and try avoid creating a session in your pre-auth filter. Note that session creation can also happen in a sneaky way by SaveToSessionResponseWrapper.saveContext() getting called e.g. upon a redirect.
I am authenticating using LDAP, and everything works fine for users within a specific domain. But I'm having difficulty understanding how I can authenticate users that are under a second domain. My current configuration shown below specifies the first domain in the user-search-base. I removed that parameter, in hopes that it would search all domains, but that didn't work. I also tried specifying the domain as part of the user name when prompted, such as domain\user, but this didn't work either.
<security:authentication-manager alias="authenticationManager">
<security:ldap-authentication-provider
user-search-filter="(samaccountname={0})"
user-search-base="dc=domain,dc=company,dc=com"
user-context-mapper-ref="userContextMapper" >
</security:ldap-authentication-provider>
</security:authentication-manager>
<security:ldap-server
url="ldap://some.url.com:3000"
manager-dn="CN=USER1,OU=FacMgr,OU=FAC,OU=Exchange,dc=domain,dc=company,dc=com"
manager-password="xxxx"/>
Will I need to create a custom search, and if so, can someone provide an example in this context?
It appears as though you're using Active Directory, in which case I wonder why you're not using the more basic ActiveDirectoryLdapAuthenticationProvider class.
At any rate, you should be able to accomplish what you need by extending either LdapAuthenticationProvider or ActiveDirectoryLdapAuthenticationProvider, and passing the appropriate domain to the superclass' method.
Create a constructor which accepts two different LdapAuthenticator objects, and add a second 'try' statement in the doAuthentication method's catch (UsernameNotFoundException notFound) statement (after the check against bad credentials). Use whatever approach you like to get the getAuthenticator method to try the second authenticator if the first one fails.
This approach should work, but if both domains have a username of jsmith, but the user in question resides on the second, you may encounter problems -- that is, this is not a particularly good solution, but it is a solution.
To build this all up properly, use a custom authentication filter (extend the UsernamePasswordAuthenticationFilter), and have the LdapAuthenticationProvider.getAuthenticator() method identify the domain from the value passed by the filter (in your custom login form).
You may need different manager accounts, but this is hopefully enough for you to go on.
The trick to making this work is to use ActiveDirectoryLdapAuthenticationProvider. To do this, just make the following changes:
In resources.groovy:
// Domain 1
ldapAuthProvider1(ActiveDirectoryLdapAuthenticationProvider,
"mydomain.com",
"ldap://mydomain.com/"
)
// Domain 2
ldapAuthProvider2(ActiveDirectoryLdapAuthenticationProvider,
"mydomain2.com",
"ldap://mydomain2.com/"
)
In Config.groovy:
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider1', 'ldapAuthProvider2']
This is all the code you need. You can pretty much remove all other grails.plugin.springsecurity.ldap.* settings in Config.groovy as they don't apply to this AD setup.
Documentation:
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ldap-active-directory
I'm beginner in spring security and I have a problem with that((I used spring security 3.1)).
I have a project and I have to read all spring security url pattern from Db instead of springSecurity application context.
how can I do it?
my point is how can I manage access to special url in my java classes instead of use below config in springSecurity application context.
<intercept-url pattern="/customer/showAll" access="hasAnyRole('OPERATOR,ADMIN')"/>
thank you
You can provide your own implementation of FilterInvocationSecurityMetadataSource.
In the Collection getAttributes(Object object) method you can load your patterns and access parameters from DB (see default implementation).
Each pattern must be converted into RequestMatcher object. An access attribute value must be converted into a collection of ConfigAttribute objects. As an input object you will have incoming request. You must populate requestMap from DB.
See here how configure Spring Security to use your own FilterInvocationSecurityMetadataSource implementation instead of default ExpressionBasedFilterInvocationSecurityMetadataSource.
I have a question regarding using Spring Security to protect against SQL injection. First of all, I know that use prepared statement can protect from any SQL injection. But In my project I want to show that use Spring Security could help to protect or mitigate against this kind of attack. what i did so far, i made connection using JDBC & Spring and I applied Spring Security and every thing is fine. My question is in my project i used two ways to protect against SQL injection. The first one is Santizing user input and the second one is using Spring Security. I could pass malicious input through Sanitizaing and I want to show that the role of spring security. for example, I pass this input:
TV' UNION SELECT credit_no From credit;--
In this case how I can tell Spring security that it doesnot give any users the credit number. By the way, I used method security level. Just I want to give me an easy way to analyze the user input to see If it has access to data which he asked such as credit.
I hope that clear
Well, your question is not 100% clear, and it may vary on your architecture, but pre post annotations can work well to grab user input.
You can create your own permission evaluator and check permission for pre authorization in your methods.
#PostFilter("hasPermission(filterObject, 'customoperation')")
public CreditCard getCreditCard(String userInput) {
//
}
and your hasPermission method (that you've read about in the link above) goes something like:
public boolean hasPermission(Authentication authentication,
Object target, Object permission) {
if ("customoperation".equals(permission)) {
//your logic here, returning true or false, filtering the object
}
return false;
}
You can also extend the expression handler to use custom functions. Check this answer.