Why could a Spring3 Security login work only exactly once until the server is restarted? - spring

Everything works like a charm the first time I login after deployment of my Spring security app. But after the first logout, I can't login again until the service is restarted! Also it seems as if the login was successful, as I can see the users data being loaded in the hibernate sql-log.
Here the relevant code fragments:
applicationContext-security.xml:
<global-method-security pre-post-annotations="enabled" />
<http auto-config="true" use-expressions="true" security="none" pattern="/bookmark/add" />
<http auto-config="true"
use-expressions="true"
access-denied-page="/user/login"
disable-url-rewriting="true">
<intercept-url pattern="/dashboard/**" access="isAuthenticated()" />
<intercept-url pattern="/user/**" access="permitAll" />
<intercept-url pattern="/**" access="permitAll" />
<form-login
default-target-url="/dashboard"
login-page="/user/login"
login-processing-url="/user/doLogin"
authentication-failure-url="/user/login/error"
username-parameter="email"
password-parameter="password" />
<logout logout-success-url="/user/logout"
logout-url="/user/doLogout"
invalidate-session="true"
delete-cookies="true" />
<remember-me services-ref="rememberMeServices" key="myfancysalt" />
<session-management invalid-session-url="/user/login">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="loginUserDetailsService">
<password-encoder ref="passwordEncoder" hash="sha-256">
<salt-source system-wide="myfancysalt" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
<beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<beans:property name="rememberMeServices" ref="rememberMeServices"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<beans:property name="userDetailsService" ref="loginUserDetailsService"/>
<beans:property name="key" value="myfancysalt"/>
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<beans:property name="key" value="myfancysalt"/>
</beans:bean>
LoginController:
#RequestMapping(value = "login", method = RequestMethod.GET)
public String login(Principal principal) {
if (principal != null) { // If user is already logged in, redirect him
return "redirect:/dashboard";
}
return "user/login";
}
#RequestMapping(value = {"login/error", "/user/doLogin"})
public ModelAndView processLogin(Principal principal) {
if (principal != null) { // If user is already logged in, redirect him
return new ModelAndView("redirect:/dashboard", null);
}
HashMap map = new HashMap();
map.put("error", true);
return new ModelAndView("user/login", map);
}
#RequestMapping(value = "logout")
public ModelAndView logout() {
return new ModelAndView("user/logout");
}
The necessary filter in web.xml is present.
Any help is very much appreciated!
### EDIT ###:
The problem lied in the concurrent session limitation. After I removed the following part from the applicationcontext-security.xml, everything works fine. Can someone tell me what's wrong with it? (I just copy/pasted it from some howto).
<session-management invalid-session-url="/user/login">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>

You can try to do:
principal == null
before you logout.

Related

Spring Security logins fail when migrating Spring mvc projects to Spring boot

I migrated a working Spring mvc project to Spring boot. Refer to Section 81.3 of this document and this question. Modules are working properly, but SpringSecurity can not login.
In the open when the home page will jump to the login page, and then log in after the home page and login page repeatedly redirects are 302 HTTP response, and then an error ERR_TOO_MANY_REDIRECTS.
After debugging, when I log on Custom UserDetailsService can correctly find and return UserDetails, custom SimpleUrlAuthenticationSuccessHandler also called onAuthenticationSuccess normally, but in the filter chain in a call FilterSecurityInterceptor this filter, SpringSecurity login status is cleared, I And does not call logout of the HTTP request.
I carefully check that in the set create-session = "stateless" clear the login status is normal, but it seems that my application can not be properly re-authorized. After the request has been SecurityContextHolder.getContext().GetAuthentication().GetPrincipal() has been anonymousUesr (Cookies correctly passed loginKey = b3668242-574a-498e-bd03-243e28dc805c; SESSIONID_HAP = 98963370-8561-40a2-9898-a5e80f7d1186).
This project is more complex, the following is an important part of the configuration and code, and their role is basically the original and the equivalent.
SpringBootConfigure.java SpringBoot enter point.
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#ImportResource({"classpath:/spring/applicationContext*.xml","classpath:/spring/appServlet/servlet*.xml"})
public class SpringBootConfigure {
...
}
spring security xml config
<http access-decision-manager-ref="accessDecisionManager">
<csrf disabled="true"/>
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/login.html" access="permitAll" />
<intercept-url pattern="/verifiCode" access="permitAll" />
<intercept-url pattern="/common/**" access="permitAll" />
<intercept-url pattern="/boot/**" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<access-denied-handler error-page="/403.html"/>
<form-login login-page='/login' authentication-success-handler-ref="successHandler"
authentication-failure-handler-ref="loginFailureHandler"/>
<custom-filter ref="captchaVerifierFilter" before="FORM_LOGIN_FILTER"/>
<logout logout-url="/logout"/>
<headers defaults-disabled="true">
<cache-control/>
</headers>
</http>
<beans:bean id="loginFailureHandler" class="com.hand.hap.security.LoginFailureHandler"/>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="passwordManager"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="captchaVerifierFilter" class="com.hand.hap.security.CaptchaVerifierFilter">
<beans:property name="captchaField" value="verifiCode"/>
</beans:bean>
<beans:bean id="successHandler" class="com.hand.hap.security.CustomAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/index"/>
</beans:bean>

