spring security can't execute authentication-success-handler-ref - spring

this is my spring-security.xml,
<http auto-config="true">
<access-denied-handler error-page="/accessDenied" />
<form-login login-page="/login"
authentication-success-handler-ref="mySuccessHandler"
authentication-failure-url="/loginError" />
<logout invalidate-session="true" logout-success-url="/main"
logout-url="/logout" delete-cookies="JSESSIONID" />
<remember-me key="j_spring_security_rememberme"/>
<intercept-url pattern="/**" access="ROLE_ADMIN"/>
<session-management invalid-session-url="/login"
session-fixation-protection="none">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="false" />
</session-management>
<session-management
session-authentication-strategy-ref="sas" />
</http>
<!-- 验证成功后跳转的方法 -->
<beans:bean id="mySuccessHandler" class="mocha.cms.security.LoginSuccessHandle" >
</beans:bean>
<!-- authentication-manager 设置alias别名 -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="defaultUserDetailServiceImpl">
<password-encoder hash="md5" base64="false">
<salt-source user-property="username" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="defaultUserDetailServiceImpl" class="mocha.cms.security.MyUserDetailServiceImpl" />
and after i click "login" button, it jumpped into MyUserDetailServiceImpl , and finish it,but then can't execut LoginSuccessHandle, what's wrong with it ?
this is the MyUserDetailServiceImpl.java
Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
AdminVo loginAdmin = adminService.getAdminByName(username);
if(loginAdmin == null){
throw new UsernameNotFoundException(username);
}
List<String> permissionIdList = ImmutableList.copyOf(Splitter. on( ",").omitEmptyStrings().split(loginAdmin.getPermissionId()));
for (String permissionId : permissionIdList) {
auths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
boolean enables = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
User user = new User(username, loginAdmin.getPassword(), enables, accountNonExpired, credentialsNonExpired, accountNonLocked,
auths);
return user;
this is LoginSuccessHandle.java
public class LoginSuccessHandle implements AuthenticationSuccessHandler{
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,ServletException {
String path = request.getContextPath() ;
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
response.sendRedirect(basePath+"manage/folder/allList.htm");
}
}

i resolved it , the problem is that the way of encryption,i used md5, not with salt,so,delete the code of <salt-source user-property="username" /> is ok

Related

Spring SwitchUserFilter working in Spring Security XML file and web.xml

I have a problem of switchuser in spring. I am new for switchuser and not getting the right way to solve this.
Here is my code:
Spring-Security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <http pattern="/index" security='none' />
<http pattern="/passwordrecovery" security='none' />
<beans:bean id="customAuthenticationSuccessHandler" class="com.ds4u.project.handler.CustomAuthenticationSuccessHandler"/>
<http auto-config="true" use-expressions="true"
authentication-manager-ref="authenticationManager">
<headers>
<cache-control />
</headers>
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<!-- role based URL protection -->
<intercept-url pattern="/admin/**" access= "hasRole('ROLE_ADMIN','ROLE_PREVIOUS_ADMINISTRATOR')" />
<intercept-url pattern="/user/**" access= "hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_POWER_USER','ROLE_PATIENT')" />
<intercept-url pattern="/patient/**" access= "hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_POWER_USER','ROLE_PATIENT')" />
<intercept-url pattern="/welcome/**" access= "hasAnyRole('ROLE_ADMIN','ROLE_NEW_PATIENT')" />
<intercept-url pattern="/poweruser/power**" access= "hasAnyRole('ROLE_ADMIN','ROLE_POWER_USER','ROLE_PROVIDER')" />
<intercept-url pattern="/provider/**" access= "hasAnyRole('ROLE_ADMIN','ROLE_POWER_USER','ROLE_PROVIDER')" />
<intercept-url pattern="/switchUser" access="hasAnyRole('ADMIN', 'ROLE_PREVIOUS_ADMINISTRATOR')"/>
<!-- It will handle user login authentication -->
<form-login login-page="/login" authentication-success-handler-ref="customAuthenticationSuccessHandler"
authentication-failure-url="/loginerror"/>
<logout logout-success-url="/" logout-url="/jlogout" delete-cookies="JSESSIONID"/>
<!-- csrf prtoection configuration -->
<csrf disabled="true" />
<!-- unauthorized access handler -->
<access-denied-handler error-page="/accessdenied" />
</http>
<beans:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<beans:property name="userDetailsService" ref="com.ds4u.project.service.UserDetailServiceImpl"/>
<beans:property name="switchUserUrl" value="/admin/impersonate"/>
<beans:property name="targetUrl" value="/admin/adminProvider"/>
<beans:property name="switchFailureUrl" value="/admin/switchUser"/>
<beans:property name="successHandler" ref="authenticationManager" />
</beans:bean>
<authentication-manager id="authenticationManager">
<authentication-provider>
<password-encoder ref="encoder"/>
<jdbc-user-service data-source-ref="DatabaseName"
users-by-username-query="
select UserName,Password, IsEnable from user where UserName = ? and IsEnable in(1,4)"
authorities-by-username-query=" select u.username, ur.authority from user u,
authorities ur where u.authorityId = ur.id and u.username =? " />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10" />
</beans:bean></beans:beans>
What will be the swithuserurl, targetUrl, switchFailureUrl, successHandler in switchuserprocessingfilter bean?
My Web.XML is.
<filter><filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter><filter-name>switchUserProcessingFilter</filter-name>
<filter-class>
org.springframework.security.web.authentication.switchuser.SwitchUserFilter
</filter-class>
</filter>
<filter-mapping><filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping><filter-name>switchUserProcessingFilter</filter-name>
<url-pattern>/"what can be put here?"</url-pattern>
</filter-mapping>
In web.xml what will be the filterMapping for switchUserProcessingFilter filter name?
My CustomAuthenticationSuccessHandler code is---
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
HttpSession session = request.getSession();
/* Set some session variables */
User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
session.setAttribute("uname", authUser.getUsername());
session.setAttribute("auhtorities", authUser.getAuthorities());
/* Set target url to redirect */
String targetUrl = determineTargetUrl(authentication);
redirectStrategy.sendRedirect(request, response, targetUrl);
}
protected String determineTargetUrl(Authentication authentication){
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
if(authorities.contains("ROLE_USER")){
return "/user/userhome";
}else if(authorities.contains("ROLE_ADMIN")){
return "/admin/home";
}else if(authorities.contains("ROLE_POWER_USER")){
return "/poweruser/poweruserhome";
}
else if(authorities.contains("ROLE_PATIENT")){
return "/patient/home";
}
else if(authorities.contains("ROLE_PROVIDER")){
return "/provider/home";
}
else if(authorities.contains("ROLE_NEW_PATIENT")){
return "/welcome/home";
}
return "accessdenial.do";
}
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}
What will be the code in userdetailsservice class as it reference in switchUserProcessingFilter bean in security xml?
When I was running this code then it gives me the error like:
Error creating bean with name
'org.springframework.security.filterChains': Cannot resolve reference
to bean
'org.springframework.security.web.DefaultSecurityFilterChain#2'
I copied SWITCHUSERFILTER from Google and somewhere but it is not processing and is giving errors.

