So I'm trying to implement a SSO/Integrated security system for an AIX server (so IBM JRE). It uses Kerberos to authenticate against AD.
Keep in mind the data below is sanitized.
Command my AD admin used to create the keytab file on the AD server (notice /kvno 2).
ktpass /princ HTTP/local.domain.com@LOCALDOMAIN.NET /mapuser PSLDAP@LOCALDOMAIN.NET /pass <PASSWORD> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 2 /out krb5.keytab
My krb5.conf file:
[libdefaults]
default_realm = LOCALDOMAIN.NET
default_keytab_name = FILE:/keytabs/krb.keytab
default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac
dns_lookup_kdc = true
dns_lookup_realm = true
[realms]
LOCALDOMAIN.NET = {
kdc = localdc08.localdomain.net:88
kdc = otherdc08.localdomain.net:88
admin_server = localdc08.localdomain.net:749
master_kdc = localdc08.localdomain.net
default_domain = LOCALDOMAIN.NET
}
[domain_realm]
.LOCALDOMAIN.NET = LOCALDOMAIN.NET
LOCALDOMAIN.NET = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdomain.net = LOCALDOMAIN.NET
.localdomain.net = LOCALDOMAIN.NET
[logging]
kdc = FILE:/var/krb5/log/krb5kdc.log
admin_server = FILE:/var/krb5/log/kadmin.log
kadmin_local = FILE:/var/krb5/log/kadmin_local.log
default = FILE:/var/krb5/log/krb5lib.log
Here's my krb5Login.conf for the LoginModule:
krbServer {
com.ibm.security.auth.module.Krb5LoginModule required
credsType=acceptor
refreshKrb5Config=true
principal="HTTP/local.domain.com"
useKeytab="/keytabs/krb5.keytab"
debug=true;
};
Here's the java I'm running (can't disclose the whole thing because IP)
context = new LoginContext("krbServer");
context.login();
// Get server credentials
Subject sub = context.getSubject();
serverCred = Subject.doAs(sub, new PrivilegedExceptionAction<GSSCredential>() {
public GSSCredential run() throws GSSException {
// mechanism OID for SPNEGO authentication
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
// null name defaults to currently logged in name
GSSCredential cred = authManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
spnegoOid,
GSSCredential.ACCEPT_ONLY);
return cred;
}
});
context.logout();
When I call the above code, I get the following debug output:
Constructor With Arg: krbServer Version: 1.7.0 Home: /dev/jre
LoginContext Constructed
[JGSS_DBG_CRED] Thread-2 JAAS config: debug=true
[JGSS_DBG_CRED] Thread-2 JAAS config: principal=HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 JAAS config: credsType=accept only
[JGSS_DBG_CRED] Thread-2 config: useDefaultCcache=false (default)
[JGSS_DBG_CRED] Thread-2 config: useCcache=null
[JGSS_DBG_CRED] Thread-2 config: useDefaultKeytab=false
[JGSS_DBG_CRED] Thread-2 config: useKeytab=/keytabs/krb5.keytab
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[JGSS_DBG_CRED] Thread-2 JAAS config: forwardable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: renewable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: proxiable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: tryFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: useFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: moduleBanner=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: interactive login? no
[JGSS_DBG_CRED] Thread-2 JAAS config: refreshKrb5Config = true
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[JGSS_DBG_CRED] Thread-2 Try keytab for principal=HTTP/local.domain.com
[KRB_DBG_KTAB] KeyTab:Thread-2Loading the keytab file ... >>> KeyTab: load() entry length: 73
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): HTTP
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): local.domain.com
[KRB_DBG_KDC] EncryptionKey:Thread-2: >>> EncryptionKey: config default key type is rc4-hmac
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No Kerberos creds in keytab for principal HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 Login successful
[JGSS_DBG_CRED] Thread-2 kprincipal : HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 HTTP/local.domain.com@LOCALDOMAIN.NET added to Subject
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
LoginContext login() method executed
LoginContext getSubject() method executed
Subject doAs() method executed, serverCred Name: default Lifetime: 2147483647
[JGSS_DBG_CRED] Thread-2 KeyTab is removed from subject
[JGSS_DBG_CRED] Thread-2 KerberosKey Kerberos Principal HTTP/local.domain.com@LOCALDOMAIN.NETKey Version 2key EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: <MASKED>
When I then call
public String validate(String encToken) {
byte[] token = Base64.decode(encToken);
GSSContext authContext;
try {
authContext = authManager.createContext(serverCred);
authContext.acceptSecContext(token, 0, token.length);
if (authContext.isEstablished()) {
return authContext.getSrcName().toString();
}
} catch (GSSException e) {
// fall through to the return
}
return null;
}
}
I discover that the "acceptSecContext" command being called on my token returns a value. I've been under the impression that acceptSecContext only returns a value that needs to be passed back to the initiator. However, the initiator does not expect a response back. Additionally (and more importantly), the .isEstablished() method returns false.
So my questions are
1) Is there anything wrong with the above setup?
2) Why does this happen when I call the login() method for the context object?
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
If it found key 23 version 2, why does it then say "No keys to add to Subject for principal@domain? Why didn't it add the key that it found? Does it have a problem with kvno=2?
3) I've searched pretty exhaustively and I can't determine how to parse the output from acceptSecContext to find out what the return value is. The return value I'm receiving (base-64 encoded) is oQcwBaADCgEC
.
Edit: Update. The return value from acceptSecContext hex values are: 0xA1 0x07 0x30 0x05 0xA0 0x03 0x0A 0x01 0x02
It APPPEARS from the following site (https://msdn.microsoft.com/en-us/library/ms995330.aspx#http-sso-2_topic2) that the first hex value (A1) corresponds to a NegTokenTarg. That makes sense.
The next octet should be the length (with uppermost bit 1 if the length needs more octets). Since the uppermost bit is 0, the length is 7 octets. Checks out.
The next octet (0x30) denotes a Constructed SEQUENCE, with the next octet being the SEQUENCE length (0x05); 5 octets, checks out.
Then we have 0xA0, 0x03, 0x0A, 0x01 which denotes a Sequence Element 0 (negResult).
The final octet (0x02) is the ENUMERATED value, which is "rejected".
So my token is being rejected. How do I figure out "why"? I guess I'll need to engage the AD team to find out exactly what is happening on their end.