Showing posts with label springframework. Show all posts
Showing posts with label springframework. Show all posts

02 March 2019

Spring security multiple authentication provider


In your WebSecurityConfigurerAdapter you will need to add more than auth

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.authenticationProvider(new MyFirstAuthenticationProvider(userRepository, bCryptPasswordEncoder()));

    auth.authenticationProvider(new MySecondAuthenticationProvider(userRepository, bCryptPasswordEncoder()));

}

Then Create MyFirstAuthenticationProvider and MySecondAuthenticationProvider like:

public class MyFirstAuthenticationProvider extends DaoAuthenticationProvider {

    public MyFirstAuthenticationProvider(UserRepository userRepository,
                                              BCryptPasswordEncoder bCryptPasswordEncoder) {

        super.setPasswordEncoder(bCryptPasswordEncoder);
        super.setUserDetailsService(......)
        );
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MyFirstAuthenticationToken.class.isAssignableFrom(authentication);
    }
}


public class MyFirstAuthenticationToken extends UsernamePasswordAuthenticationToken {

    public MyFirstAuthenticationToken(UserEntity principal, Object credentials,
                                                   Collection<? extends GrantedAuthority> authorities) {
        super(principal, credentials, authorities);
    }
}
And the same for MySecondAuthenticationProvider.

You will need to use the authentication providers/token in the authenticaiton/authorization filters.


07 December 2017

Very important notes about Spring @Transnational

Sprint @Transnational is being ignored in the following cases:

1. when the caller method is calling the @Transaction annotated method from the same class

2. When the Annotated method is not public

@Transnational by default don't rollback for Checked Exceptions


class A{
     void caller(){
            doInTransactionMethod(); // @Transnational is ignored
     }

    @Transnational // by default rollback for RuntimeExceptions
    public <return type> doInTransactionMethod(<params>){ // should be public as well
    }
}

The problem is, I keep forgetting about the above 3 simple rules, So I tried to writing down here to try not to forget about it

 Also, here is a tweet that talks about public default limitation: https://twitter.com/mohewedy/status/1099781513888100352

18 March 2017

Using spwrap inside spring transactions

spwrap is a little library that simplify calls to database stored procedures in java.

Read this introduction to talk an idea about spwrap before continue reading this post.

We have talked before about how to use spwrap in spring boot application.

Today we will talk about a new feature just release in version 0.0.18, which is spwrap now can participate in spring transactions.

spwrap itself doesn't allow spanning transaction across DAO method calls. but as part of 0.0.18, it will participate in spring Transactions if spwrap is used inside spring and there's an active transaction.

Suppose we have a spring project with Datasource transaction manager is enabled.

And we have  SupplierDAO which is a spwrap DAO defined like this:


public interface SupplierDAO {

    @StoredProc("insert_new_supplier")
    void insertSupplier(@Param(VARCHAR) String name);
}

And we have a domain object supplier and its spring-data-jpa repository

@Entity
public class Supplier {

    @Id    @GeneratedValue(strategy = AUTO)
    private Long id;

    @Column(unique = true)
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
// -- repository
public interface SupplierRepo extends JpaRepository<Supplier, Long> {
}

And here's the service class:

@Service
public class SupplierService {

    private SupplierDAO supplierDAO;
    private SupplierRepo supplierRepo;

    public SupplierService(SupplierDAO supplierDAO, SupplierRepo supplierRepo) {
        this.supplierDAO = supplierDAO;
        this.supplierRepo = supplierRepo;
    }

    @Transactional
    public void add2Suppliers(){
        final String supplierName = "Abdullah";

        supplierDAO.insertSupplier(supplierName);   // << will rolled-back

        Supplier s2 = new Supplier();
        s2.setName(supplierName);
        supplierRepo.save(s2);      // throws exception
    }