Spring Security 4.1 upgrade - HttpServletRequest isUserInRole returning false

After login successfully, isUserInRole method of HttpServletRequest class is returning false. It was returning true prior to Spring Security version upgrade to 4.1.3.
spring-security-core-4.1.3, spring-security-web-4.1.3, and spring-security-config-4.1.3 jars are present in the class-path
Spring-Security.xml
...
<spring:bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
</spring:bean>
<spring:bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter"/>
<spring:bean id="webExpressionVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter" />
<spring:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<spring:constructor-arg>
<spring:list>
<spring:ref bean="roleVoter"/>
<spring:ref bean="authenticatedVoter"/>
<spring:ref bean="webExpressionVoter"/>
</spring:list>
</spring:constructor-arg>
</spring:bean>
<security:http access-decision-manager-ref="accessDecisionManager" use-expressions="true">
<security:intercept-url pattern="/login.jsp" access="hasAuthority('ROLE_ANONYMOUS')" />
<security:intercept-url pattern="/index*" access="hasAuthority('ROLE_USER')"/>
<security:form-login login-page="/login.jsp"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/accessDenied.jsp" />
<security:logout invalidate-session="true" delete-cookies="JSESSIONID"/>
<security:csrf disabled="true"/>
</security:http>
<security:authentication-manager alias="secAuthManager">
<security:authentication-provider ref="securityProvider" />
</security:authentication-manager>
<spring:bean id="securityProvider" class="com.SecurityProvider"/>
...
class SecurityProvider
public class SecurityProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
...
List<GrantedAuthority> grantedAuthorities = ...
return new UsernamePasswordAuthenticationToken(user, password, grantedAuthorities);
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
If I replaces 4.1.3 security jars with 3.2.9 version and remove <security:csrf disabled="true"/> from Spring-Security.xml then it works.
The issue got resolved after adding ROLE_ prefix for each GrantedAuthority in List<GrantedAuthority> grantedAuthorities.

