Example usage for javax.security.auth.kerberos KerberosPrincipal KerberosPrincipal

List of usage examples for javax.security.auth.kerberos KerberosPrincipal KerberosPrincipal

Introduction

In this page you can find the example usage for javax.security.auth.kerberos KerberosPrincipal KerberosPrincipal.

Prototype

public KerberosPrincipal(String name) 

Source Link

Document

Constructs a KerberosPrincipal from the provided string input.

Usage

From source file:net.shibboleth.idp.authn.spnego.impl.SPNEGOAuthnController.java

/**
 * Process an input GSS token from the client and attempt to complete the context establishment process.
 * /* w ww. ja  v a 2  s  . c  om*/
 * @param conversationKey the conversation key
 * @param authorizationHeader the token from the client
 * @param httpRequest the HTTP request
 * @param httpResponse the HTTP response
 * 
 * @return the response view
 * @throws ExternalAuthenticationException 
 * @throws IOException 
 */
@RequestMapping(value = "/{conversationKey}", method = RequestMethod.GET, headers = "Authorization")
@Nullable
public ModelAndView continueSPNEGO(@PathVariable @Nonnull @NotEmpty final String conversationKey,
        @RequestHeader(HttpHeaders.AUTHORIZATION) @Nonnull @NotEmpty final String authorizationHeader,
        @Nonnull final HttpServletRequest httpRequest, @Nonnull final HttpServletResponse httpResponse)
        throws ExternalAuthenticationException, IOException {

    final ProfileRequestContext prc = ExternalAuthentication.getProfileRequestContext(conversationKey,
            httpRequest);

    if (!authorizationHeader.startsWith("Negotiate ")) {
        return replyUnauthorizedNegotiate(prc, httpRequest, httpResponse);
    }

    final SPNEGOContext spnegoCtx = getSPNEGOContext(prc);
    if (spnegoCtx == null || spnegoCtx.getKerberosSettings() == null) {
        log.error("Kerberos settings not found in profile request context");
        finishWithError(conversationKey, httpRequest, httpResponse, AuthnEventIds.INVALID_AUTHN_CTX);
        return null;
    }

    GSSContextAcceptor acceptor = spnegoCtx.getContextAcceptor();
    if (acceptor == null) {
        try {
            acceptor = createGSSContextAcceptor(spnegoCtx);
            spnegoCtx.setContextAcceptor(acceptor);
        } catch (final GSSException e) {
            log.error("Unable to create GSSContextAcceptor", e);
            finishWithException(conversationKey, httpRequest, httpResponse,
                    new ExternalAuthenticationException(SPNEGO_NOT_AVAILABLE, e));
            return null;
        }
    }

    final byte[] gssapiData = Base64.decodeBase64(authorizationHeader.substring(10).getBytes());
    log.trace("SPNEGO negotiation, Authorization header received, gssapi-data: {}", gssapiData);

    // NTLM Authentication is not supported.
    if (isNTLMMechanism(gssapiData)) {
        log.warn("NTLM is unsupported, failing context negotiation");
        acceptor.logout();
        finishWithError(conversationKey, httpRequest, httpResponse, NTLM_UNSUPPORTED);
        return null;
    }

    byte[] tokenBytes;
    try {
        tokenBytes = acceptor.acceptSecContext(gssapiData, 0, gssapiData.length);
        log.trace("GSS token accepted");
    } catch (final Exception e) {
        log.debug("Exception processing GSS token", e);
        acceptor.logout();
        finishWithException(conversationKey, httpRequest, httpResponse,
                new ExternalAuthenticationException(SPNEGO_NOT_AVAILABLE, e));
        return null;
    }

    // If the context is established, we can attempt to retrieve the name of the "context initiator."
    // In the case of the Kerberos mechanism, the context initiator is the Kerberos principal of the client.
    if (acceptor.getContext() != null && acceptor.getContext().isEstablished()) {
        log.debug("GSS security context is complete");
        try {
            final GSSName clientGSSName = acceptor.getContext().getSrcName();
            if (clientGSSName == null) {
                // This case should never happen, but we observed it. Handle it as authentication failure.
                log.error("Error extracting principal name from security context");
                acceptor.logout();
                finishWithException(conversationKey, httpRequest, httpResponse,
                        new ExternalAuthenticationException(SPNEGO_NOT_AVAILABLE));
                return null;
            }
            final KerberosPrincipal kerberosPrincipal = new KerberosPrincipal(clientGSSName.toString());

            log.info("SPNEGO/Kerberos authentication succeeded for principal: {}", clientGSSName.toString());

            acceptor.logout();
            finishWithSuccess(conversationKey, httpRequest, httpResponse, kerberosPrincipal);
        } catch (final GSSException e) {
            log.error("Error extracting principal name from security context", e);
            acceptor.logout();
            finishWithException(conversationKey, httpRequest, httpResponse,
                    new ExternalAuthenticationException(SPNEGO_NOT_AVAILABLE, e));
        }
    } else {
        // The context is not complete yet.
        // return "WWW-Authenticate: Negotiate <data>" to the browser
        log.trace("SPNEGO negotiation in process, output token: {}", tokenBytes);
        return replyUnauthorizedNegotiate(prc, httpRequest, httpResponse,
                Base64.encodeBase64String(tokenBytes));
    }

    return null;
}

