当使用带有委托的Kerberos时,GSS和SSPI有什么区别?
我在Tomcat中有运行Java代码的中间件。中间件使用Kerberos (GSS )对用户进行身份验证。如果授权头中没有Kerberos令牌,则中间件返回401并附加WWW身份验证:协商响应头以初始化SPNEGO身份验证。
使用GSSContext.acceptSecContext检查传入的服务票证效果很好。
不过,我在代表团的案件中有一些问题。
正如名称“中间件”所指出的,我的java服务必须使用Kerberos身份验证使用原始用户主体调用后端服务。为此,我实现了Kerberos Java委托机制。另外,AD被正确配置,tomcat作为一个具有特定服务帐户的服务运行。
为了测试这个实现,我编写了一个Java测试客户机,它使用GSS来获取中间件的票据。运行具有管理权限的Java或使用kinit -f获得可转发的票证客户机和中间件组合工作得很好:客户端获得票证,中间件接受票证,GSSContext.getCredDelegState()返回true,使用GSSContext.getDelegCred()中间件获得委托凭据,后端登录运行良好。
此外,我还用浏览器和一个小型C#测试客户端测试了中间件实现。两者都使用SPNEGO。在这种情况下,授权也是有效的。我得到了身份验证成功的消息,我得到了用户主体。使用浏览器或我的C#测试客户端,可以在中间件中获得以下调试打印:
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator false KeyTab is D:/app/Tomcat_9019_SSO/conf/tomcat.keytab refreshKrb5Config is true principal is HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Refreshing Kerberos configuration
Java config name: C:\Windows\kerb5.ini
Loading krb5 profile at C:\Windows\kerb5.ini
Loaded from Java config
>>> KdcAccessibility: reset
principal is HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Will use keytab
Commit Succeeded
2020-03-18 06:36:50.254 INFO .e.s.a.t.a.KerberosCheckAuthTicketAction [TC~3~c80e3d5b-3] : Starting check of incoming Kerberos service ticket.
Search Subject for SPNEGO ACCEPT cred (<<DEF>>, sun.security.jgss.spnego.SpNegoCredElement)
Search Subject for Kerberos V5 ACCEPT cred (<<DEF>>, sun.security.jgss.krb5.Krb5AcceptCredential)
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Search Subject for Kerberos V5 ACCEPT cred (<<DEF>>, sun.security.jgss.krb5.Krb5AcceptCredential)
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Entered Krb5Context.acceptSecContext with state=STATE_NEW
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Using builtin default etypes for permitted_enctypes
default etypes for permitted_enctypes: 18 17 20 19 16 23.
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
MemoryCache: add 1584509810/000627/5EBDF35F49476E365F32DE53C3CAFA81C4730A13D881ECA15E9F43023F99A80B/CLIENTUSERD@MYDOMAIN.NET to CLIENTUSERD@MYDOMAIN.NET|HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
>>> KrbApReq: authenticate succeed.
Krb5Context setting peerSeqNumber to: 947381056
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Krb5Context setting mySeqNumber to: 214468704
>>> Constrained deleg from GSSCaller{UNKNOWN}
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator true KeyTab is D:/app/Tomcat_9019_SSO/conf/tomcat.keytab refreshKrb5Config is false principal is HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
default etypes for default_tkt_enctypes: 23 18 17.
>>> KrbAsReq creating message
>>> KrbKdcReq send: kdc=kb01.mydomain.net UDP:88, timeout=30000, number of retries =3, #bytes=174
>>> KDCCommunication: kdc=kb01.mydomain.net UDP:88, timeout=30000,Attempt =1, #bytes=174
>>> KrbKdcReq send: #bytes read=175
>>>Pre-Authentication Data:
PA-DATA type = 11
PA-ETYPE-INFO etype = 23, salt =
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 23, salt = null, s2kparams = null
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 16
>>>Pre-Authentication Data:
PA-DATA type = 15
>>> KdcAccessibility: remove kb01.mydomain.net
>>> KDCRep: init() encoding tag is 126 req type is 11
>>>KRBError:
sTime is Wed Mar 18 06:36:50 CET 2020 1584509810000
suSec is 765149
error code is 25
error Message is Additional pre-authentication required
sname is krbtgt/MYDOMAIN.NET@MYDOMAIN.NET
eData provided.
msgType is 30
>>>Pre-Authentication Data:
PA-DATA type = 11
PA-ETYPE-INFO etype = 23, salt =
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 23, salt = null, s2kparams = null
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 16
>>>Pre-Authentication Data:
PA-DATA type = 15
KrbAsReqBuilder: PREAUTH FAILED/REQ, re-send AS-REQ
default etypes for default_tkt_enctypes: 23 18 17.
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
default etypes for default_tkt_enctypes: 23 18 17.
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>> KrbAsReq creating message
>>> KrbKdcReq send: kdc=kb01.mydomain.net UDP:88, timeout=30000, number of retries =3, #bytes=253
>>> KDCCommunication: kdc=kb01.mydomain.net UDP:88, timeout=30000,Attempt =1, #bytes=253
>>> KrbKdcReq send: #bytes read=90
>>> KrbKdcReq send: kdc=kb01.mydomain.net TCP:88, timeout=30000, number of retries =3, #bytes=253
>>> KDCCommunication: kdc=kb01.mydomain.net TCP:88, timeout=30000,Attempt =1, #bytes=253
>>>DEBUG: TCPClient reading 2154 bytes
>>> KrbKdcReq send: #bytes read=2154
>>> KdcAccessibility: remove kb01.mydomain.net
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
[Krb5LoginModule] authentication failed
Message stream modified (41)使用Java客户端,我在中间件中获得了这个调试打印:
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator false KeyTab is D:/app/Tomcat_9019_SSO/conf/tomcat.keytab refreshKrb5Config is true principal is HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Refreshing Kerberos configuration
Java config name: C:\Windows\kerb5.ini
Loading krb5 profile at C:\Windows\kerb5.ini
Loaded from Java config
>>> KdcAccessibility: reset
principal is HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Will use keytab
Commit Succeeded
2020-03-18 06:47:41.029 INFO .e.s.a.t.a.KerberosCheckAuthTicketAction [TC~9~c80e3d5b-9] : Starting check of incoming Kerberos service ticket.
Search Subject for SPNEGO ACCEPT cred (<<DEF>>, sun.security.jgss.spnego.SpNegoCredElement)
Search Subject for Kerberos V5 ACCEPT cred (<<DEF>>, sun.security.jgss.krb5.Krb5AcceptCredential)
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Search Subject for Kerberos V5 ACCEPT cred (<<DEF>>, sun.security.jgss.krb5.Krb5AcceptCredential)
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Found KeyTab D:\app\Tomcat_9019_SSO\conf\tomcat.keytab for HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Entered Krb5Context.acceptSecContext with state=STATE_NEW
Looking for keys for: HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
Added key: 23version: 0
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Using builtin default etypes for permitted_enctypes
default etypes for permitted_enctypes: 18 17 20 19 16 23.
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
MemoryCache: add 1584510459/567826/FDE0027391B8BF26BF807FF04E5FD5F7CE38794A3264EB298BB36F736B2CF050/CLIENTUSERD@MYDOMAIN.NET to CLIENTUSERD@MYDOMAIN.NET|HTTP/SERVICE.MYDOMAIN.NET@MYDOMAIN.NET
>>> KrbApReq: authenticate succeed.
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>>Delegated Creds have pname=CLIENTUSERD@MYDOMAIN.NET sname=krbtgt/MYDOMAIN.NET@MYDOMAIN.NET authtime=20200318054735Z starttime=20200318054739Z endtime=20200318154735ZrenewTill=null
Krb5Context setting peerSeqNumber to: 99984043
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Krb5Context setting mySeqNumber to: 161819208但是,这里的主要问题是,对于Java,委托是有效的,对于浏览器和C#客户机,委托不起作用。注意,已将浏览器配置为白名单域以进行委托。
附加信息:i配置了受约束的委托。带有中间件的Tomcat运行在带有AD服务帐户的Windows 2016服务器上。
我比较了发送给中间件的服务票:
Java (可转发),委托工作: 10980字节
C# (委托不工作):8572字节
浏览器(委托不工作):8572字节
比较而言,我使用了kinit而没有-f选项来获得不可转发的tgt,并测量了大小:
Java (不可转发,委托不工作):8174字节
顺便说一下,这也会产生同样的错误。
发布于 2020-03-24 05:22:59
这是我自己问题的答案。
我意识到域(我正在工作)有3个域控制器:在我的中间件中,krb5.ini配置了第一个域控制器:
[realms]
MYDOMAIN.NET = {
kdc = d01.mydomain.net
admin_server = d01.mydomain.net
default_domain = MYDOMAIN.NET
} 我的Java测试客户端有以下代码行
System.setProperty("java.security.krb5.kdc", d01.mydomain.net);然而,我的客户端计算机使用的是我使用“klist”命令看到的d02.mydomain.net。
#2> Client: CLIENTUSERD @ MYDOMAIN.NET
Server: HTTP/SERVICE.MYDOMAIN.NET @ MYDOMAIN.NET
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a00000 -> forwardable renewable pre_authent
Start Time: 3/24/2020 5:33:39 (local)
End Time: 3/24/2020 15:33:39 (local)
Renew Time: 3/31/2020 5:33:39 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0
Kdc Called: d02.mydomain.net由于某些原因--我现在还不清楚--如果错误的域控制器必须一起工作的话,委托就不起作用。如果我在中间件中将域控制器更改为d03.mydomain.net,则委托可以正常工作。然而,在任何组合中,票的验收都是很好的。可能域控制器的时间不同步。
发布于 2020-03-18 16:16:51
如何为AD中的中间件服务帐户配置委托?无约束还是无约束?
尝试获取由java和C#客户端发送的票的副本,并比较票证大小。它们应该大致相同,但是如果一个大得多,那么较大的那个包含一个委托的TGT。
根据日志,它看起来像是Java客户端发送了一个不受约束的票证(委托的TGT,AKA转发了),并且正在使用它。
我们无法看到C#票证包含什么,但是中间件在接收到KDC后正试图立即与KDC联系,这似乎表明它可能试图将它交换为委托的票证,但是由于中间件无法首先获得它自己的票证,所以失败了。不过,这是个有点疯狂的猜测,因为日志并没有以某种方式说明它为什么要启动AS-REQ。
您可能会考虑在中间件和KDC之间获取一个网络跟踪,以查看它在C#中发送的内容。
https://stackoverflow.com/questions/60734272
复制相似问题