Tag Archives: Security

Implementing CSRF protection with Angular-js

After 2 articles on the security, I continue with the set up of the CSRF protection using Spring security.

The main idea behind is to prevent some one else to create (forge) a request without our authorization. Imagine that a page uses JavaScript to send something like http://my.bank.com/pay/15000/cayman_account, if you are connected to your bank in another tab browser, the request could be successful…
To avoid that, for each request, the server sends a unique identifier (Spring uses a UUID) and it must be part of the request you send back to the server.

Fortunately, Angular provides a support for CSRF protection. Following the documentation, the server needs to provide a cookie named XSRF-TOKEN and Angular will send its value in a header named X-XSRF-TOKEN. On the server side, Spring then verifies that the value from the header is the expected one and continue the process, otherwise, it sends an error.

But to make them working together, we need to make some adjustments.
I use the same pet store application I used in my previous article and it is still available on github.

Let’s go to the code!
First of all, on the server side, Spring provides the identifier as a request attribute, because in a standard Spring-MVC application, it is very simple to add it in an HTML form using expression language. But with our SOA approach, we are just sending data, therefore we need to put it in the cookie we send to the browser. To do that, I defined a filter which just take the CSRF token and set a cookie:

@Component
public class CsrfInjectorFilter extends OncePerRequestFilter {

	private static final String XSRF_TOKEN = "XSRF-TOKEN";
	private static final Logger LOG = LoggerFactory.getLogger(CsrfInjectorFilter.class);

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws ServletException, IOException {

		CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
		if (csrfToken != null) {
			Cookie cookie = new Cookie(XSRF_TOKEN, csrfToken.getToken());
			//mandatory to avoid duplicate cookies in browser
			cookie.setPath("/");
			response.addCookie(cookie);
		}else {
			LOG.debug("No csrf token found!!");
		}
		chain.doFilter(request, response);
	}
}

Note: I choose to define the cookie name as Angular expects it, but it also possible to define its name on the client side (using $httpProvider.defaults.xsrfCookieName) and keeping the web service ignore who is the client.

There is also one important thing you must absolutely do (I spent half of a day with that!), you have to set a path to your cookie! Otherwise, for some reasons, the browser does not replace the cookie when it is changed, and it simply manage several cookies with the same name, resulting in CSRF errors on the server side. I tested this issue with Firefox and Chrome.
On the other side, I need to configure Angular to return the header as expected by Spring, this is done in the app.js file:

petstoreApp.config(['$httpProvider', function($httpProvider){
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';
}]);

We can see that the code is very straightforward.

Angular-js and Restful web services access

Following my previous article about the integration of Spring Security with web services, I will now explain how I integrate it with an Angular-js project.
For that purpose, I am a little bit lazy and I use a project I already written instead of building a completely new one.

The project is a “funny” pet-store based on Spring boot (I like it definitely!), using an H2 database and Flyway to restore its content at each start.
The full project is available on Github.

The web services are defined with Spring MVC in the net.classnotfound.pet.web.PetController:

package net.classnotfound.pet.web;
...
@RestController
public class PetController {
	
	@Autowired
	private PetService petService;
	
	@RequestMapping(value = "/pet/all", method = RequestMethod.GET)
	@ResponseBody
	public Collection<JsonPet> findAll() {
		...
	}
	
	@Transactional(propagation= Propagation.SUPPORTS)
	@RequestMapping(value = "/pet/{id}", method = RequestMethod.GET)
	@ResponseBody
	public JsonPet find(@PathVariable("id") final Integer id) {
		...
	}

	@Transactional(propagation= Propagation.REQUIRED)
	@RequestMapping(value = "/pet", method = RequestMethod.POST, consumes = {"application/json" })
	@ResponseStatus(HttpStatus.CREATED)
	public @ResponseBody JsonPet save(@RequestBody final JsonPet jsonPet) {
		...
	}
}

The PetService is the class responsible of business processes (mainly access data here).

We can see that there are 3 actions available to:

  • display the list of pets in the store
  • display the detail of a pet
  • create a “new” pet in the store

