
com.marklogic.client.impl.HTTPKerberosAuthInterceptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of marklogic-client-api Show documentation
Show all versions of marklogic-client-api Show documentation
The official MarkLogic Java client API.
The newest version!
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.client.impl;
import java.io.IOException;
import java.util.Map;
import java.util.Date;
import java.util.Set;
import java.util.Base64;
import java.security.Principal;
import java.security.PrivilegedAction;
import com.marklogic.client.FailedRequestException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.kerberos.KerberosTicket;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* An HTTP Request interceptor that modifies the request headers to enable
* Kerberos authentication. It appends the Kerberos authentication token to the
* 'Authorization' request header for Kerberos authentication
*
*/
public class HTTPKerberosAuthInterceptor implements Interceptor {
String host;
Map krbOptions;
LoginContext loginContext;
public HTTPKerberosAuthInterceptor(String host, Map krbOptions) {
this.host = host;
this.krbOptions = krbOptions;
try {
buildSubjectCredentials();
} catch (LoginException e) {
throw new FailedRequestException(e.getMessage(), e);
}
}
/**
* Class to create Kerberos Configuration object which specifies the Kerberos
* Login Module to be used for authentication.
*
*/
static private class KerberosLoginConfiguration extends Configuration {
Map krbOptions = null;
public KerberosLoginConfiguration() {}
KerberosLoginConfiguration(Map krbOptions) {
this.krbOptions = krbOptions;
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return new AppConfigurationEntry[] { new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, krbOptions) };
}
}
/**
* This method checks the validity of the TGT in the cache and build the
* Subject inside the LoginContext using Krb5LoginModule and the TGT cached by
* the Kerberos client. It assumes that a valid TGT is already present in the
* kerberos client's cache.
*
* @throws LoginException
*/
private void buildSubjectCredentials() throws LoginException {
Subject subject = new Subject();
/**
* We are not getting the TGT from KDC here. The actual TGT is got from the
* KDC using kinit or equivalent but we use the cached TGT in order to build
* the LoginContext and populate the TGT inside the Subject using
* Krb5LoginModule
*/
LoginContext lc = new LoginContext("Krb5LoginContext", subject, null,
(krbOptions != null) ? new KerberosLoginConfiguration(krbOptions) : new KerberosLoginConfiguration());
lc.login();
loginContext = lc;
}
/**
* This method is responsible for getting the client principal name from the
* subject's principal set
*
* @return String the Kerberos principal name populated in the subject
* @throws IllegalStateException if there is more than 0 or more than 1
* principal is present
*/
private String getClientPrincipalName() {
final Set principalSet = getContextSubject().getPrincipals();
if (principalSet.size() != 1)
throw new IllegalStateException(
"Only one principal is expected. Found 0 or more than one principals :" + principalSet);
return principalSet.iterator().next().getName();
}
private Subject getContextSubject() {
Subject subject = loginContext.getSubject();
if (subject == null)
throw new IllegalStateException("Kerberos login context without subject");
return subject;
}
/**
* This method builds the Authorization header for Kerberos. It
* generates a request token based on the service ticket, client principal name and
* time-stamp
*
* @param serverPrincipalName
* the name registered with the KDC of the service for which we
* need to authenticate
* @return the HTTP Authorization header token
*/
private String buildAuthorizationHeader(String serverPrincipalName) throws LoginException
{
/*
* Get the principal from the Subject's private credentials and populate the
* client and server principal name for the GSS API
*/
final String clientPrincipal = getClientPrincipalName();
final CreateAuthorizationHeaderAction action = new CreateAuthorizationHeaderAction(clientPrincipal,
serverPrincipalName);
/*
* Check if the TGT in the Subject's private credentials are valid. If
* valid, then we use the TGT in the Subject's private credentials. If not,
* we build the Subject's private credentials again from valid TGT in the
* Kerberos client cache.
*/
Set
© 2015 - 2025 Weber Informatics LLC | Privacy Policy