use of org.codice.ddf.security.handler.api.InvalidSAMLReceivedException in project ddf by codice.
the class WebSSOFilter method handleRequest.
private void handleRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain filterChain, List<AuthenticationHandler> handlers) throws IOException, ServletException {
if (handlers.size() == 0) {
LOGGER.warn("Handlers not ready. Returning status code 503, Service Unavailable. Check system configuration and bundle state.");
returnSimpleResponse(HttpServletResponse.SC_SERVICE_UNAVAILABLE, httpResponse);
return;
}
// First pass, see if anyone can come up with proper security token from the get-go
HandlerResult result = null;
LOGGER.debug("Checking for existing tokens in request.");
for (AuthenticationHandler auth : handlers) {
result = auth.getNormalizedToken(httpRequest, httpResponse, filterChain, false);
if (result.getStatus() != HandlerResult.Status.NO_ACTION) {
LOGGER.debug("Handler {} set the result status to {}", auth.getAuthenticationType(), result.getStatus());
break;
}
}
// If we haven't received usable credentials yet, go get some
if (result == null || result.getStatus() == HandlerResult.Status.NO_ACTION) {
LOGGER.debug("First pass with no tokens found - requesting tokens");
// This pass, tell each handler to do whatever it takes to get a SecurityToken
for (AuthenticationHandler auth : handlers) {
result = auth.getNormalizedToken(httpRequest, httpResponse, filterChain, true);
if (result.getStatus() != HandlerResult.Status.NO_ACTION) {
LOGGER.debug("Handler {} set the result status to {}", auth.getAuthenticationType(), result.getStatus());
break;
}
}
}
final String path = httpRequest.getRequestURI();
String ipAddress = httpRequest.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = httpRequest.getRemoteAddr();
}
if (result != null) {
switch(result.getStatus()) {
case REDIRECTED:
// handler handled the response - it is redirecting or whatever
// necessary to get their tokens
LOGGER.debug("Stopping filter chain - handled by plugins");
return;
case NO_ACTION:
// should never occur - one of the handlers should have returned a token
LOGGER.warn("No handlers were able to determine required credentials, returning bad request to {}. Check policy configuration for path: {}", ipAddress, path);
returnSimpleResponse(HttpServletResponse.SC_BAD_REQUEST, httpResponse);
return;
case COMPLETED:
if (result.getToken() == null) {
LOGGER.warn("Completed without credentials for {} - check context policy configuration for path: {}", ipAddress, path);
returnSimpleResponse(HttpServletResponse.SC_BAD_REQUEST, httpResponse);
return;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Attaching result handler to the http request - token is instance of {} from classloader {}", result.getToken().getClass().getName(), result.getToken().getClass().getClassLoader());
}
httpRequest.setAttribute(DDF_AUTHENTICATION_TOKEN, result);
break;
default:
LOGGER.warn("Unexpected response from handler - ignoring. Remote IP: {}, Path: {}", ipAddress, path);
return;
}
} else {
LOGGER.warn("Expected login credentials from {} - didn't find any. Returning a bad request for path: {}", ipAddress, path);
returnSimpleResponse(HttpServletResponse.SC_BAD_REQUEST, httpResponse);
return;
}
// If we got here, we've received our tokens to continue
LOGGER.debug("Invoking the rest of the filter chain");
try {
filterChain.doFilter(httpRequest, httpResponse);
} catch (InvalidSAMLReceivedException e) {
// we tried to process an invalid or missing SAML assertion
returnSimpleResponse(HttpServletResponse.SC_UNAUTHORIZED, httpResponse);
} catch (Exception e) {
LOGGER.debug("Exception in filter chain - passing off to handlers. Msg: {}", e.getMessage(), e);
// First pass, see if anyone can come up with proper security token
// from the git-go
result = null;
for (AuthenticationHandler auth : handlers) {
result = auth.handleError(httpRequest, httpResponse, filterChain);
if (result.getStatus() != HandlerResult.Status.NO_ACTION) {
LOGGER.debug("Handler {} set the status to {}", auth.getAuthenticationType(), result.getStatus());
break;
}
}
if (result == null || result.getStatus() == HandlerResult.Status.NO_ACTION) {
LOGGER.debug("Error during authentication - no error recovery attempted - returning bad request.");
httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
httpResponse.flushBuffer();
}
}
}
use of org.codice.ddf.security.handler.api.InvalidSAMLReceivedException in project ddf by codice.
the class LoginFilter method handleAuthenticationToken.
private Subject handleAuthenticationToken(HttpServletRequest httpRequest, SAMLAuthenticationToken token) throws ServletException {
Subject subject;
try {
LOGGER.debug("Validating received SAML assertion.");
boolean wasReference = false;
boolean firstLogin = true;
if (token.isReference()) {
wasReference = true;
LOGGER.trace("Converting SAML reference to assertion");
Object sessionToken = httpRequest.getSession(false).getAttribute(SecurityConstants.SAML_ASSERTION);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Http Session assertion - class: {} loader: {}", sessionToken.getClass().getName(), sessionToken.getClass().getClassLoader());
LOGGER.trace("SecurityToken class: {} loader: {}", SecurityToken.class.getName(), SecurityToken.class.getClassLoader());
}
SecurityToken savedToken = null;
try {
savedToken = ((SecurityTokenHolder) sessionToken).getSecurityToken(token.getRealm());
} catch (ClassCastException e) {
httpRequest.getSession(false).invalidate();
}
if (savedToken != null) {
firstLogin = false;
token.replaceReferenece(savedToken);
}
if (token.isReference()) {
String msg = "Missing or invalid SAML assertion for provided reference.";
LOGGER.debug(msg);
throw new InvalidSAMLReceivedException(msg);
}
}
SAMLAuthenticationToken newToken = renewSecurityToken(httpRequest.getSession(false), token);
SecurityToken securityToken;
if (newToken != null) {
firstLogin = false;
securityToken = (SecurityToken) newToken.getCredentials();
} else {
securityToken = (SecurityToken) token.getCredentials();
}
if (!wasReference) {
// wrap the token
SamlAssertionWrapper assertion = new SamlAssertionWrapper(securityToken.getToken());
// get the crypto junk
Crypto crypto = getSignatureCrypto();
Response samlResponse = createSamlResponse(httpRequest.getRequestURI(), assertion.getIssuerString(), createStatus(SAMLProtocolResponseValidator.SAML2_STATUSCODE_SUCCESS, null));
BUILDER.get().reset();
Document doc = BUILDER.get().newDocument();
Element policyElement = OpenSAMLUtil.toDom(samlResponse, doc);
doc.appendChild(policyElement);
Credential credential = new Credential();
credential.setSamlAssertion(assertion);
RequestData requestData = new RequestData();
requestData.setSigVerCrypto(crypto);
WSSConfig wssConfig = WSSConfig.getNewInstance();
requestData.setWssConfig(wssConfig);
X509Certificate[] x509Certs = (X509Certificate[]) httpRequest.getAttribute("javax.servlet.request.X509Certificate");
requestData.setTlsCerts(x509Certs);
validateHolderOfKeyConfirmation(assertion, x509Certs);
if (assertion.isSigned()) {
// Verify the signature
WSSSAMLKeyInfoProcessor wsssamlKeyInfoProcessor = new WSSSAMLKeyInfoProcessor(requestData, new WSDocInfo(samlResponse.getDOM().getOwnerDocument()));
assertion.verifySignature(wsssamlKeyInfoProcessor, crypto);
assertion.parseSubject(new WSSSAMLKeyInfoProcessor(requestData, new WSDocInfo(samlResponse.getDOM().getOwnerDocument())), requestData.getSigVerCrypto(), requestData.getCallbackHandler());
}
// Validate the Assertion & verify trust in the signature
assertionValidator.validate(credential, requestData);
}
// if it is all good, then we'll create our subject
subject = securityManager.getSubject(securityToken);
if (firstLogin) {
boolean hasSecurityAuditRole = Arrays.stream(System.getProperty("security.audit.roles").split(",")).filter(subject::hasRole).findFirst().isPresent();
if (hasSecurityAuditRole) {
SecurityLogger.audit("Subject has logged in with admin privileges", subject);
}
}
if (!wasReference && firstLogin) {
addSamlToSession(httpRequest, token.getRealm(), securityToken);
}
} catch (SecurityServiceException e) {
LOGGER.debug("Unable to get subject from SAML request.", e);
throw new ServletException(e);
} catch (WSSecurityException e) {
LOGGER.debug("Unable to read/validate security token from request.", e);
throw new ServletException(e);
}
return subject;
}
use of org.codice.ddf.security.handler.api.InvalidSAMLReceivedException in project ddf by codice.
the class LoginFilter method renewSecurityToken.
private SAMLAuthenticationToken renewSecurityToken(HttpSession session, SAMLAuthenticationToken savedToken) throws ServletException, WSSecurityException {
if (session != null) {
SecurityAssertion savedAssertion = new SecurityAssertionImpl(((SecurityToken) savedToken.getCredentials()));
if (savedAssertion.getIssuer() != null && !savedAssertion.getIssuer().equals(SystemBaseUrl.getHost())) {
return null;
}
if (savedAssertion.getNotOnOrAfter() == null) {
return null;
}
long afterMil = savedAssertion.getNotOnOrAfter().getTime();
long timeoutMillis = (afterMil - System.currentTimeMillis());
if (timeoutMillis <= 0) {
throw new InvalidSAMLReceivedException("SAML assertion has expired.");
}
if (timeoutMillis <= 60000) {
// within 60 seconds
try {
LOGGER.debug("Attempting to refresh user's SAML assertion.");
Subject subject = securityManager.getSubject(savedToken);
LOGGER.debug("Refresh of user assertion successful");
for (Object principal : subject.getPrincipals()) {
if (principal instanceof SecurityAssertion) {
SecurityToken token = ((SecurityAssertion) principal).getSecurityToken();
SAMLAuthenticationToken samlAuthenticationToken = new SAMLAuthenticationToken((java.security.Principal) savedToken.getPrincipal(), token, savedToken.getRealm());
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Setting session token - class: {} classloader: {}", token.getClass().getName(), token.getClass().getClassLoader());
}
((SecurityTokenHolder) session.getAttribute(SecurityConstants.SAML_ASSERTION)).addSecurityToken(savedToken.getRealm(), token);
LOGGER.debug("Saved new user assertion to session.");
return samlAuthenticationToken;
}
}
} catch (SecurityServiceException e) {
LOGGER.debug("Unable to refresh user's SAML assertion. User will log out prematurely.", e);
session.invalidate();
} catch (Exception e) {
LOGGER.info("Unhandled exception occurred.", e);
session.invalidate();
}
}
}
return null;
}
Aggregations