The attributes of the requestMapping annotation seem explicit, for example, with @RequestMapping(value = “/pet”, method = RequestMethod.POST, consumes = {“application/json” }), I express that the method can be reach with /pet URL, by using the POST method and it needs json.
Based on Spring, the conversion from Json to Java Object (and the opposite) is totally hidden (it relies on Jackson API) and it avoid this burden to the developer (meaning me, here!).

Now that the landscape is set, let’s have a look at the security configuration (it should be familiar to whose who read my previous article):

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.inMemoryAuthentication().
	  withUser("admin").password("password").roles("ADMIN", "USER").and().
	  withUser("user").password("password").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception { 
	
	http
	.csrf().disable()
	.authorizeRequests()
	.antMatchers("/login").anonymous()
	.antMatchers(HttpMethod.GET, "/pet/**").access("hasRole('USER')")
	.antMatchers(HttpMethod.POST, "/pet/**").access("hasRole('ADMIN')");
	
	http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
	FormLoginConfigurer formLogin = http.formLogin();
	formLogin.loginProcessingUrl("/login");
	formLogin.usernameParameter("username");
	formLogin.passwordParameter("password");
	formLogin.successHandler(authenticationSuccessHandler);
	formLogin.failureHandler(authenticationFailureHandler);
	
}

I started with the users definition with their roles.
And after that, Y can see how I restricted access to the features, as previously, I disabled the CSRF protection but I will come back to it in a next article.

Now, if a unauthenticated user tries to access the protected resources, he will receive an HTTP 401 error. Let’s see how I deal with it on the client side (Angular-js).
The web pages are located in

The idea is to have the generic process to intercept the right HTTP code when the user needs to be authenticated, and redirect him automatically to the login page .
The application is based on the single page principle, for that purpose, I use the ngRoute module, it is configured in the app.js file:

petstoreApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/pets', {
	      templateUrl: 'partials/pet-list.html',
	      controller: 'PetListCtrl'
      }).
      when('/pets/new', {
    	  templateUrl: 'partials/pet-new.html',
    	  controller: 'PetNewCtrl'
      }).
      when('/pets/:petId', {
          templateUrl: 'partials/pet-detail.html',
          controller: 'PetDetailCtrl'
      }).
      when('/login', {
          templateUrl: 'partials/login.html',
          controller: 'LoginCtrl'
        }).
      otherwise({
        redirectTo: '/pets'
      });
  }]);

As expected, we can find our 3 pages related to the web services features and another one to ask credentials to users. This one will be used when redirecting unauthenticated users.
For that purpose, the application is configured with an Angular-js interceptor. All the requests sent or received can be manipulated by interceptor, this is very useful for common purposes like error management or authentication, and it is exactly the way I use it (still in the app.js file):

petstoreApp.factory('errorInterceptor', ['$q', '$location', '$window', '$injector', function($q, $location, $window, $injector) {
	var authSrv;
	var popupSrv;
	var errorInterceptor = {
			'responseError' : function(rejection) {
				var status = rejection.status;
				if (rejection.data){
					if (status == 401) {//Unauthenticated, redirect to login page
						$window.location.href="/#/login";
						return;
					} else if (status == 418) {//undefined error->HTTP code 418 ( I'm a teapot) is responsibility of the caller
						return $q.reject(rejection);
					} else{
						popupSrv = popupSrv || $injector.get('popUpSrv');
						popupSrv.alert("Erreur: "+rejection.data.message+ (rejection.data.stackTrace?"\r\n___________________________________\r\n\r\nErreur complète:\r\n" + rejection.data.stackTrace:''));
						return;
					} 
				} else {
					popupSrv = popupSrv || $injector.get('popUpSrv');
					popupSrv.alert("Erreur inconnue( http status: "+status+")");
					return;
				}
				return $q.reject(rejection);
			}};
	return errorInterceptor;
}]);
petstoreApp.config(['$httpProvider', function($httpProvider) {  
    $httpProvider.interceptors.push('errorInterceptor');
}]);

The interceptor is in charge of managing the HTTP 401 code by redirecting to the login form, and also of the display of a generic message error.
For more information about interceptors and their usage, you can directly have a look at the official site.