From source file:com.example.ManualSpnegoNegotiateServlet.java

/**
 * Use of Kerberos is wrapped in an HTTP auth-scheme of "Negotiate" [RFC 4559].
 *
 * The auth-params exchanged use data formats defined for use with the GSS-API [RFC 2743]. In particular, they follow the formats set for the SPNEGO [RFC 4178] and
 * Kerberos [RFC 4121] mechanisms for GSSAPI. The "Negotiate" auth-scheme calls for the use of SPNEGO GSSAPI tokens that the specific mechanism type specifies.
 *
 * The current implementation of this protocol is limited to the use of SPNEGO with the Kerberos protocol.
 *
 * @param request//from   w w w  . ja  va 2s  .c o m
 * @param response
 * @throws ServletException
 *
 * @return true upon successful authentication, false otherwise
 */
protected boolean attemptNegotiation(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, UnsupportedEncodingException, IOException {
    log.debug("Attempting negotiation.");

    String header = request.getHeader("Authorization");

    /**
     * Guard clause to check for Negotiate header.
     *
     * If the server receives a request for an access-protected object, and if an acceptable Authorization header has not been sent, the server responds with a "401
     * Unauthorized" status code, and a "WWW-Authenticate:" header as per the framework described in [RFC 2616]. The initial WWW-Authenticate header will not carry
     * any gssapi-data.
     */
    if (header == null || header.length() < 10 || !header.startsWith("Negotiate ")) {
        response.setHeader("WWW-Authenticate", "Negotiate");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        log.debug("Proper authorization header not found, returning challenge.");
        return false;
    }

    /**
     * A client may initiate a connection to the server with an "Authorization" header containing the initial token for the server. This form will bypass the initial
     * 401 error from the server when the client knows that the server will accept the Negotiate HTTP authentication type.
     */
    log.debug("Authorization header found, continuing negotiation.");

    /**
     * The data following the word Negotiate is the GSS-API data to process.
     */
    byte gssapiData[] = Base64.decode(header.substring(10));

    log.debug("GSS API data: " + Arrays.toString(gssapiData));

    /**
     * Guard clause to check for the unsupported NTLM authentication mechanism.
     */
    if (isNtlmMechanism(gssapiData)) {
        log.warn("Got request for unsupported NTLM mechanism, aborting negotiation.");
        return false;
    }

    /**
     * The server attempts to establish a security context. Establishment may result in tokens that the server must return to the client. Tokens are BASE-64 encoded
     * GSS-API data.
     */
    GSSContext gssContext = null;
    LoginContext loginContext = null;
    String outToken = null;

    try {
        final String domainUsername = "Zeus";
        final String domainUserPassword = "Z3usP@55";
        final CallbackHandler handler = SpnegoProvider.getUsernamePasswordHandler(domainUsername,
                domainUserPassword);

        loginContext = new LoginContext("spnego-server", handler);
        loginContext.login();
        Subject subject = loginContext.getSubject();

        Oid spnegoOid = new Oid("1.3.6.1.5.5.2"); // for spnego answers
        Oid kerbv5Oid = new Oid("1.2.840.113554.1.2.2"); // for chromium (they send a kerbv5 token instead of spnego)
        final Oid[] oids = new Oid[] { spnegoOid, kerbv5Oid };

        final GSSManager manager = GSSManager.getInstance();
        final PrivilegedExceptionAction<GSSCredential> action = new PrivilegedExceptionAction<GSSCredential>() {
            public GSSCredential run() throws GSSException {
                return manager.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, oids,
                        GSSCredential.ACCEPT_ONLY);
            }
        };

        GSSCredential serverCreds = Subject.doAs(subject, action);

        log.debug("Mechs: " + Arrays.toString(serverCreds.getMechs()));

        gssContext = manager.createContext(serverCreds);

        log.debug("Context created. " + gssContext);

        byte tokenBytes[] = gssContext.acceptSecContext(gssapiData, 0, gssapiData.length);
        outToken = Base64.encode(tokenBytes);
    } catch (PrivilegedActionException ex) {
        log.error("", ex);
    } catch (LoginException ex) {
        log.error("", ex);
    } catch (GSSException gsse) {
        gsse.printStackTrace();
        log.error("GSSException:       " + gsse.getMessage());
        log.error("GSSException major: " + gsse.getMajorString());
        log.error("GSSException minor: " + gsse.getMinorString());
        throw new ServletException(gsse);
    }

    /**
     * If the context is established, we can attempt to retrieve the name of the "context initiator." In the case of the Kerberos mechanism, the context initiator is
     * the Kerberos principal of the client. Additionally, the client may be delegating credentials.
     */
    if (gssContext != null && gssContext.isEstablished()) {
        log.debug("Context established, attempting Kerberos principal retrieval.");

        try {
            Subject subject = new Subject();
            GSSName clientGSSName = gssContext.getSrcName();
            KerberosPrincipal clientPrincipal = new KerberosPrincipal(clientGSSName.toString());
            subject.getPrincipals().add(clientPrincipal);
            log.info("Got client Kerberos principal: " + clientGSSName);
            response.getWriter().println("Hello, " + clientPrincipal);

            /**
             * Retrieve LogonInfo (for example, GroupSIDs) from the PAC Authorization Data
             * from a Kerberos Ticket that was issued by Active Directory.
             */
            byte[] kerberosTokenData = gssapiData;
            try {
                SpnegoToken token = SpnegoToken.parse(gssapiData);
                kerberosTokenData = token.getMechanismToken();
            } catch (DecodingException dex) {
                // Chromium bug: sends a Kerberos response instead of an spnego response with a Kerberos mechanism
            } catch (Exception ex) {
                log.error("", ex);
            }

            try {
                Object[] keyObjs = IteratorUtils
                        .toArray(loginContext.getSubject().getPrivateCredentials(KerberosKey.class).iterator());
                KerberosKey[] keys = new KerberosKey[keyObjs.length];
                System.arraycopy(keyObjs, 0, keys, 0, keyObjs.length);

                KerberosToken token = new KerberosToken(kerberosTokenData, keys);
                log.info("Authorizations: ");
                for (KerberosAuthData authData : token.getTicket().getEncData().getUserAuthorizations()) {
                    if (authData instanceof KerberosPacAuthData) {
                        PacSid[] groupSIDs = ((KerberosPacAuthData) authData).getPac().getLogonInfo()
                                .getGroupSids();
                        log.info("GroupSids: " + Arrays.toString(groupSIDs));
                        response.getWriter().println("Found group SIDs: " + Arrays.toString(groupSIDs));
                    } else {
                        log.info("AuthData without PAC: " + authData.toString());
                    }
                }
            } catch (Exception ex) {
                log.error("", ex);
            }

            if (gssContext.getCredDelegState()) {
                GSSCredential delegateCredential = gssContext.getDelegCred();
                GSSName delegateGSSName = delegateCredential.getName();
                Principal delegatePrincipal = new KerberosPrincipal(delegateGSSName.toString());
                subject.getPrincipals().add(delegatePrincipal);
                subject.getPrivateCredentials().add(delegateCredential);
                log.info("Got delegated Kerberos principal: " + delegateGSSName);
            }

            /**
             * A status code 200 status response can also carry a "WWW-Authenticate" response header containing the final leg of an authentication. In this case, the
             * gssapi-data will be present.
             */
            if (outToken != null && outToken.length() > 0) {
                response.setHeader("WWW-Authenticate", "Negotiate " + outToken.getBytes());
                response.setStatus(HttpServletResponse.SC_OK);
                log.debug("Returning final authentication data to client to complete context.");
                log.debug("Negotiation completed.");
                return true;
            }
        } catch (GSSException gsse) {
            log.error("GSSException:       " + gsse.getMessage());
            log.error("GSSException major: " + gsse.getMajorString());
            log.error("GSSException minor: " + gsse.getMinorString());

            response.addHeader("Client-Warning", gsse.getMessage());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    } else {
        /**
         * Any returned code other than a success 2xx code represents an authentication error. If a 401 containing a "WWW-Authenticate" header with "Negotiate" and
         * gssapi-data is returned from the server, it is a continuation of the authentication request.
         */
        if (outToken != null && outToken.length() > 0) {
            response.setHeader("WWW-Authenticate", "Negotiate " + outToken.getBytes());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            log.debug("Additional authentication processing required, returning token.");
            return false;
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            log.warn("Kerberos negotiation failed.");
        }
    }

    log.debug("Negotiation completed.");

    return true;
}

From source file:com.sonymobile.jenkins.plugins.kerberossso.KerberosFilterTest.java

private void fakePrincipal(String principal) throws LoginException, IOException, ServletException {
    if (!principal.contains("@")) {
        throw new AssertionError(
                "Principal name must have realm specified as system may not be configured with default one");
    }/*from ww  w. j a  v a2s  . c  om*/
    KerberosAuthenticator mockAuthenticator = mock(KerberosAuthenticator.class);
    when(mockAuthenticator.authenticate(any(HttpServletRequest.class), any(HttpServletResponse.class)))
            .thenReturn(new KerberosPrincipal(principal));
    registerFilter(mockAuthenticator);
}

From source file:ddf.security.assertion.impl.SecurityAssertionImpl.java

@Override
public Principal getPrincipal() {
    if (securityToken != null) {
        if (principal == null || !principal.getName().equals(name)) {
            String authMethod = null;
            if (authenticationStatements != null) {
                for (AuthnStatement authnStatement : authenticationStatements) {
                    AuthnContext authnContext = authnStatement.getAuthnContext();
                    if (authnContext != null) {
                        AuthnContextClassRef authnContextClassRef = authnContext.getAuthnContextClassRef();
                        if (authnContextClassRef != null) {
                            authMethod = authnContextClassRef.getAuthnContextClassRef();
                        }//  ww  w  .j  a  va  2s.  c o  m
                    }
                }
            }
            if (SAML2Constants.AUTH_CONTEXT_CLASS_REF_X509.equals(authMethod)
                    || SAML2Constants.AUTH_CONTEXT_CLASS_REF_SMARTCARD_PKI.equals(authMethod)
                    || SAML2Constants.AUTH_CONTEXT_CLASS_REF_SOFTWARE_PKI.equals(authMethod)
                    || SAML2Constants.AUTH_CONTEXT_CLASS_REF_SPKI.equals(authMethod)
                    || SAML2Constants.AUTH_CONTEXT_CLASS_REF_TLS_CLIENT.equals(authMethod)) {
                principal = new X500Principal(name);
            } else if (SAML2Constants.AUTH_CONTEXT_CLASS_REF_KERBEROS.equals(authMethod)) {
                principal = new KerberosPrincipal(name);
            } else if (principal instanceof GuestPrincipal
                    || name.startsWith(GuestPrincipal.GUEST_NAME_PREFIX)) {
                principal = new GuestPrincipal(name);
            } else {
                principal = new AssertionPrincipal(name);
            }
        }
        return principal;
    }
    return null;
}

From source file:com.xebialabs.overthere.cifs.winrm.WinRmClient.java

private void configureHttpClient(final DefaultHttpClient httpclient) throws GeneralSecurityException {
    configureTrust(httpclient);/*from   w  w w  .ja  v  a 2s  .  c  om*/

    configureAuthentication(httpclient, BASIC, new BasicUserPrincipal(username));

    if (enableKerberos) {
        String spnServiceClass = kerberosUseHttpSpn ? "HTTP" : "WSMAN";
        httpclient.getAuthSchemes().register(KERBEROS, new WsmanKerberosSchemeFactory(!kerberosAddPortToSpn,
                spnServiceClass, unmappedAddress, unmappedPort));
        httpclient.getAuthSchemes().register(SPNEGO, new WsmanSPNegoSchemeFactory(!kerberosAddPortToSpn,
                spnServiceClass, unmappedAddress, unmappedPort));
        configureAuthentication(httpclient, KERBEROS, new KerberosPrincipal(username));
        configureAuthentication(httpclient, SPNEGO, new KerberosPrincipal(username));
    }

    httpclient.getParams().setBooleanParameter(HANDLE_AUTHENTICATION, true);
}

From source file:com.xebialabs.overthere.winrm.WinRmClient.java

private void configureHttpClient(final HttpClientBuilder httpclient) throws GeneralSecurityException {
    configureTrust(httpclient);/*from   w  w w .  j  a v a  2  s.  c  om*/
    BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    httpclient.setDefaultCredentialsProvider(credentialsProvider);

    configureAuthentication(credentialsProvider, BASIC, new BasicUserPrincipal(username));

    if (enableKerberos) {
        String spnServiceClass = kerberosUseHttpSpn ? "HTTP" : "WSMAN";
        RegistryBuilder<AuthSchemeProvider> authSchemeRegistryBuilder = RegistryBuilder.create();
        authSchemeRegistryBuilder.register(KERBEROS, new WsmanKerberosSchemeFactory(!kerberosAddPortToSpn,
                spnServiceClass, unmappedAddress, unmappedPort));
        authSchemeRegistryBuilder.register(SPNEGO, new WsmanSPNegoSchemeFactory(!kerberosAddPortToSpn,
                spnServiceClass, unmappedAddress, unmappedPort));
        httpclient.setDefaultAuthSchemeRegistry(authSchemeRegistryBuilder.build());
        configureAuthentication(credentialsProvider, KERBEROS, new KerberosPrincipal(username));
        configureAuthentication(credentialsProvider, SPNEGO, new KerberosPrincipal(username));
    }

    httpclient.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(soTimeout).build());
    httpclient.setDefaultRequestConfig(
            RequestConfig.custom().setAuthenticationEnabled(true).setConnectTimeout(connectionTimeout).build());
}

From source file:net.java.jaspicoil.MSPacSpnegoServerAuthModule.java

private Subject fetchSubjectFromLoginModuleWithPrincipal(String jaasContextName, String servicePrincipal,
        Krb5LoginConfig loginConfig) throws LoginException {
    final Set<Principal> princ = new HashSet<Principal>(1);
    princ.add(new KerberosPrincipal(servicePrincipal));
    // Create a new editable Subject
    final Subject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>());
    return fetchSubjectFromLoginModule(jaasContextName, sub, loginConfig);
}

From source file:io.druid.security.kerberos.KerberosAuthenticator.java

private String getPrincipalFromRequestNew(HttpServletRequest req) {
    String authorization = req//w w w  .  ja  va 2s .co  m
            .getHeader(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.AUTHORIZATION);
    if (authorization == null || !authorization
            .startsWith(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.NEGOTIATE)) {
        return null;
    } else {
        authorization = authorization.substring(
                org.apache.hadoop.security.authentication.client.KerberosAuthenticator.NEGOTIATE.length())
                .trim();
        final Base64 base64 = new Base64(0);
        final byte[] clientToken = base64.decode(authorization);
        try {
            DerInputStream ticketStream = new DerInputStream(clientToken);
            DerValue[] values = ticketStream.getSet(clientToken.length, true);

            // see this link for AP-REQ format: https://tools.ietf.org/html/rfc1510#section-5.5.1
            for (DerValue value : values) {
                if (isValueAPReq(value)) {
                    APReq apReq = new APReq(value);
                    Ticket ticket = apReq.ticket;
                    EncryptedData encData = ticket.encPart;
                    int eType = encData.getEType();

                    // find the server's key
                    EncryptionKey finalKey = null;
                    Subject serverSubj = loginContext.getSubject();
                    Set<Object> serverCreds = serverSubj.getPrivateCredentials(Object.class);
                    for (Object cred : serverCreds) {
                        if (cred instanceof KeyTab) {
                            KeyTab serverKeyTab = (KeyTab) cred;
                            KerberosPrincipal serverPrincipal = new KerberosPrincipal(this.serverPrincipal);
                            KerberosKey[] serverKeys = serverKeyTab.getKeys(serverPrincipal);
                            for (KerberosKey key : serverKeys) {
                                if (key.getKeyType() == eType) {
                                    finalKey = new EncryptionKey(key.getKeyType(), key.getEncoded());
                                    break;
                                }
                            }
                        }
                    }

                    if (finalKey == null) {
                        log.error("Could not find matching key from server creds.");
                        return null;
                    }

                    // decrypt the ticket with the server's key
                    byte[] decryptedBytes = encData.decrypt(finalKey, KeyUsage.KU_TICKET);
                    decryptedBytes = encData.reset(decryptedBytes);
                    EncTicketPart decrypted = new EncTicketPart(decryptedBytes);
                    String clientPrincipal = decrypted.cname.toString();
                    return clientPrincipal;
                }
            }
        } catch (Exception ex) {
            Throwables.propagate(ex);
        }
    }

    return null;
}

