My web application uses spring security to authenticate user on login. I also have concurrency control to avoid user to login twice on different machine. This is working fine but my problem is that:
If user is login on a machine, then close the browser. And he reopen the web app , try to login again he gets the following msg 'Maximum sessions of 1 for this principal exceeded' . I want to invalidate the session on browser closed. How can I do this?
Spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<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"
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-3.1.xsd">
<security:global-method-security
secured-annotations="enabled" />
<security:http auto-config="false"
authentication-manager-ref="authenticationManager" use-expressions="true">
<!-- Override default login and logout pages -->
<security:form-login
authentication-failure-handler-ref="fail"
authentication-success-handler-ref="success" login-page="/car/login.xhtml"
default-target-url="/jsf/car/home.xhtml" />
<security:logout invalidate-session="true"
logout-url="/j_spring_security_logout" success-handler-ref="customLogoutHandler" delete-cookies="JSESSIONID"/>
<security:session-management>
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:intercept-url pattern="/jsf/**"
access="isAuthenticated()" />
<security:intercept-url pattern="/run**"
access="isAuthenticated()" />
<security:intercept-url pattern="/pages/login.xhtml"
access="permitAll" />
</security:http>
<bean id="success" class="com.car.LoginSuccess" />
<bean id="fail" class="com.car.LoginFailed">
<property name="defaultFailureUrl" value="/?login_error=true" />
</bean>
<bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder"
hash="sha" />
</security:authentication-provider>
</security:authentication-manager>
public class FilterToGetTimeOut extends OncePerRequestFilter {
#Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException {
try {
if(request.getRequestURI().equals("/") || request.getRequestURI().equals("/car/login.xhtml")){
if(request.getSession().getAttribute("login") != null && (Boolean)request.getSession().getAttribute("login") == true){
response.sendRedirect("/jsf/car/home.xhtml"); //After login page
}
} else if(request.getSession().getAttribute("login") == null && !request.getRequestURI().equals("/j_spring_security_logout")){
response.sendRedirect(request.getContextPath()+"/?timeout=true"); //If timeout is true send session timeout error message to JSP
}
filterChain.doFilter(request, response);
} catch (Exception e) {
//Log Exception
}
}
Add below code for "/"(first page) request and logout request.
#Controller
public class LoginController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView loadApp(HttpServletRequest request) {
HttpSession session= request.getSession(false);
SecurityContextHolder.clearContext();
if(session != null) {
session.invalidate();
}
return new ModelAndView("/car/login");
}
}
Use this filter How to get session time out message using Spring security
Related
I am working on a Spring-MVC application in which we are using Spring-Security for authentication and authorization. In our application we send out emails with URL's. Many times the user is not logged in, but after login, we would want to redirect to the original link after login. Thank you. Tried XML configuration, but it is not working.
Xml config :
<!-- Global Security settings -->
<security:http pattern="/resources/**" security="none"/>
<security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true">
<security:form-login login-page="/login" username-parameter="j_username" password-parameter="j_password"
login-processing-url="/j_spring_security_check" default-target-url="/canvaslisting"
always-use-default-target="true" authentication-failure-url="/denied"/>
<security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService"
token-validity-seconds="1209600" data-source-ref="dataSource"/>
<security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/>
<security:intercept-url pattern="/**" requires-channel="https"/>
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
<security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/>
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control session-registry-ref="sessionReg" max-sessions="5" expired-url="/login"/>
</security:session-management>
</security:http>
<beans:bean id="sessionReg" class="org.springframework.security.core.session.SessionRegistryImpl"/>
<beans:bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg index="0" value="_spring_security_remember_me"/>
<beans:constructor-arg index="1" ref="userDetailsService"/>
<beans:constructor-arg index="2" ref="jdbcTokenRepository"/>
<property name="alwaysRemember" value="true"/>
</beans:bean>
<beans:bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="createTableOnStartup" value="false"/>
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<!-- Remember me ends here -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="LoginServiceImpl">
<security:password-encoder ref="encoder"/>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11"/>
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="filterProcessesUrl" value="/login" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler">
<beans:bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="useReferer" value="true"/>
</beans:bean>
</beans:property>
<beans:property name="authenticationFailureHandler">
<beans:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login?login_error=t" />
</beans:bean>
</beans:property>
</beans:bean>
</beans>
Thank you.
Although you have not shown how you have configured your tag, so I am assuming that, you already have, that see bellow code.
<security:http auto-config="true" use-expressions="false">
<security:form-login login-page="/login" login-processing-url="/login"
username-parameter="custom_username"
password-parameter="custom_password"
default-target-url="/appointments/"
always-use-default-target="true"
authentication-failure-url="/login?error=true"
/>
<security:intercept-url pattern="/appointments/*" access="ROLE_USER"/>
<security:intercept-url pattern="/schedule/*" access="ROLE_FOO"/>
<security:intercept-url pattern="/**" access="ROLE_ANONYMOUS, ROLE_USER"/>
</security:http>
so, if you are not mentioning these two lines
default-target-url="/appointments/"
always-use-default-target="true"
, then by default spring security will redirect you user to the same page (which he requested), and got authentication prompt.
If this still does not full fills your requirement then you may need to implement your own filter or take a look at FilterSecurityInterceptor or MethodSecurityInterceptor .
Bellow is an Example, which will help you to achieve your goal:
To understand this problem better, take a look on below example:
- user receives a newsletter mail where he's invited to vote for more beautiful holidays picture. The URL contains a hash parameter used to authenticate user in the page.
- when user clicks on given URL, it will arrive to voting page as already authenticated user.
So My Custom Filter Will be like bellow:
package com.osigu.ehr.config;
public class OneShotActionFilter extends GenericFilterBean {
private static final Logger LOGGER =
LoggerFactory.getLogger(OneShotActionFilter.class);
private static Map<String, String> users = new HashMap<String, String>();
static {
users.put("0000000000001", "bartosz");
users.put("0000000000002", "admin");
users.put("0000000000003", "mod");
}
private static final String PARAM_NAME = "uio";
private AuthenticationManager authenticationManager;
private UserDetailsService userDetailsService;
private final RedirectStrategy redirectStrategy = new
DefaultRedirectStrategy();
private enum AuthenticationStates {
REDIRECT, CONTINUE;
}
public void setAuthenticationManager(AuthenticationManager
authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException,
ServletException {
LOGGER.debug("One shot filter invoked");
if (attemptAuthentication(request) == AuthenticationStates.REDIRECT) {
// Note that we should handle that dynamically but for learning purposes
//we'll consider that one-shot
// authentication works only for this URL
this.redirectStrategy.sendRedirect((HttpServletRequest) request,
(HttpServletResponse) response,
"/secret/one-shot-action");
} else {
LOGGER.debug("User was not correctly authenticated, continue filter chain");
// continue execution of all other filters
// You can test the code without this fragment in the pages without ?uio parameter. You should see blank page because of
// security filter chain interruption.
filterChain.doFilter(request, response);
}
}
private AuthenticationStates attemptAuthentication(ServletRequest request) {
AuthenticationStates state = AuthenticationStates.CONTINUE;
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
String code = request.getParameter(PARAM_NAME);
if ((authentication == null || !authentication.isAuthenticated()) && code !=
null &&
users.containsKey(code)) {
LOGGER.debug("Checking user for code " + code);
UserDetails user = userDetailsService.loadUserByUsername(users.get(code));
LOGGER.debug("Found user from code (" + users.get(code) + "). User found is " + user);
if (user != null) {
users.remove(code);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword());
authentication = this.authenticationManager.authenticate(authRequest);
if (authentication != null && authentication.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authentication);
state = AuthenticationStates.REDIRECT;
}
}
}
return state;
}
}
And Finally Configure it in your xml, like bellow
<security:http authentication-manager-ref="frontend" auto-config="true" use-
expressions="true" access-denied-page="/access-denied">
<-- other filters are defined here -->
<security:custom-filter ref="oneShootAuthFilter"
after="CONCURRENT_SESSION_FILTER"/>
</security:http>
<bean id="oneShootAuthFilter"
class="com.waitingforcode.security.filter.OneShotActionFilter">
<property name="authenticationManager" ref="frontend" />
<property name="userDetailsService" ref="inMemoryUserService" />
</bean>
To test the filter, we can try to access to http://localhost:8080/?uio=0000000000001. You should be redirected (but only once) to http://localhost:8080/secret/one-shot-action page
I wrote this example for better clarity and as reference for future questions.
Do up vote if you think it helped you to clear your doubt.
you can also visit this link
I have a problem. Suppose I login into the application and accessing different pages and leaving the application ideal for 5 min in http://localhost:8080/InformationManagement/smartapp/allFileNetStatus and then trying to access once the session get expired and get redirected to login page.
Once I enter the credentials it get logged in it get me to http://localhost:8080/InformationManagement/smartapp/allFileNetStatus instead of home page(http://localhost:8080/InformationManagement/)
Note: My Login page and Home page URL is same
How can I control this in spring security.
Code:
<http pattern="/resources" security="none" />
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/logout" access="permitAll" />
<intercept-url pattern="/denied" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/user" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/user/create" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/user/update"
access="hasAnyRole('ROLE_READ','ROLE_ADMIN')" />
<intercept-url pattern="/smartapp/getNewFileNetStatus" access="hasRole('ROLE_SMARTAPP')" />
<intercept-url pattern="/smartapp/allFileNetStatus" access="hasRole('ROLE_SMARTAPP')" />
<intercept-url pattern="/user/alluser" access="hasAnyRole('ROLE_READ','ROLE_ADMIN')" />
<intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
<form-login login-page="/login" authentication-failure-url="/login/failure"
default-target-url="/" />
<access-denied-handler error-page="/denied" />
<logout invalidate-session="true" logout-success-url="/logout/success"
logout-url="/logout" />
</http>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"></beans:property>
</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">
<password-encoder hash="md5"></password-encoder>
</authentication-provider>
</authentication-manager>
HomeController.java
#Controller
#RequestMapping("/")
public class HomeController {
/*
* #Value("${msg}") private String msg;
*/
#Autowired
UserDetailsService userService;
Logger logger = Logger.getLogger(HomeController.class);
#RequestMapping(value = "/help", method = RequestMethod.GET)
public String getAdminPage() {
return "help";
}
#RequestMapping(method = RequestMethod.GET)
public String getHomePage(Model model, HttpSession session) {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
/* The user is logged in :) */
if (logger.isInfoEnabled()) {
logger.info("User got logged in...");
}
int passwordResetValue = userService.userPasswordReset(auth
.getName());
session.setAttribute("username",auth.getName());
System.out.println("username-- set-->"+session.getAttribute("username"));
System.out.println("passwordResetValue" + passwordResetValue);
if (passwordResetValue == 0) {
return "home";
} else {
return "redirect:/password/changePassword?value=reset";
}
} else {
if (logger.isInfoEnabled()) {
logger.info("Redirected to Login Page");
}
return "access/login";
}
}
AccessController.java
#Controller
#RequestMapping
public class AccessController {
#RequestMapping(value = "/denied")
public String denied() {
return "access/denied";
}
#RequestMapping("/login")
public String login() {
/*System.out.println("message-->" + message);
model.addAttribute("message", message);*/
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
auth.getPrincipal();
/* The user is logged in :) */
System.out.println("eeee");
return "redirect:/";
} else {
System.out.println("Finalalaay" + auth.getDetails());
return "access/login";
}
}
#RequestMapping(value = "/login/failure")
public String loginFailure(final RedirectAttributes redirect) {
String message = "Please verify username and password";
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
/* The user is logged in :) */
return "redirect:/";
} else {
redirect.addFlashAttribute("message", message);
return "redirect:/login";
}
}
#RequestMapping(value = "/logout/success")
public String logoutSuccess(final RedirectAttributes redirect) {
String message = "You have been successfully logged out.";
redirect.addFlashAttribute("message", message);
return "redirect:/login";
}
}
You should implement your own AuthenticationSuccessHandler for that.
<!-- Add to your form login the handler-->
<form-login login-page="/login" authentication-failure-url="/login/failure"
default-target-url="/" authentication-success-handler-ref="homeRedirectSuccessHandler" />
<beans:bean id="homeRedirectSuccessHandler"
class="your.package.HomeRedirectSuccessHandler" />
And in your HomeRedirectSuccessHandler:
protected void handle(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
redirectStrategy.sendRedirect(request, response, "yourHomepage.html);
}
I am new with RESTful web services in spring,whenever i am requesting the URL through postman,i am getting random generated token from server side, here you are controller code,through this i am getting random generated token.
#RequestMapping(value = "/api/authenticate", method = RequestMethod.POST)
public #ResponseBody
Result doLogIn(#RequestParam("BulkData") String bulkData, HttpServletResponse response) throws Exception {
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = null;
try {
actualObj = mapper.readTree(bulkData);
} catch (IOException e1) {
e1.printStackTrace();
return new Result("Invalid Request", ResultCodes.LOGIN_FAILURE);
}
String userName = actualObj.get("userName").asText();
String password = actualObj.get("password").asText();
logger.debug("[REST]: Attempting login for -> " + userName);
UserDetails details = userDetailService.loadUserByUsername(userName);
// validate password
if (details != null && !details.getPassword().equals(password)) {
logger.debug("[REST]: Invalid username/password");
try {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid username/password");
} catch (IOException e) {
e.printStackTrace();
}
return new Result("Invalid username or password", ResultCodes.LOGIN_FAILURE);
}
// Generate token. ATM, use only username
String generatedToken = Jwts.builder().setSubject(userName)
.setIssuedAt(new Date())
// set token expiration time
.setExpiration(new Date(System.currentTimeMillis() + Config.TOKEN_EXPIRY_PERIOD))
.signWith(SignatureAlgorithm.HS256, servletContext.getInitParameter("API_SECRET_KEY"))
.compact();
// provide token to user in form of a Http Header
response.addHeader(Config.AUTH_TOKEN_HEADER_NAME, generatedToken);
return new Result("Login Success", ResultCodes.LOGIN_SUCCESS_TOKEN_GENERATED);
}
and here is the code for authorization , to do so i am using AuthenticationTokenProcessingFilter,
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
#Autowired
private UserDetailService userDetailService;
#Autowired
private AuthenticationManager authenticationManager;
private static Logger logger = Logger.getLogger(AuthenticationTokenProcessingFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// Exclude login URL
if(req.getRequestURI().endsWith("/api/authenticate")) {
chain.doFilter(req, response);
return;
}
// Client must send token in header
String authHeader = req.getHeader(Config.AUTH_TOKEN_HEADER_NAME);
if (authHeader == null) {
logger.error("[REST]: Authentication header was null...");
throw new ServletException("Missing or invalid Authorization header.");
}
// Parse token, fetch user and reload Security Context
try {
String SECRET_KEY = getServletContext().getInitParameter("API_SECRET_KEY");
Jws<Claims> claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(authHeader);
Claims claim = claims.getBody();
String userName = claim.getSubject();
logger.debug("[REST]: Token of user -> " + userName + " expires: " + claim.getExpiration());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userName, userDetailService.loadUserByUsername(userName).getPassword());
token.setDetails(new WebAuthenticationDetails(req));
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (SignatureException e) {
logger.debug("[REST]: Invalid token");
throw new ServletException("Invalid token.");
}
chain.doFilter(req, response);
// clear security context now because we are going for Stateless Web Services
SecurityContextHolder.getContext().setAuthentication(null);
}
now i want to use this generated token to call this method ,
#RequestMapping(value="/api/admin/getEmployeerole", method=RequestMethod.POST)
public List<EmployeeRole> EmployeeRoleList() {
List<EmployeeRole> getRole=employeeRoleService.getAll();
return getRole;
}
now what is happening here when i am writing this URL to postman and adding generated token into header ,and i have used authorization type (No auth), i have also tried with basic Authorization, still my request is going to customAuthenticationEntrypoint and it throws Access denied exception,that the user Role is annonymous, at server side i am getting status 401 unauthorized.it would be great if someone can help to get over from this..
here You are my spring security configuration..
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="hp.bootmgr.authentication.provider" />
<http pattern="/resources/**" security="none" />
<http pattern="/api/**" realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="customAuthenticationEntryPoint">
<!-- <custom-filter position="FORM_LOGIN_FILTER" /> -->
<intercept-url pattern="/api/authenticate" access="permitAll()" />
<intercept-url pattern="/api/admin/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/api/user/**" access="hasAnyRole('ADMIN', 'EMPLOYEE')" />
<intercept-url pattern="/api/member/**" access="hasAnyRole('ADMIN', 'MEMBER')" />
<!--<form-login
login-page="/api/authenticate"
login-processing-url="/j_spring_security_check"
username-parameter="userName"
password-parameter="password" />-->
<logout logout-url="/logout"/>
<csrf disabled="true"/>
</http>
<http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint">
<access-denied-handler error-page="/403" />
<intercept-url pattern="/login" access="true"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<!-- Allow access to user pages to admin, as long as there is no more other rules-->
<intercept-url pattern="/user/**" access="hasAnyRole('ADMIN', 'EMPLOYEE')" />
<intercept-url pattern="/member/**" access="hasAnyRole('ADMIN', 'MEMBER')" />
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?failed=1"
login-processing-url="/j_spring_security_check"
username-parameter="userName"
password-parameter="password" />
<logout logout-success-url="/login?logout=1" invalidate-session="true" logout-url="/logout"/>
<!-- enable csrf protection -->
<csrf disabled="true"/>
<session-management>
<concurrency-control max-sessions="1" expired-url="/login" />
</session-management>
</http>
<beans:bean id="customAuthenticationEntryPoint" class="hp.bootmgr.web.services.authentication.CustomAuthenticationEntryPoint" />
<beans:bean id="authenticationTokenProcessingFilter" class="hp.bootmgr.web.services.authentication.AuthenticationTokenProcessingFilter" />
<beans:bean id="authenticationEntryPoint" class="hp.bootmgr.security.AuthenticationEntryPoint">
<beans:constructor-arg name="loginUrl" value="/login"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailService" />
</authentication-manager>
</beans:beans>
I am using java config for spring security and I am trying to replace this code with no luck
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
cant find any info about how to use the position in java config
Update i am trying to replace this code by java config but with no luck
<security:http
realm="Protected API"
use-expressions="true"
auto-config="false"
create-session="stateless"
entry-point-ref="unauthorizedEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/rest/user/authenticate" access="permitAll" />
<security:intercept-url method="GET" pattern="/rest/news/**" access="hasRole('user')" />
<security:intercept-url method="PUT" pattern="/rest/news/**" access="hasRole('admin')" />
<security:intercept-url method="POST" pattern="/rest/news/**" access="hasRole('admin')" />
<security:intercept-url method="DELETE" pattern="/rest/news/**" access="hasRole('admin')" />
</security:http>
<bean id="unauthorizedEntryPoint" class="net.dontdrinkandroot.example.angularrestspringsecurity.rest.UnauthorizedEntryPoint" />
<bean class="net.dontdrinkandroot.example.angularrestspringsecurity.rest.AuthenticationTokenProcessingFilter" id="authenticationTokenProcessingFilter">
<constructor-arg ref="userDao" />
</bean>
and this is my AuthenticationTokenProcessingFilter
public class AuthenticationTokenProcessingFilter extends UsernamePasswordAuthenticationFilter
{
private final UserDetailsService userService;
public AuthenticationTokenProcessingFilter(UserDetailsService userService)
{
this.userService = userService;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException
{
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
String authToken = this.extractAuthTokenFromRequest(httpRequest);
String userName = TokenUtils.getUserNameFromToken(authToken);
if (userName != null) {
UserDetails userDetails = this.userService.loadUserByUsername(userName);
if (TokenUtils.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request)
{
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting an HTTP request");
}
return (HttpServletRequest) request;
}
private String extractAuthTokenFromRequest(HttpServletRequest httpRequest)
{
/* Get token from header */
String authToken = httpRequest.getHeader("X-Auth-Token");
/* If token not found get it from request parameter */
if (authToken == null) {
authToken = httpRequest.getParameter("token");
}
return authToken;
}
Hope this is clearer
Here are the filter classes in the order of execution and with the addFilter method of the HttpSecurity class you add your own filters:
#Override
public void configure(HttpSecurity http) throws Exception {
http.addFilter(new AuthenticationTokenProcessingFilter());
...
You have to either extend or provide an instance of the defined Spring filters. The order is based on the class or superclass so you don't have to add the position:
JavaDoc
I want to write my own LDAP authentication provider. I am extending AbstractUserDetailsAuthenticationProvider, which has a method retrieveUser(String username, UsernamePasswordAuthenticationToken authentication).
I want to override this method and write my own data retrieving method. How to do that in Java? How to make an LDAP query and how connect to the LDAP server? I was searching in Internet but I didn't find anything that helped.
EDIT: 22.01.2013
#Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
LdapUser userDetail = null;
log.entry("retrieveUser", authentication.getPrincipal());
UsernamePasswordAuthenticationToken userToken = authentication;
String userName = userToken.getName();
userName = userName != null ? userName.toLowerCase() : userName;
String password = userToken.getCredentials().toString();
try {
if (password == null || "".equals(password)) {
log.debug("retrieveUser", "no password provided");
throw new AuthenticationCredentialsNotFoundException(
"Invalid login or password");
}
}
catch (AuthenticationCredentialsNotFoundException e) {
log.debug("retrieveUser", "no password provided");
}
// connection with ldap and check retrieved username and password
connect = connection(userName, password);
if (connect) {
log.debug("retrieve user", "correct connection with ldap");
userDetail = new LdapUser();
setUserDetails(userDetail, ctx, username);
} else {
log.error("retrieve user", "Failed connection");
}
log.exit("retrieveUser", "user logged: " + userDetail);
return userDetail;
}
My security.xml file
<http auto-config='true'>
<intercept-url pattern="/**/*.ico" filters="none" />
<intercept-url pattern="/**/*.gif" filters="none" />
<intercept-url pattern="/**/*.jpg" filters="none" />
<intercept-url pattern="/**/*.css" filters="none" />
<intercept-url pattern="/**/*.js" filters="none" />
<intercept-url pattern="/**/*.png" filters="none" />
<intercept-url pattern="/logout.jsp*" filters="none" />
<intercept-url pattern="/index.jsp*" filters="none" />
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" />
<logout logout-success-url="/index.jsp"/>
<form-login login-page="/index.jsp"
authentication-failure-url="/error_ldap.jsp"
default-target-url="/main_ldap.jsp" always-use-default-target="true" />
</http>
<authentication-manager>
<authentication-provider ref="ldapAuthenticationProvider">
<password-encoder hash="sha" />
</authentication-provider>
</authentication-manager>
When login is suceed I got redirect to main_ldap.jsp, but if authentication fail, I got this error. I tried to throw exception UsernameNotFoundException instead returning null in retrieveUser method (which is not allowed) but anything happend (only i got this exception).
You can connect to LDAP from java:
http://docs.oracle.com/javase/jndi/tutorial/ldap/security/ldap.html
but spring security already has ldap integration, you can use of the methods described here:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ldap.html
...
xml config for using your own UserDetails service is:
<b:bean id="userDetailsService" class="your.class.here">
</b:bean>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>