GSSException 创建凭证

GSSException createCredential

主要编辑:2015-05-27: 在取得一定程度的成功后,更新了我目前卡住的地方,而不是留下漫无边际的 post... .真的可以用一些关于这个的指针 - 有点陷入困境....

我 运行 Linux 应用程序服务器 (WebSphere) 上的一些代码需要对为 "Integrated Authentication" 配置的 IIS Web 服务进行身份验证,但我在形成授权时遇到一些问题:协商令牌。 我还应该说,我需要将此令牌放入 HTTP header 以用于我随后将构建的 JAX-WS SOAP 请求。我知道我的 SOAP 请求本身有效,因为我们之前使用 WS-Security 用户名令牌配置文件并且它工作正常 - 事实证明尝试切换到 kerberos 很困难...

我认为我的问题是 initSecContext。似乎在第一次调用时,上下文是以 "some" 方式配置的,并且有一些返回的令牌数据,但是 .isEstablished 是错误的。我遇到的问题是将 initSecContext 调用置于循环中 - 似乎 IIS 在我执行此操作时只是关闭了连接。任何人都可以给我一些指示 - 我似乎正在采用其他 post 人员和 Oracle 样本使用的方法(尽管 IBM/WebSphere 样本只进行一次 initSecContext 调用并且不检查 .isEstablished 哪个根据 Oracle 文档,我觉得很奇怪)。

无论如何,我得到的错误如下(注意 Ready: 属性 似乎清楚地说 initSecContext 需要循环 - 至少对我来说);

[5/27/15 6:51:11:605 UTC] 0000004f SystemOut     O INFO: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: After initSecContext:
--- GSSContext ---
        Owner:          domainuser@MYDOMAIN.COM
        Peer:           HTTP/iishost.mycorp.com
        State:          initialized
        Lifetime:       indefinite
        Ready:          no
        Flags:
                Confidentiality         off
                Delegation              on
                Integrity               off
                MutualAuthn             on
                ReplayDetection         off
                SequenceDetection       off
                DelegatedCred:          unknown
--- End of GSSContext ---

[5/27/15 6:51:11:605 UTC] 0000004f SystemOut     O INFO: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: Context is not established, trying again
[5/27/15 6:51:11:606 UTC] 0000004f SystemOut     O ERROR: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: IOException during context establishment: Connection reset

我的代码如下;

            LoginContext lc = getLoginContext(contextName);
            final Subject subject = lc.getSubject();

            String b64Token = (String) Subject.doAs(subject, new PrivilegedExceptionAction() {
                @Override
                public Object run() throws PrivilegedActionException, GSSException {
                    // Create socket to server
                    Socket socket;
                    DataInputStream inStream = null;
                    DataOutputStream outStream = null;
                    try {
                        socket = new Socket("iishost.mycorp.com", 443);
                        inStream = new DataInputStream(socket.getInputStream());
                        outStream = new DataOutputStream(socket.getOutputStream());
                    } catch (IOException ex) {
                        System.out.println("Exception setting up server sockets: " + ex.getMessage());
                    }
                    GSSName gssName = manager.createName(userName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
                    GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
                            GSSCredential.DEFAULT_LIFETIME,
                            KRB5_MECH_OID,
                            GSSCredential.INITIATE_ONLY);

                    gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
                            GSSCredential.INDEFINITE_LIFETIME,
                            SPNEGO_MECH_OID,
                            GSSCredential.INITIATE_ONLY);
                    GSSName gssServerName = manager.createName(servicePrincipal, KERBEROS_V5_PRINCIPAL_NAME);
                    GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
                            SPNEGO_MECH_OID,
                            gssCred,
                            GSSContext.DEFAULT_LIFETIME);
                    clientContext.requestCredDeleg(true);
                    clientContext.requestMutualAuth(true);
                    byte[] token = new byte[0];

                    while (!clientContext.isEstablished()) {
                        try {
                            token = clientContext.initSecContext(token, 0, token.length);
// IF I LOOK AT token HERE THERE IS CERTAINLY TOKEN DATA THERE - .isEstablished IS STILL FALSE                          
                            outStream.writeInt(token.length);
                            outStream.write(token);
                            outStream.flush();

                            // Check if we're done
                            if (!clientContext.isEstablished()) {
                                token = new byte[inStream.readInt()];
                                inStream.readFully(token);
                            }
                        } catch (IOException ex) {

// THIS EXCEPTION IS THROWN ON SECOND ITERATION - LOOKS LIKE IIS CLOSES THE CONNECTION                      
                            System.out.println("IOException during context establishment: " + ex.getMessage());
                        }
                    }
                    String b64Token = Base64.encode(token);
                    clientContext.dispose();        // I'm assuming this won't invalidate the token in some way as I need to use it later
                    return b64Token;                
                }
            });

这个文档告诉我不需要在 initSecContext 上循环,但是 .isEstablished returns false 对我来说:http://www-01.ibm.com/support/knowledgecenter/SS7K4U_8.5.5/com.ibm.websphere.zseries.doc/ae/tsec_SPNEGO_token.html?cp=SS7K4U_8.5.5%2F1-3-0-20-4-0&lang=en