From source file:io.druid.security.kerberos.KerberosAuthenticator.java

private void initializeKerberosLogin() throws ServletException {
    String principal;/*w  ww  . j  a  v  a  2  s  . c  o m*/
    String keytab;

    try {
        principal = SecurityUtil.getServerPrincipal(serverPrincipal, node.getHost());
        if (principal == null || principal.trim().length() == 0) {
            throw new ServletException("Principal not defined in configuration");
        }
        keytab = serverKeytab;
        if (keytab == null || keytab.trim().length() == 0) {
            throw new ServletException("Keytab not defined in configuration");
        }
        if (!new File(keytab).exists()) {
            throw new ServletException("Keytab does not exist: " + keytab);
        }

        Set<Principal> principals = new HashSet<Principal>();
        principals.add(new KerberosPrincipal(principal));
        Subject subject = new Subject(false, principals, new HashSet<Object>(), new HashSet<Object>());

        DruidKerberosConfiguration kerberosConfiguration = new DruidKerberosConfiguration(keytab, principal);

        log.info("Login using keytab " + keytab + ", for principal " + principal);
        loginContext = new LoginContext("", subject, null, kerberosConfiguration);
        loginContext.login();

        log.info("Initialized, principal %s from keytab %s", principal, keytab);
    } catch (Exception ex) {
        throw new ServletException(ex);
    }
}

