How to change password hashing algorithm when using spring security? - spring

I'm working on a legacy Spring MVC based web Application which is using a - by current standards - inappropriate hashing algorithm. Now I want to gradually migrate all hashes to bcrypt. My high level strategy is:
New hashes are generated with bcrypt by default
When a user successfully logs in and has still a legacy hash, the app replaces the old hash with a new bcrypt hash.
What is the most idiomatic way of implementing this strategy with Spring Security? Should I use a custom Filter or my on AccessDecisionManager or …?

You'll probably have to customize your AuthenticationProvider since that is where the password is actually compared with the user data and you have all the information you need available.
In the authenticate method, you would first load the user data. Then check the user-supplied password with both a BCryptPasswordEncoder and your legacy one. If neither returns a match, throw a BadCredentialsException.
If the user authenticates successfully (very important :-)) and the password is legacy format (the legacy encoder matched), you would then call some additional code to update the user's account data and replace the legacy hash with a bcrypt one. The BCryptPasswordEncoder can be also be used to create new hashes.
If you want, you could detect in advance whether the stored hash was already bcrypt before doing the comparisons. Bcrypt strings have quite a distinct format.
Note also that to make it harder to guess valid account names, you should try to make the method behave the same both when a supplied username exists and when it doesn't (in terms of the time it takes). So call the encoders even when you don't have any user data for the supplied username.

i think best way to do this is to specify password encoder to authentication provider some thing like below, for more information refer doc
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="passwordEncoder">
<salt-source ref="saltSource" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"
id="passwordEncoder" />
<beans:bean class="org.springframework.security.authentication.dao.ReflectionSaltSource"
id="saltSource">
<beans:property name="userPropertyToUse" value="userName" />
</beans:bean>

Related

Spring security - securing method request with hasPermission

The common usage is:
<intercept-url pattern="/**" access"ROLE_ADMIN" />
Is it possible to do something like:
<intercept-url pattern="/**" access"hasPermission("addSomething1") />
I haven't seen hasPermission among security expression listed under allowed:
We have only:
authentication; denyAll; hasAnyRole(list of roles); hasIpAddress; isAnonymous() etc.
I am just guessing if "hasPermission" is allowed for method security then it should be also for web-requests too.
Thanks,
Yap, it is possible. You just need to switch to expression based evaluation
 <security:http use-expressions="true">