spring rest access in outside of application without login

I have one application using spring 4 and all the methods are rest(using RestController). I used spring-security(role based) for login and authentication url.
Below is my spring-security.xml
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" use-expressions="true">
<security:form-login login-page="/public/login"
default-target-url="/auth/userhome" authentication-failure-url="/public/fail2login" always-use-default-target="true"/>
<security:intercept-url pattern="/index.jsp" access="permitAll" />
<security:intercept-url pattern="/public/**" access="permitAll" />
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:logout logout-success-url="/public/logout" />
<security:intercept-url pattern="/auth/**" access="fullyAuthenticated" />
<security:intercept-url pattern="/**" access="denyAll" />
<security:session-management
session-fixation-protection="migrateSession" invalid-session-url="/login">
<security:concurrency-control
max-sessions="1" expired-url="/login" />
</security:session-management>
</security:http>
<security:authentication-manager>
<security:authentication-provider
user-service-ref="hbUserDetailService">
<security:password-encoder hash="plaintext" />
</security:authentication-provider>
</security:authentication-manager>
</beans>
Service:
package com.arat.budget.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.arat.budget.dao.UserDao;
import com.arat.budget.model.UserRoles;
import com.arat.budget.model.Users;
#Service
public class HbUserDetailsService implements UserDetailsService {
#Autowired
private UserDao userDao;
#SuppressWarnings("unchecked")
#Transactional
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
Users user = userDao.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRoleses());
return buildUserForAuthentication(user, authorities);
}
// Converts com.mkyong.users.model.User user to
// org.springframework.security.core.userdetails.User
private User buildUserForAuthentication(Users user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRoles> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (UserRoles userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
#RestController
public class PostAuthController {
#RequestMapping(value = "/auth/userhome", method = RequestMethod.GET)
public String executeSecurity(ModelMap model, Principal principal) {
String name = principal.getName();
model.addAttribute("author", name);
model.addAttribute("message",
"Welcome To Login Form Based Spring Security Example!!!");
return "auth/welcome";
}
}
I am able to login without any issue. But I have one controller with /auth/employee/{id} and request mapping.
Since /auth/** is fullyAuthenticated so how other application can access the rest endpoint
#RestController
#RequestMapping(value="/auth")
public class EmployeeController{
#RequestMapping("/employee/{id}",method=RequestMethod.GET)
public List<Employee> getEmployee(#PathVariable int id){
return userDao.getEmployee(id);
}
}
Could you please help me how can I access /auth/employee/1001 in another application without login?
Note: I am using tiles to render the page in this application
You can use Basic Authentication for this. Extend BasicAuthenticationEntryPoint class and create a custom implementation of it.
public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
#Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
//Authentication failed, send error response.
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 : " + authException.getMessage());
}
#Override
public void afterPropertiesSet() throws Exception {
setRealmName("MY_TEST_REALM");
super.afterPropertiesSet();
}
}
For more info refer this.
Hope this helps.
I got my solution.
I created a separate api url which will expose only resources and added basic auth filter.
My spring-security.xml looks like below.
<?xml version="1.0"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- Oauth start -->
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager">
<intercept-url pattern="/oauth/token"
access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<http pattern="/api/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<anonymous enabled="false" />
<intercept-url pattern="/api/**" access="ROLE_APP" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<beans:bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="test" />
</beans:bean>
<beans:bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="test/client" />
<beans:property name="typeName" value="Basic" />
</beans:bean>
<beans:bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<beans:bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager" ref="clientAuthenticationManager" />
</beans:bean>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</beans:list>
</beans:constructor-arg>
</beans:bean>
<authentication-manager id="clientAuthenticationManager">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager">
<authentication-provider
user-service-ref="hbUserDetailService">
<password-encoder hash="plaintext" />
</authentication-provider>
<!-- <authentication-provider>
<jdbc-user-service data-source-ref="spring_db_DataSource"/>
</authentication-provider> -->
</authentication-manager>
<beans:bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails" />
</beans:bean>
<beans:bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<beans:bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<beans:property name="tokenStore" ref="tokenStore" />
<beans:property name="supportRefreshToken" value="true" />
<beans:property name="accessTokenValiditySeconds" value="120" />
<beans:property name="clientDetailsService" ref="clientDetails" />
</beans:bean>
<beans:bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<beans:property name="tokenServices" ref="tokenServices" />
</beans:bean>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="test" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="restapp"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_APP" scope="read,write,trust" secret="secret" />
<oauth:client client-id="restapp"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="restapp" authorities="ROLE_APP" />
</oauth:client-details-service>
<!-- <global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<expression-handler ref="oauthExpressionHandler" />
</global-method-security> -->
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<!-- Oauth end -->
<!-- Form based security starts-->
<http auto-config="true" use-expressions="true"
authentication-manager-ref="authenticationManagerForRest">
<form-login login-page="/public/login"
default-target-url="/auth/userhome" authentication-failure-url="/public/fail2login"
always-use-default-target="true" />
<intercept-url pattern="/index.jsp"
access="permitAll" />
<intercept-url pattern="/public/**"
access="permitAll" />
<intercept-url pattern="/resources/**"
access="permitAll" />
<logout logout-success-url="/public/logout" />
<access-denied-handler error-page="/403.html"/>
<intercept-url pattern="/auth/**"
access="fullyAuthenticated" />
<intercept-url pattern="/**" access="denyAll" />
<session-management
session-fixation-protection="migrateSession" invalid-session-url="/login">
<concurrency-control
max-sessions="1" expired-url="/login" />
</session-management>
</http>
<authentication-manager alias="authenticationManagerForRest">
<authentication-provider
user-service-ref="hbUserDetailService">
<password-encoder hash="plaintext" />
</authentication-provider>
</authentication-manager>
<!-- Form based security ends -->
</beans:beans>
deploy the project and to get the access token
localhost:8080/<context>/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=<uer>&password=<password>
it will give the access token using which we can involke the rest end point

Spring Security Pre-Authentication / Login

I did a proof of concept with Spring Security in order to perform pre authentication by using the PRE_AUTH_FILTER filter. It worked OK, but I'd like to know if I can redirect to the login page if the this filter does not work, because I get HTTP 403.
I mean, if the initial request does not contain the SM_USER field in the header, how can I redirect to the login page? I need to consider these two scenarios (when it contains the field - SM_USER -, and when not) and I was not able to get it working. Any ideas about it?
Pra-authentication works smoothly with login authentication in Spring Security. You just setup a working login form configuration, and add the PRE_AUTH_FILTER filter.
Spring only redirects to login page, if after passing the authentication filters, it detects that user is not authenticated when he should be. So if the request contains the expected field in header, the user will be authenticated by the PRE_AUTH_FILTER filter, and will not go to the login page. But if it does not contain one, Spring security will detect a lack of authentication and redirect to login page.
These are my settings:
<http auto-config="true" use-expressions="true" entry-point-ref="http403EntryPoint">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/logout" access="permitAll" />
<intercept-url pattern="/accessdenied" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<custom-filter before="PRE_AUTH_FILTER" ref="siteminderFilter" />
<form-login login-page="/login" default-target-url="/list" authentication-failure-url="/accessdenied" />
<logout logout-success-url="/logout" />
</http>
<beans:bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<beans:property name="principalRequestHeader" value="SM_USER"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="exceptionIfHeaderMissing" value="false" />
</beans:bean>
<beans:bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
<beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:property name="userDetailsService" ref="customUserDetailsService"/>
</beans:bean>
</beans:property>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="employeeDAO" />
<authentication-provider ref="preauthAuthProvider" />
</authentication-manager>
<beans:bean id="customUserDetailsService" class="com.test.security.CustomUserDetailsService"></beans:bean>
<beans:bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></beans:bean>

Cannot make Bcrypt hash to work when password is being checked back

I am using Bcrypt to hash passwords and using Random as per Spring documentation. I am using Spring Security 3.2.5.RELEASE.
I have the following OAuth2 security configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
<beans:bean id="userService" class="com.nando.api.service.DefaultUserService" />
<beans:bean id="webServiceClientService"
class="com.nando.api.service.DefaultWebServiceClientService" />
<beans:bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="webServiceClientService" />
</beans:bean>
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<beans:bean id="webSecurityExpressionHandler"
class="org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler" />
<beans:bean id="methodSecurityExpressionHandler"
class="org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler" />
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<beans:bean id="tokenStore"
class="com.nando.api.service.DefaultAccessTokenService" />
<beans:bean id="oauthRequestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<!-- TODO arguments here -->
<beans:constructor-arg name="clientDetailsService" ref="webServiceClientService" />
<!-- <beans:property name="securityContextAccessor" ref="oauthRequestFactory" /> -->
</beans:bean>
<beans:bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<beans:property name="tokenStore" ref="tokenStore" />
<!-- TODO here -->
<beans:property name="requestFactory" ref="oauthRequestFactory" />
</beans:bean>
<beans:bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<beans:bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" />
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<authentication-manager id="oauthClientAuthenticationManager">
<authentication-provider user-service-ref="clientDetailsUserService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<oauth2:authorization-server
token-services-ref="tokenStore" client-details-service-ref="webServiceClientService"
user-approval-page="oauth/authorize" error-page="oauth/error">
<oauth2:authorization-code />
</oauth2:authorization-server>
<beans:bean id="nonceServices"
class="com.nando.api.service.DefaultOAuthNonceService" />
<beans:bean id="resourceServerFilter"
class="com.nando.api.filters.OAuthSigningTokenAuthenticationFilter">
<beans:property name="authenticationEntryPoint" ref="oauthAuthenticationEntryPoint" />
<beans:property name="nonceServices" ref="nonceServices" />
<beans:property name="tokenStore" ref="tokenStore" />
<beans:property name="resourceId" value="nando" />
</beans:bean>
<global-method-security pre-post-annotations="enabled"
order="0" proxy-target-class="true">
<expression-handler ref="methodSecurityExpressionHandler" />
</global-method-security>
<http security="none" pattern="/resource/**" />
<http security="none" pattern="/favicon.ico" />
<http use-expressions="true" create-session="stateless"
authentication-manager-ref="oauthClientAuthenticationManager"
entry-point-ref="oauthAuthenticationEntryPoint" pattern="/oauth/token">
<intercept-url pattern="/oauth/token" access="hasAuthority('OAUTH_CLIENT')" />
<http-basic />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="webSecurityExpressionHandler" />
</http>
<http use-expressions="true" create-session="stateless"
entry-point-ref="oauthAuthenticationEntryPoint" pattern="/services/**">
<intercept-url pattern="/services/**"
access="hasAuthority('USE_WEB_SERVICES')" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="webSecurityExpressionHandler" />
</http>
<http use-expressions="true">
<intercept-url pattern="/session/list"
access="hasAuthority('VIEW_USER_SESSIONS')" />
<intercept-url pattern="/oauth/**"
access="hasAuthority('USE_WEB_SERVICES')" />
<intercept-url pattern="/login/**" access="permitAll()" />
<intercept-url pattern="/login" access="permitAll()" />
<intercept-url pattern="/logout" access="permitAll()" />
<intercept-url pattern="/**" access="isFullyAuthenticated()" />
<form-login default-target-url="/ticket/list" login-page="/login"
login-processing-url="/login/submit" authentication-failure-url="/login?loginFailed"
username-parameter="username" password-parameter="password" />
<logout logout-url="/logout" logout-success-url="/login?loggedOut"
delete-cookies="JSESSIONID" invalidate-session="true" />
<session-management invalid-session-url="/login"
session-fixation-protection="changeSessionId">
<concurrency-control error-if-maximum-exceeded="true"
max-sessions="1" session-registry-ref="sessionRegistry" />
</session-management>
<csrf />
<expression-handler ref="webSecurityExpressionHandler" />
</http>
</beans:beans>
The problem is:
When it runs it goes to org.springframework.security.authentication.dao.DaoAuthenticationProvider and the method:
additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) fails because the salt is empty.
It should have a Random Salt. This is how I am creating my password and storing on the database. I have verified the retrieved password from the database and it is correct.
UserPrincipal principal = new UserPrincipal();
principal.setUserName(userName);
UUID userID = UUIDs.timeBased();
principal.setUserID(userID);
String salt = BCrypt.gensalt(HASHING_ROUNDS, RANDOM);
byte[] hash = BCrypt.hashpw(password, salt).getBytes();
principal.setHashedPassword(Converters.byteArray2ByteBuffer(hash));
Where:
private static final SecureRandom RANDOM;
static {
try {
RANDOM = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
private static final int HASHING_ROUNDS = 10;
The password is hashed and generated properly. It is saved properly on the database and retrieved properly. But when it gets checked, the presented password is not hashed so that the comparison fails.
First, this.saltSource is null because I have no salt beans defined. I thought this was random and the salt was the old way of doing it.
Now, when looking at the debugger:
if (this.saltSource != null) {
salt = this.saltSource.getSalt(userDetails);
}
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}
The presentedPassword is not hashed and the salt is empty. So the (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) test checks and it fails.
If I am using a Random salt, how can I make this to work? What am I missing?

creating <intercept-url pattern> dynamically with spring security 3

Hi I am new to Spring security 3 but with the help of this site I successfully developed Authentication and Authorization. Now I want to remove intercept-url pattern from my context-security.xml. I am looking to fetch authorities for specific user form database and create dynamically. Here i did...
in context-security.xml
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FIRST" ref="requestMappings"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<beans:property name="objectDefinitionSource" ref="requestMappings" />
</beans:bean>
<beans:bean id="requestMappings" class="com.nmmc.common.security.repository.RequestMappingFactoryBean" />
<http auto-config="true" once-per-request="false">
<!-- Restrict URLs based on role -->
<intercept-url pattern="/login.works" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/login/validate.works" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/css/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-page="/login.works" login-processing-url="/j_spring_security_check"
default-target-url="/login/validate.works"
authentication-failure-url="/login.works" />
<logout logout-url="/j_spring_security_logout"
logout-success-url="/login.works" invalidate-session="true" />
<session-management invalid-session-url="/login.works"
session-fixation-protection="none">
<concurrency-control max-sessions="50"
error-if-maximum-exceeded="true" />
</session-management>
</http>
<authentication-manager>
<authentication-provider ref="customAuthenticationProvider"></authentication-provider>
</authentication-manager>
<beans:bean id="customAuthenticationProvider"
class="com.nmmc.common.security.repository.CustomAuthenticationProvider"></beans:bean>
in RequestMappingFactoryBean
import org.springframework.beans.factory.FactoryBean;
public class RequestMappingFactoryBean implements FactoryBean{
private final static String EOL = System.getProperty("line.separator");
public Object getObject() throws Exception
{
StringBuffer sb = new StringBuffer();
sb.append("CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON");
sb.append(EOL);
sb.append("PATTERN_TYPE_APACHE_ANT");
sb.append(EOL);
sb.append("/**login.works=IS_AUTHENTICATED_ANONYMOUSLY");
sb.append(EOL);
sb.append("/user/**=ROLE_ADMIN");
return sb.toString();
}
public Class getObjectType()
{
return String.class;
}
public boolean isSingleton()
{
return true;
}
}
Also when I remove ref from
<custom-filter before="FIRST" ref="requestMappings"/>
then it gives error that ref must be define also if i define it and run my app it gives error like
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Security namespace does not support decoration of element [custom-filter]
thats why i define as given.
Is there any changes in my code to run it?
Read the first answer at How to dynamically decide <intercept-url> access attribute value in Spring Security?
It has an outline of the solution.

Resources