Search code examples
gwtspring-securitycross-context

Securing a GWT app with a request param to be checked in a crosscontext attribute


My application is supposed to received a request parameter called sessionId which is supposed to be used to lookup for a crosscontext attribute.

I was looking at Spring Security to implement this and I think already have a good implementation of my AuthenticationProvider :

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ServletContext servletContext = request.getSession().getServletContext();
String sessionId = request.getParameter("sessionId");
if (sessionId != null) {
    ServletContext sc = request.getSession().getServletContext();
    Object obj = sc.getContext("/crosscontext").getAttribute(sessionId);

    if (obj != null) {
        // return new Authentication
    }
} else {
    logger.error("No session id provided in the request");
    return null;
}
if (!GWT.isProdMode()) {
        // return new Authentication
} else {
    logger.error("No session id provided in the request");
    return null;
}
}

Now, what I would like to do is to configure Spring Security to not prompt for a user name and password, to let it reach this authentication provider call the authenticate method.

How can I achieve this ?


Solution

  • I fixed my issue by reviewing the design of my security and going for something closer to the preauthenticated mechanisms that are already provided by Spring Security.

    I extended 2 components of Spring Security. First one is an AbstractPreAuthenticatedProcessingFilter, usually his role is to provide the principal provided in the headers. In my case, I retrieve the header value and search in the context shared between 2 application for an attribute that corresponds to that header and returns it as principal :

    public class MyApplicationPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
    
    private static final Logger logger = Logger.getLogger(MyApplicationPreAuthenticatedProcessingFilter.class);
    
    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
    
        if (MyApplicationServerUtil.isProdMode()) {
            String principal = request.getHeader("MY_HEADER");
            String attribute = (String) request.getSession().getServletContext().getContext("/crosscontext").getAttribute(principal);
            logger.info("In PROD mode - Found value in crosscontext: " + attribute);
            return attribute;
        } else {
            logger.debug("In DEV mode - passing through ...");
            return "";
        }
    }
    
    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return null;
    }
    
    }
    

    The other component is the AuthenticationProvider which will just check if the authentication contains a principal when it runs in prod mode (GWT prod) :

    public class MyApplicationAuthenticationProvider implements AuthenticationProvider {
    
    private static final Logger logger = Logger.getLogger(MyApplicationAuthenticationProvider.class);
    
    public static final String SESSION_ID = "sessionId";
    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    
        if (MyApplicationServerUtil.isProdMode()) {
            if (StringUtils.isNotEmpty((String) authentication.getPrincipal())) {
                logger.warn("Found credentials: " + (String) authentication.getPrincipal());
                Authentication customAuth = new CustomAuthentication("ROLE_USER");
                customAuth.setAuthenticated(true);
                return customAuth;
            } else {
                throw new PreAuthenticatedCredentialsNotFoundException("Nothing returned from crosscontext for sessionId attribute ["
                        + (String) authentication.getPrincipal() + "]");
            }
        } else {
            Authentication customAuth = new CustomAuthentication("ROLE_USER");
            customAuth.setAuthenticated(true);
            return customAuth;
        }
    }
    
    @Override
    public boolean supports(Class<?> authentication) {
        return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
    }
    
    }
    

    I understand that it might not be the most secure application. However, it will already be running in a secure environment. But if you have suggestions for improvement, they're welcome !