Kerberos委派:GSSUtil.createSubject仅返回具有主体名称的主题 [英] Kerberos delegation: GSSUtil.createSubject returns subject with principal name only

查看:325
本文介绍了Kerberos委派:GSSUtil.createSubject仅返回具有主体名称的主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做kerberos代表团.我注意到GSSUtil.createSubject(context.getSrcName(), clientCred)返回的主题中没有凭据. 在此之前,我已经完成了GSSCredential clientCred = context.getDelegCred();,它返回了凭据. 当我从同一域中的一台计算机访问我的服务时,它可以工作,而如果从同一域中的另一台计算机进行访问,则不能. 困惑AD需要哪些其他设置? 任何帮助都将受到高度赞赏.

以下是我的代码:

public class KerberosTest {

    public Subject loginImpl(byte[] kerberosTicket, String propertiesFileName) throws Exception {
        System.setProperty("sun.security.krb5.debug", "true");
//        // no effect // System.setProperty("javax.security.auth.useSubjectCredsOnly","false");

        final Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
        Subject serviceUserSubject = new Subject();
        final Map<String,String> optionMap = new HashMap<String,String>();
        HashMap<String, String> shared = new HashMap<>();

            optionMap.put("keyTab", "C:\\kerberos_files\\sapuser.keytab");
            optionMap.put("principal", "HTTP/SAPTEST@EQSECTEST.LOCAL"); // default realm
//            optionMap.put("principal", "kerberosuser"); // default realm
            optionMap.put("useFirstPass", "true");
            optionMap.put("doNotPrompt", "true");
            optionMap.put("refreshKrb5Config", "true");
            optionMap.put("useTicketCache", "false");
            optionMap.put("renewTGT", "false");
            optionMap.put("useKeyTab", "true");
            optionMap.put("storeKey", "true");
            optionMap.put("isInitiator", "true");
            optionMap.put("useSubjectCredsOnly", "false");

            optionMap.put("debug", "true"); // switch on debug of the Java implementation
            krb5LoginModule.initialize(serviceUserSubject, null, shared, optionMap);

            // login using details mentioned inside keytab
            boolean loginOk = krb5LoginModule.login();
            System.out.println("Login success: " + loginOk);

            // This API adds Kerberos Credentials to the the Subject's private credentials set
            boolean commitOk = krb5LoginModule.commit();

        }

        System.out.println("Principal from subject: " + serviceUserSubject.getPrincipals()); // this must display name of user to which the keytab corresponds to



        Subject clientSubject = getClientContext(serviceUserSubject, kerberosTicket);
        System.out.println("Client Subject-> " + clientSubject);
        System.out.println("Client principal-> "+clientSubject.getPrincipals().toArray()[0]);

        return clientSubject;
    }

    // Completes the security context initialisation and returns the client name.
    private Subject getClientContext(Subject subject, final byte[] kerberosTicket) throws PrivilegedActionException {
        Subject clientSubject = Subject.doAs(subject, new KerberosValidateAction(kerberosTicket));
        return clientSubject;
    }

    private class KerberosValidateAction implements PrivilegedExceptionAction<Subject> {
        byte[] kerberosTicket;

        public KerberosValidateAction(byte[] kerberosTicket) {
            this.kerberosTicket = kerberosTicket;
        }

        @Override
        public Subject run() throws Exception {
            GSSManager gssManager = GSSManager.getInstance();
            GSSContext context = gssManager.createContext((GSSCredential) null);

            Oid kerberosOid = new Oid("1.2.840.113554.1.2.2");

//             context.requestCredDeleg(true); // needed when we are demanding ticket from KDC. In our scenario, we are getting ticket from browser(client)

            // Called by the context acceptor upon receiving a token from the peer. This is our context acceptor
            // This method may return an output token which the application will need to send to the peer for further processing by its initSecContext call.
            // We will only accept the incoming token from Peer (browser) and fwd it to third party system
            while (!context.isEstablished()) {
                byte[] nextToken = context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
            }

            boolean established = context.isEstablished();
            String user = context.getSrcName().toString();
            String serviceAccnt = context.getTargName().toString();


            //check if the credentials can be delegated
            if (!context.getCredDelegState()) {
                System.out.println("credentials can not be delegated!");
                return null;
            }

            //get the delegated credentials from the calling peer...
            GSSCredential clientCred = context.getDelegCred();
            //Create a Subject out of the delegated credentials.
            //With this Subject the application server can impersonate the client that sent the request.

            Subject clientSubject = GSSUtil.createSubject(context.getSrcName(), clientCred);
            return clientSubject; // ***this contains only principal name and not credentials !!
        }
    }

解决方案

我发现了一个重要的观点,但在任何地方都没有记载. -

在AD中配置kerberos服务用户时,信任此用户进行委派(仅Kerberos)"仅对保存此更改后创建的新TGT生效.

例如,如果用户在客户端计算机A上登录,例如在上午10:00.
管理员在上午10:30启用向kerberos服务用户的委派.
当用户从计算机A上的浏览器中访问应用程序URL时,该委派将不起作用,因为在启用委派之前(上午10:00)已创建了他的TGT.

