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:
parent
9f285d92e7
commit
c6d86122db
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue