/** * Authenticate the user making this request, based on the specified login configuration. Return * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we * have created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication should be performed * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); return (true); } // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); /* Try to reauthenticate using data cached by SSO. If this fails, either the original SSO logon was of DIGEST or SSL (which we can't reauthenticate ourselves because there is no cached username and password), or the realm denied the user's reauthentication for some reason. In either case we have to prompt the user for a logon */ if (reauthenticateFromSSO(ssoId, request)) return true; } // Validate any credentials already included with this request String username = null; String password = null; MessageBytes authorization = request.getCoyoteRequest().getMimeHeaders().getValue("authorization"); if (authorization != null) { authorization.toBytes(); ByteChunk authorizationBC = authorization.getByteChunk(); if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { authorizationBC.setOffset(authorizationBC.getOffset() + 6); // FIXME: Add trimming // authorizationBC.trim(); CharChunk authorizationCC = authorization.getCharChunk(); Base64.decode(authorizationBC, authorizationCC); // Get username and password int colon = authorizationCC.indexOf(':'); if (colon < 0) { username = authorizationCC.toString(); } else { char[] buf = authorizationCC.getBuffer(); username = new String(buf, 0, colon); password = new String(buf, colon + 1, authorizationCC.getEnd() - colon - 1); } authorizationBC.setOffset(authorizationBC.getOffset() - 6); } principal = context.getRealm().authenticate(username, password); if (principal != null) { register(request, response, principal, Constants.BASIC_METHOD, username, password); return (true); } } StringBuilder value = new StringBuilder(16); value.append("Basic realm=\""); if (config.getRealmName() == null) { value.append(REALM_NAME); } else { value.append(config.getRealmName()); } value.append('\"'); response.setHeader(AUTH_HEADER_NAME, value.toString()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return (false); }
@Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { if (checkForCachedAuthentication(request, response, true)) { return true; } MessageBytes authorization = request.getCoyoteRequest().getMimeHeaders().getValue("authorization"); if (authorization == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("authenticator.noAuthHeader")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } authorization.toBytes(); ByteChunk authorizationBC = authorization.getByteChunk(); if (!authorizationBC.startsWithIgnoreCase("negotiate ", 0)) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.authHeaderNotNego")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } authorizationBC.setOffset(authorizationBC.getOffset() + 10); byte[] decoded = Base64.decodeBase64( authorizationBC.getBuffer(), authorizationBC.getOffset(), authorizationBC.getLength()); if (getApplyJava8u40Fix()) { SpnegoTokenFixer.fix(decoded); } if (decoded.length == 0) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.authHeaderNoToken")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } LoginContext lc = null; GSSContext gssContext = null; byte[] outToken = null; Principal principal = null; try { try { lc = new LoginContext(getLoginConfigName()); lc.login(); } catch (LoginException e) { log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return false; } Subject subject = lc.getSubject(); // Assume the GSSContext is stateless // TODO: Confirm this assumption final GSSManager manager = GSSManager.getInstance(); // IBM JDK only understands indefinite lifetime final int credentialLifetime; if (Globals.IS_IBM_JVM) { credentialLifetime = GSSCredential.INDEFINITE_LIFETIME; } else { credentialLifetime = GSSCredential.DEFAULT_LIFETIME; } final PrivilegedExceptionAction<GSSCredential> action = new PrivilegedExceptionAction<GSSCredential>() { @Override public GSSCredential run() throws GSSException { return manager.createCredential( null, credentialLifetime, new Oid("1.3.6.1.5.5.2"), GSSCredential.ACCEPT_ONLY); } }; gssContext = manager.createContext(Subject.doAs(subject, action)); outToken = Subject.doAs(lc.getSubject(), new AcceptAction(gssContext, decoded)); if (outToken == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.ticketValidateFail")); } // Start again response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } principal = Subject.doAs( subject, new AuthenticateAction(context.getRealm(), gssContext, storeDelegatedCredential)); } catch (GSSException e) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.ticketValidateFail"), e); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } catch (PrivilegedActionException e) { Throwable cause = e.getCause(); if (cause instanceof GSSException) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.serviceLoginFail"), e); } } else { log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } finally { if (gssContext != null) { try { gssContext.dispose(); } catch (GSSException e) { // Ignore } } if (lc != null) { try { lc.logout(); } catch (LoginException e) { // Ignore } } } // Send response token on success and failure response.setHeader("WWW-Authenticate", "Negotiate " + Base64.encodeBase64String(outToken)); if (principal != null) { register(request, response, principal, Constants.SPNEGO_METHOD, principal.getName(), null); Pattern p = noKeepAliveUserAgents; if (p != null) { MessageBytes ua = request.getCoyoteRequest().getMimeHeaders().getValue("user-agent"); if (ua != null && p.matcher(ua.toString()).matches()) { response.setHeader("Connection", "close"); } } return true; } response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; }