如果用户从计算机A注销并重新登录,将生成新的TGT.委派现在非常适合该用户.

I am doing kerberos delegation. I noticed that GSSUtil.createSubject(context.getSrcName(), clientCred) returns a Subject without having credentials in it. Prior to that i've done GSSCredential clientCred = context.getDelegCred(); which returns the credentials. Edit: When I hit my service from one machine in same domain, it works, while if accessed from other machine in same domain, it doesn't. Confused what additional settings are needed on AD ? Any help is highly appreciated.

Following is my code:

public class KerberosTest {

    public Subject loginImpl(byte[] kerberosTicket, String propertiesFileName) throws Exception {
        System.setProperty("sun.security.krb5.debug", "true");
//        // no effect // System.setProperty("javax.security.auth.useSubjectCredsOnly","false");

        final Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
        Subject serviceUserSubject = new Subject();
        final Map<String,String> optionMap = new HashMap<String,String>();
        HashMap<String, String> shared = new HashMap<>();

            optionMap.put("keyTab", "C:\\kerberos_files\\sapuser.keytab");
            optionMap.put("principal", "HTTP/SAPTEST@EQSECTEST.LOCAL"); // default realm
//            optionMap.put("principal", "kerberosuser"); // default realm
            optionMap.put("useFirstPass", "true");
            optionMap.put("doNotPrompt", "true");
            optionMap.put("refreshKrb5Config", "true");
            optionMap.put("useTicketCache", "false");
            optionMap.put("renewTGT", "false");
            optionMap.put("useKeyTab", "true");
            optionMap.put("storeKey", "true");
            optionMap.put("isInitiator", "true");
            optionMap.put("useSubjectCredsOnly", "false");

            optionMap.put("debug", "true"); // switch on debug of the Java implementation
            krb5LoginModule.initialize(serviceUserSubject, null, shared, optionMap);

            // login using details mentioned inside keytab
            boolean loginOk = krb5LoginModule.login();
            System.out.println("Login success: " + loginOk);

            // This API adds Kerberos Credentials to the the Subject's private credentials set
            boolean commitOk = krb5LoginModule.commit();

        }

        System.out.println("Principal from subject: " + serviceUserSubject.getPrincipals()); // this must display name of user to which the keytab corresponds to



        Subject clientSubject = getClientContext(serviceUserSubject, kerberosTicket);
        System.out.println("Client Subject-> " + clientSubject);
        System.out.println("Client principal-> "+clientSubject.getPrincipals().toArray()[0]);

        return clientSubject;
    }

    // Completes the security context initialisation and returns the client name.
    private Subject getClientContext(Subject subject, final byte[] kerberosTicket) throws PrivilegedActionException {
        Subject clientSubject = Subject.doAs(subject, new KerberosValidateAction(kerberosTicket));
        return clientSubject;
    }

    private class KerberosValidateAction implements PrivilegedExceptionAction<Subject> {
        byte[] kerberosTicket;

        public KerberosValidateAction(byte[] kerberosTicket) {
            this.kerberosTicket = kerberosTicket;
        }

        @Override
        public Subject run() throws Exception {
            GSSManager gssManager = GSSManager.getInstance();
            GSSContext context = gssManager.createContext((GSSCredential) null);

            Oid kerberosOid = new Oid("1.2.840.113554.1.2.2");

//             context.requestCredDeleg(true); // needed when we are demanding ticket from KDC. In our scenario, we are getting ticket from browser(client)

            // Called by the context acceptor upon receiving a token from the peer. This is our context acceptor
            // This method may return an output token which the application will need to send to the peer for further processing by its initSecContext call.
            // We will only accept the incoming token from Peer (browser) and fwd it to third party system
            while (!context.isEstablished()) {
                byte[] nextToken = context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
            }

            boolean established = context.isEstablished();
            String user = context.getSrcName().toString();
            String serviceAccnt = context.getTargName().toString();


            //check if the credentials can be delegated
            if (!context.getCredDelegState()) {
                System.out.println("credentials can not be delegated!");
                return null;
            }

            //get the delegated credentials from the calling peer...
            GSSCredential clientCred = context.getDelegCred();
            //Create a Subject out of the delegated credentials.
            //With this Subject the application server can impersonate the client that sent the request.

            Subject clientSubject = GSSUtil.createSubject(context.getSrcName(), clientCred);
            return clientSubject; // ***this contains only principal name and not credentials !!
        }
    }

解决方案

I figured out one important point, which I didn't find anywhere documented. -

While configuring the kerberos service user in AD, "Trust this user for delegation (Kerberos Only)" will come in effect only for new TGTs which are created after this change is saved.

For example, if the user is logged in on client machine A, say at 10:00 AM.
Administrator enables the delegation to kerberos service user at 10:30 AM.
When the user hits an application URL from browser on machine A, the delegation will not work because his TGT is created before the delegation is turned on (at 10:00 AM).

If user logs out from the machine A and relogins, a new TGT will be generated. Delegation works perfectly for this user now.

这篇关于Kerberos委派:GSSUtil.createSubject仅返回具有主体名称的主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