Sends the WWW-Authenticate header if a non-Negotiate authorization he… (#1700)

* Sends the WWW-Authenticate header if a non-Negotiate authorization header was given

Fixes #1698

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

* Dumb compilation error

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

* Adds a test to show the challenge is sent.

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

* Refactor the conditionals per Greg's suggestion

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

* Add the expected license header

Signed-off-by: Josh Elser <elserj@apache.org>
This commit is contained in:
Josh Elser 2017-08-01 22:18:04 -04:00 committed by Joakim Erdfelt
parent 1a07ddd787
commit 1fd3e4ad1b
2 changed files with 134 additions and 22 deletions

View File

@ -72,27 +72,8 @@ public class SpnegoAuthenticator extends LoginAuthenticator
return new DeferredAuthentication(this);
}
// check to see if we have authorization headers required to continue
if ( header == null )
{
try
{
if (DeferredAuthentication.isDeferred(res))
{
return Authentication.UNAUTHENTICATED;
}
LOG.debug("SpengoAuthenticator: 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);
}
}
else if (header != null && header.startsWith(HttpHeader.NEGOTIATE.asString()))
// The client has responded to the challenge we sent previously
if (header != null && header.startsWith(HttpHeader.NEGOTIATE.asString().toLowerCase()))
{
String spnegoToken = header.substring(10);
@ -104,7 +85,25 @@ public class SpnegoAuthenticator extends LoginAuthenticator
}
}
return Authentication.UNAUTHENTICATED;
// 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("SpengoAuthenticator: 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);
}
}
@Override

View File

@ -0,0 +1,113 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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 static org.junit.Assert.assertEquals;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.junit.Before;
import org.junit.Test;
/**
* Test class for {@link SpnegoAuthenticator}.
*/
public class SpnegoAuthenticatorTest {
private SpnegoAuthenticator _authenticator;
@Before
public void setup() throws Exception
{
_authenticator = new SpnegoAuthenticator();
}
@Test
public void testChallengeSentWithNoAuthorization() throws Exception
{
HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null)
{
@Override
public Server getServer()
{
return null;
}
};
Request req = new Request(channel, null);
HttpOutput out = new HttpOutput(channel)
{
@Override
public void close()
{
return;
}
};
Response res = new Response(channel, out);
MetaData.Request metadata = new MetaData.Request(new HttpFields());
metadata.setURI(new HttpURI("http://localhost"));
req.setMetaData(metadata);
assertEquals(Authentication.SEND_CONTINUE, _authenticator.validateRequest(req, res, true));
assertEquals(HttpHeader.NEGOTIATE.asString(), res.getHeader(HttpHeader.WWW_AUTHENTICATE.asString()));
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, res.getStatus());
}
@Test
public void testChallengeSentWithUnhandledAuthorization() throws Exception
{
HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null)
{
@Override
public Server getServer()
{
return null;
}
};
Request req = new Request(channel, null);
HttpOutput out = new HttpOutput(channel)
{
@Override
public void close()
{
return;
}
};
Response res = new Response(channel, out);
HttpFields http_fields = new HttpFields();
// Create a bogus Authorization header. We don't care about the actual credentials.
http_fields.add(HttpHeader.AUTHORIZATION, "Basic asdf");
MetaData.Request metadata = new MetaData.Request(http_fields);
metadata.setURI(new HttpURI("http://localhost"));
req.setMetaData(metadata);
assertEquals(Authentication.SEND_CONTINUE, _authenticator.validateRequest(req, res, true));
assertEquals(HttpHeader.NEGOTIATE.asString(), res.getHeader(HttpHeader.WWW_AUTHENTICATE.asString()));
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, res.getStatus());
}
}