And now, it works! The web site can access resources protected with Spring security. In the real world, I should display the new pet button only for admin users, it means that I should also provide a service indicate which actions are available for a user.

For those who missed the point, the sources of the project are available here.

Securing Restful web services using Spring-Security

After several months of silent, I woke up… With some security interests!
The security is a common requirement on many web projects, and fortunately, Spring helps us to implement it.
The most common way to do it is just defining a set of rules and letting Spring manage the login and so on.
In this demo, I will use Spring-boot (for its simplicity) but the security configuration is exactly the same with a web application.
And to be clear, I do not have the pretentiousness that this is THE way to follow when you need to secure your web services and I am convinced that someone else found another way to do it, but this is my solution, I used it several times, and it works perfectly, so maybe it will help someone else… One day 🙂

To start simply, I just built a simple web site with 2 pages:

  • the home page (/index.html), which is freely accessible
  • and another page (/secured/page.html) which is in a restricted area

Using Spring-boot, the structure is something like:

structure

By default, Spring boot published everything under the static directory and is accessible via http://localhost:8080/

For instance, everybody can access to our pages, it’s time to remedy to that state.

Let’s start with the interesting part of the Maven Configuration:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.3.2.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<java.version>1.8</java.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

The starter dependencies are somehow facilitators provided by Spring boot to add some dependencies, I think that we can guess their purpose just by their name. For more information about this pom, you can have a look to the Spring-boot site.

Now, we have to restrict access to the secured part of the site, this is done here:

