在跨林域中使用java获取Kerberos票证

时间:2016-06-29 21:30:10

标签: kerberos

两个域a.com和b.com之间存在跨林信任。我可以使用以下代码检索a.com的kerberos票证,其中为a.com配置了服务主体和kdc以及领域详细信息。但与b.com凭据相同的配置无法检索b.com的kerberos票证。在krb5.conf文件中是否需要进行额外的配置?由于跨林信任但无法生成kerberos票证,a.com服务帐户能够验证b.com的kerberos票证。请帮我解决这个问题

                package sample;

            import java.io.File;
            import java.io.FileOutputStream;
            import java.io.IOError;
            import java.io.IOException;
            import java.io.PrintStream;
            import java.security.Principal;
            import java.security.PrivilegedAction;
            import java.util.Set;

            import javax.annotation.Resource;
            import javax.annotation.Resources;
            import javax.security.auth.Subject;
            import javax.security.auth.login.LoginContext;
            import javax.security.auth.login.LoginException;
            import javax.sql.DataSource;

            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 com.sun.security.auth.callback.DialogCallbackHandler;

            import sun.misc.BASE64Encoder;

            /**
             * Tool to retrieve a kerberos ticket. This one will not be stored in the
             * windows ticket cache.
             */

            public final class KerberosTicketRetriever {
                private final static Oid KERB_V5_OID;
                private final static Oid KRB5_PRINCIPAL_NAME_OID;

                static {
                    try {
                        KERB_V5_OID = new Oid("1.2.840.113554.1.2.2");
                    KRB5_PRINCIPAL_NAME_OID = new Oid("1.2.840.113554.1.2.2.1");

                } catch (final GSSException ex) {
                    throw new Error(ex);
                }
            }

            /**
             * Not to be instanciated
             */
            private KerberosTicketRetriever() {
            };

            /**
             *
             */
            private static class TicketCreatorAction implements PrivilegedAction<Object> {
                final String userPrincipal;
                final String applicationPrincipal;

                private StringBuffer outputBuffer;

                /**
                 *
                 * @param userPrincipal
                 *            p.ex. <tt>MuelleHA@MYFIRM.COM</tt>
                 * @param applicationPrincipal
                 *            p.ex. <tt>HTTP/webserver.myfirm.com</tt>
                 */
                private TicketCreatorAction(final String userPrincipal, final String applicationPrincipal) {
                    this.userPrincipal = userPrincipal;
                    this.applicationPrincipal = applicationPrincipal;
                }

                private void setOutputBuffer(final StringBuffer newOutputBuffer) {
                    outputBuffer = newOutputBuffer;
                }

                /**
                 * Only calls {@link #createTicket()}
                 * 
                 * @return <tt>null</tt>
                 */
                public Object run() {
                    try {
                        createTicket();
                    } catch (final GSSException ex) {
                        throw new Error(ex);
                    }

                    return null;
                }

                /**
                 *
                 * @throws GSSException
                 */
                private void createTicket() throws GSSException {
                    final GSSManager manager = GSSManager.getInstance();
                    final GSSName clientName = manager.createName(userPrincipal, KRB5_PRINCIPAL_NAME_OID);
                    final GSSCredential clientCred = manager.createCredential(clientName, 8 * 3600, KERB_V5_OID,
                            GSSCredential.INITIATE_ONLY);

                    final GSSName serverName = manager.createName(applicationPrincipal, KRB5_PRINCIPAL_NAME_OID);

                    final GSSContext context = manager.createContext(serverName, KERB_V5_OID, clientCred,
                            GSSContext.DEFAULT_LIFETIME);
                    context.requestMutualAuth(true);
                    context.requestConf(false);
                    context.requestInteg(true);

                    final byte[] outToken = context.initSecContext(new byte[0], 0, 0);

                    if (outputBuffer != null) {
                        // outputBuffer.append(String.format("Src Name: %s\n",
                        // context.getSrcName()));
                        // outputBuffer.append(String.format("Target : %s\n",
                        // context.getTargName()));
                        outputBuffer.append(new BASE64Encoder().encode(outToken));
                        // outputBuffer.append("\n");
                    }

                    context.dispose();
                }
            }

            /**
             *
             * @param realm
             *            p.ex. <tt>MYFIRM.COM</tt>
             * @param kdc
             *            p.ex. <tt>kerbserver.myfirm.com</tt>
             * @param applicationPrincipal
             *            cf. {@link #TicketCreatorAction(String, String)}
             * @throws GSSException
             * @throws LoginException
             */
            static public String retrieveTicket(final String realm, final String kdc, final String applicationPrincipal)
                    throws GSSException, LoginException {

                // create the jass-config-file
                final File jaasConfFile;
                try {
                    jaasConfFile = File.createTempFile("jaas.conf", null);
                    final PrintStream bos = new PrintStream(new FileOutputStream(jaasConfFile));
                    bos.print(String.format(
                            "Krb5LoginContext { com.sun.security.auth.module.Krb5LoginModule required useTicketCache=false doNotPrompt=false debug=true; };"));
                    bos.close();
                    jaasConfFile.deleteOnExit();
                } catch (final IOException ex) {
                    throw new IOError(ex);
                }

                String krb5ConfigFilePath = "krb5.ini";
                // System.setProperty("java.security.krb5.conf", krb5ConfigFilePath);
                // set the properties
                System.setProperty("java.security.krb5.realm", realm);
                System.setProperty("java.security.krb5.kdc", kdc);
                System.setProperty("java.security.auth.login.config", jaasConfFile.getAbsolutePath());

                // get the Subject(), i.e. the current user under Windows
                final Subject subject = new Subject();
                final LoginContext lc = new LoginContext("Krb5LoginContext", subject, new DialogCallbackHandler());
                lc.login();

                // extract our principal
                final Set<Principal> principalSet = subject.getPrincipals();
                if (principalSet.size() != 1)
                    throw new AssertionError("No or several principals: " + principalSet);
                final Principal userPrincipal = principalSet.iterator().next();

                // now try to execute the SampleAction as the authenticated Subject
                // action.run() without doAsPrivileged leads to
                // No valid credentials provided (Mechanism level: Failed to find any
                // Kerberos tgt)
                final TicketCreatorAction action = new TicketCreatorAction(userPrincipal.getName(), applicationPrincipal);
                final StringBuffer outputBuffer = new StringBuffer();
                action.setOutputBuffer(outputBuffer);
                Subject.doAsPrivileged(lc.getSubject(), action, null);

                return outputBuffer.toString();
            }

            public static void main (final String args[]) throws Throwable
                {
                    final String ticket = retrieveTicket("a.com", "a.com", "a_service"_account);
                        System.out.println(ticket);
                    }
            }





                            Debug is  true storeKey false useTicketCache false useKeyTab false doNotPrompt false ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is false principal is null tryFirstPass is false useFirstPass is false storePass is false clearPass is false
                        [Krb5LoginModule] user entered username: testuser-b_7@b.com

                Java config name: null
                Native config name: C:\Windows\krb5.ini
                >>> KdcAccessibility: reset
                Using builtin default etypes for default_tkt_enctypes
                default etypes for default_tkt_enctypes: 17 16 23.
                >>> KrbAsReq creating message
                getKDCFromDNS using UDP
                >>> KrbKdcReq send: kdc=m.b.com. UDP:88, timeout=30000, number of retries =3, #bytes=154
                >>> KDCCommunication: kdc=m.b.com. UDP:88, timeout=30000,Attempt =1, #bytes=154
                >>> KrbKdcReq send: #bytes read=197
                >>>Pre-Authentication Data:
                     PA-DATA type = 19
                     PA-ETYPE-INFO2 etype = 17, salt = b.comtestuser-b_7, s2kparams = null
                     PA-ETYPE-INFO2 etype = 23, salt = null, s2kparams = null

                >>>Pre-Authentication Data:
                     PA-DATA type = 2
                     PA-ENC-TIMESTAMP
                >>>Pre-Authentication Data:
                     PA-DATA type = 16

                >>>Pre-Authentication Data:
                     PA-DATA type = 15

                >>> KdcAccessibility: remove m.b.com.:88
                >>> KDCRep: init() encoding tag is 126 req type is 11
                >>>KRBError:
                     sTime is Mon Jul 04 11:06:17 EDT 2016 1467644777000
                     suSec is 666515
                     error code is 25
                     error Message is Additional pre-authentication required
                     sname is krbtgt/b.com@b.com
                     eData provided.
                     msgType is 30
                >>>Pre-Authentication Data:
                     PA-DATA type = 19
                     PA-ETYPE-INFO2 etype = 17, salt = b.comtestuser-b_7, s2kparams = null
                     PA-ETYPE-INFO2 etype = 23, salt = null, s2kparams = null

                >>>Pre-Authentication Data:
                     PA-DATA type = 2
                     PA-ENC-TIMESTAMP
                >>>Pre-Authentication Data:
                     PA-DATA type = 16

                >>>Pre-Authentication Data:
                     PA-DATA type = 15

                KrbAsReqBuilder: PREAUTH FAILED/REQ, re-send AS-REQ
                Using builtin default etypes for default_tkt_enctypes
                default etypes for default_tkt_enctypes: 17 16 23.
                Using builtin default etypes for default_tkt_enctypes
                default etypes for default_tkt_enctypes: 17 16 23.
                >>> EType: sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType
                >>> KrbAsReq creating message
                getKDCFromDNS using UDP
                >>> KrbKdcReq send: kdc=m.b.com. UDP:88, timeout=30000, number of retries =3, #bytes=236
                >>> KDCCommunication: kdc=m.b.com. UDP:88, timeout=30000,Attempt =1, #bytes=236
                >>> KrbKdcReq send: #bytes read=96
                >>> KrbKdcReq send: kdc=m.b.com. TCP:88, timeout=30000, number of retries =3, #bytes=236
                >>> KDCCommunication: kdc=m.b.com. TCP:88, timeout=30000,Attempt =1, #bytes=236
                >>>DEBUG: TCPClient reading 1520 bytes
                >>> KrbKdcReq send: #bytes read=1520
                >>> KdcAccessibility: remove m.b.com.:88
                >>> EType: sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType
                >>> KrbAsRep cons in KrbAsReq.getReply testuser-b_7
                principal is testuser-b_7@b.com
                Commit Succeeded 

                Found ticket for testuser-b_7@b.com to go to krbtgt/b.com@b.com expiring on Mon Jul 04 21:06:17 EDT 2016
                Entered Krb5Context.initSecContext with state=STATE_NEW
                Found ticket for testuser-b_7@b.com to go to krbtgt/b.com@b.com expiring on Mon Jul 04 21:06:17 EDT 2016
                Service ticket not found in the subject
                >>> Credentials acquireServiceCreds: main loop: [0] tempService=krbtgt/a.com@b.com
                Using builtin default etypes for default_tgs_enctypes
                default etypes for default_tgs_enctypes: 17 16 23.
                >>> CksumType: sun.security.krb5.internal.crypto.RsaMd5CksumType
                >>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
                getKDCFromDNS using UDP
                >>> KrbKdcReq send: kdc=m.b.com. UDP:88, timeout=30000, number of retries =3, #bytes=1463
                >>> KDCCommunication: kdc=m.b.com. UDP:88, timeout=30000,Attempt =1, #bytes=1463
                >>> KrbKdcReq send: #bytes read=1430
                >>> KdcAccessibility: remove m.b.com.:88
                >>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
                >>> Credentials acquireServiceCreds: no tgt; searching thru capath
                >>> Credentials acquireServiceCreds: inner loop: [1] tempService=krbtgt/com@b.com
                Using builtin default etypes for default_tgs_enctypes
                default etypes for default_tgs_enctypes: 17 16 23.
                >>> CksumType: sun.security.krb5.internal.crypto.RsaMd5CksumType
                >>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
                getKDCFromDNS using UDP
                >>> KrbKdcReq send: kdc=m.b.com. UDP:88, timeout=30000, number of retries =3, #bytes=1457
                >>> KDCCommunication: kdc=m.b.com. UDP:88, timeout=30000,Attempt =1, #bytes=1457
                >>> KrbKdcReq send: #bytes read=89
                >>> KdcAccessibility: remove m.b.com.:88
                >>> KDCRep: init() encoding tag is 126 req type is 13
                >>>KRBError:
                     sTime is Mon Jul 04 11:06:17 EDT 2016 1467644777000
                     suSec is 165721
                     error code is 7
                     error Message is Server not found in Kerberos database
                     sname is krbtgt/com@b.com
                     msgType is 30
                >>> Credentials acquireServiceCreds: inner loop: [2] tempService=krbtgt/COM@b.com
                Using builtin default etypes for default_tgs_enctypes
                default etypes for default_tgs_enctypes: 17 16 23.
                >>> CksumType: sun.security.krb5.internal.crypto.RsaMd5CksumType
                >>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
                getKDCFromDNS using UDP
                >>> KrbKdcReq send: kdc=bd.b.com. UDP:88, timeout=30000, number of retries =3, #bytes=1455
                >>> KDCCommunication: kdc=bd.b.com. UDP:88, timeout=30000,Attempt =1, #bytes=1455
                >>> KrbKdcReq send: #bytes read=87
                >>> KdcAccessibility: remove bd.b.com.:88
                >>> KDCRep: init() encoding tag is 126 req type is 13
                >>>KRBError:
                     sTime is Mon Jul 04 11:06:17 EDT 2016 1467644777000
                     suSec is 194031
                     error code is 7
                     error Message is Server not found in Kerberos database
                     sname is krbtgt/COM@b.com
                     msgType is 30
                >>> Credentials acquireServiceCreds: no tgt; cannot get creds
                KrbException: Fail to create credential. (63) - No service creds
                    at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:156)
                    at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:458)
                    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:690)
                    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
                    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
                    at sample.KerberosTicketRetriever$TicketCreatorAction.createTicket(KerberosTicketRetriever.java:123)
                    at sample.KerberosTicketRetriever$TicketCreatorAction.run(KerberosTicketRetriever.java:90)
                    at java.security.AccessController.doPrivileged(Native Method)
                    at javax.security.auth.Subject.doAsPrivileged(Subject.java:483)
                    at sample.KerberosTicketRetriever.retrieveTicket(KerberosTicketRetriever.java:194)
                    at sample.KerberosTicketRetriever.main(KerberosTicketRetriever.java:202)
                Exception in thread "main" java.lang.Error: GSSException: No valid credentials provided (Mechanism level: Fail to create credential. (63) - No service creds)
                    at sample.KerberosTicketRetriever$TicketCreatorAction.run(KerberosTicketRetriever.java:94)
                    at java.security.AccessController.doPrivileged(Native Method)
                    at javax.security.auth.Subject.doAsPrivileged(Subject.java:483)
                    at sample.KerberosTicketRetriever.retrieveTicket(KerberosTicketRetriever.java:194)
                    at sample.KerberosTicketRetriever.main(KerberosTicketRetriever.java:202)
                Caused by: GSSException: No valid credentials provided (Mechanism level: Fail to create credential. (63) - No service creds)
                    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:767)
                    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
                    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
                    at sample.KerberosTicketRetriever$TicketCreatorAction.createTicket(KerberosTicketRetriever.java:123)
                    at sample.KerberosTicketRetriever$TicketCreatorAction.run(KerberosTicketRetriever.java:90)
                    ... 4 more
                Caused by: KrbException: Fail to create credential. (63) - No service creds
                    at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:156)
                    at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:458)
                    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:690)
                    ... 8 more
                LSA: Found Ticket
                LSA: Made NewWeakGlobalRef
                LSA: Found PrincipalName
                LSA: Made NewWeakGlobalRef
                LSA: Found DerValue
                LSA: Made NewWeakGlobalRef
                LSA: Found EncryptionKey
                LSA: Made NewWeakGlobalRef
                LSA: Found TicketFlags
                LSA: Made NewWeakGlobalRef
                LSA: Found KerberosTime
                LSA: Made NewWeakGlobalRef
                LSA: Found String
                LSA: Made NewWeakGlobalRef
                LSA: Found DerValue constructor
                LSA: Found Ticket constructor
                LSA: Found PrincipalName constructor
                LSA: Found EncryptionKey constructor
                LSA: Found TicketFlags constructor
                LSA: Found KerberosTime constructor
                LSA: Finished OnLoad processing

0 个答案:

没有答案