/** * Returns the {@link AuthenticationToken} for the request. * * <p>It looks at the received HTTP cookies and extracts the value of the {@link * AuthenticatedURL#AUTH_COOKIE} if present. It verifies the signature and if correct it creates * the {@link AuthenticationToken} and returns it. * * <p>If this method returns <code>null</code> the filter will invoke the configured {@link * AuthenticationHandler} to perform user authentication. * * @param request request object. * @return the Authentication token if the request is authenticated, <code>null</code> otherwise. * @throws IOException thrown if an IO error occurred. * @throws AuthenticationException thrown if the token is invalid or if it has expired. */ protected AuthenticationToken getToken(HttpServletRequest request) throws IOException, AuthenticationException { AuthenticationToken token = null; String tokenStr = null; Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(AuthenticatedURL.AUTH_COOKIE)) { tokenStr = cookie.getValue(); try { tokenStr = signer.verifyAndExtract(tokenStr); } catch (SignerException ex) { throw new AuthenticationException(ex); } break; } } } if (tokenStr != null) { token = AuthenticationToken.parse(tokenStr); if (!token.getType().equals(authHandler.getType())) { throw new AuthenticationException("Invalid AuthenticationToken type"); } if (token.isExpired()) { throw new AuthenticationException("AuthenticationToken expired"); } } return token; }
/** * Destroys the filter. * * <p>It invokes the {@link AuthenticationHandler#destroy()} method to release any resources it * may hold. */ @Override public void destroy() { if (authHandler != null) { authHandler.destroy(); authHandler = null; } if (secretProvider != null) { secretProvider.destroy(); } }
/** * If the request has a valid authentication token it allows the request to continue to the target * resource, otherwise it triggers an authentication sequence using the configured {@link * AuthenticationHandler}. * * @param request the request object. * @param response the response object. * @param filterChain the filter chain object. * @throws IOException thrown if an IO error occurred. * @throws ServletException thrown if a processing error occurred. */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { boolean unauthorizedResponse = true; int errCode = HttpServletResponse.SC_UNAUTHORIZED; AuthenticationException authenticationEx = null; HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; boolean isHttps = "https".equals(httpRequest.getScheme()); try { boolean newToken = false; AuthenticationToken token; try { token = getToken(httpRequest); } catch (AuthenticationException ex) { LOG.warn("AuthenticationToken ignored: " + ex.getMessage()); // will be sent back in a 401 unless filter authenticates authenticationEx = ex; token = null; } if (authHandler.managementOperation(token, httpRequest, httpResponse)) { if (token == null) { if (LOG.isDebugEnabled()) { LOG.debug("Request [{}] triggering authentication", getRequestURL(httpRequest)); } token = authHandler.authenticate(httpRequest, httpResponse); if (token != null && token.getExpires() != 0 && token != AuthenticationToken.ANONYMOUS) { token.setExpires(System.currentTimeMillis() + getValidity() * 1000); } newToken = true; } if (token != null) { unauthorizedResponse = false; if (LOG.isDebugEnabled()) { LOG.debug( "Request [{}] user [{}] authenticated", getRequestURL(httpRequest), token.getUserName()); } final AuthenticationToken authToken = token; httpRequest = new HttpServletRequestWrapper(httpRequest) { @Override public String getAuthType() { return authToken.getType(); } @Override public String getRemoteUser() { return authToken.getUserName(); } @Override public Principal getUserPrincipal() { return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null; } }; if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) { String signedToken = signer.sign(token.toString()); createAuthCookie( httpResponse, signedToken, getCookieDomain(), getCookiePath(), token.getExpires(), isHttps); } filterChain.doFilter(httpRequest, httpResponse); } } else { unauthorizedResponse = false; } } catch (AuthenticationException ex) { // exception from the filter itself is fatal errCode = HttpServletResponse.SC_FORBIDDEN; authenticationEx = ex; LOG.warn("Authentication exception: " + ex.getMessage(), ex); } if (unauthorizedResponse) { if (!httpResponse.isCommitted()) { createAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, isHttps); if (authenticationEx == null) { httpResponse.sendError(errCode, "Authentication required"); } else { httpResponse.sendError(errCode, authenticationEx.getMessage()); } } } }
/** * Initializes the authentication filter. * * <p>It instantiates and initializes the specified {@link AuthenticationHandler}. * * <p> * * @param filterConfig filter configuration. * @throws ServletException thrown if the filter or the authentication handler could not be * initialized properly. */ @Override public void init(FilterConfig filterConfig) throws ServletException { String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX); configPrefix = (configPrefix != null) ? configPrefix + "." : ""; Properties config = getConfiguration(configPrefix, filterConfig); String authHandlerName = config.getProperty(AUTH_TYPE, null); String authHandlerClassName; if (authHandlerName == null) { throw new ServletException( "Authentication type must be specified: " + PseudoAuthenticationHandler.TYPE + "|" + KerberosAuthenticationHandler.TYPE + "|<class>"); } if (authHandlerName.toLowerCase(Locale.ENGLISH).equals(PseudoAuthenticationHandler.TYPE)) { authHandlerClassName = PseudoAuthenticationHandler.class.getName(); } else if (authHandlerName .toLowerCase(Locale.ENGLISH) .equals(KerberosAuthenticationHandler.TYPE)) { authHandlerClassName = KerberosAuthenticationHandler.class.getName(); } else { authHandlerClassName = authHandlerName; } try { Class<?> klass = Thread.currentThread().getContextClassLoader().loadClass(authHandlerClassName); authHandler = (AuthenticationHandler) klass.newInstance(); authHandler.init(config); } catch (ClassNotFoundException ex) { throw new ServletException(ex); } catch (InstantiationException ex) { throw new ServletException(ex); } catch (IllegalAccessException ex) { throw new ServletException(ex); } validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, "36000")) * 1000; // 10 hours secretProvider = (SignerSecretProvider) filterConfig.getServletContext().getAttribute(SIGNATURE_PROVIDER_ATTRIBUTE); if (secretProvider == null) { String signerSecretProviderClassName = config.getProperty(configPrefix + SIGNER_SECRET_PROVIDER_CLASS, null); if (signerSecretProviderClassName == null) { String signatureSecret = config.getProperty(configPrefix + SIGNATURE_SECRET, null); if (signatureSecret != null) { secretProvider = new StringSignerSecretProvider(signatureSecret); } else { secretProvider = new RandomSignerSecretProvider(); randomSecret = true; } } else { try { Class<?> klass = Thread.currentThread() .getContextClassLoader() .loadClass(signerSecretProviderClassName); secretProvider = (SignerSecretProvider) klass.newInstance(); customSecretProvider = true; } catch (ClassNotFoundException ex) { throw new ServletException(ex); } catch (InstantiationException ex) { throw new ServletException(ex); } catch (IllegalAccessException ex) { throw new ServletException(ex); } } try { secretProvider.init(config, validity); } catch (Exception ex) { throw new ServletException(ex); } } else { customSecretProvider = true; } signer = new Signer(secretProvider); cookieDomain = config.getProperty(COOKIE_DOMAIN, null); cookiePath = config.getProperty(COOKIE_PATH, null); }