-1

这与如何将 kerberos 客户端凭据委托给服务器几乎是相同的问题?

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

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

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

  • 我们让 SPNEGO auth 在 AppServer 中运行和工作

  • AppServer 上 keytab 文件中的 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)
4

1 回答 1

0

按照建议,我回答我自己的问题:
首先确保在 keytab 文件中列出的用户的活动目录中允许委派。对于委托,我们添加了一个完整的主机名和一个用户名,服务在第二个服务器上运行时使用的用户名(委托目标服务器 - 这里是 windows)。 AD 委派选项卡
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>

带有所有需要的初始化参数,如库网页上描述的,当然还有过滤器映射。

使用以下选项启动 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=false

非常重要——没有它就行不通。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);
}
于 2018-01-24T17:47:41.997 回答