using ACS to help us gateway saml to jwt, amidst ws-fedp


To an ACS namespace, add a realty IDP (by  giving ACS the URI of the metadata that enables easy import of the configuration parameters). In our case that value is

https://ssoportal.rapmlsqa.com/spinitiatedssohandler.aspx/VCRD/24. We assign it to no (existing) RPs. but then we make an RP, and a new default rule group:

Our intent is to induce the OWIN-pipelined, IIS-hosted, ws-fedp handler in our recent MVC app, in a local IIS8 express instance, talk to ACS as the IDP/FP (using a home realm value that induces ACS to talk in turn to our realty IDP).

The SP is thus named https://localhost:44300/, with display name owin.

The RP is configured as shown next:

image

and its rule group is tied to a concrete issuer, that ties to the IDP we just nominated.

image

With these pass through rules and having nominated JWT as the output token format, we are expecting our ws-fedp reply to deliver us a JWT assertion, with claims now in that signed blob format.

So, we alter the SP a little, to point at this Ws-fedp FP:

image

and upon running it we do note that its pipeline is apparently well=configured for JWT token handling:

image

 

A bug or two fixed, the immediate result is

image

With a bit of fiddling in security token handler land we could at least read some of the basic claims:

 

image

 

Source:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.IdentityModel.Tokens; 6 using System.Security.Claims; 7 using System.Xml; 8 using System.Text; 9 using System.IO; 10 11 namespace WebApplication1 12 { 13 public class CustomJwtSecurityTokenHandler : JwtSecurityTokenHandler 14 { 15 16 const string Base64EncodingType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"; 17 const string EncodingType = "EncodingType"; 18 const string DefaultNameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"; 19 const string AcsNameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"; 20 const char ParameterSeparator = '&'; 21 const string BinarySecurityToken = "wsse:BinarySecurityToken"; 22 const string ValueType = "ValueType"; 23 24 // Override ValidateSignature so that it gets the SigningToken from the configuration if it doesn't exist in 25 // the validationParameters object. 26 private const string KeyName = "https://localhost/TestRelyingParty"; 27 private const string ValidIssuerString = "https://mySTSname/trust"; 28 29 public override SecurityToken ReadToken(string tokenString) 30 { 31 XmlReader reader = XmlReader.Create(new StringReader(tokenString)); 32 33 if (!tokenString.Contains("Binary")) 34 { 35 return base.ReadToken(tokenString); 36 } 37 else 38 { 39 return base.ReadToken(reader); 40 } 41 } 42 public override SecurityToken ReadToken(System.Xml.XmlReader reader) 43 { 44 if (reader == null) 45 { 46 throw new ArgumentNullException("reader"); 47 } 48 49 XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateDictionaryReader(reader); 50 51 byte[] binaryData; 52 string encoding = dictionaryReader.GetAttribute(EncodingType); 53 if (encoding == null || encoding == Base64EncodingType) 54 { 55 dictionaryReader.Read(); 56 binaryData = dictionaryReader.ReadContentAsBase64(); 57 } 58 else 59 { 60 throw new SecurityTokenException( 61 "Cannot read SecurityToken as its encoding is" + encoding + ". Expected a BinarySecurityToken with base64 encoding."); 62 } 63 64 string serializedToken = Encoding.UTF8.GetString(binaryData); 65 66 return ReadToken(serializedToken); 67 } 68 public override bool CanReadToken(string tokenString) 69 { 70 return true; 71 } 72 public override bool CanReadToken(System.Xml.XmlReader reader) 73 { 74 bool canRead = false; 75 76 if (reader != null) 77 { 78 if (reader.IsStartElement(BinarySecurityToken) 79 && (reader.GetAttribute(ValueType) == "urn:ietf:params:oauth:token-type:jwt")) 80 { 81 canRead = true; 82 } 83 } 84 85 return canRead; 86 } 87 88 public override ClaimsPrincipal ValidateToken(JwtSecurityToken jwt) 89 { 90 var vparms = new TokenValidationParameters 91 { 92 ValidAudiences = Configuration.AudienceRestriction.AllowedAudienceUris.Select(s => s.ToString()) 93 }; 94 return ValidateToken(jwt, vparms); 95 } 96 97 public override ClaimsPrincipal ValidateToken(JwtSecurityToken jwt, TokenValidationParameters validationParameters) 98 { 99 // set up valid issuers 100 if ((validationParameters.ValidIssuer == null) && 101 (validationParameters.ValidIssuers == null || !validationParameters.ValidIssuers.Any())) 102 { 103 validationParameters.ValidIssuers = new List<string> { ValidIssuerString }; 104 } 105 // and signing token. 106 if (validationParameters.IssuerSigningToken == null) 107 { 108 var resolver = (System.IdentityModel.Tokens.NamedKeyIssuerTokenResolver)this.Configuration.IssuerTokenResolver; 109 if (resolver.SecurityKeys != null) 110 { 111 IList<SecurityKey> skeys; 112 if (resolver.SecurityKeys.TryGetValue(KeyName, out skeys)) 113 { 114 var tok = new NamedKeySecurityToken(KeyName, skeys); 115 validationParameters.IssuerSigningToken = tok; 116 } 117 } 118 } 119 return base.ValidateToken(jwt, validationParameters); 120 } 121 } 122 }

 

To insert it into the handling logic:

 

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace WebApplication1 7 { 8 using Microsoft.Owin.Security.Cookies; 9 using Microsoft.Owin.Security.WsFederation; 10 using Owin; 11 public partial class Startup1 12 { 13 public void ConfigureAuth(IAppBuilder app) 14 { 15 app.UseCookieAuthentication( 16 new CookieAuthenticationOptions 17 { 18 AuthenticationType = 19 WsFederationAuthenticationDefaults.AuthenticationType 20 }); 21 22 var foo = new WsFederationAuthenticationOptions 23 { 24 //MetadataAddress = "https://login.windows.net/rapmlsqa.com/federationmetadata/2007-06/federationmetadata.xml", 25 // MetadataAddress = "https://ssoportal.rapmlsqa.com/spinitiatedssohandler.aspx/VCRD/24", 26 // Wtrealm = "https://wsfedreso.azurewebsites.net/", 27 MetadataAddress = "https://vcrdazuresso.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml ", 28 Wtrealm = "https://localhost:44300/", 29 }; 30 foo.SecurityTokenHandlers.AddOrReplace(new CustomJwtSecurityTokenHandler()); 31 32 app.UseWsFederationAuthentication(foo); 33 } 34 } 35 }

Just a proof of concept! (i.e. don’t rely on any code I produce!)

Advertisements

About home_pw@msn.com

Computer Programmer who often does network administration with focus on security servers. Very strong in Microsoft Azure cloud!
This entry was posted in AAD, Azure AD. Bookmark the permalink.