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
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.
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.
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 :)
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.
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);