Kerberos委派:GSSUtil.createSubject仅返回具有主体名称的主题

时间:2019-05-27 05:58:58

标签: java kerberos spnego kerberos-delegation

我正在做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 !!
        }
    }

1 个答案:

答案 0 :(得分:0)

我发现了一个重要的观点,没有发现任何记载。 -

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

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

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