/*
* Copyright (c) 2012. The Genome Analysis Centre, Norwich, UK
* MISO project contacts: Robert Davey, Mario Caccamo @ TGAC
* *********************************************************************
*
* This file is part of MISO.
*
* MISO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MISO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MISO. If not, see <http://www.gnu.org/licenses/>.
*
* *********************************************************************
*/
package uk.ac.bbsrc.tgac.miso.webapp.context;
import com.eaglegenomics.simlims.core.manager.SecurityManager;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.util.*;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.web.filter.OncePerRequestFilter;
import uk.ac.bbsrc.tgac.miso.core.security.util.LimsSecurityUtils;
import uk.ac.bbsrc.tgac.miso.integration.util.SignatureHelper;
/**
* uk.ac.bbsrc.tgac.miso.webapp.context
* <p/>
* Info
*
* @author Rob Davey
* @date 09/02/12
* @since 0.1.6
*/
public class RestSignatureFilter extends OncePerRequestFilter {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
SecurityManager securityManager;
private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
/**
* Creates a new RestSignatureFilter instance with a default HttpSessionSecurityContextRepository set
*/
public RestSignatureFilter() {
super();
}
/**
* Creates a new RestSignatureFilter instance with a defined SecurityContextRepository
*
* @param securityContextRepository of type SecurityContextRepository
*/
public RestSignatureFilter(SecurityContextRepository securityContextRepository) {
super();
this.securityContextRepository = securityContextRepository;
}
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
User userdetails = null;
com.eaglegenomics.simlims.core.User user = null;
logger.debug("HEADERS: ");
Enumeration es = request.getHeaderNames();
while (es.hasMoreElements()) {
String key = (String) es.nextElement();
logger.info(key + " -> " + request.getHeader(key));
}
String loginName = request.getHeader(SignatureHelper.USER_HEADER);
if (loginName == null) {
SecurityContext sc = securityContextRepository.loadContext(new HttpRequestResponseHolder(request, response));
if (sc != null && sc.getAuthentication() != null) {
logger.debug("User already logged in - chaining");
SecurityContextHolder.getContextHolderStrategy().setContext(sc);
filterChain.doFilter(request, response);
}
throw new BadCredentialsException("Cannot enact RESTful request without a user specified!");
}
if (loginName.equals("notification")) {
logger.info("Incoming notification request");
userdetails = new User("notification", "none", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_INTERNAL"));
}
else {
logger.debug("Incoming user REST API request");
user = securityManager.getUserByLoginName(loginName);
if (user != null) {
userdetails = LimsSecurityUtils.toUserDetails(user);
}
}
//String url = request.getHeader(SignatureHelper.URL_X_HEADER);
String signature = request.getHeader(SignatureHelper.SIGNATURE_HEADER);
if (signature == null) {
throw new BadCredentialsException("Cannot enact RESTful request without a signature!");
}
boolean validSignature = false;
try {
if (loginName.equals("notification")) {
validSignature = SignatureHelper.validateSignature(request, SignatureHelper.PUBLIC_KEY, signature);
}
else {
validSignature = SignatureHelper.validateSignature(request,
SignatureHelper.generatePrivateUserKey(
(user.getLoginName() + "::" + user.getPassword())
.getBytes("UTF-8")),
signature);
}
}
catch (InvalidKeyException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
try {
if (!validSignature) {
logger.error("REST KEY INVALID");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "REST signature failed validation.");
}
} catch (Exception e) {
logger.error("UNABLE TO UNDERTAKE SIGNATURE VALIDATION");
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "The REST Security Server experienced an internal error.");
}
logger.debug("REST KEY OK. Security!");
if (userdetails != null) {
PreAuthenticatedAuthenticationToken newAuthentication = new PreAuthenticatedAuthenticationToken(userdetails, userdetails.getPassword(), userdetails.getAuthorities());
newAuthentication.setAuthenticated(true);
newAuthentication.setDetails(userdetails);
try {
SecurityContext sc = SecurityContextHolder.getContextHolderStrategy().getContext();
sc.setAuthentication(newAuthentication);
SecurityContextHolder.getContextHolderStrategy().setContext(sc);
logger.debug("Set context - chaining");
}
catch (AuthenticationException a) {
a.printStackTrace();
}
filterChain.doFilter(request, response);
}
else {
throw new AuthenticationCredentialsNotFoundException("No valid user found to authenticate");
}
}
}