Just found Daniel Cazzulino@Clarius has packaged some of my work in a reusable NuGet package. Pretty cool…
http://nuget.org/List/Packages/netfx-Microsoft.IdentityModel.Swt
Posted by zamd on April 27, 2011
Just found Daniel Cazzulino@Clarius has packaged some of my work in a reusable NuGet package. Pretty cool…
http://nuget.org/List/Packages/netfx-Microsoft.IdentityModel.Swt
Posted in WIF | Leave a Comment »
Posted by zamd on February 8, 2011
SAML 1.1/SAML 2.0 is the default token format when using ACS as the authentication service for your website. In this model, your website talks to ACS using WS-Federation protocol and what it normally gets back is a Saml token. This scenarios is fairly straight-forward as WIF natively supports WS-Federation protocol & SAML1.1/SAML 2.0 token formats.
There are cases where you might want to return a Simple Web Tokens (SWT) after a successful authentication. For example, you might want to use this same SWT (available as a bootstrap token) to call other downstream REST/OData services as depicted in the following diagram.
ACS fully supports returning an SWT token after a successfully WS-Fed authentication but WIF currently doesn’t support SWT tokens. You would have to write a custom Security Token Handler for WIF to process SWT tokens coming back to your website. I have created some extensions which enables this and other OAuth WRAP related scenarios. Feel free to download the code from my SkyDrive.
Posted in WIF, Windows Azure AppFabric | 10 Comments »
Posted by zamd on February 8, 2011
This would hopefully be a multi-part series showing some tricks to enable claims-based-security in Silverlight 4.0. Silverlight 5.0 would have a much better story around claim-based-security as mentioned here.
In this first post, I’ll give you a high level overview of the solution. The main idea is to use the ‘WCF Routing Service’ in the DMZ to route both token issuance requests & business requests to the actual backend services.
1. Routing Service looks for a token issuing request and forwards it to the STS where the actual authentication is performed. After the successful authentication, STS issues a SAML token which goes back to Silverlight client via the routing service. Routing Service also terminates the SSL and backend is called using straight HTTP. This model offers strong security on the internet while keeping the internal deployment simpler & efficient. This model also resembles with the standard SSL offloading setup where a hardware load-balancer is used to terminate the SSL.
2. Once the Silverlight client got a SAML token, it can attach it to all subsequent message sent to business service(s). Routing Services forwards al the business messages (messages which doesn’t match the token issuance filter) to the actual backend services again doing the protocol transitioning from HTTPS to HTTP. Please note, here you can use the rich filtering mechanism provided by the Routing services to decide which messages should to which services. I used a very simple MatchAll filter which forwards all the non-token-issuance messages to the business service.
To implement the 1st part of solution I have used the WSTrustClient class & the associated bindings from the identity training kit.
var stsBinding = new WSTrustBindingUsernameMixed();
var stsCreds = new UsernameCredentials(vm.UserId, vm.Password);
var client = new WSTrustClient(
stsBinding,
new EndpointAddress(vm.SelectedEndpoint),
stsCreds);
var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Bearer);
rst.AppliesTo = new EndpointAddress(vm.AppliesTo);
client.IssueCompleted += new System.EventHandler<IssueCompletedEventArgs>(client_IssueCompleted);
client.IssueAsync(rst);
For the 2nd part I have implemented a message inspector along with an extension method which makes it super easy to attach the SAML with outgoing messages.
client.AttachToken(vm.SecurityToken.RawToken);
client.GetDataCompleted += new EventHandler<ServiceReference1.GetDataCompletedEventArgs>(client_GetDataCompleted);
client.GetDataAsync(32);
Posted in Security, WCF, WIF | 11 Comments »
Posted by zamd on August 13, 2010
WIF provides an API to develop Security Token Services (STSs) which can then be exposed using either WS-Trust (Active-STS) or WS-Federation(Passive-STS) protocols. As mentioned in last post, WIF currently doesn’t support OAuth WRAP protocol so out of box a WIF based SecurityTokenService cannot be used as an OAuth WRAP issuer. In this post, I’ll show you some extensions I have created to expose a service, based on WIF’s token issuance object model (SecurityTokenService, RequestSecurityTokenRequest etc), as an OAuth WRAP issuer.
1: Create an issuer using the standard WIF approach. The only difference is that I’m using a symmetric key for signatures.
public class OAuthIssuer : SecurityTokenService
{
public OAuthIssuer(SecurityTokenServiceConfiguration config):base(config){}
protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
{
return new ClaimsIdentity(new Claim[] {
new Claim(ClaimTypes.Name, "John"),
new Claim("email", "John@test.com") });
}
protected override Scope GetScope(IClaimsPrincipal principal,
RequestSecurityToken request)
{
var scope = new Scope
{
AppliesToAddress = request.AppliesTo.Uri.AbsoluteUri
};
scope.TokenEncryptionRequired = false;
scope.SymmetricKeyEncryptionRequired = false;
scope.SigningCredentials = new SymmetricSigningCredentials("Sapm9PPZZHlo=");
return scope;
}
}
2: Host the issuer using following code:
var config = new OAuthIssuerConfiguration()
{
SecurityTokenService = typeof(OAuthIssuer)
};
config.TokenIssuerName = "MyCustomIssuer";
config.SecurityTokenHandlers.AddOrReplace(new CustomUserNameSecurityTokenHandler
{
UserNamePasswordValidator = (uid, pwd) =>
{
Console.WriteLine(uid + " validated.");
}
});
var sh = new OAuthServiceHost(config, new Uri("http://localhost:9111"));
sh.Open();
That’s it, A WIF based OAuth WRAP issuer is ready.
OAuthServiceHost inherits from WCF WebServiceHost and exposes a fixed OAuth WRAP contract to the outside world.
public class OAuthServiceHost : WebServiceHost
{
internal OAuthIssuerConfiguration Configuration { get; set; }
public OAuthServiceHost(OAuthIssuerConfiguration config)
: this(config, null) { }
public OAuthServiceHost(OAuthIssuerConfiguration config, Uri baseAddress)
: base(typeof(OAuthIssuerContract), baseAddress)
{
this.Configuration = config;
}
}
The implementation of OAuth WRAP contract transforms the incoming token issuance request into WIF’s token issuance object model (RequestSecurityTokenRequest etc) and starts the token issuance pipeline. At the end of the pipeline, it packages the final set of claim in a Simple Web Token and returns it back.
Posted in WIF | 6 Comments »
Posted by zamd on July 31, 2010
OAuth WRAP and SWT (Simple Web Token) have emerged as a standard way for employing claim-based-security to the REST services. Conceptually this model is very similar to the one used in SOAP world. A client goes to an issuer, authenticates itself using some token and gets back a different token (containing claims) in SWT format.
WIF provides a rich API and object model to claim-enable your .Net applications but currently it doesn’t natively support OAuth or SWT. In this post, I’ll show how you can extend WIF to bring claim-based-security to REST services. My goal is to implement this functionality in such a way that all the WIF goodness around claims-transformation (ClaimsAuthenticationManager), claim-based-authorization (ClaimsAuthorizationManager) etc can be used exactly the same way in the REST world.
I have achieved this by introducing an OAuth WRAP channel which sits in the WCF channel stack and perform an almost identical job to its SOAP counterpart WS-Security channel. I have implemented the OAuth WRAP channel using the interceptor API from the REST Starter Kit.
WebServiceHost2 host = new WebServiceHost2(typeof(TestService), new Uri(http://localhost:9090));
host.Interceptors.Add(new OAuthWrapSecurityChannel());
host.Open();
The OAuth channel takes care of extracting the token from the incoming message, running it through the validation pipeline (based on WIF SecurityTokenHandler framework), calling ClaimsAuthenticationManager, setting the WCF authorization context so that ClaimsAuthorizationManager can be called, and finally presenting the claims to the service method in the standard WIF way: Thread.CurrentPrincipal
Now with OAuth channel plugged in, if I call the service with a token issues by the Windows AppFabric ACS:
I get following output on the service side.
And from the service code, you would notice that standard WIF API is used to access incoming claims.
[WebGet]
string Hello()
{
Console.WriteLine("Hello called…");
Console.WriteLine("——————");
var cp = Thread.CurrentPrincipal as IClaimsPrincipal;
if (cp != null)
{
foreach (var id in cp.Identities)
{
Console.WriteLine("Authentication Type: " + id.AuthenticationType);
Console.WriteLine("Is Authenticated: " + id.IsAuthenticated);
Console.WriteLine("Name: " + id.Name);
Console.WriteLine();
Console.WriteLine("Claims…");
foreach (var c in id.Claims)
{
Console.WriteLine(c.ClaimType + ": " + c.Value);
}
}
}
return "Hello, World";
}
WIF would be configured using exactly same configuration settings required for a SOAP service.
In summary, these extensions implement OAuth WRAP protocol head for Windows Identity Foundation and re-uses all the neat WIF APIs for deriving the service behaviour. In the next post, I’ll discuss how to create a local OAuth WRAP issuer using the SecurityTokenService WIF API.
Feel free to download the source and experiment.
Posted in WCF, WIF, Windows Azure AppFabric | 6 Comments »
Posted by zamd on June 3, 2010
Extending upon my last post, where I have talked about basic integration, this post will go into the details of claims-based-delegation in WF 4.0 & AppFabric.
Again I’ll be using activities from the Workflow Security Pack. Let’s start with a diagram which captures the main components of solution and their interactions:
I have attached complete solution with this post. I tried to keep the solution self-contained by using file-based certificates and other shortcuts so hopefully you should be able to get it working by just hitting Ctrl-F5
Feel free to download and experiment and let me know your thoughts…
Posted in WF4, WFSP, WIF | 10 Comments »
Posted by zamd on May 18, 2010
WIF is framework to claim-enable ASP.net applications and WCF services. WF 4.0 introduced a new paradigm for developing services (known as Workflow Services), whose implementation is based on workflow. Windows Server AppFabric provides the hosting, management & monitoring capabilities for services with a primary focus on workflow services.
WIF integration with Workflow services can be seen at couple of different scopes.
1. Claims-Enabled Workflow Service
As workflow services are standard WCF services, WIF can easily be enabled at the WCF layer using the standard configuration based approach documented in MSDN. This would claims-enable your workflow services and you can use various WIF’s extensions (code-based) for claims-transformation (ClaimsAuthenticationManager) and claims-based authorization (ClaimsAuthorizationManager).
2. Workflow Services calling other Claims-Enabled Services
WF 4.0 provides messaging activities to call other services from workflows. In most cases, Claims-Enabled services require a token from an STS. In a non-WF world, you can either use wsFederationHttpBinding or the new fine grained WIF API (WSTrustChannelFactory) to do this (you can use IssuedSecurityTokenProvider directly). The wsFederationHttpBinding approach kind of works (transparently) in Workflow services world as well but could be quite expensive in terms of performance. See my post on messaging activities for additional details. The wsFederationHttpBinding approach is also not suitable for scenarios, where you need fine-grained control of issued tokens or you want to use issued token in long-running scenarios without re-acquiring them.
3. WIF in middle-tier Workflow Services
WIF enables claims-based-delegation using then ActAs/OnBehalfOf element of WS-Trust protocol. In code-based services, you can access the incoming token in the middle-tier service and then use this when acquiring a SAML token to call a backend service. With this model, the backend service can see all the identities involved in the call chain. Claims-based delegation is not easily possible in workflow services when using wsFederationHttpBinding.
1 & 2 be greatly enhanced by introducing custom activities which can decouple token acquisition from its use; much like activity counterpart of WIF’s WSTrustChannelFactory API.
![]()
In above diagram InitializeSamlSecurityToken custom activity encapsulate the functionality of acquiring a token from a STS using the WS-Trust protocol. Internally it uses the standard correlated Request-Reply pair configured for WS-Trust contract. I’ll talk more about TokenFlowScope in a future post but here it enables the Ping activity to use the acquired token when calling a service which requires Saml token. I have attached complete solution with post (STS, Test Service & a Test Client)which also includes alpha drop of WFSP binaries as well. Feel free to download and experiment and let me know your thoughts.
Posted in WF4, WFSP, WIF | 9 Comments »
Posted by zamd on April 27, 2010
In some interop scenarios, subject name and its format needs to be included in the Saml token/assertion generated by the STS. You can easily configure a WIF based STS to generate this by adding a NameIdentifier claim and by settings it’s format property.
protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal,
RequestSecurityToken request, Scope scope)
{
var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, "me@zamd.com");
nameIdentifierClaim.Properties[ClaimProperties.SamlNameIdentifierFormat] = "EMAIL";
return new ClaimsIdentity(
new Claim[]
{
new Claim(System.IdentityModel.Claims.ClaimTypes.Name, "Zulfiqar"),
nameIdentifierClaim
});
This generates following Saml Assertion where you can see the generated NameIdentifier & format attribute.
<saml:AttributeStatement xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Subject><saml:NameIdentifier Format="EMAIL">me@zamd.com</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Zulfiqar</saml:AttributeValue></saml:Attribute></saml:AttributeStatement>
Posted in WIF | 1 Comment »
Posted by zamd on March 10, 2010
Few people have asked me for the source code of ExtractSAMLAssertion helper method/class, which I have used in my article and blog posts. So here you go…
Please note this is just raw test code and doesn’t have any error checking and other related goodies.
class Program
{
static void Main(string[] args)
{
var binding = new WSHttpBinding(SecurityMode.Message);
binding.Security.Message.ClientCredentialType = MessageCredentialType.None;
binding.Security.Message.EstablishSecurityContext = false;
var fac = new WSTrustChannelFactory(binding, “http://localhost:9000/STS”);
fac.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
fac.Open();
var rst = new RequestSecurityToken {
AppliesTo = new EndpointAddress(“http://localhost”),
RequestType = WSTrustFeb2005Constants.RequestTypes.Issue
};
var token = fac.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
var rpCert = new X509Certificate2(“localhost.pfx”, “a”);
var xml = ExtractSAMLAssertion(token, rpCert);
}
private static string ExtractSAMLAssertion(GenericXmlSecurityToken token, X509Certificate2 rpCert)
{
string txtAssertion = string.Empty;
var handlerCol = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
var han = handlerCol.OfType<EncryptedSecurityTokenHandler>().FirstOrDefault();
if (han != null)
{
han.Configuration.ServiceTokenResolver = new EncryptedKeyResolver(rpCert);
var sr = new StringReader(token.TokenXml.OuterXml);
var rdr2 = XmlReader.Create(sr);
var rtok = han.ReadToken(rdr2) as SamlSecurityToken;
var stat = rtok.Assertion.Statements[0];
var ms = new MemoryStream();
var memWriter = XmlDictionaryWriter.CreateTextWriter(ms);
stat.WriteXml(memWriter, new SamlSerializer(), new WSSecurityTokenSerializer());
memWriter.Flush();
ms.Seek(0, SeekOrigin.Begin);
txtAssertion = new StreamReader(ms).ReadToEnd();
}
return txtAssertion;
}
}
class EncryptedKeyResolver : SecurityTokenResolver
{
// Relying party certificate – must hold private key.
X509Certificate2 rpCert;
public EncryptedKeyResolver(X509Certificate2 rpCert)
{
this.rpCert = rpCert;
}
protected override bool TryResolveSecurityKeyCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityKey key)
{
key = null;
try
{
var ekec = keyIdentifierClause as EncryptedKeyIdentifierClause;
if (ekec != null)
{
switch (ekec.EncryptionMethod)
{
case “http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p”:
{
var encKey = ekec.GetEncryptedKey();
var rsa = rpCert.PrivateKey as RSACryptoServiceProvider;
var decKey = rsa.Decrypt(encKey, true);
key = new InMemorySymmetricSecurityKey(decKey);
return true;
}
}
var data = ekec.GetEncryptedKey();
var id = ekec.EncryptingKeyIdentifier;
}
}
catch (Exception eexx)
{
Console.WriteLine(eexx);
throw eexx;
}
return false;
}
protected override bool TryResolveTokenCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token)
{
throw new NotImplementedException();
}
protected override bool TryResolveTokenCore(SecurityKeyIdentifier keyIdentifier, out SecurityToken token)
{
throw new NotImplementedException();
}
}
Posted in Federation/STS, WIF | 7 Comments »