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.

About WCF Security
Husnu Kaplan
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
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];
}
}
}