From source file:net.java.jaspicoil.MSPacSpnegoServerAuthModule.java

/**
 * Authenticate a received service request.
 * <p/>/*from   w  w w .jav  a2  s. c o m*/
 * This method is called to transform the mechanism-specific request message
 * acquired by calling getRequestMessage (on messageInfo) into the validated
 * application message to be returned to the message processing runtime. If
 * the received message is a (mechanism-specific) meta-message, the method
 * implementation must attempt to transform the meta-message into a
 * corresponding mechanism-specific response message, or to the validated
 * application request message. The runtime will bind a validated
 * application message into the the corresponding service invocation.
 * <p>
 * This method conveys the outcome of its message processing either by
 * returning an AuthStatus value or by throwing an AuthException.
 * <p/>
 * From a performance point of view this method will be called twice for
 * each resource with a security constraint on it. Resources with no
 * security constraint do not result in a call to this method.
 * 
 * @param messageInfo
 *            A contextual object that encapsulates the client request and
 *            server response objects, and that may be used to save state
 *            across a sequence of calls made to the methods of this
 *            interface for the purpose of completing a secure message
 *            exchange.
 * @param clientSubject
 *            A Subject that represents the source of the service request.
 *            It is used by the method implementation to store Principals
 *            and credentials validated in the request.
 * @param serviceSubject
 *            A Subject that represents the recipient of the service
 *            request, or null. It may be used by the method implementation
 *            as the source of Principals or credentials to be used to
 *            validate the request. If the Subject is not null, the method
 *            implementation may add additional Principals or credentials
 *            (pertaining to the recipient of the service request) to the
 *            Subject.
 * @return An AuthStatus object representing the completion status of the
 *         processing performed by the method. The AuthStatus values that
 *         may be returned by this method are defined as follows:
 *         <p/>
 *         <ul>
 *         <li>AuthStatus.SUCCESS when the application request message was
 *         successfully validated. The validated request message is
 *         available by calling getRequestMessage on messageInfo.
 *         <p/>
 *         <li>AuthStatus.SEND_SUCCESS to indicate that
 *         validation/processing of the request message successfully
 *         produced the secured application response message (in
 *         messageInfo). The secured response message is available by
 *         calling getResponseMessage on messageInfo.
 *         <p/>
 *         <li>AuthStatus.SEND_CONTINUE to indicate that message validation
 *         is incomplete, and that a preliminary response was returned as
 *         the response message in messageInfo.
 *         <p/>
 *         When this status value is returned to challenge an application
 *         request message, the challenged request must be saved by the
 *         authentication module such that it can be recovered when the
 *         module's validateRequest message is called to process the request
 *         returned for the challenge.
 *         <p/>
 *         <li>AuthStatus.SEND_FAILURE to indicate that message validation
 *         failed and that an appropriate failure response message is
 *         available by calling getResponseMessage on messageInfo.
 *         </ul>
 * @throws AuthException When the message processing failed without
 *         establishing a failure response message (in messageInfo).
 */
