如何在运行Tomcat的Linux服务器上委派kerberos客户端凭据?

时间:2017-12-20 18:56:27

标签: java kerberos kerberos-delegation

这与How to delegate the kerberos client credentials to the server?

几乎相同

但没有答案。这就是我再次提出这个问题的原因。希望有人可以提供帮助。

可以为服务器端的客户端(远程用户)获​​取服务票据,以便使用该票证对另一个后端进行身份验证吗?

场景:用户(IE)==> AppServer(Tomcat,在Linux下)==>后端(webservice - Windows上的REST服务)

  • 我们已经运行SPNEGO auth并在AppServer中工作

  • AppServer中密钥表文件中的AD用户有权访问 代表团(希望如此)

  • GSSManager可以创建的前提条件是什么 可用于委派的凭证? ('context.getDelegCred()' 不应该失败 'GSSManager.getInstance()。的createContext(this.serverCredentials)'

必须有人解决了这个问题吗?

“Forwardable Ticket true”是否表示来自keytab文件的用户具有委派权限?有谁知道这个?

提前致谢

HelloKDC.java的输出(参见下面的摘录)

Client Principal = HTTP/servername.domain.com@CORP1.AD1.COMPANY.NET
Server Principal = krbtgt/CORP1.AD1.COMPANY.NET@CORP1.AD1.COMPANY.NET
Session Key = EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: xx xx xx xx xx xx xx xx   xx xx xx xx xx xx xx xx  ................

Forwardable Ticket true
Forwarded Ticket false
Proxiable Ticket false
Proxy Ticket false
Postdated Ticket false
Renewable Ticket false
Initial Ticket false
Auth Time = Wed Dec 20 16:52:03 CET 2017
Start Time = Wed Dec 20 16:52:03 CET 2017
End Time = Thu Dec 21 02:52:03 CET 2017
Renew Till = null
Client Addresses  Null
        Private Credential: /opt/app/tomcat/ssoad1/servername.domain.com.keytab for HTTP/servername.domain.com@CORP1.AD1.COMPANY.NET

Connection test successful.

从HelloKDC.java中提取(也来自net.sourceforge.spnego):

// Name of our krb5 config file
final String krbfile = "/opt/app/tomcat/ssoad1/krb5.ini";

// Name of our login config file
final String loginfile = "/opt/app/tomcat/ssoad1/jaas.conf";

// Name of our login module
//final String module = "spnego-client";
final String module = "com.sun.security.jgss.krb5.initiate";

// set some system properties
System.setProperty("java.security.krb5.conf", krbfile);
System.setProperty("java.security.auth.login.config", loginfile);
System.setProperty("sun.security.krb5.debug", "true");

final LoginContext loginContext = new LoginContext(module);

// attempt to login
loginContext.login();

// output some info
System.out.println("Subject=" + loginContext.getSubject());

// logout
loginContext.logout();

System.out.println("Connection test successful.");

的Jaas.conf:

com.sun.comcurity.jgss.krb5.initiate {
    com.sun.comcurity.auth.module.Krb5LoginModule required
    doNotPrompt=true
    principal="HTTP/servername.domain.com@CORP1.AD1.COMPANY.NET"
    useKeyTab=true
    keyTab="/opt/app/tomcat/ssoad1/servername.domain.com.keytab"
    storeKey=true;
};  

com.sun.security.jgss.krb5.accept {
    com.sun.security.auth.module.Krb5LoginModule required
    doNotPrompt=true
    principal="HTTP/servername.domain.com@CORP1.AD1.COMPANY.NET"
    useKeyTab=true
    keyTab="/opt/app/tomcat/ssoad1/servername.domain.com.keytab"
    storeKey=true
    useTicketCache=true
    isInitiator=true
    refreshKrb5Config=true
    moduleBanner=true
    storePass=true;
};

spnego-client {
    com.sun.security.auth.module.Krb5LoginModule required;
};

spnego-server {
    com.sun.security.auth.module.Krb5LoginModule required
    principal="HTTP/servername.domain.com@CORP1.AD1.COMPANY.NET"
    useKeyTab=true
    keyTab="/opt/app/tomcat/ssoad1/servername.domain.com.keytab"
    storeKey=true
    useTicketCache=true
    isInitiator=false
    refreshKrb5Config=true
    moduleBanner=true
;
};

krb5.ini

[libdefaults]
        default_realm = CORP1.AD1.COMPANY.NET
        default_keytab_name = FILE:/opt/app/tomcat/ssoad1/servername.domain.com.keytab
        default_tkt_enctypes = rc4-hmac
        default_tgs_enctypes = rc4-hmac
        forwardable  = true
        renewable  = true
        noaddresses = true
        clockskew  = 300
        udp_preference_limit = 1

[realms]
        CORP1.AD1.COMPANY.NET = {
                kdc = ndcr001k.corp1.ad1.company.net:88
                default_domain = domain.com
        }

[domain_realm]
        .domain.com = CORP1.AD1.COMPANY.NET

来自net.sourceforge.spnego.SpnegoAuthenticator.java

    SpnegoAuthenticator.LOCK.lock();
    try {
        LOGGER.fine("create context");
        LOGGER.fine("serverCredentials="+this.serverCredentials.toString());
        context = SpnegoAuthenticator.MANAGER.createContext(this.serverCredentials);
        context.requestCredDeleg(true);
        LOGGER.fine("clientModuleName="+clientModuleName.toString());
        LOGGER.fine("context.getCredDelegState()="+context.getCredDelegState());
        token = context.acceptSecContext(gss, 0, gss.length); // When I understand right : gss contains the token from the authorized client (IE Windows user)
        LOGGER.fine("token="+token);
        LOGGER.fine("context.getDelegCred()="+context.getDelegCred());
    } finally {
        SpnegoAuthenticator.LOCK.unlock();
    }

创建以下异常:

javax.servlet.ServletException: GSSException: No valid credentials provided
    net.sourceforge.spnego.SpnegoHttpFilter.doFilter(SpnegoHttpFilter.java:287)
Root Cause

GSSException: No valid credentials provided
    sun.security.jgss.krb5.Krb5Context.getDelegCred(Krb5Context.java:511)
    sun.security.jgss.GSSContextImpl.getDelegCred(GSSContextImpl.java:614)
    sun.security.jgss.spnego.SpNegoContext.getDelegCred(SpNegoContext.java:1064)
    sun.security.jgss.GSSContextImpl.getDelegCred(GSSContextImpl.java:614)
    net.sourceforge.spnego.SpnegoAuthenticator.doSpnegoAuth(SpnegoAuthenticator.java:503)

1 个答案:

答案 0 :(得分:0)

根据建议我回答我自己的问题:
首先确保在keytab文件中列出的用户的活动目录中允许委派。对于委托,我们添加一个完整的限定主机名和一个用户名,在该用户名下,服务在第二个服务器上运行(委托目标服务器 - 这里是windows)。 AD Delegation tab
AD管理员应该知道如何创建密钥表文件并将其交给您 创建一个jaas.conf和一个krb5.ini文件,如问题所述。

使用http://spnego.sourceforge.net/中的库。
将过滤器添加到web.xml:

<filter>
    <filter-name>SpnegoHttpFilter</filter-name>
    <filter-class>net.sourceforge.spnego.SpnegoHttpFilter</filter-class>
    ....
    ....
    <init-param>
        <param-name>spnego.allow.delegation</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>SpnegoHttpFilter</filter-name>
    <url-pattern>/sc2</url-pattern>
</filter-mapping>

包含所有需要的init参数,如库网页上描述的那样,当然还有过滤器映射。

使用以下选项启动Tomcat:

CATALINA_OPTS="-Dsun.security.krb5.debug=[true|false]
-Djava.security.auth.login.config=/opt/app/tomcat/ssoad1/jaas.conf
-Djava.security.krb5.conf=/opt/app/tomcat/ssoad1/krb5.ini
-Djavax.security.auth.useSubjectCredsOnly=false" 

最后一个选项

  

-Djavax.security.auth.useSubjectCredsOnly =假

非常重要 - 没有它它不起作用。 spnego.sourceforge.net网站上没有提到这一点。

然后魔法真的起作用了:
该应用程序充当http客户端,其中包含来自浏览器调用应用程序的用户的凭据。

private void doServiceCall(HttpServletRequest request, StringBuilder sb) throws GSSException, MalformedURLException, PrivilegedActionException, IOException {
       if (request instanceof DelegateServletRequest) {
            DelegateServletRequest dsr = (DelegateServletRequest) request;
            GSSCredential creds = dsr.getDelegatedCredential();
            if (null == creds) {
                sb.append("No delegated creds.");
            } else {
                sb.append(creds.getName().toString());

                SpnegoHttpURLConnection spnego =
                    new SpnegoHttpURLConnection(creds);

                HttpURLConnection con = spnego.connect(new URL("https://server.domain.com/ServiceFactory/servicenamexyz/Get?KeyConditionValue=ACTION_OUTPUT"));

                sb.append("<br />HTTP Status Code: " + spnego.getResponseCode());
                sb.append("<br />HTTP Status Message: " + spnego.getResponseMessage());

                String contentType = con.getContentType();
                sb.append("<br />HTTP Content Type: " + contentType);

                StringBuilder result = new StringBuilder();
                String line;
                BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                reader.close();

                sb.append("<br />HTTP Content: " + result.toString());

                spnego.disconnect();
            }

        } else {
            sb.append("Request not a delegate.");
        }
       br(sb);
}