package no.niths.security;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Security filter that checks for session token and validates user
* <p>
* This filter runs after BasicAuthenticationFilter @see BasicAuthenticationFilter
* and checks for developer key+token, key+application token and session-token
* </p>
* <p>
* If no developer key+token and no application key+token is provided
* in the request, the session-token will not be validated. In other words
* Developer token+key and application token+key must be provided to access
* restricted resources.
* </p>
* <p>
* This class does not handle the actual verification, it only extracts the
* tokens from the http request and passes them to the class responsible for
* the verification @see {@link RequestAuthenticationProvider}
* </p>
* <p>
* For an understanding of how Spring security works, I recommend the book:
* "Spring security 3" from Peter Mularien {@link http://www.springsecuritybook.com/}
* </p>
*
*
*/
public class RequestAuthenticationFilter extends OncePerRequestFilter {
Logger logger = org.slf4j.LoggerFactory
.getLogger(RequestAuthenticationFilter.class);
@Autowired
private RestAuthenticationEntryPoint entryPoint;
@Autowired
private RequestAuthenticationProvider authProvider;
/**
* Handles the verification process.
* <p>
* Checks for authentication headers and based
* on the information authenticates the user
* <p>
* @param req
* the HttpServletRequest
* @param res
* the HttpServletResponse
* @param chain
* the Security filter chain
* @throws ServletException
* , IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
// Debug
// logger.debug(req.getProtocol());
//add no cache header
res.addHeader("Cache-Control","no-cache");
logger.debug("Incoming request, firing security filter;");
// Checking if Basic Authentication has been set,
// if not, we check for a Session-Token header
Authentication currentAuth = SecurityContextHolder.getContext()
.getAuthentication();
if (currentAuth == null) { // If basic auth has been populated,
// do not check for session token
logger.debug("No Basic Authentication header found");
logger.debug("Starting request authentication process...");
// Wrapper
RequestAuthenticationInfo authInfo = new RequestAuthenticationInfo(
new RequestHolderDetails());
String developerToken = req.getHeader("Developer-token");
String applicationToken = req.getHeader("Application-token");
logger.debug("HTTP headers have been processed.");
if (developerToken != null && applicationToken != null) {
logger.debug("Developer token found: " + developerToken);
logger.debug("Application token found: " + applicationToken);
authInfo.setDeveloperToken(developerToken);
authInfo.setAppToken(applicationToken);
String sessionToken = req.getHeader("Session-token");
if (sessionToken != null) {
logger.debug("Session-token header found: " + sessionToken);
authInfo.setSessionToken(sessionToken);
}else{
logger.debug("No session header found");
}
try {
logger.debug("Calling authentication provider to authenticate the header(s)");
// Let the authentication provider authenticate the request
// Will throw AuthenticationException, so it is important
// that every exception extends AuthenticationException.
// Exceptions are catched in AbstractRestController.
Authentication authResult = authProvider
.authenticate(authInfo);
logger.debug("Authentication success!");
// Set the result as the authentication object
setAuthorization(authResult);
} catch (AuthenticationException ae) {
logger.debug("Authentication failed for developer with token: " + developerToken);
logger.debug("Authentication failed for app with token: "+ applicationToken);
if (sessionToken != null) {
logger.debug("Authentication failed for session: "+ sessionToken);
}
// Login failed, clear authentication object
setAuthorization(new RequestAuthenticationInfo(new RequestHolderDetails()));
// We send the error to the entry point
entryPoint.commence(req, res, ae);
}
}else{
setAuthorization(new RequestAuthenticationInfo(new RequestHolderDetails()));
logger.debug("Could not find required headers(Developer/Application), authentication process ends...");
}
}
logger.debug("Continuing spring security filter chain");
chain.doFilter(req, res);
}
private void setAuthorization(Authentication auth){
SecurityContextHolder.getContext().setAuthentication(auth);
}
public RequestAuthenticationProvider getAuthProvider() {
return authProvider;
}
public void setAuthProvider(RequestAuthenticationProvider authProvider) {
this.authProvider = authProvider;
}
public RestAuthenticationEntryPoint getEntryPoint() {
return entryPoint;
}
public void setEntryPoint(RestAuthenticationEntryPoint entryPoint) {
this.entryPoint = entryPoint;
}
}