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.
Related
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
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 :)
How do I fire my method on authentication success?
I wanted to update my database column 'last login date'. Looked around on google but still can't understand how it should be done.
Here is my 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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd"
xmlns:security="http://www.springframework.org/schema/security">
<beans:bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<beans:property name="url" value="jdbc:mysql://localhost:3306/myDB"/>
<beans:property name="username" value="root"/>
<beans:property name="password" value="root"/>
</beans:bean>
<!-- login page are exempted from security-->
<security:http pattern="/login" security="none"/>
<security:http auto-config="true">
<intercept-url pattern="/page1" access="ROLE_USER_ADMIN,ROLE_ADMIN,ROLE_PAGE1" />
<intercept-url pattern="/page2" access="ROLE_USER_ADMIN,ROLE_ADMIN,ROLE_PAGE2" />
<intercept-url pattern="/page3" access="ROLE_USER_ADMIN,ROLE_ADMIN,ROLE_PAGE3" />
<intercept-url pattern="/*" access="ROLE_USER_ADMIN,ROLE_ACCOUNT" /> <!--/** all url -->
<security:session-management>
<security:concurrency-control
max-sessions="2"
expired-url="/login" />
</security:session-management>
<!-- access deny for non privileged user -->
<access-denied-handler error-page="/access-denied" />
<!-- Logout -->
<logout logout-success-url="/login?logout" />
</security:http>
<beans:bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<!-- After login, return to the last visited page -->
<beans:property name="useReferer" value="true" />
</beans:bean>
<beans:bean id="authenticationSuccessHandlerWithoutReferer" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<!-- After login, stay to the same page -->
<beans:property name="useReferer" value="false" />
</beans:bean>
<beans:bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource1"
users-by-username-query="query-for-username-and-password"
authorities-by-username-query="query-for-username-enabled-authority" />
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
I am new to Spring Security. Hope someone could help me out.
EDIT
#Component
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Autowired
AppUserDAO appUserDAO;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String a = df.format(new Date());
System.out.println(authentication.getName()+"### "+a);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getPrincipal().toString();
appUserDAO.updateLastLoginAndIp(a, username);
}
}
You can override authenticationSuccessHandler with any custom implementation you wanted to perform. Here you want to update user login date or some other similar activities
public class CustomAuthenticationSuccessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException,ServletException {
super.onAuthenticationSuccess(request, response, authentication);
//Now add your custom logic to update database
}
}
Now you need to update authenticationSuccessHandler confiuguration in xml file as shown below.
<beans:bean id="authenticationSuccessHandler" class="yourpackage.CustomAuthenticationSuccessHandler">
<beans:property name="useReferer" value="true" />
</beans:bean>
Optionally,
<beans:bean id="authenticationSuccessHandlerWithoutReferer" class="yourpackage.CustomAuthenticationSuccessHandler">
<beans:property name="useReferer" value="false" />
</beans:bean>
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);