Skip to content

Commit

Permalink
KNOX-1850 - KnoxSession should honor the current subject for Kerberos…
Browse files Browse the repository at this point in the history
… login
  • Loading branch information
pzampino committed Apr 9, 2019
1 parent 52194f7 commit 8d28295
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 46 deletions.
Expand Up @@ -102,6 +102,23 @@ public class KnoxSession implements Closeable {
public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n";

private static final KnoxShellMessages LOG = MessagesFactory.get(KnoxShellMessages.class);

private static final CredentialsProvider EMPTY_CREDENTIALS_PROVIDER = new BasicCredentialsProvider();
static {
EMPTY_CREDENTIALS_PROVIDER.setCredentials(AuthScope.ANY,
new Credentials() {
@Override
public Principal getUserPrincipal () {
return null;
}

@Override
public String getPassword () {
return null;
}
});
}

private boolean isKerberos;

private URL jaasConfigURL;
Expand Down Expand Up @@ -312,46 +329,32 @@ protected CloseableHttpClient createClient(ClientContext clientContext) throws G

System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");

final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

credentialsProvider.setCredentials(AuthScope.ANY, new Credentials() {
@Override
public Principal getUserPrincipal() {
return null;
}

@Override
public String getPassword() {
return null;
}
});

final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();
final Registry<AuthSchemeProvider> authSchemeRegistry =
RegistryBuilder.<AuthSchemeProvider>create().register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();

return HttpClients.custom().setConnectionManager(connectionManager)
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.setDefaultCredentialsProvider(credentialsProvider).build();
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.setDefaultCredentialsProvider(EMPTY_CREDENTIALS_PROVIDER)
.build();
} else {
AuthCache authCache = new BasicAuthCache();
BasicScheme authScheme = new BasicScheme();
authCache.put(host, authScheme);
context = new BasicHttpContext();
context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE,
authCache);
context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE, authCache);

CredentialsProvider credentialsProvider = null;
if (clientContext.username() != null && clientContext.password() != null) {
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider
.setCredentials(new AuthScope(host.getHostName(), host.getPort()),
new UsernamePasswordCredentials(clientContext.username(),
clientContext.password()));
credentialsProvider.setCredentials(new AuthScope(host.getHostName(), host.getPort()),
new UsernamePasswordCredentials(clientContext.username(),
clientContext.password()));
}
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
.setConnectionManager(connectionManager)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
}

}
Expand Down Expand Up @@ -457,22 +460,26 @@ public String base() {
public CloseableHttpResponse executeNow(HttpRequest request ) throws IOException {
/* check for kerberos */
if (isKerberos) {
LoginContext lc;
Subject subject = Subject.getSubject(AccessController.getContext());
try {
Configuration jaasConf;
try {
jaasConf = new JAASClientConfig(jaasConfigURL);
} catch (Exception e) {
LOG.failedToLoadJAASConfiguration(jaasConfigURL.toExternalForm());
throw new KnoxShellException(e.toString(), e);
}
if (subject == null) {
LOG.noSubjectAvailable();
Configuration jaasConf;
try {
jaasConf = new JAASClientConfig(jaasConfigURL);
} catch (Exception e) {
LOG.failedToLoadJAASConfiguration(jaasConfigURL.toExternalForm());
throw new KnoxShellException(e.toString(), e);
}

lc = new LoginContext(JGSS_LOGIN_MOUDLE,
Subject.getSubject(AccessController.getContext()),
new TextCallbackHandler(),
jaasConf);
lc.login();
return Subject.doAs(lc.getSubject(),
LoginContext lc = new LoginContext(JGSS_LOGIN_MOUDLE,
null,
new TextCallbackHandler(),
jaasConf);
lc.login();
subject = lc.getSubject();
}
return Subject.doAs(subject,
(PrivilegedAction<CloseableHttpResponse>) () -> {
CloseableHttpResponse response;
try {
Expand Down
Expand Up @@ -29,6 +29,9 @@ public interface KnoxShellMessages {
@Message( level = MessageLevel.WARN, text = "Unable to create provided PEM encoded trusted cert - falling through for other truststores: {0}" )
void unableToLoadProvidedPEMEncodedTrustedCert(@StackTrace( level = MessageLevel.DEBUG ) IOException e);

@Message( level = MessageLevel.DEBUG, text = "No available Subject; Using JAAS configuration login" )
void noSubjectAvailable();

@Message( level = MessageLevel.DEBUG, text = "Using JAAS configuration file implementation: {0}" )
void usingJAASConfigurationFileImplementation(String implName);

Expand Down
Expand Up @@ -23,8 +23,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.junit.Test;

import javax.security.auth.Subject;
import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
Expand Down Expand Up @@ -98,10 +102,10 @@ public void testJAASConfigOption() {

try {
ClientContext context = ClientContext.with("https://localhost:8443/gateway/dt")
.kerberos()
.enable(true)
.jaasConf(testJaasConf)
.end();
.kerberos()
.enable(true)
.jaasConf(testJaasConf)
.end();
assertNotNull(context);
assertEquals(context.kerberos().jaasConf(), testJaasConf);

Expand All @@ -116,6 +120,55 @@ public void testJAASConfigOption() {
assertEquals("Using default JAAS configuration", logCapture.logMessages.get(1));
assertTrue(logCapture.logMessages.get(2).startsWith("JAAS configuration: "));
assertTrue(logCapture.logMessages.get(2).endsWith("jaas.conf"));
assertEquals("No available Subject; Using JAAS configuration login", logCapture.logMessages.get(3));
assertEquals("Using JAAS configuration file implementation: com.sun.security.auth.login.ConfigFile",
logCapture.logMessages.get(4));
} finally {
logger.removeHandler(logCapture);
logger.setLevel(originalLevel);
}
}

/**
* Validate that JAAS configuration is not applied when a kerberos Subject is available.
* (KNOX-1850)
*/
@Test
public void testUseCurrentSubject() {
final Logger logger = Logger.getLogger("org.apache.knox.gateway.shell");
final Level originalLevel = logger.getLevel();
logger.setLevel(Level.FINEST);
LogHandler logCapture = new LogHandler();
logger.addHandler(logCapture);

try {
ClientContext context = ClientContext.with("https://localhost:8443/gateway/dt")
.kerberos()
.enable(true)
.end();
assertNotNull(context);

Subject testSubject = new Subject();

try {
KnoxSession session = KnoxSession.login(context);
Subject.doAs(testSubject, (PrivilegedAction<CloseableHttpResponse>) () -> {
try {
return session.executeNow(null);
} catch (IOException e) {
e.printStackTrace();
}
return null;
});
} catch (Exception e) {
// Expected because the HTTP request is null, which is irrelevant for this test
}

if(!logCapture.logMessages.isEmpty()) {
for (String logMessage : logCapture.logMessages) {
assertFalse(logMessage.startsWith("No available Subject"));
}
}
} finally {
logger.removeHandler(logCapture);
logger.setLevel(originalLevel);
Expand Down

0 comments on commit 8d28295

Please sign in to comment.