Skip to content

Commit

Permalink
Issue #2868 - Adding SPNEGO authentication support for Jetty Client.
Browse files Browse the repository at this point in the history
Renamed server-side classes and added javadocs.
Deprecated old server-side classes in favor of the new ones.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
  • Loading branch information
sbordet committed Sep 28, 2018
1 parent eb00e6c commit 2b11d30
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.security.ConfigurableSpnegoLoginService;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SpnegoLoginService2;
import org.eclipse.jetty.security.authentication.AuthorizationService;
import org.eclipse.jetty.security.authentication.SpnegoAuthenticator2;
import org.eclipse.jetty.security.authentication.ConfigurableSpnegoAuthenticator;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
Expand Down Expand Up @@ -88,7 +88,7 @@ public class SPNEGOAuthenticationTest extends AbstractHttpClientServerTest
private Path serviceKeyTabPath = testDirPath.resolve("service.keytab");
private Path clientKeyTabPath = testDirPath.resolve("client.keytab");
private SimpleKdcServer kdc;
private SpnegoAuthenticator2 authenticator;
private ConfigurableSpnegoAuthenticator authenticator;

@BeforeEach
public void prepare() throws Exception
Expand Down Expand Up @@ -123,7 +123,7 @@ private void startSPNEGO(Scenario scenario, Handler handler) throws Exception
server = new Server();
server.setSessionIdManager(new DefaultSessionIdManager(server));
HashLoginService authorizationService = new HashLoginService(realm, realmPropsPath.toString());
SpnegoLoginService2 loginService = new SpnegoLoginService2(realm, AuthorizationService.from(authorizationService, ""));
ConfigurableSpnegoLoginService loginService = new ConfigurableSpnegoLoginService(realm, AuthorizationService.from(authorizationService, ""));
loginService.addBean(authorizationService);
loginService.setKeyTabPath(serviceKeyTabPath);
loginService.setServiceName(serviceName);
Expand All @@ -138,7 +138,7 @@ private void startSPNEGO(Scenario scenario, Handler handler) throws Exception
mapping.setPathSpec("/secure");
mapping.setConstraint(constraint);
securityHandler.addConstraintMapping(mapping);
authenticator = new SpnegoAuthenticator2();
authenticator = new ConfigurableSpnegoAuthenticator();
securityHandler.setAuthenticator(authenticator);
securityHandler.setLoginService(loginService);
securityHandler.setHandler(handler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,20 @@
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;

public class SpnegoLoginService2 extends ContainerLifeCycle implements LoginService
/**
* <p>A configurable (as opposed to using system properties) SPNEGO LoginService.</p>
* <p>At startup, this LoginService will login via JAAS the service principal, composed
* of the {@link #getServiceName() service name} and the {@link #getHostName() host name},
* for example {@code HTTP/wonder.com}, using a {@code keyTab} file as the service principal
* credentials.</p>
* <p>Upon receiving a HTTP request, the server tries to authenticate the client
* calling {@link #login(String, Object, ServletRequest)} where the GSS APIs are used to
* verify client tokens and (perhaps after a few round-trips) a {@code GSSContext} is
* established.</p>
*/
public class ConfigurableSpnegoLoginService extends ContainerLifeCycle implements LoginService
{
private static final Logger LOG = Log.getLogger(SpnegoLoginService2.class);
private static final Logger LOG = Log.getLogger(ConfigurableSpnegoLoginService.class);

private final GSSManager _gssManager = GSSManager.getInstance();
private final String _realm;
Expand All @@ -59,43 +70,67 @@ public class SpnegoLoginService2 extends ContainerLifeCycle implements LoginServ
private String _hostName;
private SpnegoContext _context;

public SpnegoLoginService2(String realm, AuthorizationService authorizationService)
public ConfigurableSpnegoLoginService(String realm, AuthorizationService authorizationService)
{
_realm = realm;
_authorizationService = authorizationService;
}

/**
* @return the realm name
*/
@Override
public String getName()
{
return _realm;
}

/**
* @return the path of the keyTab file containing service credentials
*/
public Path getKeyTabPath()
{
return _keyTabPath;
}

/**
* @param keyTabFile the path of the keyTab file containing service credentials
*/
public void setKeyTabPath(Path keyTabFile)
{
_keyTabPath = keyTabFile;
}

/**
* @return the service name, typically "HTTP"
* @see #getHostName()
*/
public String getServiceName()
{
return _serviceName;
}

/**
* @param serviceName the service name
* @see #setHostName(String)
*/
public void setServiceName(String serviceName)
{
_serviceName = serviceName;
}

/**
* @return the host name of the service
* @see #setServiceName(String)
*/
public String getHostName()
{
return _hostName;
}

/**
* @param hostName the host name of the service
*/
public void setHostName(String hostName)
{
_hostName = hostName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,22 @@
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;

public class SpnegoAuthenticator2 extends LoginAuthenticator
/**
* <p>A LoginAuthenticator that uses SPNEGO and the GSS API to authenticate requests.</p>
* <p>A successful authentication from a client is cached for a configurable
* {@link #getAuthenticationDuration() duration} using the HTTP session; this avoids
* that the client is asked to authenticate for every request.</p>
*
* @see org.eclipse.jetty.security.ConfigurableSpnegoLoginService
*/
public class ConfigurableSpnegoAuthenticator extends LoginAuthenticator
{
private static final Logger LOG = Log.getLogger(SpnegoAuthenticator2.class);
private static final Logger LOG = Log.getLogger(ConfigurableSpnegoAuthenticator.class);

private final String _authMethod;
private Duration _authenticationDuration = Duration.ofNanos(-1);

public SpnegoAuthenticator2()
public ConfigurableSpnegoAuthenticator()
{
this(Constraint.__SPNEGO_AUTH);
}
Expand All @@ -59,7 +67,7 @@ public SpnegoAuthenticator2()
*
* @param authMethod the auth method
*/
public SpnegoAuthenticator2(String authMethod)
public ConfigurableSpnegoAuthenticator(String authMethod)
{
_authMethod = authMethod;
}
Expand All @@ -70,6 +78,9 @@ public String getAuthMethod()
return _authMethod;
}

/**
* @return the authentication duration
*/
public Duration getAuthenticationDuration()
{
return _authenticationDuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
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);
Expand Down

0 comments on commit 2b11d30

Please sign in to comment.