Skip to content

Commit

Permalink
Added a check for 'remote:' URLs in intercept(), replaced URL with UR…
Browse files Browse the repository at this point in the history
…I, and reformatted code.
  • Loading branch information
SDIPro committed Oct 5, 2016
1 parent bfbf1e9 commit 3859b13
Showing 1 changed file with 168 additions and 195 deletions.
Expand Up @@ -25,8 +25,8 @@
import com.orientechnologies.orient.core.security.OCredentialInterceptor;
import com.orientechnologies.orient.core.serialization.OBase64Utils;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URISyntaxException;
import java.net.URI;

import java.security.Principal;
import java.security.PrivilegedAction;
Expand All @@ -51,197 +51,170 @@
* @author S. Colin Leister
*
*/
public class OKerberosCredentialInterceptor implements OCredentialInterceptor
{
private String _Principal;
private String _ServiceTicket;

public String getUsername() { return _Principal; }
public String getPassword() { return _ServiceTicket; }

public void intercept(final String url, final String principal, final String spn) throws OSecurityException
{
// While the principal can be determined from the ticket cache, if a client keytab is used instead,
// it may contain multiple principals.
if(principal == null || principal.isEmpty()) throw new OSecurityException("OKerberosCredentialInterceptor Principal cannot be null!");

_Principal = principal;

String actualSPN = spn;

// spn should be the SPN of the service.
if(spn == null || spn.isEmpty())
{
// If spn is null or an empty string, the SPN will be generated from the URL like this:
// OrientDB/host
if(url == null || url.isEmpty()) throw new OSecurityException("OKerberosCredentialInterceptor URL and SPN cannot both be null!");

try
{
URL remoteURL = new URL(url);

String host = remoteURL.getHost();

actualSPN = "OrientDB/" + host;
}
catch(MalformedURLException mue)
{
throw new OSecurityException("OKerberosCredentialInterceptor Could not create SPN from URL: " + url);
}
}

// Defaults to the environment variable.
String config = System.getenv("KRB5_CONFIG");
String ckc = OGlobalConfiguration.CLIENT_KRB5_CONFIG.getValueAsString();
if(ckc != null) config = ckc;

// Defaults to the environment variable.
String ccname = System.getenv("KRB5CCNAME");
String ccn = OGlobalConfiguration.CLIENT_KRB5_CCNAME.getValueAsString();
if(ccn != null) ccname = ccn;

// Defaults to the environment variable.
String ktname = System.getenv("KRB5_CLIENT_KTNAME");
String ckn = OGlobalConfiguration.CLIENT_KRB5_KTNAME.getValueAsString();
if(ckn != null) ktname = ckn;

if(config == null) throw new OSecurityException("OKerberosCredentialInterceptor KRB5 Config cannot be null!");
if(ccname == null && ktname == null) throw new OSecurityException("OKerberosCredentialInterceptor KRB5 Credential Cache and KeyTab cannot both be null!");

LoginContext lc = null;

try
{
System.setProperty("java.security.krb5.conf", config);

OKrb5ClientLoginModuleConfig cfg = new OKrb5ClientLoginModuleConfig(principal, ccname, ktname);

lc = new LoginContext("ignore", null, null, cfg);
lc.login();
}
catch(LoginException lie)
{
OLogManager.instance().debug(this, "intercept() LoginException", lie);

throw new OSecurityException("OKerberosCredentialInterceptor Client Validation Exception!");
}

Subject subject = lc.getSubject();

// Assign the client's principal name.
// _Principal = getFirstPrincipal(subject);

// if(_Principal == null) throw new OSecurityException("OKerberosCredentialInterceptor Cannot obtain client principal!");

_ServiceTicket = getServiceTicket(subject, principal, actualSPN);

try
{
lc.logout();
}
catch(LoginException loe)
{
OLogManager.instance().debug(this, "intercept() LogoutException", loe);
}

if(_ServiceTicket == null) throw new OSecurityException("OKerberosCredentialInterceptor Cannot obtain the service ticket!");
}

private String getFirstPrincipal(Subject subject)
{
if(subject != null)
{
final Object[] principals = subject.getPrincipals().toArray();
final Principal p = (Principal)principals[0];

return p.getName();
}

return null;
}

private String getServiceTicket(final Subject subject, final String principal, final String servicePrincipalName)
{
try
{
GSSManager manager = GSSManager.getInstance();
GSSName serviceName = manager.createName(servicePrincipalName, GSSName.NT_USER_NAME);

Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");

// Initiator.
final GSSContext context = manager.createContext(serviceName, krb5Oid, null, GSSContext.DEFAULT_LIFETIME);

if(context != null)
{
// http://docs.oracle.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
// When performing operations as a particular Subject, e.g. Subject.doAs(...) or Subject.doAsPrivileged(...),
// the to-be-used GSSCredential should be added to Subject's private credential set. Otherwise,
// the GSS operations will fail since no credential is found.
boolean useNativeJgss = Boolean.getBoolean("sun.security.jgss.native");

if(useNativeJgss)
{
OLogManager.instance().info(this, "getServiceTicket() Using Native JGSS");

try
{
GSSName clientName = manager.createName(principal, GSSName.NT_USER_NAME);

// null: indicates using the default principal.
GSSCredential cred = manager.createCredential(clientName, GSSContext.DEFAULT_LIFETIME, krb5Oid, GSSCredential.INITIATE_ONLY);

subject.getPrivateCredentials().add(cred);
}
catch(GSSException gssEx)
{
OLogManager.instance().error(this, "getServiceTicket() Use Native JGSS GSSException", gssEx);
}
}

// The GSS context initiation has to be performed as a privileged action.
byte [] serviceTicket = Subject.doAs(subject, new PrivilegedAction<byte[]>()
{
public byte[] run()
{
try
{
byte[] token = new byte[0];

// This is a one pass context initialisation.
context.requestMutualAuth(false);
context.requestCredDeleg(false);
return context.initSecContext(token, 0, token.length);
}
catch(Exception inner)
{
OLogManager.instance().debug(this, "getServiceTicket() doAs() Exception", inner);
}

return null;
}
});


if(serviceTicket != null) return OBase64Utils.encodeBytes(serviceTicket);

// Temporary, for Java 7 support.
// if(serviceTicket != null) return new sun.misc.BASE64Encoder().encode(serviceTicket);

// if(serviceTicket != null) return java.util.Base64.getEncoder().encodeToString(serviceTicket);

context.dispose();
}
else
{
OLogManager.instance().debug(this, "getServiceTicket() GSSContext is null!");
}
}
catch(Exception ex)
{
OLogManager.instance().error(this, "getServiceTicket() Exception", ex);
}

return null;
}
public class OKerberosCredentialInterceptor implements OCredentialInterceptor {
private String principal;
private String serviceTicket;

public String getUsername() { return this.principal; }
public String getPassword() { return this.serviceTicket; }

public void intercept(final String url, final String principal, final String spn) throws OSecurityException
{
// While the principal can be determined from the ticket cache, if a client keytab is used instead,
// it may contain multiple principals.
if(principal == null || principal.isEmpty()) throw new OSecurityException("OKerberosCredentialInterceptor Principal cannot be null!");

this.principal = principal;

String actualSPN = spn;

// spn should be the SPN of the service.
if(spn == null || spn.isEmpty()) {
// If spn is null or an empty string, the SPN will be generated from the URL like this:
// OrientDB/host
if(url == null || url.isEmpty()) throw new OSecurityException("OKerberosCredentialInterceptor URL and SPN cannot both be null!");

try {
String tempURL = url;

// Without the // URI can't parse URLs correctly, so we add //.
if(tempURL.startsWith("remote:") && !tempURL.startsWith("remote://"))
tempURL = tempURL.replace("remote:", "remote://");

URI remoteURI = new URI(tempURL);

String host = remoteURI.getHost();

if(host == null) throw new OSecurityException("OKerberosCredentialInterceptor Could not create SPN from URL: " + url);

actualSPN = "OrientDB/" + host;
} catch(URISyntaxException ex) {
throw new OSecurityException("OKerberosCredentialInterceptor Could not create SPN from URL: " + url);
}
}

// Defaults to the environment variable.
String config = System.getenv("KRB5_CONFIG");
String ckc = OGlobalConfiguration.CLIENT_KRB5_CONFIG.getValueAsString();
if(ckc != null) config = ckc;

// Defaults to the environment variable.
String ccname = System.getenv("KRB5CCNAME");
String ccn = OGlobalConfiguration.CLIENT_KRB5_CCNAME.getValueAsString();
if(ccn != null) ccname = ccn;

// Defaults to the environment variable.
String ktname = System.getenv("KRB5_CLIENT_KTNAME");
String ckn = OGlobalConfiguration.CLIENT_KRB5_KTNAME.getValueAsString();
if(ckn != null) ktname = ckn;

if(config == null) throw new OSecurityException("OKerberosCredentialInterceptor KRB5 Config cannot be null!");
if(ccname == null && ktname == null) throw new OSecurityException("OKerberosCredentialInterceptor KRB5 Credential Cache and KeyTab cannot both be null!");

LoginContext lc = null;

try {
System.setProperty("java.security.krb5.conf", config);

OKrb5ClientLoginModuleConfig cfg = new OKrb5ClientLoginModuleConfig(principal, ccname, ktname);

lc = new LoginContext("ignore", null, null, cfg);
lc.login();
} catch(LoginException lie) {
OLogManager.instance().debug(this, "intercept() LoginException", lie);

throw new OSecurityException("OKerberosCredentialInterceptor Client Validation Exception!");
}

Subject subject = lc.getSubject();

// Assign the client's principal name.
// this.principal = getFirstPrincipal(subject);

// if(this.principal == null) throw new OSecurityException("OKerberosCredentialInterceptor Cannot obtain client principal!");

this.serviceTicket = getServiceTicket(subject, principal, actualSPN);

try {
lc.logout();
} catch(LoginException loe) {
OLogManager.instance().debug(this, "intercept() LogoutException", loe);
}

if(this.serviceTicket == null) throw new OSecurityException("OKerberosCredentialInterceptor Cannot obtain the service ticket!");
}

private String getFirstPrincipal(Subject subject) {
if(subject != null) {
final Object[] principals = subject.getPrincipals().toArray();
final Principal p = (Principal)principals[0];

return p.getName();
}

return null;
}

private String getServiceTicket(final Subject subject, final String principal, final String servicePrincipalName) {
try {
GSSManager manager = GSSManager.getInstance();
GSSName serviceName = manager.createName(servicePrincipalName, GSSName.NT_USER_NAME);

Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");

// Initiator.
final GSSContext context = manager.createContext(serviceName, krb5Oid, null, GSSContext.DEFAULT_LIFETIME);

if(context != null) {
// http://docs.oracle.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
// When performing operations as a particular Subject, e.g. Subject.doAs(...) or Subject.doAsPrivileged(...),
// the to-be-used GSSCredential should be added to Subject's private credential set. Otherwise,
// the GSS operations will fail since no credential is found.
boolean useNativeJgss = Boolean.getBoolean("sun.security.jgss.native");

if(useNativeJgss) {
OLogManager.instance().info(this, "getServiceTicket() Using Native JGSS");

try {
GSSName clientName = manager.createName(principal, GSSName.NT_USER_NAME);

// null: indicates using the default principal.
GSSCredential cred = manager.createCredential(clientName, GSSContext.DEFAULT_LIFETIME, krb5Oid, GSSCredential.INITIATE_ONLY);

subject.getPrivateCredentials().add(cred);
} catch(GSSException gssEx) {
OLogManager.instance().error(this, "getServiceTicket() Use Native JGSS GSSException", gssEx);
}
}

// The GSS context initiation has to be performed as a privileged action.
byte [] serviceTicket = Subject.doAs(subject, new PrivilegedAction<byte[]>() {
public byte[] run() {
try {
byte[] token = new byte[0];

// This is a one pass context initialisation.
context.requestMutualAuth(false);
context.requestCredDeleg(false);
return context.initSecContext(token, 0, token.length);
} catch(Exception inner) {
OLogManager.instance().debug(this, "getServiceTicket() doAs() Exception", inner);
}

return null;
}
});

if(serviceTicket != null) return OBase64Utils.encodeBytes(serviceTicket);

context.dispose();
} else {
OLogManager.instance().debug(this, "getServiceTicket() GSSContext is null!");
}
} catch(Exception ex) {
OLogManager.instance().error(this, "getServiceTicket() Exception", ex);
}

return null;
}
}

0 comments on commit 3859b13

Please sign in to comment.