Fix a bug around handling "Negotiate" case-insensitively in SpnegoAut… (#1710)

* Fix a bug around handling "Negotiate" case-insensitively in SpnegoAuthenticator

Closes #1709

Signed-off-by: Josh Elser <elserj@apache.org>

* Clean up isAuthSchemeNegotiate(String) since we don't need to use startsWith()

Signed-off-by: Josh Elser <elserj@apache.org>
This commit is contained in:
Josh Elser 2017-08-07 21:02:44 -04:00 committed by Joakim Erdfelt
parent 9f285d92e7
commit c6d86122db
2 changed files with 78 additions and 1 deletions

View File

@ -66,6 +66,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
HttpServletResponse res = (HttpServletResponse)response;
String header = req.getHeader(HttpHeader.AUTHORIZATION.asString());
String authScheme = getAuthSchemeFromHeader(header);
if (!mandatory)
{
@ -73,7 +74,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
}
// The client has responded to the challenge we sent previously
if (header != null && header.startsWith(HttpHeader.NEGOTIATE.asString().toLowerCase()))
if (header != null && isAuthSchemeNegotiate(authScheme))
{
String spnegoToken = header.substring(10);
@ -106,6 +107,47 @@ public class SpnegoAuthenticator extends LoginAuthenticator
}
}
/**
* Extracts the auth_scheme from the HTTP Authorization header, {@code Authorization: <auth_scheme> <token>}.
*
* @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
{

View File

@ -19,6 +19,8 @@
package org.eclipse.jetty.security.authentication;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import javax.servlet.http.HttpServletResponse;
@ -110,4 +112,37 @@ 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"));
}
}