这与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)
答案 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);
}