使用Geneva框架创建本地令牌缓存

发布于 2024-07-11 03:48:54 字数 2696 浏览 6 评论 0原文

还没有看到很多与日内瓦相关的问题,我已经在 日内瓦论坛以及...

我正在研究一个场景,其中我们有一个具有广泛安装基础的win forms应用程序,它将在整个操作过程中频繁调用我​​们集中托管的各种服务。

这些服务均使用日内瓦框架,所有客户都应首先调用我们的 STS,以便获得令牌以允许访问服务。

开箱即用,使用 ws2007FederationHttpBinding,应用程序可以配置为在每次服务调用之前从 STS 检索令牌,但显然这不是最有效的方法,因为我们几乎重复了调用服务的工作。

或者,我已经实现了从应用程序“手动”检索令牌所需的代码,然后在调用服务操作时传递相同的预检索令牌(基于 WSTrustClient 示例和论坛上的帮助); 效果很好,所以我们确实有一个解决方案,但我相信它不是很优雅,因为它需要在代码中构建 WCF 通道,远离美妙的 WCF 配置。

我更喜欢 ws2007FederationHttpBinding 方法,客户端只需像任何其他 WCF 服务一样调用该服务,而无需了解有关Geneva的任何信息,并且绑定负责令牌交换。

然后有人(乔恩·辛普森)给了我[我认为]一个好主意 - 添加一项服务,托管在应用程序本身中以缓存本地检索的令牌。 本地缓存服务将实现与STS相同的合约; 当接收到请求时,它会检查缓存令牌是否存在,如果存在,则返回它,否则它将调用“真实”STS,检索新令牌,缓存它并返回它。 然后,客户端应用程序仍然可以使用 ws2007FederationHttpBinding,但不再将 STS 作为颁发者,而是使用本地缓存;

通过这种方式,我认为我们可以实现两全其美 - 无需服务特定的自定义代码即可缓存令牌; 我们的缓存应该能够处理所有 RP 的令牌。

我创建了一个非常简单的原型来看看它是否有效,并且 - 不幸的是,这并不奇怪 - 我有点卡住了 -

我的本地服务(当前是控制台应用程序)收到请求,并且 - 第一次 - 调用 STS 来检索token,缓存它并成功返回给客户端,客户端随后使用它来调用 RP。 一切正常。

然而,第二次,我的本地 cahce 服务再次尝试使用相同的令牌,但客户端失败并出现 MessageSecurityException -

“安全处理器无法在消息中找到安全标头。这可能是因为该消息是不安全的消息错误或因为通信双方之间存在绑定不匹配,如果服务配置为安全性而客户端未使用安全性,则可能会发生这种情况。”

是否有什么东西可以阻止同一令牌多次使用? 我对此表示怀疑,因为当我按照 WSTrustClient 示例重用该令牌时,它运行良好; 我缺少什么? 我的想法可行吗? 好的吗?