@SuppressWarnings("unchecked")
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
        throws AuthException {

    // Extra check (disabled withour -ea) if mandatory value is consistent
    // with initialize phase
    assert messageInfo.getMap().containsKey(IS_MANDATORY_INFO_KEY) == this.mandatory;

    // Get the servlet context
    final HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage();
    final HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage();

    // Invalidate any existing session to prevent session fixture attempt
    HttpSession session = request.getSession(false);
    if (session != null) {
        final SessionState state = (SessionState) session.getAttribute(MAGIC_SESSION_STATE_KEY);
        if (state == null) {
            // Session was not created by us, we will invalidate an existing
            // session that was not created by us
            session.invalidate();
            LOG.warning(
                    "An existing session was invalidated. This might be a session fixture attempt, so failing the authentication.");
            return AuthStatus.SEND_FAILURE;
        } else if (SessionState.ESTABLISHED.equals(state)) {
            // The context was already fully established once within this
            // session.
            return AuthStatus.SUCCESS;
        }
    }

    debugRequest(request);

    // should specify encoder
    final String authorization = request.getHeader(AUTHORIZATION_HEADER);

    if (authorization != null && authorization.startsWith(NEGOTIATE)) {

        final String negotiateString = authorization.substring(NEGOTIATE.length() + 1);

        final byte[] requestToken = Base64.decodeBase64(negotiateString);

        if (serviceSubject == null) {
            // If no service subject was provided by the container then set
            // a service subject
            // from the global context.
            serviceSubject = this.serviceSubject;
        }

        try {
            // Create a validation action
            byte[] gssToken = null;
            final KerberosValidateAction kva = new KerberosValidateAction(this.servicePrincipal, requestToken,
                    serviceSubject);
            try {
                // Validate using the service (server) Subject
                gssToken = Subject.doAs(this.serviceSubject, kva);
            } catch (final PrivilegedActionException e) {
                final GSSException gex = new GSSException(GSSException.DEFECTIVE_TOKEN);
                gex.initCause(e);
                gex.setMinor(GSSException.UNAVAILABLE, "Unable to perform Kerberos validation");
                throw gex;
            }

            if (kva.getContext() != null) {
                final String responseToken = Base64.encodeBase64String(gssToken);
                response.setHeader(AUTHENTICATION_HEADER, "Negotiate " + responseToken);
                debugToken("GSS Response token set to {0}", gssToken);
            }

            if (!kva.isEstablished()) {
                debug("GSS Dialog must continue to succeed");

                session.setAttribute(MAGIC_SESSION_STATE_KEY, SessionState.IN_PROGRESS);

                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return AuthStatus.SEND_CONTINUE;

            } else {

                final Oid mechId = kva.getMech();
                final GSSName name = kva.getSrcName();

                if (!authorizeCaller(request, requestToken, name, clientSubject)) {
                    return sendFailureMessage(response, "Failed to authorize the caller/client");
                }

                // As no valid session should exist anymore, simply create a
                // new one
                session = request.getSession(true);

                final Principal clientPrincipal = new KerberosPrincipal(
                        name.canonicalize(GSS_KRB5_MECH_OID).toString());

                updateSessionAndHeader(request, session, clientPrincipal);

                session.setAttribute(MAGIC_SESSION_STATE_KEY, SessionState.ESTABLISHED);
                /*
                 * Store the mechId in the MessageInfo to indicate which
                 * authentication mechanism was used successfully (JASPIC
                 * Requirement)
                 */
                messageInfo.getMap().put(AUTH_TYPE_INFO_KEY,
                        mechId != null ? mechId.toString() : "Undefined GSS Mechanism");

                debug("GSS Dialog is complete");

            }

        } catch (final GSSException gsse) {
            debug("GSS Dialog has failed : {0}", gsse);

            if (requestToken != null) {
                debug("Bad token detected {0}", gsse);
                debugToken("Bad token was {0}", requestToken);

                if (isNTLMToken(requestToken)) {
                    // There is a high probability it was a NTLM SPNEGO
                    // token
                    return sendFailureMessage(response, "No support for NTLM");
                }
            }

            // for other errors throw an AuthException
            final AuthException ae = new AuthException();
            ae.initCause(gsse);
            throw ae;
        }

    } else if (this.mandatory) {

        response.setHeader(AUTHENTICATION_HEADER, NEGOTIATE);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        debug("Negotiate was added to the HTTP header : {0}", NEGOTIATE);

        return AuthStatus.SEND_CONTINUE;

    } else if (authorization != null) {
        LOG.warning("An authorization header was ignored.");
    }

    return AuthStatus.SUCCESS;
}