Spring security jdbc config to auth user with multiple roles

I am currently working on a java based invoice app.
What I need is , to auth a user with multiple Roles, e.g Peter should have role ROLE_SETTING,ROLE_REPORT,ROLE_QUOTE, while Anne only has one role ROLE_SETTING etc...
Here is my spring-security-config.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.2.xsd">
<http auto-config="true">
<access-denied-handler error-page="/403page" />
<intercept-url pattern="/makebill*" access="ROLE_ADMIN,ROLE_MAKEBILL" />
<intercept-url pattern="/report*" access="ROLE_ADMIN,ROLE_REPORT" />
<intercept-url pattern="/stock*" access="ROLE_ADMIN,ROLE_STOCK" />
<intercept-url pattern="/customer*" access="ROLE_ADMIN,ROLE_CUSTOMER" />
<!-- <intercept-url pattern="/setting*" access="ROLE_ADMIN,ROLE_SETTING" /> -->
<intercept-url pattern="/mainmenu*" access="ROLE_ADMIN,ROLE_MAKEBILL,ROLE_SETTING,ROLE_CUSTOMER,ROLE_REPORT,ROLE_STOCK" />
<form-login
login-page='/login' username-parameter="username"
password-parameter="password" default-target-url="/mainmenu"
authentication-failure-url="/login?authfailed" />
<logout logout-success-url="/login?logout" />
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from person where username=?"
authorities-by-username-query="select username, role from person, role where username =? " />
</authentication-provider>
</authentication-manager>
</beans:beans>
the authentication-manager currently working fine with just one role, what i mean is...when the sql query authorities-by-username-query="select username, role from person, role where username =? " runs, if the returned value is just one role, e.g ROLE_REPORT, the application works fine, but if have a record in db like, ROLE_REPORT,ROLE_SETTING,ROLE_CUSTOMER , when the query retrieves this value, the application will return me 404 error, it seems I won't be able to grant a user with multiple roles.
Can anyone please point me out what I have done wrong.
Thanks.
I found a solution myself, implemented my own UserDetails, here are the code
#Service("assembler")
public class Assembler {
#Transactional(readOnly = true)
User buildUserFromUserEntity(Person person) {
String username = person.getUsername();
String password = person.getPassword();
boolean enabled = true;
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
String[] authStrings = person.getRole().split(",");
for(String authString : authStrings) {
System.out.println("all auth roles: " + authString);
authorities.add(new SimpleGrantedAuthority(authString));
}
User user = new User(username, password, enabled,
true, true, true, authorities);
return user;
}
}
#Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired private PersonService personService;
#Autowired private Assembler assembler;
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = null;
Person person = null;
List<Person> listPeople = personService.listPeople();
for (Person p: listPeople) {
if (p.getUsername().equals(username)) {
person = p;
}
}
if (person == null)
throw new UsernameNotFoundException("user not found");
return assembler.buildUserFromUserEntity(person);
}
}
and here is the spring-security-config.xml
<http auto-config="true">
<access-denied-handler error-page="/403page" />
<intercept-url pattern="/makebill*" access="ROLE_ADMIN,ROLE_MAKEBILL" />
<intercept-url pattern="/report*" access="ROLE_ADMIN,ROLE_REPORT" />
<intercept-url pattern="/stock*" access="ROLE_ADMIN,ROLE_STOCK" />
<intercept-url pattern="/customer*" access="ROLE_ADMIN,ROLE_CUSTOMER" />
<intercept-url pattern="/setting*" access="ROLE_ADMIN,ROLE_SETTING" />
<intercept-url pattern="/mainmenu*" access="ROLE_ADMIN,ROLE_MAKEBILL,ROLE_SETTING,ROLE_CUSTOMER,ROLE_REPORT,ROLE_STOCK" />
<form-login
login-page='/login' username-parameter="username"
password-parameter="password" default-target-url="/mainmenu"
authentication-failure-url="/login?authfailed" />
<logout logout-success-url="/login?logout" />
</http>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>
I am now able to assign multiple roles to a single user perfectly.
Thanks for reading :)

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

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.