@Configuration
@EnableWebSecurity
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().
          withUser("admin").password("password").roles("ADMIN", "USER").and().
          withUser("user").password("password").roles("USER");
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception { 
        http
        .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/secured/**").access("hasRole('USER')");
        
        //indicate that we are user login form authentication
        http.formLogin();
    }
}

For the demo, I define my users directly in the application, this is AuthenticationManagerBuilder.inMemoryAuthentication().

Inside the configure(HttpSecurity http) method, you can see that I just defined the URL of the secured part, indicating who can access it based on role.
And finally, I indicate that I want to use the form login authentication as it is provided by Spring.

According to the configuration, the users can access freely the home page, but only the users authenticated and with the right role can access to the secured part. This is a perfect configuration for a standard web site, but remember that we nee to secure a web service, the redirection to a login form is not an acceptable way for that purpose and we need to customise this behavior.

The first issue to solve is to avoid to redirection to the login form in case of unauthenticated access, I do it by changing the AuthenticationEntryPoint with mine:

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
			throws IOException, ServletException {
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
	}
}

As you can see, this is very simple, I just need to send the right HTTP code to inform my client that it needs to authenticate before accessing the resource it requested.
And to indicate to Spring that I slightly changed the authentication, it is very complicated because… Well, it’s Spring, so, I just need to add the following in my SecurityJavaConfig:

[...]
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
[...]
protected void configure(HttpSecurity http) throws Exception {
	http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
}

Now, when someone… As we are dealing with web services,I should say something tries to access to secured resources, it just receives an unauthorized HTTP code instead of a redirection to the login page.
That’s a good point but we have also to manage the successful and erroneous authentication. Instead of redirecting to a page, we have to inform the client that the credentials are valid or not .
For each case, we need to define two different classes:

  • in case of success, we let Spring clean-up the temporary data:
    @Component
    public class RestAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    	@Override
    	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    			Authentication authentication) throws IOException, ServletException {
    		clearAuthenticationAttributes(request);
    	}
    }
    
  • in case of error, we return an HTTP code and an optional message:
    @Component
    public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler{
    	@Override
    	public void onAuthenticationFailure(HttpServletRequest arg0, HttpServletResponse arg1, AuthenticationException arg2)
    			throws IOException, ServletException {
    		arg1.sendError(HttpServletResponse.SC_FORBIDDEN, "Wrong username or password");
    	}
    }
    
  • And then the last step is to add them to the Spring configuration:

    [...]
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;
    
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    [...]
    protected void configure(HttpSecurity http) throws Exception {
    	[...]
    	FormLoginConfigurer formLogin = http.formLogin();
    	[...]
    	formLogin.successHandler(authenticationSuccessHandler);
    	formLogin.failureHandler(authenticationFailureHandler);
    
    }
    

    Now, we can define our web services, and Spring will manage authentication for us.
    To protect your services, obviously, you need to add something like:

    http
    .authorizeRequests()
    [...]
    .antMatchers(HttpMethod.GET, "/secured/services/**")
    .access("hasRole('SERVICE_USER')");
    

    And you can also restrict access by the HTTP methods, someone can read data (GET method) but could not be allowed to modify it (POST/PUT methods).
    That’s it!

    In a next post, I will show how I used it with Angular-js, stay tuned 😀

    (the full project is available on Github)

Add CORS management with Tomcat and Angular-Js

In one of my projects, I decided to setup a SOA architecture using Angular-Js as the UI layer. My main focus is to have a clear separation between the business and the presentation. Another benefit of this is that it is possible the use different servers to these 2 parts.
But doing this causes an issue, because of security, an Ajax request cannot connect to a server which is in another domain from where it is originated. It is done like that to avoid some malicious code executed in a page sends information to another server but in my case, it’s a problem. This behavior is called the Cross-origin Resource Sharing and fortunately, most modern browsers (it excludes IE) can deal with this but the server needs more configuration.
On the server side (Tomcat), there is a provided filter that we need to add to our web configuration (CorsFilter).
In the web.xml, we add:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
    </init-param>
</filter>

I added also some parameters but the default values should be enough.

Now, the server can manage the headers sent by the browser and with this configuration, the filter will automatically allow the request, it is also possible to configure the filter to restrict access to certain domains, but in my case, as I am already in a restricted network, it is not needed.

Another issue I encountered was with the web session. My services need an authenticated user, it is done using an authentication page and a web session. But when the CORS principle is used, by default, the browser does not send the session cookie, to enable it, I added in my Angular app:

var classNotFound = angular.module('classNotFound', ['ngRoute', 'ui.bootstrap', ...])
	.config(['$httpProvider', function($httpProvider) {//mandatory to enable cors feature (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
		$httpProvider.defaults.withCredentials = true;
	}])

Now it works!

Multithreading and Spring Security

I manage a Spring project where I need to create a new thread to launch an asynchronous task. This project uses Spring Security and an Oracle proxy user (I will describe it in a future post), which means that, for each starting transaction, a call is made to the security context to get the current user.
The problem is that the new thread must access the database, then it tries to access the security context managed by Spring. But as Spring Security uses a ThreadLocal to store the security context, I receive the usual NullPointerException.
But fortunately, Spring is a well designed API and I can solve this issue by simply adding the security context to the thread:

public class CalculatorTask{
    public CalculatorTask(final Data data, final MyDao dao, final SecurityContext context) {
        super();
        this.data = data;
        this.myDao = dao;
        this.context = context;
    }

    @Override
    @Transactional
    public void run() {
        LOG.info("Starting asynchronous calculation");
        SecurityContextHolder.setContext(context);
        myDao.doStuff(data);
        //Make here some amazing action
        ...
        LOG.info("Finishing asynchronous calculation");
    }
}

Note that the context is only set in the run() method.

And how I call it:

public class MyClass {
    private static final Logger LOG = LoggerFactory.getLogger(BsBillSetServiceImpl.class);

    @Autowired
    private TaskExecutor executor;

    @Autowired
    private MyDao myDao;

    @Override
    public void calcul(final  Object data) {
        
        SecurityContext context = SecurityContextHolder.getContext();

        CalculatorTask CalculatorTask = new CalculatorTask(data, myDao, context);
        executor.execute(CalculatorTask);
        LOG.info("The calculation has been launched");
    }
}

So simple even if at the first beginning, it was more like “What the f…!!!” 😀

Spring Security with JSF 2 and custom login form

Here, I am integrating Spring Security with JSF 2 using a custom login form.

First, the maven dependencies for Spring-Security (I consider that the JSF project is already set-up, if it is not the case, you can check here):

<properties>
    ...
    <spring.security.version>3.2.4.RELEASE</spring.security.version>
</properties>
...
<!-- Spring-Security dependencies -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>${spring.security.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>${spring.security.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>${spring.security.version}</version>
</dependency>

In the web.xml, we have to configure the Spring-Security filter as follow:

<!-- Enable Spring Filter: Spring Security works on the concept of Filters -->
<!-- Declare the Spring filter -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>
<!-- Defines urls pattern on which the filter is applied -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

Note: if you don’t add the forward to it, the managed bean will not be able to send the request to the filter (I experienced that!!).

We need a simple index.xhtml which will be protected by Spring (I don’t describe it here) and a custom login page which receive the credentials typed by the user.
This page contains only the user name, the password and another field method which is here to show how we can get it on the server:

<h:form id="loginFormId" prependId="false">
    <div class="full-box" style="text-align: center">
        <div class="child-box box-c3">
            <h3>Login</h3>
            <div class="fluid-row">
                <div class="fluid-column fluid-c12">
                    <div class="forLabel" style="width: 30%">
                        <h:outputLabel for="username" value="User" />
                    </div>
                    <div class="forField" style="width: 65%">
                        <h:inputText id="username" required="true"
                            requiredMessage="Please enter username (or go to hell...)" />
                        <h:messages for="username" />
                    </div>
                </div>
                <div class="fluid-column fluid-c12">
                    <div class="forLabel" style="width: 30%">
                        <h:outputLabel for="password" value="Password" />
                    </div>
                    <div class="forField" style="width: 65%">
                        <h:inputSecret id="password" required="true"
                            requiredMessage="Please enter password (otherwise you'll die!!)"
                            name="password" />
                        <h:messages for="password" />
                    </div>
                </div>
                <div class="fluid-column fluid-c12">
                    <div class="forLabel" style="width: 30%">
                        <h:outputText value="Authentication" />
                    </div>
                    <div class="forField" style="width: 65%">
                        <h:selectBooleanCheckbox id="method" name="method" />
                        <h:outputLabel for="method" value="LDAP" />
                    </div>
                </div>
            </div>
            <ui:fragment rendered="${!empty param['error']}">
                <div>Connection failed: user and/or password are wrong.</div>
            </ui:fragment>
            <div id="loginBtnPanelId">
                <h:commandButton id="btnLoginId" value="Login" type="submit"
                    action="${loginManager.doLogin()}" styleClass="loginPanelBtn" />
            </div>
        </div>
    </div>
</h:form>

The form is very simple, we can see the 3 fields and a portion which is conditionally rendered if error param is available.
The content of this form is sent to a managed bean which is responsible of forwarding data to the Spring-Security filter:

import java.io.IOException;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

@ManagedBean
@RequestScoped
public class LoginManager {

    public String doLogin() throws IOException, ServletException {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher("/j_spring_security_check");
        dispatcher.forward((ServletRequest) context.getRequest(), (ServletResponse) context.getResponse());
        FacesContext.getCurrentInstance().responseComplete();
        return null;
    }

}

Now, we need to have a look to the Spring configuration file, the security is configured as follow:

<security:http use-expressions="true">
    <!-- refers to http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html -->
    <security:intercept-url pattern="/faces/login.xhtml"
        access="anonymous" />
    <security:intercept-url pattern="/css/**"
        access="anonymous" />
    <security:intercept-url pattern="/**"
        access="authenticated" />
    <security:form-login login-page="/faces/login.xhtml"
        authentication-failure-url="/faces/login.xhtml?error=1"
        default-target-url="/faces/index.xhtml"
        authentication-details-source-ref="myAuthenticationDetailsSource"
        username-parameter="username" password-parameter="password" />
</security:http>

We can see that we have to enable anonymous access to the login form (otherwise, you will see some strange messages in your browser, I let you guess why). To have a beautiful login page, we also allow anonymous access to the CSS, the rest of the site has a restricted access controlled by Spring.
As we use a custom login form, the form-login element must indicate which one we want to use with the login-page attribute.
To be able to store the custom field (the method if you forgot it), we have to implement a custom class, it is the one we see in the authentication-details-source-ref attribute.

This is how it is defined in the Spring configuration file:

<bean id="myAuthenticationDetailsSource"
    class="net.classnotfound.jsf.spring.security.security.MyAuthenticationDetailsSource">
</bean>

And the class which implements the org.springframework.security.authentication.AuthenticationDetailsSource interface:

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

/**
 * This class provides a custom AuthenticationDetail which stores the connection
 * type method (Oracle/Ldap)
 *
 */
public class MyAuthenticationDetailsSource implements AuthenticationDetailsSource {

    /**
     * returns the {@link WebAuthenticationDetails} according to LuxFact rule
     * 
     * @param context
     */
    @Override
    public WebAuthenticationDetails buildDetails(final HttpServletRequest context) {
        return new MyAuthenticationDetails(context);
    }

}

This class provides an implementation of a org.springframework.security.web.authentication.WebAuthenticationDetails which will store our extra parameter, its implementation is very simple:

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.web.authentication.WebAuthenticationDetails;

/**
 * this class stores data used for authentication (mainly the authentication
 * method)
 * 
 */
public class MyAuthenticationDetails extends WebAuthenticationDetails {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private final String method;

    public MyAuthenticationDetails(final HttpServletRequest request) {
        super(request);
        method = request.getParameter("method");
    }

    public String getMethod() {
        return method;
    }

}

As we can see, this class does nothing else than getting the custom parameter from the request and storing it.

Now, to use this extra parameter, we need to customize the way a user is authenticated. As this task is, by default, done by Spring, it means that we have to write a new class which implements the org.springframework.security.authentication.AuthenticationProvider interface. We can see its declaration in the Spring configuration file here:

<bean id="myAuthenticationProvider"
    class="net.classnotfound.jsf.spring.security.security.MyAuthenticationProvider">
</bean>

<security:authentication-manager>
    <!-- create a custom AuthenticationProvider class to tune the login 
        process -->
    <security:authentication-provider
        ref="myAuthenticationProvider" />
</security:authentication-manager>

And its implementation:

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public class MyAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(final Authentication authentication) throws AuthenticationException {

        Authentication res = isValid(authentication);
        if (!res.isAuthenticated()) {
            throw new BadCredentialsException("Bad credentials");
        }
        return res;
    }

    private Authentication isValid(final Authentication authentication) {
        Authentication res = authentication;
        System.out.println("Selected method: "+((MyAuthenticationDetails)authentication.getDetails()).getMethod());
        if ("Admin".equals(authentication.getPrincipal())&&"Password".equals(authentication.getCredentials())) {
            res = createSuccessAuthentication(authentication);
        }
        return res;
    }

    @Override
    public boolean supports(final Class authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

    protected Authentication createSuccessAuthentication(final Authentication authentication) {
        // Ensure we return the original credentials the user supplied,
        // so subsequent attempts are successful even with encoded passwords.
        // Also ensure we return the original getDetails(), so that future
        // authentication events after cache expiry contain the details
        final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), authentication.getAuthorities());
        result.setDetails(authentication.getDetails());

        return result;
    }

}