Oracle 文档告诉我应该:https://docs.oracle.com/javase/7/docs/api/org/ietf/jgss/GSSContext.html

我唯一的犹豫是,从 Oracle 文档看来我正在开始应用程序对话,但我试图做的只是获取令牌,稍后我将在我的代码中使用 JAX-WS 到 post 我实际的 Web 服务调用(包括 http header 中的 spnego/kerberos 令牌)- 这是我的问题的原因吗?

只是一个更新。我现在有这个工作 - 我以前的代码基本上没问题 - 这只是我对如何将 Kerberos 令牌添加到 JAX-WS 请求的理解。事实证明,这只是将 Handler 附加到 bindingProvider 的问题。然后处理程序获取 Kerberos 令牌并将其添加到请求的 header - 简单易行。

下面是我的工作处理程序,它被添加到通过调用 bindingProvider.getBinding().getHandlerChain()

获得的处理程序链中
public class HTTPKerberosHandler implements SOAPHandler<SOAPMessageContext> {

    private final String contextName;
    private final String servicePrincipal;
    private static Oid KRB5_MECH_OID = null;
    private static Oid SPNEGO_MECH_OID = null;
    private static Oid KERBEROS_V5_PRINCIPAL_NAME = null;
    final String className = this.getClass().getName();

    static {
        try {
            KERBEROS_V5_PRINCIPAL_NAME = new Oid("1.2.840.113554.1.2.2.1");
            KRB5_MECH_OID = new Oid("1.2.840.113554.1.2.2");
            SPNEGO_MECH_OID = new Oid("1.3.6.1.5.5.2");
        } catch (final GSSException ex) {
            System.out.println("Exception creating mechOid's: " + ex.getMessage());
            ex.printStackTrace();
        }
    }

    public HTTPKerberosHandler(final String contextName, final String servicePrincipal) {
        this.contextName = contextName;
        this.servicePrincipal = servicePrincipal;
    }

    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }

    @Override
    public void close(MessageContext context) {
        // No action
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        if (((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY))) {
            return handleRequest(context);
        } else {
            return handleResponse(context);
        }
    }

    private boolean handleRequest(SOAPMessageContext context) {
        byte[] token = getKerberosToken(contextName, servicePrincipal);

        HashMap<String, String> sendTransportHeaders = new HashMap<String, String>();
        sendTransportHeaders.put("Authorization", "Negotiate " + Base64.encode(token));
        context.put(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES, sendTransportHeaders);

        return true;
    }

    private boolean handleResponse(SOAPMessageContext context) {
        logger.logInformation(className, "handleResponse", "Inbound response detected");
        return true;
    }

    public byte[] getKerberosToken(final String contextName, final String servicePrincipal) {

        try {
            LoginContext lc = getLoginContext(contextName);

            final Subject subject = lc.getSubject();

            byte[] token = (byte[]) Subject.doAs(subject, new PrivilegedExceptionAction() {
                @Override
                public Object run() throws PrivilegedActionException, GSSException {
                    final String methodName = "getKerberosToken/run";
                    final GSSManager manager = GSSManager.getInstance();

                    Set<Principal> principals = subject.getPrincipals();
                    Iterator it = principals.iterator();
                    String principalName = ((Principal) it.next()).getName();
                    logger.logInformation(className, methodName, "Using principal: [" + principalName + "]");

                    GSSName gssName = manager.createName(principalName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
                    GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
                            GSSCredential.DEFAULT_LIFETIME,
                            KRB5_MECH_OID,
                            GSSCredential.INITIATE_ONLY);

                    gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
                            GSSCredential.INDEFINITE_LIFETIME,
                            SPNEGO_MECH_OID,
                            GSSCredential.INITIATE_ONLY);
                    logger.logInformation(className, methodName, "Client TGT obtained: " + gssCred.toString());

                    GSSName gssServerName = manager.createName(servicePrincipal, GSSName.NT_USER_NAME);

                    GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
                            SPNEGO_MECH_OID,
                            gssCred,
                            GSSContext.DEFAULT_LIFETIME);

                    logger.logInformation(className, methodName, "Service ticket obtained: " + clientContext.toString());

                    byte[] token = new byte[0];
                    token = clientContext.initSecContext(token, 0, token.length);
                    clientContext.dispose();
                    return token;
                }
            });

            return token;
        } catch (PrivilegedActionException ex) {
            logger.logError(HTTPKerberosHandler.class.getName(), methodName, "PrivilegedActionException: " + ex.getMessage());
        } catch (Exception ex) {
            logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Exception: " + ex.getMessage());
        }

        return null;
    }

    private LoginContext getLoginContext(String contextName) {

        LoginContext lc = null;
        try {
            lc = new LoginContext(contextName);

            lc.login();
        } catch (LoginException le) {
            logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Login exception: [" + le.getMessage() + "]");
            le.printStackTrace();
        }

        return lc;
    }

}