服务器使用用户帐户的 WCF Kerberos 客户端模式
我们有一个 WCF(Windows Communication Foundation)客户端和服务应用程序。 我们使用带有 Kerberos 的 Windows 身份验证。
问题是该服务可能在多个帐户之一下运行(可能是网络服务,可能是特定用户帐户 - 取决于 IT 团队)。 该帐户不太可能每天都会更改,但可能偶尔会更改(也许每隔几个月)。 此外,我们将此客户端/服务包交付给多个组,每个组可能有自己的帐户,用于运行服务(这只是让您知道我们无法为单个团队提供自定义解决方案)。
现在,上面段落成为问题的原因显然是,如果服务不在系统或网络服务帐户(即用户帐户)中运行,则客户端必须在其端点的身份中指定用户帐户的名称。
有关此限制的详细信息,请参阅:http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/feb6bc31-9a4b-4f8d-a887-ef6d2c7abe41 和 http://www.vistax64.com/indigo /146204-using-localhost-vs-environment-machinename.html
现在,这似乎使得处理 IT 部门更改运行服务的帐户的情况变得困难。 如果有的话,处理这个问题的模式是什么? 其他人是如何处理这个问题的? 我想到的一个解决方案是,当服务的用户帐户发生更改时,管理员会发送一封电子邮件,其中包含一个指向更新客户端或配置文件的应用程序的网络链接,因此客户端引用新的用户帐户。 但这似乎很黑客。
不可否认,这很像端点移动的 URI。 除此之外,我认为人们有更多的期望,即更改 URI 是客户端应该知道的事情,但更改运行服务的帐户对客户端来说应该是相对透明的。
顺便说一句,如果重要的话,这需要托管在 IIS 7.0 上。
We have a WCF (Windows Communication Foundation) client and service application. We're using Windows Authentication with Kerberos.
The issue is that the service may be run under one of many accounts (maybe Network Service, maybe a specific user account -- depends on the IT group). This account is not not likely to change daily, but possibly on occassion (every few months maybe). Additionally, we deliver this client/service package to several groups, and each group may have its own account that they use to run the service on (this is to just let you know that we can't do a custom solution for a single team).
Now the reason the above paragraph is an issue is apparently if the service is not running in the SYSTEM or NETWORK SERVICE account, i.e., a user account, then the client must specify the name of the user account in the identity of its endpoint.
For more on this restriction see: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/feb6bc31-9a4b-4f8d-a887-ef6d2c7abe41
and http://www.vistax64.com/indigo/146204-using-localhost-v-s-environment-machinename.html
Now this seemingly makes it tough to deal with the situation where the IT department changes the account that the service runs on. What is the pattern for handling this, if there is one? How have other people handled this? One solution I've thought of is that the admin sends out an email when the user account of the service has changed, which has a weblink to an application that updates the client or a config file, so the client refers to the new user account. But that seems hackish.
Admittedly, this is a lot like the URI of the endpoint moving. Except, I think there's a lot more expectation on behalf of people that changing the URI is something the client should have to know about, but changing the account the service is running on is something that should be relatively transparent to the client.
BTW, this is required to be hosted on IIS 7.0, if that matters.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为您可以将 NegotiateServiceCredential 属性设置为确实如此,您的绑定使用 SPNego 而不是硬-cold Kerberos。 当设置为true时,客户端不需要指定SPN,它可以连接到运行非机器帐户的服务器。
请注意,由于客户端不再请求特定的 SPN,因此它无法再检测是否连接到服务的被劫持的模仿者,但这通常是一个小问题,除非您真的对安全性很偏执。
另外,顺便说一句:WCF 请求帐户名作为 SPN 的事实基本上是一个脑残。 它客户端应使用 DsMakeSpn API 来撰写来自服务名称、主机和端口的 SPN。 服务器应在启动时为其自身注册该 SPN,或者让管理员使用 setspn.exe。 这是 Kerberos/ActiveDirecotry/Windows 环境中所有传统(表现良好)服务的做法。
更新
第二,虽然我没有看到任何指定客户端必须使用帐户名称作为 SPN 的内容。 看起来更像是文档疏忽,而不是记录正确的方式,他们只是推荐了基本上是一种不好的做法。 或者也许只是论坛的建议很糟糕,因为我没有深入了解 MSDN 绑定规范实际上对要使用的 SPN 有何说明...
我没有方便测试的 WCF 环境,但也许您可以配置客户端请求正确的 SPN,例如
YourService/server:port
,并且您还在服务器端注册相同的 SPN。 可以手动作为留给管理员的练习,也可以在服务启动时自动从服务中取消注册,并在关闭时取消注册。 正确的方法是让管理员来完成,但实际上这很痛苦,大多数服务都会自行注册 SPN,您也可以遵循这种做法。 要注册 SPN,您的服务将调用 DsWriteAccountSpn 。 写入必须传播到 AD 并在 AD 服务器之间复制,这至少是让服务自动注册/自动取消注册 SPN 的做法值得怀疑的一个原因。如果您想了解有关 SPN 的神奇世界以及它们如何破坏您的一天的更多信息,您可以阅读 服务发布和服务主体名称如何工作。
更新
我确信您可以使用任何您喜欢的 SPN。 大多数示例使用帐户名称作为“UPN”(用户主体名称)而不是 SPN,但这只是为了方便示例,因为使用真正的 SPN 会遇到在用户帐户下设置 SPN 的管理问题(同样) ,为什么管理员应该这样做......)。 从覆盖服务的身份进行身份验证,相关强调:
I think you can set NegotiateServiceCredential property to True so your binding uses SPNego instead of hard-cold Kerberos. When is set to true, the client does not need to specify the SPN and it can connect to a server running a non-machine account.
Note that since the client no longer requests a specific SPN, it can no longer detect if is connected to a hijacked impersonator of the service, but this is usually a minor concern unless you are really paranoid about security.
Also, as a side rant: the fact that WCF requests as SPN the account name is basically a brain fart. It client should use the DsMakeSpn API to compose the SPN from the service name, host and port. The server should register that SPN for itslef at start up or let an administrator do it using setspn.exe. This is the way they do it by all traditional (well behaved) services in the Kerberos/ActiveDirecotry/Windows environment.
Update
On second though I don't see anything specifying that the client must use the account name as SPN. Looks more like a documentation oversight, instead of documenting the proper way they just recommended what is basically a bad practice. Or maybe just the forum advice is bad, since I did not dig to see what does the MSDN binding spec actually says about the SPN to use...
I don't have a WCF environment handy to test with, but perhaps you can configure the clients to requests a proper SPN like
YourService/server:port
and you also register the same SPN on the server side. Either manually as an exercise left to the admins, or automatically from your service when it starts up, and unregister it at shut down. The proper way to do it is to let the admins do it, but in reality that is such a pain that most services register the SPN themselves and you can probably follow this practice too. To register an SPN, your service calls DsWriteAccountSpn. The write has to propagate to the AD and be replicated between AD servers, and this at least one reason why having the service auto-register/auto-unregister the SPN is a questionable practice.If you want to learn more about the wonderfool world of SPNs and how they can wreck your day, you can read up on How Service Publication and Service Principal Names Work.
Update
I'm pretty sure you can use any SPN you like. Most exmaples out there use the account name as 'UPN' (User Principal Name) instead of SPN, but that is just for the convenience of samples as using a true SPN would run into administrative issues setting up the SPN under an user account (again, why admins should do it...). From Overriding the Identity of a Service for Authentication, relevant emphasized:
将
NegotiateServiceCredential
和EstablishSecurityContext
属性设置为False
。Set
NegotiateServiceCredential
andEstablishSecurityContext
properties toFalse
.