Hi,
I am trying to obtain a service ticket for a cross-realm service within one
hierarchy (forest).
The root realm is COMPANY.NET, my realm is R004.COMPANY.NET, target realm is
R002.COMPANY.NET and
SPN ldap/server.r002.company.net.
Host to realm mapping in my krb5.conf:
[domain_realm]
.r004.company.net = R004.COMPANY.NET
r004.company.net = R004.COMPANY.NET
.company.net = COMPANY.NET
company.net = COMPANY.NET
I have tested the same case with MIT Kerberos and SSPI and both have a
completely different approach
of requesting service tickets. They do:
TGS-REQ for ldap/server.r002.company.net to a KDC in my home realm
TGS-REP is krbtgt/[email protected]
TGS-REQ for ldap/server.r002.company.net to a KDC in R002.COMPANY.NET with
krbtgt/[email protected]
TGS-REP is ldap/[email protected]
This works as desired.
JGSS in turn does this:
Match hostname to domain realm => COMPANY.NET
TGS-REQ for krbtgt/COMPANY.NET
TGS-REP is krbtgt/[email protected]
TGS-REQ for ldap/server.r002.company.net to a KDC in COMPANY.NET with
krbtgt/[email protected]
TGS-REP is krbtgt/[email protected]
and here happens the crash
KrbException: Message stream modified (41)
KrbException: Fail to create credential. (63) - No service creds
at
sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:299)
at
sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:454)
at
sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:641)
at
sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
at
sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
in KrbKdcRep.java#check(), lines 54 to 56:
if (!req.reqBody.sname.equalsWithoutRealm(rep.encKDCRepPart.sname)) {
rep.encKDCRepPart.key.destroy();
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
}
This code assumes that the ticket is already the final service ticket but it is
an intermediate TGT
for the target realm. I would expect another TGS-REQ/TGS-REP from JGSS. Due to
the logic implemented,
the only known workaround is to add another [domain_realm] mapping but this is
daunting because we have
tens of those and I do not know all realms/hostnames upfront due to dynamic TGT
referrals.
Another case is HTTP proxy (HTTP/proxyfarm.company.net). JGSS requests at
COMPANY.NET but
receives a TGT for R002.COMPANY.NET. Especially in this case, I am not able to
know the realm upfront.
Adding the domain realm mapping does not help because this file is used
initially only or even worse,
direct hostname to realm mapping is hell. Removing [domain_realm] makes it
immediately fail due to
the TGT referral. MIT Kerberos follows all TGT referrals as necessary.
The manpage for krb5.conf for [domain_realm] says:
"If no translation entry applies to a hostname used for a service principal for
a service ticket request,
the library will try to get a referral to the appropriate realm from the client
realm's KDC..."
I would expect that the TGS logic would resemble the one described above,
follow all referrals until
it gets the desired service ticket. Ultimately, not [domain_realm] is
necessary, at least with MIT Kerberos
and Active Directory.
Setup:
* KDCs are Windows Server 2008/2012
* Clients are Windows 7 Enterprise
* MIT Kerberos 1.14.1 on FreeBSD
* Oracle JDKs 1.7.0_72 and 1.80_72
All tests happen on Windows, deployment happens on HP-UX with HP JVM which is
merely a repackaged Oracle
JVM with native patches for that OS.
I have already created a bundle with log files, krb5.conf and Wireshark pcap
files, debug screenshots for
JGSS, MIT Kerberos and SSPI and will happily share in private. Also willing to
assist as necessary.
This is actually an annoying blocker disabling us to use cross-domain and
cross-forest services. I would
prefer a solution for Java 7 because we haven't migrated to Java 8 yet but
willing to do so.
How can we resolve this issue?
Thanks and regards,
Michael Osipov