    public List<Supplier> listSuppliers(){
        return supplierRepo.findAll();
    }
}

Now because the supplierDAO.insertSupplier(supplierName) insert supplier with name "Abdullah", and supplierRepo.save(s2) insert supplier with the same name, then spring frameowkr will throw DataAccessException subclass and rollback the entire transaction.

Which meaning the stored procedure that is executed as a result of calling supplierDAO.insertSupplier(supplierName) will be rollbacked as well. Again, this is a new feature as part of spwrap 0.0.18. 

You can see the full example at github: https://github.com/mhewedy/spwrap-examples/tree/master/spring-boot-transactions-mysql Don't forget, if you like the spwrap library, don't forget to like the project page at github.

02 March 2017

Using spwrap with Spring boot

spwrap is a tiny framework to make stored procedures call from java code an easy and fun task.

I've written a couple of posts about it.

Today, I am gonna show you how to use it from spring boot project.

The main point I want to emphasis here is to register DAO interfaces as Spring Bean so that I would be reused across your application:

@Configuration
public class Config {

    @Autowired
    private DataSource dataSource;

    @Bean
    public DAO dao(){
        return new DAO.Builder(dataSource)
                .config(new spwrap.Config().useStatusFields(false))
                .build();
    }

    @Bean
    public CustomerDAO customerDAO(DAO dao){
        return dao.create(CustomerDAO.class);
    }
}
See the github page https://github.com/mhewedy/spwrap-examples/tree/master/spring-boot-mysql for the complete project.

Learn more: https://github.com/mhewedy/spwrap/wiki/Using-with-Spring-Boot-other-DI-frameworks
Thanks to stored-procedure-proxy at: https://github.com/marschall/stored-procedure-proxy/wiki/Object-Lifetime

19 February 2017

spwrap: Stored Procedure call wrapper

spwrap is a Stored Procedure caller; simply execute stored procedure from java code.
Example:

public interface CustomerDAO {

    @StoredProc("create_customer")
    void createCustomer(@Param(VARCHAR) String firstName, @Param(VARCHAR) String lastName);

    @StoredProc("get_customer")
    Customer getCustomer(@Param(INTEGER) Integer id);   

    @StoredProc("list_customers")
    List<Customer> listCustomers();
}
public class Customer implements TypedOutputParamMapper<Customer>, ResultSetMapper<Customer> {

    private Integer id;
    private String firstName, lastName;

    public Customer() {
    }