and provide PermissionEvaluator to your expression handler:
<security:expression-hanlder ref="webSecurityExpressionHandler" />
<bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler>
<property name="permissionEvaluator" ref="aclPermissionEvaluator" />
</bean>
Of course you need to have PermissionEvaluator implementation. You can write your own or you can use spring-acl project.
Pavel Horal already described how to enable expressions in the intercept-url tag (BTW. After enabled it, all access attributes must been written as SpEl expression!)
But there is one thing you need to know: the expressions that are available for the intercept-url tag differ from them that are available for method based security SpEl expressions (like #PreAuthorize). It is because the first are implemented in WebSecurityExpressoonRoot but the others are implemented in MethodSecurityExpressionRoot.
See my answer at this question stackoverflow.com/questions/8321696/… it describe how to extend the web security expression root with additional expressions.

Programmatically change property value

<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/session-timeout-1.do" />
</beans:bean/>
I have 2 different session-timeout pages for different types of users. After a user logs in, the value of the property may have to change from "/session-timeout-1.do" to "/session-timeout-2.do" after checking the type of the user.
I am wondering that is there an API that can change the property value at runtime?
Or is it possible to have a variable in the config file, e.g.
<beans:property name="loginFormUrl" value="${time-out-url}">
where variable "time-out-url" can be set programmatically?
You could subclass the LoginUrlAuthenticationEntryPoint class and provide your own logic.
See the class source here:
http://git.springsource.org/spring-security/rwinchs-spring-security/blobs/2d271666a406a4409def9afcd73ea340c40a7a88/web/src/main/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.java
Specifically the method:
determineUrlToUseForThisRequest
which "Allows subclasses to modify the login form URL that should be applicable for a given request".

Spring security with Hibernate, store encrypted passwords

I'm sure this has been asked before, but I can't find anything that answers this problem.
With Spring-security, I'm using a password encoder.
<beans:bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
<authentication-manager>
<authentication-provider user-service-ref='CustomUserDetailsService'>
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
Within my UserDAOImpl I have the following code when adding a user...
#Override
public void addUser(final User user) {
user.setPassword(passwordEncoder.encodePassword(user.getPassword(), "salt"));
sessionFactory.getCurrentSession().save(user);
}
My password gets encoded correctly, but always gets read as invalid, which sort of makes sense as I don't know how Spring would know my salt was "salt" - how do you tell spring security as well as Hibernate to use the same salt? Am I missing something about how spring security manages passwords?
The recommended way is to use a standard password encoder, that will use a random salt, ans store this salt with the digested password. This way, you don't need to provide any salt. If you want to provide your own salt, then you need to inject a SaltSource into the DAO authenticator, as explained by the documentation (and of course use the same source when you encode the password to create a new user):
The StandardPasswordEncoder in the crypto package uses a random 8-byte
salt, which is stored in the same field as the password.
Note
The legacy approach to handling salt was to inject a SaltSource into
the DaoAuthenticationProvider, which would obtain a salt value for a
particular user and pass it to the PasswordEncoder. Using a random
salt and combining it with the password data field means you don't
have to worry about the details of salt handling (such as where the
the value is stored), as it is all done internally. So we'd strongly
recommend you use this approach unless you already have a system in
place which stores the salt separately.
In your case, the SaltSource would always return the "salt". Note that this way of salting is insecure, because all the users sharing a common password (yes, it happens) end up with the same hashed password. This means that an attacker finding the password of one user also finds the password of all the users sharing the same password.

Spring Security: custom userdetails

I'm pretty new to Java and Spring 3 (used primarily PHP the past 8 years). I've gotten spring security 3 to work with all the default userDetails and userDetailsService and I know I can access the logged in user's username in a controller by using:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName(); //get logged in username
But there are two problems I can't figure out:
There are a lot of other user details I would like stored when a user logs in (such as DOB, gender, etc.) and to be accessible via the controllers later on. What do I need to do so that the userDetails object that is created contains my custom fields?
I'm already calling "HttpSession session = request.getSession(true);" at the top of each of my methods in my controller. Is it possible to store the logged in user's userDetails in a session upon login so that I don't need to also call "Authentication auth = SecurityContextHolder.getContext().getAuthentication();" at the beginning of every method?
Security-applicationContext.xml:
<global-method-security secured-annotations="enabled"></global-method-security>
<http auto-config='true' access-denied-page="/access-denied.html">
<!-- NO RESTRICTIONS -->
<intercept-url pattern="/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/*.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!-- RESTRICTED PAGES -->
<intercept-url pattern="/admin/*.html" access="ROLE_ADMIN" />
<intercept-url pattern="/member/*.html" access="ROLE_ADMIN, ROLE_STAFF" />
<form-login login-page="/login.html"
login-processing-url="/loginProcess"
authentication-failure-url="/login.html?login_error=1"
default-target-url="/member/home.html" />
<logout logout-success-url="/login.html"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" authorities-by-username-query="SELECT U.username, UR.authority, U.userid FROM users U, userroles UR WHERE U.username=? AND U.roleid=UR.roleid LIMIT 1" />
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
login.jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<tiles:insertDefinition name="header" />
<tiles:insertDefinition name="menu" />
<tiles:insertDefinition name="prebody" />
<h1>Login</h1>
<c:if test="${not empty param.login_error}">
<font color="red"><c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.<br /><br /></font>
</c:if>
<form name="f" action="<c:url value='/loginProcess'/>" method="POST">
<table>
<tr><td>User:</td><td><input type='text' name='j_username' value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' /></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password' /></td></tr>
<tr><td> </td><td><input type="checkbox" name="_spring_security_remember_me" /> Remember Me</td></tr>
<tr><td> </td><td><input name="submit" type="submit" value="Login" /></td></tr>
</table>
</form>
<tiles:insertDefinition name="postbody" />
<tiles:insertDefinition name="footer" />
There's an awful lot going on in this question. I'll try to address it in pieces...
Q#1: There are a couple possible approaches here.
Approach #1: If you have other attributes that you want to add to your UserDetails object, then you should provide your own alternate implementation of the UserDetails interface that includes those attributes along with corresponding getters and setters. This would require that you also provide your own alternate implementation of the UserDetailsService interface. This component would have to understand how to persist these additional attributes to the underlying datastore, or when reading from that datastore, would have to understand how to populate those additional attributes. You'd wire all of this up like so:
<beans:bean id="userDetailsService" class="com.example.MyCustomeUserDetailsService">
<!-- ... -->
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
<beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
Approache #2: Like me, you may find (especially over the span of several iterations) that you're better served to keep domain-specific user/account details separate from Spring Security specific user/account details. This may or may not be the case for you. But if you can find any wisdom in this approach, then you'd stick with the setup you have currently and add an additional User/Account domain object, corresponding repository/DAO, etc. If you want to retrieve the domain-specific user/account, you can do so as follows:
User user = userDao.getByUsername(SecurityContextHolder.getContext().getAuthentication().getName());
Q#2: Spring Security automatically stores the UserDetails in the session (unless you've explicitly taken steps to override that behavior). So there's no need for you to do this yourself in each of your controller methods. The SecurityContextHolder object you've been dealing with is actually populated (by SS) with SecurityContext including the Authentication object, UserDetails, etc. at the beginning of every request. This context is cleared at the end of each request, but the data always remains in the session.
It's worth noting, however, that it's not really a great practice to be dealing with HttpServletRequest, HttpSession objects, etc. in a Spring MVC controller if you can avoid it. Spring almost always offers cleaner, more idiomatic means of achieving things without the need for doing so. The advantage to that would be that controller method signatures and logic cease to be dependent on things that are difficult to mock in a unit test (e.g. the HttpSession) and instead of dependent on your own domain objects (or stubs/mocks of those domain objects). This drastically increases the testability of your controllers... and thus increases the liklihood that you actually WILL test your controllers. :)
Hope this helps some.
In my opinion, Custom UserDetails implementation is great but should only be used for immutable characteristics of your user.
Once your custom User object overrides UserDetails, it's not easily changed. You have to create a whole new authentication object with the modified details and cannot just stick the modified UserDetails object back into the security context.
In application that I'm building I've realized this and had to rearchitect it so that upon successful authentication details about the user that are changing with every request (but that I don't want to reload from the db on every page load) are going to need to be kept in the session separately, but still only accessible/changeable after an authentication check.
Trying to figure out if this WebArgumentResolver mentioned in https://stackoverflow.com/a/8769670/1411545 is a better solution for my situation.
Accessing the session directly is a bit messy, and can be error prone. For example, if the user is authenticated using remember-me or some other mechanism which doesn't involve a redirect, the session won't be populated until after that request completes.
I would use a custom accessor interface to wrap the calls to the SecurityContextHolder. See my answer to this related question.

Dynamically configuring java beans based on property file in Spring

Wondering if there is a way to dynamically instantiate beans based on set of values in your property file using PropertyPlaceholderConfigurer class.
I have a java bean say Student with two attributes: "name" and "subject"
I have a property file with:
student.1.name=student1name
student.1.subject=student1subject
student.2.name=student2name
student.2.name=student2subject
Now I have a Classroom object that can take a list of students.
I am wondering if there is a way we could do this using Spring. The challenge here is that the number of students could vary.
If there was only one student object then:
<bean id="student" class="com.abc.Student">
<property name="name" value="${student.1.name}" />
<property name="subject"
value="${student.1.subject}" />
</bean>
<bean id="classRoom" class="com.abc.ClassRoom">
<property name="student" ref="student" />
</bean>
would have worked. But in this case we have a list of n Students. And the value of n could vary depending on the number of entries in the properties file.
I'm with Kevin--IMO you're going about this the wrong way.
One possible workaround would be to create a bean that takes the property file as an argument, reads it in, and exposes a list of students (which would need to be indexed on something, like the n in the existing property file).
The classroom bean could then use that list of students.
But it sure looks like you're trying to duplicate the functionality of a DB, without a DB, in an awkward way.
I don't think there's a way to do that with PropertyPlaceholderConfigurer. Usually when I have a situation like that I choose a configuration format of either JSON or XML and use GSON/Jackson/JAXB to unmarshall the data into objects.

Resources