As we can see, the extra parameter is extracted from the org.springframework.security.core.Authentication.getDetails() method.

The whole Spring configuration file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">


    <!-- Enable security annotations usage -->

    <bean id="myAuthenticationDetailsSource"
        class="net.classnotfound.jsf.spring.security.security.MyAuthenticationDetailsSource">
    </bean>

    <bean id="myAuthenticationProvider"
        class="net.classnotfound.jsf.spring.security.security.MyAuthenticationProvider">
    </bean>


    <security:authentication-manager>
        <!-- create a custom AuthenticationProvider class to tune the login 
            process -->
        <security:authentication-provider
            ref="myAuthenticationProvider" />
    </security:authentication-manager>

    <security:http use-expressions="true">
        <!-- refers to http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html -->
        <security:intercept-url pattern="/faces/login.xhtml"
            access="anonymous" />
        <security:intercept-url pattern="/css/**"
            access="anonymous" />
        <security:intercept-url pattern="/**"
            access="authenticated" />
        <security:form-login login-page="/faces/login.xhtml"
            authentication-failure-url="/faces/login.xhtml?error=1"
            default-target-url="/faces/index.xhtml"
            authentication-details-source-ref="myAuthenticationDetailsSource"
            username-parameter="username" password-parameter="password" />
    </security:http>

</beans>

Source files are available here.