diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc index 47f565af6a4..5a3c700eaea 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc @@ -19,11 +19,12 @@ [[spnego-support]] === SPNEGO Support -Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a way for users to be seamlessly authenticated when running on a Windows or Active Directory based network. -Jetty supports this type of authentication and authorization through the JDK (which has been enabled since the later versions of Java 6 and 7). -Also important to note is that this is an _incredibly_ fragile setup where everything needs to be configured just right for things to work, otherwise it can fail in fun and exciting, not to mention obscure, ways. +Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a way for users +to be seamlessly authenticated when running on systems that rely on Kerberos +for authentication, such as Windows Active Directory based networks. -There is a substantial amount of configuration and testing required to enable this feature as well as knowledge and access to central systems on a Windows network such as the Active Domain Controller and the ability to create and maintain service users. +Jetty supports this type of authentication and authorization through the JDK +(which has been enabled since the later versions of Java 6 and 7). ==== Configuring Jetty and SPNEGO @@ -31,97 +32,62 @@ To run with SPNEGO enabled the following command line options are required: [source,screen, subs="{sub-order}"] ---- --Djava.security.krb5.conf=/path/to/jetty/etc/krb5.ini \ --Djava.security.auth.login.config=/path/to/jetty/etc/spnego.conf \ --Djavax.security.auth.useSubjectCredsOnly=false +-Djava.security.krb5.conf=/path/to/krb5.ini ---- -For debugging the SPNEGO authentication the following options are very helpful: +For debugging the SPNEGO authentication the following options are helpful: [source,screen, subs="{sub-order}"] ---- --Dorg.eclipse.jetty.LEVEL=debug \ --Dsun.security.spnego.debug=all +-Dorg.eclipse.jetty.LEVEL=debug +-Dsun.security.spnego.debug=true +-Dsun.security.jgss.debug=true +-Dsun.security.krb5.debug=true ---- -SPNEGO Authentication must be enabled in the webapp in the following way. +SPNEGO authentication must be enabled in the webapp in the following way. The name of the role will be different for your network. [source, xml, subs="{sub-order}"] ---- - - - - Secure Area - /secure/me/* - - - - MORTBAY.ORG - - - - SPNEGO - Test Realm - - - /loginError.html?param=foo - - - + + + Secure Area + /secure/me/* + + + + MORTBAY.ORG + + + + SPNEGO + Test Realm + + + /loginError.html?param=foo + + ---- -A corresponding `UserRealm` needs to be created either programmatically if embedded, via the `jetty.xml` or in a context file for the webapp. +A corresponding `UserRealm` needs to be created either programmatically if +embedded, via the `jetty.xml` or in a context file for the webapp. -This is what the configuration within a Jetty xml file would look like. +This is what the configuration within a context XML file would look like: [source, xml, subs="{sub-order}"] ---- - - - - - Test Realm - /etc/spnego.properties - - - - + + + + Test Realm + + + + + ---- -This is what the configuration within a context xml file would look like. - -[source, xml, subs="{sub-order}"] ----- - - - - - Test Realm - - /etc/spnego.properties - - - - true - - - ----- - -There are a number of important configuration files with S3pnego that are required. The default values for these configuration files from this -test example are found in the `/etc` folder of the Jetty distribution. - -spnego.properties:: - configures the user realm with runtime properties -krb5.ini:: - configures the underlying kerberos setup -spnego.conf:: - configures the glue between gssapi and kerberos - -It is important to note that the keytab file referenced in the `krb5.ini` and the `spnego.conf` files needs to contain the keytab for the `targetName` for the http server. -To do this use a process similar to this: - On the Windows Active Domain Controller run: [source, screen, subs="{sub-order}"] @@ -129,15 +95,15 @@ On the Windows Active Domain Controller run: $ setspn -A HTTP/linux.mortbay.org ADUser ---- -To create the keytab file use the following process: +To create the keyTab file use the following process: [source, screen, subs="{sub-order}"] ---- $ ktpass -out c:\dir\krb5.keytab -princ HTTP/linux.mortbay.org@MORTBAY.ORG -mapUser ADUser -mapOp set -pass ADUserPWD -crypto RC4-HMAC-NT -pType KRB5_NT_PRINCIPAL ---- -This step will give you the keytab file which should then be copied to the machine running the http server and referenced from the configuration files. -For our testing we put the keytab into the `/etc` directory of Jetty and referenced it from there. +This step will give you the keyTab file which should then be copied to the +machine running the http server and referenced from the configuration files. ==== Configuring Firefox @@ -161,7 +127,6 @@ The follows steps have been required to inform Internet Explorer that it should 7. Tools -> Options -> Advanced -> Security -> Ok 8. Close IE then reopen and browse to your SPNEGO protected resource - You *must* use hostname and not the IP. If you use the IP it will default to NTLM authentication. The following conditions must be true for SPNEGO authentication to work: diff --git a/jetty-security/src/main/config/etc/README.spnego b/jetty-security/src/main/config/etc/README.spnego deleted file mode 100644 index 85917c832c0..00000000000 --- a/jetty-security/src/main/config/etc/README.spnego +++ /dev/null @@ -1,62 +0,0 @@ -This setup will enable you to authenticate a user via SPNEGO into your -webapp. - -To run with SPNEGO enabled the following command line options are required: - --Djava.security.krb5.conf=/path/to/jetty/etc/krb5.ini --Djava.security.auth.login.config=/path/to/jetty/etc/spnego.conf --Djavax.security.auth.useSubjectCredsOnly=false - -The easiest place to put these lines are in the start.ini file. - -For debugging the SPNEGO authentication the following options are helpful: - --Dorg.eclipse.jetty.LEVEL=debug --Dsun.security.spnego.debug=true - - -SPNEGO Authentication is enabled in the webapp with the following setup. - - - - Secure Area - /secure/me/* - - - MORTBAY.ORG <-- this is the domain that the user is a member of - - - - - SPNEGO - Test Realm - (optionally to add custom error page) - - /loginError.html?param=foo - - - -A corresponding UserRealm needs to be created either programmatically if -embedded, via the jetty.xml or in a context file for the webapp. - -(in the jetty.xml) - - - - - Test Realm - /etc/spnego.properties - - - - -(context file) - - - - Test Realm - /etc/spnego.properties - - - true - diff --git a/jetty-security/src/main/config/etc/krb5.ini b/jetty-security/src/main/config/etc/krb5.ini deleted file mode 100644 index 283880c0748..00000000000 --- a/jetty-security/src/main/config/etc/krb5.ini +++ /dev/null @@ -1,23 +0,0 @@ -[libdefaults] -default_realm = MORTBAY.ORG -default_keytab_name = FILE:/path/to/jetty/etc/krb5.keytab -permitted_enctypes = aes128-cts aes256-cts arcfour-hmac-md5 -default_tgs_enctypes = aes128-cts aes256-cts arcfour-hmac-md5 -default_tkt_enctypes = aes128-cts aes256-cts arcfour-hmac-md5 - - - -[realms] -MORTBAY.ORG = { - kdc = 192.168.2.30 - admin_server = 192.168.2.30 - default_domain = MORTBAY.ORG -} - -[domain_realm] -mortbay.org= MORTBAY.ORG -.mortbay.org = MORTBAY.ORG - -[appdefaults] -autologin = true -forwardable = true diff --git a/jetty-security/src/main/config/etc/spnego.conf b/jetty-security/src/main/config/etc/spnego.conf deleted file mode 100644 index 3d5caf8300f..00000000000 --- a/jetty-security/src/main/config/etc/spnego.conf +++ /dev/null @@ -1,19 +0,0 @@ -com.sun.security.jgss.initiate { - com.sun.security.auth.module.Krb5LoginModule required - principal="HTTP/vm.mortbay.org@MORTBAY.ORG" - keyTab="/path/to/jetty/etc/krb5.keytab" - useKeyTab=true - storeKey=true - debug=true - isInitiator=false; -}; - -com.sun.security.jgss.accept { - com.sun.security.auth.module.Krb5LoginModule required - principal="HTTP/vm.mortbay.org@MORTBAY.ORG" - useKeyTab=true - keyTab="/path/to/jetty/etc/krb5.keytab" - storeKey=true - debug=true - isInitiator=false; -}; diff --git a/jetty-security/src/main/config/etc/spnego.properties b/jetty-security/src/main/config/etc/spnego.properties deleted file mode 100644 index 86862eaef1e..00000000000 --- a/jetty-security/src/main/config/etc/spnego.properties +++ /dev/null @@ -1 +0,0 @@ -targetName = HTTP/vm.mortbay.org \ No newline at end of file diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java index 588464545f1..41ca74c4463 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java @@ -23,9 +23,9 @@ import javax.servlet.ServletContext; import org.eclipse.jetty.security.Authenticator.AuthConfiguration; import org.eclipse.jetty.security.authentication.BasicAuthenticator; import org.eclipse.jetty.security.authentication.ClientCertAuthenticator; +import org.eclipse.jetty.security.authentication.ConfigurableSpnegoAuthenticator; import org.eclipse.jetty.security.authentication.DigestAuthenticator; import org.eclipse.jetty.security.authentication.FormAuthenticator; -import org.eclipse.jetty.security.authentication.SpnegoAuthenticator; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.security.Constraint; @@ -66,10 +66,10 @@ public class DefaultAuthenticatorFactory implements Authenticator.Factory authenticator=new DigestAuthenticator(); else if (Constraint.__FORM_AUTH.equalsIgnoreCase(auth)) authenticator=new FormAuthenticator(); - else if ( Constraint.__SPNEGO_AUTH.equalsIgnoreCase(auth) ) - authenticator = new SpnegoAuthenticator(); - else if ( Constraint.__NEGOTIATE_AUTH.equalsIgnoreCase(auth) ) // see Bug #377076 - authenticator = new SpnegoAuthenticator(Constraint.__NEGOTIATE_AUTH); + else if (Constraint.__SPNEGO_AUTH.equalsIgnoreCase(auth)) + authenticator = new ConfigurableSpnegoAuthenticator(); + else if (Constraint.__NEGOTIATE_AUTH.equalsIgnoreCase(auth)) // see Bug #377076 + authenticator = new ConfigurableSpnegoAuthenticator(Constraint.__NEGOTIATE_AUTH); if (Constraint.__CERT_AUTH.equalsIgnoreCase(auth)||Constraint.__CERT_AUTH2.equalsIgnoreCase(auth)) authenticator=new ClientCertAuthenticator(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java deleted file mode 100644 index 41f30f0a736..00000000000 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java +++ /dev/null @@ -1,196 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.security; - -import java.util.Properties; - -import javax.security.auth.Subject; -import javax.servlet.ServletRequest; - -import org.eclipse.jetty.server.UserIdentity; -import org.eclipse.jetty.util.B64Code; -import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.ietf.jgss.GSSContext; -import org.ietf.jgss.GSSCredential; -import org.ietf.jgss.GSSException; -import org.ietf.jgss.GSSManager; -import org.ietf.jgss.GSSName; -import org.ietf.jgss.Oid; - -/** - * @deprecated use {@link ConfigurableSpnegoLoginService} instead - */ -@Deprecated -public class SpnegoLoginService extends AbstractLifeCycle implements LoginService -{ - private static final Logger LOG = Log.getLogger(SpnegoLoginService.class); - - protected IdentityService _identityService;// = new LdapIdentityService(); - protected String _name; - private String _config; - - private String _targetName; - - public SpnegoLoginService() - { - - } - - public SpnegoLoginService( String name ) - { - setName(name); - } - - public SpnegoLoginService( String name, String config ) - { - setName(name); - setConfig(config); - } - - @Override - public String getName() - { - return _name; - } - - public void setName(String name) - { - if (isRunning()) - { - throw new IllegalStateException("Running"); - } - - _name = name; - } - - public String getConfig() - { - return _config; - } - - public void setConfig( String config ) - { - if (isRunning()) - { - throw new IllegalStateException("Running"); - } - - _config = config; - } - - - - @Override - protected void doStart() throws Exception - { - Properties properties = new Properties(); - Resource resource = Resource.newResource(_config); - properties.load(resource.getInputStream()); - - _targetName = properties.getProperty("targetName"); - - LOG.debug("Target Name {}", _targetName); - - super.doStart(); - } - - /** - * username will be null since the credentials will contain all the relevant info - */ - @Override - public UserIdentity login(String username, Object credentials, ServletRequest request) - { - String encodedAuthToken = (String)credentials; - - byte[] authToken = B64Code.decode(encodedAuthToken); - - GSSManager manager = GSSManager.getInstance(); - try - { - Oid krb5Oid = new Oid("1.3.6.1.5.5.2"); // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html - GSSName gssName = manager.createName(_targetName,null); - GSSCredential serverCreds = manager.createCredential(gssName,GSSCredential.INDEFINITE_LIFETIME,krb5Oid,GSSCredential.ACCEPT_ONLY); - GSSContext gContext = manager.createContext(serverCreds); - - if (gContext == null) - { - LOG.debug("SpnegoUserRealm: failed to establish GSSContext"); - } - else - { - while (!gContext.isEstablished()) - { - authToken = gContext.acceptSecContext(authToken,0,authToken.length); - } - if (gContext.isEstablished()) - { - String clientName = gContext.getSrcName().toString(); - String role = clientName.substring(clientName.indexOf('@') + 1); - - LOG.debug("SpnegoUserRealm: established a security context"); - LOG.debug("Client Principal is: " + gContext.getSrcName()); - LOG.debug("Server Principal is: " + gContext.getTargName()); - LOG.debug("Client Default Role: " + role); - - SpnegoUserPrincipal user = new SpnegoUserPrincipal(clientName,authToken); - - Subject subject = new Subject(); - subject.getPrincipals().add(user); - - return _identityService.newUserIdentity(subject,user, new String[]{role}); - } - } - - } - catch (GSSException gsse) - { - LOG.warn(gsse); - } - - return null; - } - - @Override - public boolean validate(UserIdentity user) - { - return false; - } - - @Override - public IdentityService getIdentityService() - { - return _identityService; - } - - @Override - public void setIdentityService(IdentityService service) - { - _identityService = service; - } - - @Override - public void logout(UserIdentity user) - { - // TODO Auto-generated method stub - } - -} diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java deleted file mode 100644 index 8142eb7c4d8..00000000000 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java +++ /dev/null @@ -1,161 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.security.authentication; - -import java.io.IOException; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.security.ServerAuthException; -import org.eclipse.jetty.security.UserAuthentication; -import org.eclipse.jetty.server.Authentication; -import org.eclipse.jetty.server.Authentication.User; -import org.eclipse.jetty.server.UserIdentity; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.security.Constraint; - -/** - * @deprecated use {@link ConfigurableSpnegoAuthenticator} instead. - */ -@Deprecated -public class SpnegoAuthenticator extends LoginAuthenticator -{ - private static final Logger LOG = Log.getLogger(SpnegoAuthenticator.class); - private String _authMethod = Constraint.__SPNEGO_AUTH; - - public SpnegoAuthenticator() - { - } - - /** - * Allow for a custom authMethod value to be set for instances where SPNEGO may not be appropriate - * @param authMethod the auth method - */ - public SpnegoAuthenticator( String authMethod ) - { - _authMethod = authMethod; - } - - @Override - public String getAuthMethod() - { - return _authMethod; - } - - @Override - public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException - { - HttpServletRequest req = (HttpServletRequest)request; - HttpServletResponse res = (HttpServletResponse)response; - - String header = req.getHeader(HttpHeader.AUTHORIZATION.asString()); - String authScheme = getAuthSchemeFromHeader(header); - - if (!mandatory) - { - return new DeferredAuthentication(this); - } - - // The client has responded to the challenge we sent previously - if (header != null && isAuthSchemeNegotiate(authScheme)) - { - String spnegoToken = header.substring(10); - - UserIdentity user = login(null,spnegoToken, request); - - if ( user != null ) - { - return new UserAuthentication(getAuthMethod(),user); - } - } - - // A challenge should be sent if any of the following cases are true: - // 1. There was no Authorization header provided - // 2. There was an Authorization header for a type other than Negotiate - try - { - if (DeferredAuthentication.isDeferred(res)) - { - return Authentication.UNAUTHENTICATED; - } - - LOG.debug("Sending challenge"); - res.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), HttpHeader.NEGOTIATE.asString()); - res.sendError(HttpServletResponse.SC_UNAUTHORIZED); - return Authentication.SEND_CONTINUE; - } - catch (IOException ioe) - { - throw new ServerAuthException(ioe); - } - } - - /** - * Extracts the auth_scheme from the HTTP Authorization header, {@code Authorization: }. - * - * @param header The HTTP Authorization header or null. - * @return The parsed auth scheme from the header, or the empty string. - */ - String getAuthSchemeFromHeader(String header) - { - // No header provided, return the empty string - if (header == null || header.isEmpty()) - { - return ""; - } - // Trim any leading whitespace - String trimmed_header = header.trim(); - // Find the first space, all characters prior should be the auth_scheme - int index = trimmed_header.indexOf(' '); - if (index > 0) { - return trimmed_header.substring(0, index); - } - // If we don't find a space, this is likely malformed, just return the entire value - return trimmed_header; - } - - /** - * Determines if provided auth scheme text from the Authorization header is case-insensitively - * equal to {@code negotiate}. - * - * @param authScheme The auth scheme component of the Authorization header - * @return True if the auth scheme component is case-insensitively equal to {@code negotiate}, False otherwise. - */ - boolean isAuthSchemeNegotiate(String authScheme) - { - if (authScheme == null || authScheme.length() != HttpHeader.NEGOTIATE.asString().length()) - { - return false; - } - // Headers should be treated case-insensitively, so we have to jump through some extra hoops. - return authScheme.equalsIgnoreCase(HttpHeader.NEGOTIATE.asString()); - } - - @Override - public boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, User validatedUser) throws ServerAuthException - { - return true; - } - -} diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java index 9b03ed72874..27fac49fc86 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.security.authentication; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; @@ -38,16 +34,15 @@ import org.eclipse.jetty.server.Server; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -/** - * Test class for {@link SpnegoAuthenticator}. - */ +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SpnegoAuthenticatorTest { - private SpnegoAuthenticator _authenticator; + private ConfigurableSpnegoAuthenticator _authenticator; @BeforeEach - public void setup() throws Exception + public void setup() { - _authenticator = new SpnegoAuthenticator(); + _authenticator = new ConfigurableSpnegoAuthenticator(); } @Test @@ -67,7 +62,6 @@ public class SpnegoAuthenticatorTest { @Override public void close() { - return; } }; Response res = new Response(channel, out); @@ -97,7 +91,6 @@ public class SpnegoAuthenticatorTest { @Override public void close() { - return; } }; Response res = new Response(channel, out); @@ -112,37 +105,4 @@ public class SpnegoAuthenticatorTest { assertEquals(HttpHeader.NEGOTIATE.asString(), res.getHeader(HttpHeader.WWW_AUTHENTICATE.asString())); assertEquals(HttpServletResponse.SC_UNAUTHORIZED, res.getStatus()); } - - @Test - public void testCaseInsensitiveHeaderParsing() - { - assertFalse(_authenticator.isAuthSchemeNegotiate(null)); - assertFalse(_authenticator.isAuthSchemeNegotiate("")); - assertFalse(_authenticator.isAuthSchemeNegotiate("Basic")); - assertFalse(_authenticator.isAuthSchemeNegotiate("basic")); - assertFalse(_authenticator.isAuthSchemeNegotiate("Digest")); - assertFalse(_authenticator.isAuthSchemeNegotiate("LotsandLotsandLots of nonsense")); - assertFalse(_authenticator.isAuthSchemeNegotiate("Negotiat asdfasdf")); - assertFalse(_authenticator.isAuthSchemeNegotiate("Negotiated")); - assertFalse(_authenticator.isAuthSchemeNegotiate("Negotiate-and-more")); - - assertTrue(_authenticator.isAuthSchemeNegotiate("Negotiate")); - assertTrue(_authenticator.isAuthSchemeNegotiate("negotiate")); - assertTrue(_authenticator.isAuthSchemeNegotiate("negOtiAte")); - } - - @Test - public void testExtractAuthScheme() - { - assertEquals("", _authenticator.getAuthSchemeFromHeader(null)); - assertEquals("", _authenticator.getAuthSchemeFromHeader("")); - assertEquals("", _authenticator.getAuthSchemeFromHeader(" ")); - assertEquals("Basic", _authenticator.getAuthSchemeFromHeader(" Basic asdfasdf")); - assertEquals("Basicasdf", _authenticator.getAuthSchemeFromHeader("Basicasdf asdfasdf")); - assertEquals("basic", _authenticator.getAuthSchemeFromHeader(" basic asdfasdf ")); - assertEquals("Negotiate", _authenticator.getAuthSchemeFromHeader("Negotiate asdfasdf")); - assertEquals("negotiate", _authenticator.getAuthSchemeFromHeader("negotiate asdfasdf")); - assertEquals("negotiate", _authenticator.getAuthSchemeFromHeader(" negotiate asdfasdf")); - assertEquals("negotiated", _authenticator.getAuthSchemeFromHeader(" negotiated asdfasdf")); - } }