    public Customer(Integer id, String firstName, String lastName) {
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Integer id() {
        return id;
    }

    public String firstName() {
        return firstName;
    }

    public String lastName() {
        return lastName;
    }

    @Override
    public Customer map(Result<?> result) {
        if (result.isResultSet()) {// for ResultSetMapper
            return new Customer(result.getInt(1), result.getString(2), result.getString(3));
        } else { // for TypedOutputParamMapper
            return new Customer(null, result.getString(1), result.getString(2));
        }
    }

    // for TypedOutputParamMapper
    @Override
    public List<Integer> getTypes() {
        return Arrays.asList(VARCHAR, VARCHAR);
    }
}
DAO dao = new DAO.Builder(dataSource).build();
CustomerDAO customerDao = dao.create(CustomerDAO.class);

customerDao.createCustomer("Abdullah", "Muhammad");
Customer abdullah = customerDao.getCustomer(0);
// ......
Learn more at github: https://github.com/mhewedy/spwrap 

30 September 2016

Gradle is awsome

Gradle the build tool for Java and Android (and other languages) is really powerful.

I am brand new to gradle, this is the first time I try it, and I find it really powerful.

I am working - for fun - on some spring boot + angular project , I decided to go with gradle because I like Groovy (The language that grails is written as a DSL; however gradle is written in Java as well as groovy).

However Eclipse support is not as much good as Maven, but I started the spring boot using gradle as the build tool and every thing is fine.

Now I need to build the spring project as well as the angular project (which is based on angular-seed that uses npm and bower).

I find a plugin for gradle for this task (gradle-node-plugin), this plugin allow you to do:

gradle npm-install

so, the npm install command will run and that what I need, but I need it to run with gradle build command.

First the npm-install task of gradle run by default  package.js file found in src/main/java, So I have to write my own task to make it uses spring-boot conventions (src/main/resources/static)

And thanks to the author of this plugin, he makes it easily to extend his plugin, so I wrote:

task my_npm_install(type: NpmTask) {
description = "Installs dependencies from package.json"
workingDir = file("${project.projectDir}/src/main/resources/static")
args = ['install']
}

Here I am defining a new task (enhanced task), that is of type NpmTask (defined in gradle-node-plugin) then set some properties (defined by the parent task (NpmTask) ), so it can do the job.

so, now I can run: gradle my_npm_task and gradle now will run npm install against the correct package.json file.

What is remaining is to have the this task run after I run gradle build (the build task).

Thanks to the amazing tasks dependency feature provided by gradle, I can refer to some task (provided by java plugin - I think) and make it depends on another task (the one I wrote).

Like this: build.dependsOn(my_npm_install)

Then when I run gradle build, here's the output:

.....
......

So that, the build task will run my_npm_install: (here's the output of gradle build command):

:check
:nodeSetup SKIPPED
:my_npm_install
:build
.......
......

gradle run the my_npm_install task before the build task.

Again, gradle is much more powerful and flexible than maven, and have a better syntax as well.
 

05 September 2016

Using @Transactional to trigger rollback on runtime exceptions

In the last post, I've discussed some thoughts about trying to understand spring transactions.

Although not complete (and it appears it has issues as well). but today's topic is so compact and clear.

Spring follow's EJB transaction on that, it rollback on RuntimeException.

Suppose we have the following method:

@Transactionl
public void myServiceMethod(){
    updateDatabase();
    callSomeQueueOrWebService();
}

so, if the the second method call fails with RuntimeException, then the whole transaction will rollback causing the first method to rolled back.

But if you don't annotate the method with @Transactional, then both method calls (updateDatabase() and callSomeQueueOrWebService() ) will run independently and one might success however the other case fail.

Code:

Service Layer:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private String fName = "Mohammad", lName = "Hewedy";

 @Transactional
 public void updateDbAndCallWSTrans() {
  userRepo.save(User.of(null, fName, lName));
  callWsThatThrowsException();
 }

 public void updateDbAndCallWSNoTrans() {
  userRepo.save(User.of(null, fName, lName));
  callWsThatThrowsException();
 }

 public Stream<User> getDbUpdate() {
  return userRepo.findByFNameAndLName(fName, lName);
 }

 private void callWsThatThrowsException() {
  // automatic rollback for runtime exceptions only!
  throw new RuntimeException("EXCEPTION from WS");
 }


The controller layer:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 
 @RequestMapping("/tx/user")
 public ResponseEntity<?> getDbUpdate() {
  return ResponseEntity.ok(userService.getDbUpdate().toArray(User[]::new));
 }

 @RequestMapping("/tx/add-w")
 public ResponseEntity<?> updateDbAndCallWSTrans() {
  userService.updateDbAndCallWSTrans();
  return ResponseEntity.ok().build();
 }

 @RequestMapping("/tx/add-wo")
 public ResponseEntity<?> updateDbAndCallWSNoTrans() {
  userService.updateDbAndCallWSNoTrans();
  return ResponseEntity.ok().build();
 }


Note, the call to /tx/add-w will not insert any data into the database, and calls to /tx/user will return empty.

However, the call to /tx/add-wo, will insert the user object into the database, and call to /tx/user will return the inserted users object.

04 September 2016

My thoughts about Spring Transactions

I've some thoughts about spring (and spring-boot) transactions I want to list somewhere, and I think here's a nice place.

Preface

Spring do transaction management through PlatformTransactionManager interface.

This interface has implementation for different kinds of datasources, for example for DataSourceTransactionManagerHibernateTransactionManagerHibernateTransactionManagerJmsTransactionManagerJpaTransactionManager and others.

In a typical JPA application, the JpaTransactionManager is being used.

In SpringBoot, All the JpaRepository are annotated with @Transactional annotation.

This annotation used by spring to do the Declarative transaction management.

So, the Developer uses this annotation to control many things, included the transaction propagation (REQUIRED, REQUIRED_NEW, SUPPORTED, etc), the isolation level (READ_COMMITED, READ_UNCOMMITED, etc.) and the rollback exception, timeout and more.

And behind the since, the platform-specific transaction manager along with the databasource do the actual work.

@Transactionl

So, many people says, use the @Transactional annotation on the service layer, you might need to use it on DAO (now called Repository) layer, but do not use it on the controller layer.

In spring boot, as I said, all the out-of-the-box methods that you get by implementing the JpaRepository are already have the @Transactional annotation (see SimpleJpaRepository). And I think hence the @Transactional on the implementation class itself, then all your repo methods might have the annotation as well.

But this is not the problem, the problem in the Service layer.

@Transactionl in the Service layer

What if I didn't put the Transactional annotation on my service methods?
Then your method will not run in a transaction, so If you have a service method that do the following

public void serviceMethod(){
     insert1();
     insert2();
}

insert1() might succeed and inserts data into the database, while insert2() fails.

In this case you should put the @Transactional annotation on your service method if you want to have all or none.

@Transactionl and noRollbackFor

The rollback is controlled by RuleBasedTransactionAttribute
see http://docs.spring.io/autorepo/docs/spring/current/spring-framework-reference/html/transaction.html#transaction-declarative-rolling-back

In its default configuration, the Spring Framework’s transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.
Also,
When the Spring Framework’s transaction infrastructure catches an exception and is consults configured rollback rules to determine whether to mark the transaction for rollback, the strongest matching rule wins 

For rollbackFor and noRollbackFor;

I think spring take the exception thrown and check to see how it is close (in inheritance hierarchy) to the declared exceptions (in rollbackFor and noRollbackFor). If it is closer to an exception declared in rollbackFor more than one declared in noRollbackFor, then the transaction will be rollbacked. and vice versa.

ex:
We have this heirarcy:
class Exception1{}
class Exception2 extends 1{}
class Exception3 extends 2{}

@Transactional(rollbackFor=Exception1.class, noRollbackFor=Exception2 .class)
public void myMethod(){
        throw new Exception3 ();
}

In this case, the transaction will NOT be rollbacked, because the thrown exception (Exception3) is closest to exception in noRollbackFor (Exception2) than the exception in rollbackFor (Exception1)

And if the closest exception declared in rollbackFor, the spring will rollback the tx, otherwise it will not rollback it:

in RuleBasedTransactionAttribute: return !(winner instanceof NoRollbackRuleAttribute);

@Transactionl and lazy evaluation

lazy evaluation is important aspect in web development, it facilities things, lazy evaluation includes not only evaluate lazy associations in the Controller layer, but also evaluation lazy Streams. (Thanks to OpenEntityManagerInViewFilter).

But if you choose to annotate your service method with @Transactional, lazy transaction data will not be available in the Controller layer (and exceptions will be thrown as well).

Here's an example issue.

So, some people says, at service layer get all the data you want and then send it to the controller layer as eager so you don't need the service layer's transaction anymore.

I think for finder services, you might not need to have the @Transactional annotation, so you can make use of the OpenEntityManagerInViewFilter (which is provided by springboot by default) and be able to  enjoy your laziness in the controller layer.(It seems the "Open EntityManager in View" has nothing to do here, it only allow the transaction manager to use an EntityManager created by him. because if you have @Transactional and have this pattern on, the exception will continue to throw if you try to access lazy data out of the transactions.

But in case of services that updates the database, you do need to use the @Transactional annotation to control the things not to go messy!

@Transactionl on controller and service layer

If you have a finder method that returns a lazy object (java 8 stream or lazy association as in hibernate), the if you have the @Transactional annotation on the service layer, then the lazy parts of  object will not be available to the controller layer.

However, if you put the @Transactionl annotation on the controller layer as well (which many people don't recommend) then the lazy part will be available to the controller layer unless you make the transaction propagation on the service layer as REQUIRED_NEW, in this case the service layer will suspend the controller's transaction and start/end it's own transaction and will send back the object to the controller out of its transaction and the problem will still exists.

Conclusion

For now, I'll  - mostly, because some times I do not need it - use @Transactionl on Service methods that do update (Add/update/delete) the database.

However for finder service methods (that query the database), it is better to have the @Transational(readOnly=true) on it, but since I didn't understand - till now- much more, I'll choose not to use this annotation so I can deal with my laziness objects in the controller layer)

Interesting classes to see the source code of:
1. TransactionInterceptor: class source code to see what is happening internally. (very interesting)
2. TransactionAspectSupport:
  a. method: invokeWithinTransaction
  b. method: completeTransactionAfterThrowing (it shows
3. AbstractPlateformTransactoinManager
 a. method: commit (it shows the rollback if done if "setRollbackOnly" method is being called

The post above is based on my thoughts and is might not be valid.

16 January 2016

Html5Mode in angular js for Java

Here's a sample Servlet filter implementation to allow return pages from the server with the / pattern.

Note: I've marked angularjs requests with "source" header set to "ng".

@WebFilter(urlPatterns = { "/*" })
public class Html5ModeFilter implements Filter {

@Override
public void destroy() {

}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {

HttpServletRequest request = ((HttpServletRequest) req);
boolean notNgRequest = !"ng".equalsIgnoreCase(request.getHeader("source"));
String servletPath = request.getServletPath();

if (notNgRequest && !servletPath.contains(".")) { // skip .js, .css,
// .png, etc...
if (!"/".equalsIgnoreCase(servletPath)) {
((HttpServletResponse) res).sendRedirect("/?next=" + servletPath.substring(1));
return;
}
}

chain.doFilter(req, res);
}

@Override
public void init(FilterConfig arg0) throws ServletException {

}


}

20 November 2014

Implementing Spring Security with JSF (Login + RedirectStrategy)

When implementing Spring Security in JSF application, many problems happens, and one of the most important one is the redirection in case of HTTP errors!

In this post, I'll take about 2 points, the first point is how to implement the Login page (you will find many resources illustrate this - for example this) but I'll extend it allowing the user to continue on the page he was coming from (aka. Saved Request URL), the second point and the more important one is handling HTTP errors in case of Ajax requests.

Point #1 Handle Login From:

Initially, you have your JSF application (in my case I use Primefaces, but shouldn't matter at all, because the solution is JSF related not primefaces-related)


You have your xhtml login page (login.xhtml) like this:


<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">
<f:view>
    <h:form id="loginForm">
        <h:messages style="color: red;" />

        <table>
            <tr>
                <td><p:outputLabel for="usernameTxt" value="Username" /></td>
                <td><p:inputText id="usernameTxt" value="#{loginBean.username}" /></td>
            </tr>
            <tr>
                <td><p:outputLabel for="passwordTxt" value="Password" /></td>
                <td><p:password id="passwordTxt" value="#{loginBean.password}" /></td>
            </tr>
            <tr>
                <td colspan="2"><p:commandButton value="Login"
                        action="#{loginBean.login}" /></td>
            </tr>
        </table>
    </h:form>
</f:view>

</html>

Very simple!, regularly with spring security, we submit the form to /j_spring_security_check but we have different situation here, we have a command button which send POST request to the same URL of the page.

2 solutions here, I'll take about one of them (as appears in Macro-blog link above) which is using a reference for the authenticationManager from the bean action method:

first, you need to expose the authenticationManager in the security context configuration file:


    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_ADMIN" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

Note the use of "alias" attribute.

Then in you JSF Managed bean, you can inject it and use it as the following:

@Inject
private AuthenticationManager authenticationManager;

@Setter
@Getter
private String username;

@Setter
@Getter
private String password;

public LoginBean() {
}

public String login() {
    try {
        Authentication authentication = authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(
                        this.username, this.password));

        SecurityContextHolder.getContext()
                .setAuthentication(authentication);

    } catch (AuthenticationException ex) {
        log.equals(ex.getMessage());
        Util.addMessage("Login Failed: " + ex.getMessage());
        return "";
    }

    return Util.getSavedUrl() + "?faces-redirect=true";
}

The code above is pretty clear, If fail (AuthenticationExcpetion thrown, show error message), else redirect to some URL.

The point here is some URL is critical, because if the user was trying to access resource "A", then spring security asked him to login first, then after login he should access resource "A" itself not a welcome screen.

This handled by spring security, but in our case, we need to ask Spring-security explicity to give us the "SavedURL" from the session. so the implmenetation of Util.getSavedUrl() is below:

public static String getSavedUrl() {
    HttpServletRequest request = ((HttpServletRequest) FacesContext
            .getCurrentInstance().getExternalContext().getRequest());

    SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(
            request, (HttpServletResponse) FacesContext
                    .getCurrentInstance().getExternalContext()
                    .getResponse());

    if (savedRequest != null) {
        try {
            URL url = new URL(savedRequest.getRedirectUrl());
            return url.getFile().substring(
                    request.getContextPath().length());
        } catch (Exception e) {
            log.error(e.getMessage() + " Using default URL");
        }
    }
    return "admin/index.xhtml?faces-redirect=true"; // default page!
}

And that's all for the first point.

Point #2 Handle HTTP error codes for Ajax requests:

JSF (and jsf based frameworks) uses Ajax in many cases,  the PrimeFaces autocomplete is a good example.

Originally with regular HTTP requests (non-Ajax), when the user try to access a resource after session expired, spring security will send error code 302 to the browser, when browser sees the response code, he will do the redirect the Login page.


But in case of Ajax requests, the ajax client should handle this on his own.

In case of JSF, (I am not the JSF expert Guy :D ) JSF uses some internal protocol sending XML between the server and the client, and this XML is well defined in matter if the server wants the client to do redirect, the server doesn't send 302 for the client, instead, he sends a response like:

<?xml version="1.0" encoding="UTF-8"?>
<partial-response>
    <redirect url="URL to redirect to"></redirect>
</partial-response>

So, when the ajax caller (who send the JSF request), see this response, he will do redirect immediately.


So, to integrate this with Spring security we need to tell it override the cod that sends the response code and add the above xml payload just in case of Ajax requests.

To do this Spring security provide a redirect strategy (org.springframework.security.web.RedirectStrategy) that you can extends and hook the spring security at some points.

So, here's a sample implementation:


package testing.ss;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;

/**
 * Based on code from DefaultDirectStrategy and
 * https://gist.github.com/banterCZ/5160269
 * 
 * @author mhewedy
 *
 */
public class JsfRedirectStrategy implements RedirectStrategy {

    private static final String FACES_REQUEST_HEADER = "faces-request";

    protected final Log logger = LogFactory.getLog(getClass());

    private boolean contextRelative;

    /**
     * Redirects the response to the supplied URL.
     * <p>
     * If <tt>contextRelative</tt> is set, the redirect value will be the value
     * after the request context path. Note that this will result in the loss of
     * protocol information (HTTP or HTTPS), so will cause problems if a
     * redirect is being performed to change to HTTPS, for example.
     */
    public void sendRedirect(HttpServletRequest request,
            HttpServletResponse response, String url) throws IOException {
        String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
        redirectUrl = response.encodeRedirectURL(redirectUrl);

        boolean ajaxRedirect = "partial/ajax".equals(request
                .getHeader(FACES_REQUEST_HEADER));
        if (ajaxRedirect) {

            String ajaxRedirectXml = createAjaxRedirectXml(redirectUrl);
            logger.debug("Ajax partial response to redirect: "
                    + ajaxRedirectXml);

            response.setContentType("text/xml");
            response.getWriter().write(ajaxRedirectXml);
        } else {
            logger.debug("Non-ajax redirecting to '" + redirectUrl + "'");
            response.sendRedirect(redirectUrl);
        }
    }

    private String calculateRedirectUrl(String contextPath, String url) {
        if (!UrlUtils.isAbsoluteUrl(url)) {
            if (contextRelative) {
                return url;
            } else {
                return contextPath + url;
            }
        }

        // Full URL, including http(s)://

        if (!contextRelative) {
            return url;
        }

        // Calculate the relative URL from the fully qualified URL, minus the
        // last
        // occurrence of the scheme and base context.
        url = url.substring(url.lastIndexOf("://") + 3); // strip off scheme
        url = url.substring(url.indexOf(contextPath) + contextPath.length());

        if (url.length() > 1 && url.charAt(0) == '/') {
            url = url.substring(1);
        }

        return url;
    }

    /**
     * If <tt>true</tt>, causes any redirection URLs to be calculated minus the
     * protocol and context path (defaults to <tt>false</tt>).
     */
    public void setContextRelative(boolean useRelativeContext) {
        this.contextRelative = useRelativeContext;
    }

    // from https://gist.github.com/banterCZ/5160269
    private String createAjaxRedirectXml(String redirectUrl) {
        return new StringBuilder()
                .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
                .append("<partial-response><redirect url=\"")
                .append(redirectUrl)
                .append("\"></redirect></partial-response>").toString();
    }

}


Then you have to hock the LoginUrlAuthenticationEntryPoint, but because the RedirectStrategy is a final variable, you have to extend it like this:

package testing.ss;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;

/**
 * Based on code from LoginUrlAuthenticationEntryPoint
 * 
 * @author mhewedy
 *
 */
// see http://forum.spring.io/forum/spring-projects/security/88829-is-it-possible-to-change-spring-security-3-redirects-from-full-urls-to-relative-urls
@SuppressWarnings("deprecation")
public class JsfLoginUrlAuthenticationEntryPoint extends
        LoginUrlAuthenticationEntryPoint {

    Log log = LogFactory.getLog(getClass());

    private RedirectStrategy redirectStrategy;

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }

    @Override
    public void commence(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {

        String redirectUrl = null;

        if (isUseForward()) {

            if (isForceHttps() && "http".equals(request.getScheme())) {
                // First redirect the current request to HTTPS.
                // When that request is received, the forward to the login page
                // will be used.
                redirectUrl = buildHttpsRedirectUrlForRequest(request);
            }

            if (redirectUrl == null) {
                String loginForm = determineUrlToUseForThisRequest(request,
                        response, authException);

                log.debug("Server side forward to: " + loginForm);

                RequestDispatcher dispatcher = request
                        .getRequestDispatcher(loginForm);

                dispatcher.forward(request, response);

                return;
            }
        } else {
            // redirect to login page. Use https if forceHttps true

            redirectUrl = buildRedirectUrlToLoginPage(request, response,
                    authException);
        }
        redirectStrategy.sendRedirect(request, response, redirectUrl);
    }

}


Then go back and configure http tag to reference the Entry Point:

<http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint">
    .....
</http>

<beans:bean id="authenticationEntryPoint"
    class="testing.ss.JsfLoginUrlAuthenticationEntryPoint" p:loginFormUrl="/login.xhtml"
    p:redirectStrategy-ref="redirectStrategy" />
    
<beans:bean id="redirectStrategy" class="testing.ss.JsfRedirectStrategy" />

And that's all.

The complete source code on github.