这是本地缓存的(现阶段非常基本的)主要代码位 -

    static LocalTokenCache.STS.Trust13IssueResponse  cachedResponse = null; 
    public LocalTokenCache.STS.Trust13IssueResponse Trust13Issue(LocalTokenCache.STS.Trust13IssueRequest request) 
    { 
        if (TokenCache.cachedResponse == null) 
        { 
            Console.WriteLine("cached token not found, calling STS"); 
            //create proxy for real STS 
            STS.WSTrust13SyncClient sts = new LocalTokenCache.STS.WSTrust13SyncClient(); 
            //set credentials for sts 
            sts.ClientCredentials.UserName.UserName = "Yossi"; 
            sts.ClientCredentials.UserName.Password = "p@ssw0rd"; 
            //call issue on real sts 
            STS.RequestSecurityTokenResponseCollectionType stsResponse = sts.Trust13Issue(request.RequestSecurityToken); 
            //create result object - this is a container type for the response returned and is what we need to return; 
            TokenCache.cachedResponse = new LocalTokenCache.STS.Trust13IssueResponse(); 
            //assign sts response to return value... 
            TokenCache.cachedResponse.RequestSecurityTokenResponseCollection = stsResponse; 
        } 
        else 
        { 
        } 
        //...and reutn 
        return TokenCache.cachedResponse;

Haven't seen many Geneva related questions yet, I have posted this question in the Geneva Forum as well...

I'm working on a scenario where we have a win forms app with a wide installbase, which will be issuing frequent calls to various services hosted by us centrally throughout it's operation.

The services are all using the Geneva Framework and all clients are expected to call our STS first to be issued with a token to allow access to the services.

Out of the box, using the ws2007FederationHttpBinding, the app can be configured to retrieve a token from the STS before each service call, but obviously this is not the most efficient way as we're almost duplicating the effort of calling the services.

Alternatively, I have implemented the code required to retrieve the token "manually" from the app, and then pass the same pre-retrieved token when calling operations on the services (based on the WSTrustClient sample and helpon the forum); that works well and so we do have a solution,but I believeit's not very elegant as it requires building the WCF channel in code, moving away from the wonderful WCF configuration.

I much prefer the ws2007FederationHttpBinding approach where by the client simply calls the service like any other WCF service, without knowing anything about Geneva, and the bindings takes care of the token exchange.

Then someone (Jon Simpson) gave me [what I think is] a great idea - add a service, hosted in the app itself to cache locally retrieved tokens.
The local cache service would implement the same contract as the STS; when receiveing a request it would check to see if a cahced token exists, and if so would return it, otherwise it would call the 'real' STS, retrive a new token, cache it and return it.
The client app could then still use ws2007FederationHttpBinding, but instead of having the STS as the issuer it would have the local cache;

This way I think we can achieve the best of both worlds - caching of tokens without the service-sepcific custom code; our cache should be able to handle tokens for all RPs.

I have created a very simple prototype to see if it works, and - somewhat not surprising unfortunately - I am slightly stuck -

My local service (currently a console app) gets the request, and - first time around - calls the STS to retrieve the token, caches it and succesfully returns it to the client which, subsequently, uses it to call the RP. all works well.

Second time around, however, my local cahce service tries to use the same token again, but the client side fails with a MessageSecurityException -

"Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security."

Is there something preventing the same token to be used more than once? I doubt it because when I reused the token as per the WSTrustClient sample it worked well; what am I missing? is my idea possible? a good one?

Here's the (very basic, at this stage) main code bits of the local cache -

    static LocalTokenCache.STS.Trust13IssueResponse  cachedResponse = null; 
    public LocalTokenCache.STS.Trust13IssueResponse Trust13Issue(LocalTokenCache.STS.Trust13IssueRequest request) 
    { 
        if (TokenCache.cachedResponse == null) 
        { 
            Console.WriteLine("cached token not found, calling STS"); 
            //create proxy for real STS 
            STS.WSTrust13SyncClient sts = new LocalTokenCache.STS.WSTrust13SyncClient(); 
            //set credentials for sts 
            sts.ClientCredentials.UserName.UserName = "Yossi"; 
            sts.ClientCredentials.UserName.Password = "p@ssw0rd"; 
            //call issue on real sts 
            STS.RequestSecurityTokenResponseCollectionType stsResponse = sts.Trust13Issue(request.RequestSecurityToken); 
            //create result object - this is a container type for the response returned and is what we need to return; 
            TokenCache.cachedResponse = new LocalTokenCache.STS.Trust13IssueResponse(); 
            //assign sts response to return value... 
            TokenCache.cachedResponse.RequestSecurityTokenResponseCollection = stsResponse; 
        } 
        else 
        { 
        } 
        //...and reutn 
        return TokenCache.cachedResponse;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

素衣风尘叹 2024-07-18 03:48:54

这几乎令人尴尬,但多亏了论坛上的 Dominick Baier,我现在没有意识到我错过了一个重要的点(我知道这没有意义!说实话!:-)) -

每个服务代理都会检索一次令牌,假设它没有过期,所以我需要做的就是重用同一个代理,无论如何我都计划这样做,但相当愚蠢的是,我的原型上没有这样做。

另外 - 我在 MSDN WCF 示例上发现了一个非常有趣的示例 - Durable Issued Token Provider,如果我理解正确的话,它在客户端使用自定义端点行为来实现令牌缓存,非常优雅。

我仍然会考虑这种方法,因为我们有多种服务,因此我们可以通过在代理之间重复使用相同的令牌来实现更高的效率。

所以 - 两种解决方案,几乎是我的眼睛的信息; 希望我的愚蠢能在某个时候帮助别人!

This is almost embarrassing, but thanks to Dominick Baier on the forum I no now realise I've missed a huge point (I knew it didn't make sense! honestly! :-) ) -

A token gets retrieved once per service proxy, assuming it hadn't expired, and so all I needed to do is to reuse the same proxy, which I planned to do anyway, but, rather stupidly, didn't on my prototype.

In addition - I found a very interesting sample on the MSDN WCF samples - Durable Issued Token Provider, which, if I understand it correctly, uses a custom endpoint behaviour on the client side to implement token caching, which is very elegant.

I will still look at this approach as we have several services and so we could achieve even more efficiency by re-using the same token between their proxies.

So - two solutions, pretty much infornt of my eyes; hope my stupidity helps someone at some point!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文