About WCF Security

I have a couple of WCF Services that a client is going to use. When the users login on the client i want to authenticate them using a authentication service that recieves the username and password. The authentication service compares the credentials to a userrow in a database. After the client it authenticated i want the user to be authenticated to all my services.

My requiered scenario assumes that i get some kind of "object" as a result from my authentication service. I will pass this "object" to my services when i call them. My services then trust this "object" and look at it when authorizing the call.

I already know how make a custom authentication but when the call to the authentication service is complete i can’t seem to find any useful data in the ClientCredentials.IssuedToken in the client proxy .

Am i on the right track here I would appreciate if someone could describe the basics.



Answer this question

About WCF Security

  • Husnu Kaplan

    I've run into this exact same problem and haven't yet found a good solution. Gudge, could you outline the basic approach I might take in writing a custom ClientCredential class to do this caching Is it going to also mean writing a custom SecurityTokenProvider or can I just overload CreateLocalTokenProvider() to implement the cache of what the base returns I'll try that approach for now.

  • Rudolfh Bantim

    Niklas,

    I can't tell from your description whether you want the authentication service to run on the client machine or as another remote service. Can you clarify

    Either way, the authentication service needs to return something to the client ( your 'object' ) that contains information about the user and is not forgable. This typically means a security token that has been cryptographically protected, usually with some form of digital signature.

    This means that your autentication service is effectively performing the role of what Web Services folks often call a Security Token Service or STS for short. If takes in the client credentials (username/password in your case) and returns some kind of token that identifies the user. That token can then be presented to your actual services and allow them to authenticate the client.

    Can you provide some more detail about what your authentication service does The ClientCredentials.IssuedToken property is used for federated identity scenarios (of which yours is an example) but this means you need an STS out there somewhere to issue tokens...

    Gudge


  • magicalclick

    Turns out we don't cache issued tokens by default in terms of submitting them to different services. One could write a custom ClientCredential class to perform such caching. If I find time, I'll try to work up a sample.

    Gudge


  • MrTovson

    I did this as a simple test against two services using InfoCard to see if caching the provider was enough. It wasn't, so I'm guessing that means writing a custom provider as well.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ServiceModel;
    using System.ServiceModel.Security;
    using System.ServiceModel.Security.Tokens;
    using Microsoft.InfoCards;

    namespace Microsoft.ServiceModel.Samples.Federation
    {
    class CachedClientCredentials : InfoCardClientCredentials
    {
    SecurityTokenProvider cachedProvider = null;
    protected override SecurityTokenProvider CreateLocalTokenProvider(SecurityTokenParameters parameters)
    {
    if(cachedProvider == null)
    cachedProvider = base.CreateLocalTokenProvider(parameters);

    return cachedProvider;
    }
    }
    }


  • Yoni

    first of all thanks for the reply.

    It’s a STS acting like a remote service i'm trying to build. I already got the credential authentication part of my STS working. now i want my service to return a token and my client to cache it locally and use it to be authenticated on other services. I also want my token to carry some information about the user as UserID for example.

    I would love to see a simple code example how to return a custom token, how to retrieve it on the client and how to pass my token to my other services.

    Best Regards Niklas


  • Shahzad.K.Y

    The Federation sample that shipped as part of the Nov CTP shows how to issue tokens. I think SecurityTokenService.cs and SAMLTokenCreator.cs contain the code you are looking for.

    The Federation sample shows the client, service and STS portions of this scenario.

    I'm currently looking into what happens WRT client caching of tokens if two services share an STS (and accept the same issued tokens).

    Gudge


  • MarshallR

    Well, I got the basic case working. Use the same instance of this cached credentials class with each channel that you want to share tokens with.

    Hopefully I didn't make any bad assumptions here, and if I did, advice is appreciated.

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.ServiceModel;

    using System.ServiceModel.Security;

    using System.ServiceModel.Security.Tokens;

    using Microsoft.InfoCards;

    namespace Microsoft.ServiceModel.Samples.Federation

    {

    class CachedClientCredentials : InfoCardClientCredentials

    {

    Dictionary<int, SecurityToken> cachedTokens = new Dictionary<int, SecurityToken>();

    public Dictionary<int, SecurityToken> CachedTokens

    {

    get

    {

    return cachedTokens;

    }

    }

    protected override SecurityTokenProvider CreateLocalTokenProvider(SecurityTokenParameters parameters)

    {

    return new CachedSecurityTokenProvider(this, parameters);

    }

    public SecurityTokenProvider CreateBaseLocalTokenProvider(SecurityTokenParameters parameters)

    {

    return base.CreateLocalTokenProvider(parameters);

    }

    public void RemoveExpiredTokens()

    {

    foreach (int key in cachedTokens.Keys)

    {

    SecurityToken token = cachedTokens[key];

    if (token.ExpirationTime < DateTime.Now)

    {

    cachedTokens.Remove(key);

    }

    }

    }

    }

    class CachedSecurityTokenProvider : SecurityTokenProvider

    {

    CachedClientCredentials credentials = null;

    SecurityTokenParameters parameters = null;

    public CachedSecurityTokenProvider(CachedClientCredentials credentials, SecurityTokenParameters parameters)

    {

    this.credentials = credentials;

    this.parameters = parameters;

    }

    public override SecurityToken GetToken(EndpointAddress target, Uri via, TimeSpan timeout)

    {

    // Remove any expired tokens

    credentials.RemoveExpiredTokens();

    // It would be better if the provider of SecurityTokenParameters

    // implemented a real hash code. I'm not sure how safe this way is.

    int cacheKey = parameters.ToString().GetHashCode();

    // Since the token may now be tied to multiple endpoints,

    // does it make sense to reassign the address uri to the host root

    // or something else in common For now, leaving alone.

    EndpointAddress ep = target;

    // Return a cached token, otherwise get a new one.

    if (!credentials.CachedTokens.ContainsKey(cacheKey))

    {

    SecurityToken token = credentials.CreateBaseLocalTokenProvider(parameters).GetToken(ep, via, timeout);

    credentials.CachedTokens.Add(cacheKey, token);

    return token;

    }

    else return credentials.CachedTokens[cacheKey];

    }

    }

    }


  • About WCF Security