/* * Copyright (C) 2014 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.shiro; import com.intel.dcsg.cpg.io.ErrorUtil; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.web.util.WebUtils; /** * * @author jbuhacoff */ public abstract class HttpAuthenticationFilter extends AuthenticationFilter { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HttpAuthenticationFilter.class); private String authorizationHeaderName = "Authorization"; private String challengeHeaderName = "WWW-Authenticate"; private String authenticationScheme = null; // for example X509, BASIC, DIGEST private String applicationName = "Mt Wilson"; public void setApplicationName(String applicationName) { this.applicationName = applicationName; } public void setAuthenticationScheme(String authenticationScheme) { this.authenticationScheme = authenticationScheme; } public void setAuthorizationHeaderName(String requestAuthorizationHeaderName) { this.authorizationHeaderName = requestAuthorizationHeaderName; } public void setChallengeHeaderName(String responseAuthenticateHeaderName) { this.challengeHeaderName = responseAuthenticateHeaderName; } public String getApplicationName() { return applicationName; } public String getAuthenticationScheme() { return authenticationScheme; } public String getAuthorizationHeaderName() { return authorizationHeaderName; } public String getChallengeHeaderName() { return challengeHeaderName; } /** * Looks for an Authorization header (the name can be set with * setAuthorizationHeaderName) with the authenticationScheme * @param request * @return */ @Override protected boolean isAuthenticationRequest(ServletRequest request) { if( authorizationHeaderName == null ) { throw new IllegalStateException("A filter extending HttpAuthenticationFilter must set the authorization header name; default is Authorization"); } if( authenticationScheme == null ) { throw new IllegalStateException("A filter extending HttpAuthenticationFilter must set the authentication scheme"); } HttpServletRequest httpRequest = WebUtils.toHttp(request); log.debug("isAuthenticationRequest looking for {} in {}", authenticationScheme, authorizationHeaderName); String headerValue = httpRequest.getHeader(authorizationHeaderName); if( headerValue == null ) { log.debug("isAuthenticationRequest did not find {} header", authorizationHeaderName); return false; } if( headerValue.startsWith(authenticationScheme)) { return true; } return false; } protected void sendChallenge(ServletRequest request, ServletResponse response) { log.debug("sending challenge header {} to {}", challengeHeaderName, request.getRemoteAddr()); HttpServletResponse httpResponse = WebUtils.toHttp(response); httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); String authcHeader = authenticationScheme + " realm=\"" + getApplicationName() + "\""; httpResponse.addHeader(challengeHeaderName, authcHeader); } @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException authenticationException, ServletRequest request, ServletResponse response) { log.debug("onLoginFailure token: {} exception: {}: {}", token, authenticationException.getClass().getName(), authenticationException.getMessage()); if( authenticationException.getCause() != null ) { log.debug("authentication exception cause", authenticationException.getCause()); } try { sendChallenge(request, response); } catch(Exception e) { log.error("Error while sending challenge due to login failure: {}", e.getMessage()); log.debug("Error while sending challenge", e); } return false; } /** * The UnauthenticatedException is thrown from authorization code within * the business layer that requires the user to be authenticated and the * user is not - that can only happen if the client did not attempt to * send authentication tokens with the request. * * @param request * @param response * @param existing * @throws ServletException * @throws IOException */ @Override protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException { UnauthenticatedException cause = ErrorUtil.findCause(existing, UnauthenticatedException.class); if( cause != null ) { log.debug("Caught UnauthenticatedException; sending challenge"); try { sendChallenge(request, response); existing = null; } catch(Exception e) { existing = e; } } super.cleanup(request, response, existing); } }