public SpnegoPrincipal authenticate(final HttpServletRequest req
        , final HttpServletResponse resp) throws GSSException
        , IOException {
        
        // determine if we allow basic
        final boolean basicSupported = 
            this.allowBasic && (this.allowUnsecure || req.isSecure());
        
        // domain/realm of server
        final String serverRealm = this.serverPrincipal.getRealm();
        
        // Skip auth if localhost
        if (this.allowLocalhost && this.isLocalhost(req)) {
            return doLocalhost();
        }
        
        final SpnegoPrincipal principal;
        final SpnegoAuthScheme scheme = SpnegoProvider.negotiate(
                req, resp, basicSupported, this.promptIfNtlm, serverRealm);
        
        // NOTE: this may also occur if we do not allow Basic Auth and
        // the client only supports Basic Auth
        if (null == scheme) {
            LOGGER.finer("scheme null.");
            return null;
        }

        // NEGOTIATE scheme
        if (scheme.isNegotiateScheme()) {
            principal = doSpnegoAuth(scheme, resp);
            
        // BASIC scheme
        } else if (scheme.isBasicScheme()) {
            // check if we allow Basic Auth
            if (basicSupported) {
                principal = doBasicAuth(scheme, resp);
            } else {
                LOGGER.severe("allowBasic=" + this.allowBasic 
                        + "; allowUnsecure=" + this.allowUnsecure
                        + "; req.isSecure()=" + req.isSecure());
                throw new UnsupportedOperationException("Basic Auth not allowed"
                        + " or SSL required.");
            }

        // Unsupported scheme
        } else {
            throw new UnsupportedOperationException("scheme=" + scheme);
        }

        return principal;
    }