Spring Auto Login Intercept URL issue

I'm able to use the below to store a user in the SecurityContext and I get a valid Authentcation object (says im authenticated and has user_role attached) but then I still get routed to my /auth/login.html page. I stepped the code below and it is returning the "/registered/home.html" to JSF but for some reason when Spring applies the intercept rule to /registered/* it must see it as being an unauthenticated request. Any ideas?
#Named
#Scope("request")
public class SignUpDetail extends BaseAction{
#Inject
private SignUpDetailBean signUpDetailBean;
#Inject
private UserManager userManager;
#Inject #Named("am")
protected AuthenticationManager authenticationManager;
public String login(){
if(signUpDetailBean.getEmail() != null){
Users currentUser = userManager.getUser(signUpDetailBean.getEmail());
authenticateUserAndSetSession(currentUser, (HttpServletRequest) FacesUtils.getExternalContext().getRequest());
return "/registered/home.html";
}else{
return "/auth/login.html";
}
}
private void authenticateUserAndSetSession(Users user,
HttpServletRequest request)
{
UserDetails details = userManager.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken usernameAndPassword =
new UsernamePasswordAuthenticationToken(
user.getUsername(), "pwd", details.getAuthorities());
// Authenticate, just to be sure
Authentication auth = authenticationManager.authenticate(usernameAndPassword);
// Place the new Authentication object in the security context.
SecurityContextHolder.getContext().setAuthentication(auth);
}
<context:annotation-config />
<context:component-scan base-package="dc" />
<global-method-security />
<http security="none" pattern="/javax.faces.resource/**" />
<http security="none" pattern="/services/rest-api/1.0/**" />
<http security="none" pattern="/preregistered/*" />
<http access-denied-page="/auth/denied.html">
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/**"
access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS" />
<intercept-url
pattern="/registered/*"
access="ROLE_USER" />
<intercept-url
pattern="/*"
access="ROLE_ANONYMOUS" />
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/registered/home.html"
authentication-failure-url="/auth/login.html" />
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/auth/logout.html"/>
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<remember-me user-service-ref="userManager" key="dfdf"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager alias="am">
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
Store the context object in session since you have set that particular url http security to none
...
HttpSession session = request.getSession();
...
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, context);

Resources