Shared session cookie is not being recognised by authentication scheme - c#

This follows on from a previous post which started as a general issue and is now more specific.
In short, I've been following guidance (such as this from Microsoft, this from Scott Hanselman, and this from Barry Dorrans) to allow me to share the authentication cookie issued by a legacy ASP.NET web app with a new dotnet core app running on the same domain.
I'm confident that I'm using the recommended Microsoft.Owin.Security.Interop library correctly. On that side (the old ASP.NET app), the CookieAuthenticationOptions are configured with AuthenticationType and CookieName both set to the same value - SiteIdentity. This same value is also used in the interop data protector setup:
var appName = "SiteIdentity";
var encryptionSettings = new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
};
var interopProvider = DataProtectionProvider.Create(
new DirectoryInfo(keyRingSharePath),
builder =>
{
builder.SetApplicationName(appName);
builder.SetDefaultKeyLifetime(TimeSpan.FromDays(365 * 20));
builder.UseCryptographicAlgorithms(encryptionSettings);
if (!generateNewKey)
{
builder.DisableAutomaticKeyGeneration();
}
});
ShimmedDataProtector = new DataProtectorShim(
interopProvider.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
appName,
"v2"));
I log in using this app, confirm I have a cookie named SiteIdentity then switch to a new dotnet core app running on the same domain.
There, without adding authentication middleware I can confirm that I can unprotect and deserialize the cookie. I do this by setting up data protection in Startup to match the other app:
var appName = "SiteIdentity";
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keyRingSharePath))
.SetDefaultKeyLifetime(TimeSpan.FromDays(365 * 20))
.DisableAutomaticKeyGeneration()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
})
.SetApplicationName(appName);
Then in my controller I can use a data protector to manually unprotect the cookie:
var appName = "SiteIdentity";
var protector = _dataProtectionProvider.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
appName,
"v2");
var cookieValue = Request.Cookies[appName];
var format = new TicketDataFormat(protector);
var ticket = format.Unprotect(cookieValue);
I can confirm that ticket.Principal does indeed reference a claims principal representing the account which I signed in with on the other app.
However, I've found it impossible to wire up the cookie authentication middleware to properly protect my endpoints using this cookie. This is what I've added to Startup, after the data protection code above:
var protectionProvider = services.BuildServiceProvider().GetService<IDataProtectionProvider>();
var dataProtector = protectionProvider.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
appName,
"v2");
services
.AddAuthentication(appName)
.AddCookie(appName, options =>
{
options.TicketDataFormat = new TicketDataFormat(dataProtector);
options.Cookie.Name = appName;
});
By my understanding this is telling the middleware that I have an authentication scheme named "SiteIdentity" (the advice is that authentication scheme must match the ASP.NET authentication type) which expects a cookie also called "SiteIdentity" which will contain protected data that the supplied data protector can interpret.
But when I add the attribute [Authorize(AuthenticationSchemes = "SiteIdentity")] to my controller I'm kicked away to a login page.
I can't understand what I'm doing wrong. As I've shown, I can confirm that it is indeed possible to use this data protector and ticket format to interpret the authentication cookie, so I guess I must have something wrong in this middleware wiring, but I'm not sure what.

Please ignore. It turns out that my code is actually correct. I had been working on this solution for long enough that the session represented by the cookie value I was using to test had expireed. Will leave this question here in case the code benefits anyone trying to achieve the same.

Related

Possible Multiple AuthenticationSchemes in request header?

I have two webapis A and B. From A i make a request to B. A contains user info from identityserver4 where i just need to pass the token to the request header. Beside identityserver token, A also uses AAD(Azure Active Directory) where i have registred B. So from A, i also check my AAD so that i can retrieve The token from Azure to send to B, This is just so B can trust that a request is coming from a trusted registred source. As you can understand From A i have two tokens, one to check the loged in user and the other to check registred application. My A startup class look like this:
public void ConfigureServices(IServiceCollection services)
{
Config = services.ConfigureAuthConfig<AuthConfig>(Configuration.GetSection("AuthConfig"));
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<ICurrentUser, CurrentUser>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(//this coming with identityserver token and user info
idt =>
{
idt.Authority = "https://gnoauth.se:5005";
idt.ApiName = "globalnetworkApi";
idt.SaveToken = true;
idt.RequireHttpsMetadata = true;
}
);
So here is my A httpclienthelper, where i setup my client headers to send to B, As i already have the token and user from identity server so the other thing i do here is to send B authority, client id and secret to AAD for retrieving the second token:
var context = new HttpContextAccessor().HttpContext;
var accessTokenFromIdentityserver = await
context.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
var tokenfromAAD = result.AccessToken;
defaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("AAD_Authentication", tokenfromAAD);
from here i actualy have all i need, both the tokens and all claims. As you can see to the defaultrequestheaders i only cansend one token but i would like to send both tokens to B, how can i configure the request headers to be able to do that?
So here is the B startup
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("AAD_Authentication", opt =>
{
opt.Audience = Configuration["AAD:ResourceId"];
opt.Authority = $"{Configuration["AAD:InstanceId"]}{Configuration["AAD:TenantId"]}";
opt.RequireHttpsMetadata = true;
})
.AddJwtBearer("IDS4_Authentication",
idt =>
{
idt.Authority = "https://gnoauth.se:5005";
idt.Audience = "globalnetworkApi";
idt.SaveToken = true;
idt.RequireHttpsMetadata = true;
}
);
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("AAD_Authentication", "IDS4_Authentication")
.Build();
But i also setup a policy so that from some of my controllers i need to authorize both logedin user and application registration like this
[Authorize(AuthenticationSchemes = "AAD_Authentication,IDS4_Authentication", Policy = "MyPolicy")]
the big problem i have been facing is how from A to send both tokens and how to setup authenticationschemes so that B actually get two bearer authenticationschemes
ANY HELP PLEASE
It's the first time I see this thing of two authentication schemes at same time. With two JWT Bearer configurations. Usually I saw it with JWT and Cookie, but not with two JWT.
One thing you may notice, is that it's not the same authentication scheme for A than A calling B. In your case, despite A as an API, is really a client asking for authorization on B. With this point of view, you have nothing to do on A authentication to get on B.
You should use an HttpClient or TokenClient with the specific flow each time you want A call an endpoint on B.
The AddAuthentication configuration is to protect A, not for get authorization on B.
Other different matter is that you would like two Identity Providers AAD and IDS. This should use something similar to External Identity Providers.
Maybe I'm wrong or I didn't understand you. But I hope I clarify something about this question.
P.D. Azure Functions Easy Auth has something like "proxy" Identity Provider. I think it's the same idea as External Identity Provider.

Owin app with WsFederation authentication stuck in infinite redirect loop

I have an Owin app that uses Ws-Federation authentication with a SSO application (not ADFS). Whenever my Owin app receives a request, it authenticates the user by first checking if it has the right cookie, and then it builds the claims and authentication ticket from that. If it doesn't have the right cookie, it redirects to the STS, which passes back a SAML token that can be used to complete the authentication.
All of this works except one part. After the token is received and validated, for some reason it redirects back to the STS, thus creating an infinite loop. I am quite sure it is because one or more of my configuration values is wrong since it's not very clear what each property is for and if it's required. I've copied my configuration code below:
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType( CookieAuthenticationDefaults.AuthenticationType);
CookieAuthenticationOptions cookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
CookieName = "MyCookie",
CookiePath = "/CookiePath",
AuthenticationMode = AuthenticationMode.Active
};
// Basically the same as saying app.UseCookieAuthentication(app, cookieOptions)
app.Use(typeof(MyCustomCookieAuthenticationMiddleware), app, cookieOptions);
// Define properties for WsFederationAuthenticationOptions
var config = new Microsoft.IdentityModel.Protocols.WsFederationConfiguration
{
Issuer = "https://sts-domain.com/STS/",
TokenEndpoint = this.owinServerUrl // I don't know what this should be. I just made it the same as my owin start url
};
Saml2SecurityTokenHandler handler = new Saml2SecurityTokenHandler
{
Configuration = new SecurityTokenHandlerConfiguration
{
IssuerTokenResolver = new MyCustomSecurityTokenResolver
{
Thumbprint = somePublicKeyStr,
StoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,
StoreName = "My"
}
}
};
var handlers = new SecurityTokenHandlerCollection(new List<SecurityTokenHandler>() { handler });
var wsFedOptions = new WsFederationAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType,
AuthenticationMode = AuthenticationMode.Passive,
SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType, // I'm not sure what this is exactly, but I think I've seen this used in examples
Configuration = config,
Wtrealm = this.owinServerUrl, // I'm guessing what this should be
Wreply = someString, // I have no idea what this should be -- it hasn't seemed to have any effect so far
SecurityTokenHandlers = handlers,
TokenValidationParameters = new TokenValidationParameters
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType, // I'm not sure whether this should be cookie or ws federation, but I don't think it's relevant to my problem
ValidIssuer = "https://sts-domain.com/STS/", // same as config.Issuer above
}
};
app.UseWsFederationAuthentication(wsFedOptions);
AuthenticateAllRequests(app, WsFederationAuthenticationDefaults.AuthenticationType);
app.Use<MyCustomMiddleware>();
}
private static void AuthenticateAllRequests(IAppBuilder app, params string[] authenticationTypes)
{
app.Use((context, continuation) =>
{
if (context.Authentication.User?.Identity?.IsAuthenticated ?? false)
{
return continuation();
}
else
{
context.Authentication.Challenge(authenticationTypes);
return Task.CompletedTask;
}
});
}
As I indicate in my code with my comments, there are some properties I am unsure of. Unfortunately, the documentation for WsFederationAuthenticationOptions does not help me out much. For example, I know that Wtrealm and Wreply are important (perhaps Wreply less so), but all the documentation says is "Gets or sets the 'wtrealm'" and "Gets or sets the 'wreply'." I found this thread that has an explanation:
wtrealm is a URI (not necessarily a URL) that identifies the RP. The STS uses this to decide whether to issue a token and what claims to give it.
wreply is the URL that the RP would like to be redirected to with the resulting token. The STS is not bound to comply with this request... sometimes the STS has a predefined address it will redirect to based on the established trust. At the very least, the STS should refuse to redirect to a different domain than the one it associates with the realm. Otherwise, the request could be a vector to send the user to a malicious site.
This makes sense, except for the fact that while I've been testing my owin app, Wreply seems to have no effect on where the STS is redirected to pass back the token; the URL I put for Wtrealm is what determines that.
All I'd like to do is for the STS to pass back the token, authenticate the user, and carry on to the route that the user specified which started all this. I'm not sure if this is relevant, but I also thought that the cookie is supposed to be set when the STS passes back the token. If this were the case, the infinite redirect wouldn't occur because when it comes back to be authenticated, the cookie authentication would find the cookie and the app would proceed as normal.
Update 1
I have changed a few of the values and have gotten different error messages, so I thought I'd share them here in case they help shed light on what could be going on. As you can tell from my post, I don't want to share real info about the app, so bear with me. Let's say the overarching web application (what contains my owin app, along with a bunch of other stuff) has the url http://localhost/app. My owin app has the server url (what I call this.owinServerUrl in the code above) http://localhost/app/owin.
When I make WsFederationConfiguration.TokenEndpoint = "http://localhost/app", I get the infinite redirect. When I make it "http://localhost/app/owin", I don't get an infinite redirect, but I do get another error (which error I get depends on other values, which I'll explain now).
I was mistaken -- Wreply does seem to have an effect. When I don't set Wreply, I get a 414 error: request URL too long. When I do set it (and as any string, whether it's a URL that I think could make sense or just gibberish), I get a 400 bad request: request too long.
Isn't it because of your AuthenticateAllRequests function? I think you think it only runs after the user is authenticated and context.Authentication.User?.Identity?.IsAuthenticated is set. However, I think it runs after the user is authenticated and before context.Authentication.User?.Identity?.IsAuthenticated is set. Since is never set, does it just invoke authentication again by calling "context.Authentication.Challenge(authenticationTypes)" ?

Working with Azure App Service Authentication on server side [duplicate]

We have a web app built on Asp.Net core. It doesn't contain any authentication middleware configured in it.
We are hosting on Azure App Service and using the Authentication/Authorization option (EasyAuth) to authenticate against Azure AD.
The authentication works well - we get the requisite headers inserted and we can see the authenticated identity at /.auth/me. But the HttpContext.User property doesn't get populated.
Is this a compatibility issue for Asp.Net core? Or am I doing something wrong?
I've created a custom middleware that populates the User property until this gets solved by the Azure Team.
It reads the headers from the App Service Authentication and create a a user that will be recognized by the [Authorize] and has a claim on name.
// Azure app service will send the x-ms-client-principal-id when authenticated
app.Use(async (context, next) =>
{
// Create a user on current thread from provided header
if (context.Request.Headers.ContainsKey("X-MS-CLIENT-PRINCIPAL-ID"))
{
// Read headers from Azure
var azureAppServicePrincipalIdHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"][0];
var azureAppServicePrincipalNameHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"][0];
// Create claims id
var claims = new Claim[] {
new System.Security.Claims.Claim("http://schemas.microsoft.com/identity/claims/objectidentifier", azureAppServicePrincipalIdHeader),
new System.Security.Claims.Claim("name", azureAppServicePrincipalNameHeader)
};
// Set user in current context as claims principal
var identity = new GenericIdentity(azureAppServicePrincipalIdHeader);
identity.AddClaims(claims);
// Set current thread user to identity
context.User = new GenericPrincipal(identity, null);
};
await next.Invoke();
});
Yes, this is a compatibility issue. ASP.NET Core does not support flowing identity info from an IIS module (like Easy Auth) to the app code, unfortunately. This means HttpContext.User and similar code won't work like it does with regular ASP.NET.
The workaround for now is to invoke your web app's /.auth/me endpoint from your server code to get the user claims. You can then cache this data as appropriate using the x-ms-client-principal-id request header value as the cache key. The /.auth/me call will need to be properly authenticated in the same way that calls to your web app need to be authenticated (auth cookie or request header token).
I wrote a small basic middleware to do this. It will create an identity based off of the .auth/me endpoint. The identity is created in the authentication pipeline so that [authorize] attributes and policies work with the identity.
You can find it here:
https://github.com/lpunderscore/azureappservice-authentication-middleware
or on nuget:
https://www.nuget.org/packages/AzureAppserviceAuthenticationMiddleware/
Once added, just add this line to your startup:
app.UseAzureAppServiceAuthentication();
The following code decrypts the AAD token from the Azure App Service HTTP header and populates HttpContext.User with the claims. It's rough as you'd want to cache the configuration rather than look it up on every request:
OpenIdConnectConfigurationRetriever r = new OpenIdConnectConfigurationRetriever();
ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(options.Endpoint, r);
OpenIdConnectConfiguration config = await configManager.GetConfigurationAsync();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeys = config.SigningKeys.ToList(),
ValidateIssuer = true,
ValidIssuer = config.Issuer,
ValidateAudience = true,
ValidAudience = options.Audience,
ValidateLifetime = true,
ClockSkew = new TimeSpan(0, 0, 10)
};
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;
string token = context.Request.Headers["X-MS-TOKEN-AAD-ID-TOKEN"];
if (!String.IsNullOrWhiteSpace(token))
{
principal = handler.ValidateToken(token, tokenValidationParameters, out validToken);
var validJwt = validToken as JwtSecurityToken;
if (validJwt == null) { throw new ArgumentException("Invalid JWT"); }
if (principal != null)
{
context.User.AddIdentities(principal.Identities);
}
}
It only works for Azure AD. To support other ID providers (Facebook, Twitter, etc) you'd have to detect the relevant headers and figure out how to parse each provider's token. However, it should just be variations on the above theme.
You can give this library a try. I faced a similar problem and created this to simplify the use.
https://github.com/dasiths/NEasyAuthMiddleware
Azure App Service Authentication (EasyAuth) middleware for ASP.NET
CORE with fully customizable components with support for local
debugging
It hydrates the HttpContext.User by registering a custom authentication handler. To make things easier when running locally, it even has the ability to use a json file to load mocked claims.

OWIN SignOut doesn't remove cookie

I am using the OWIN middleware in an external Authentication Server that my applications authenticate to using OAuth Authorisation Code Grant flow.
I can redirect to the Authentication Server, authenticate against an external provider (Google) and redirect back to my client application with a logged in user and Application Cookie set just fine, however when I try to sign out the cookie remains after I call the AuthenticationManager.SignOut method.
My cookie options in Startup.Auth.cs are:
var cookieOptions = new CookieAuthenticationOptions
{
Provider = cookieProvider,
AuthenticationType = "Application",
AuthenticationMode = AuthenticationMode.Passive,
LoginPath = new PathString("/Account/Index"),
LogoutPath = new PathString("/Account/Logout"),
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(30),
};
app.UseCookieAuthentication(cookieOptions);
app.SetDefaultSignInAsAuthenticationType(DefaultAuthenticationTypes.ExternalCookie);
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
My login method:
var loginInfo = await AuthManager.GetExternalLoginInfoAsync();
SignInManager.ExternalSignInAsync(loginInfo, true);
var identity = AuthManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie).Result.Identity;
if (identity != null)
{
AuthManager.SignIn(
new AuthenticationProperties {IsPersistent = true},
new ClaimsIdentity(identity.Claims, "Application", identity.NameClaimType, identity.RoleClaimType));
var ticket = AuthManager.AuthenticateAsync("Application").Result;
var identity = ticket != null ? ticket.Identity : null;
if (identity == null)
{
AuthManager.Challenge("Application");
return new HttpUnauthorizedResult();
}
identity = new ClaimsIdentity(identity.Claims, "Bearer", identity.NameClaimType, identity.RoleClaimType);
AuthManager.SignIn(identity);
}
return Redirect(Request.QueryString["ReturnUrl"]);
Sign Out method:
var authTypeNames = new List<string>();
authTypeNames.Add("Google");
authTypeNames.Add("Application");
authTypeNames.Add("Bearer");
authTypeNames.Add(DefaultAuthenticationTypes.ExternalCookie);
Request.GetOwinContext().Authentication.SignOut(authTypeNames.ToArray());
I have looked at other questions like:
OWIN authentication, expire current token and remove cookie
and
OWIN - Authentication.SignOut() doesn't remove cookies
with no luck. I'm aware I could manually delete the cookie by setting a negative expiry date, but I'd prefer to use in built method if possible.
How do I get the Application Cookie to be removed when I Sign Out?
In order for the SignOut method to flag the authentication ticket (cookie) for removal from the client, the AuthenticationType parameter you pass into the SignOut method and value on the cookie must match exactly. If you want to remove more than one authentication ticket from the client then you'll have to match ALL of those AuthenticationTypes and pass those as a string[] to the SignOut method.
The AuthenticationType of an authentication ticket usually prefixed with the name of the host web container (i.e. something like ".AspNet.") followed by whatever you bootstrapped your OWIN CookieAuthentication settings with.
It looks like you set your AuthenticationType string value to "Application" in Startup.Auth.cs. Try simply calling:
Request.GetOwinContext().Authentication.SignOut("Application");
If that's not working for you, I would debug your application and take a look at the specific AuthenticationType on the identity for each type of authenticated user your application allows, note the value of the AuthenticationType for each one and try including them all in a string[] in your SignOut call.
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
FormsAuthentication.SignOut();
Session.Abandon();
From an other StackOverFlow answer which worked for me: OWIN - Authentication.SignOut() doesn't seem to remove the cookie
Use only one of these:
Request.GetOwinContext().Authentication.SignOut();
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.Current.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
https://dzone.com/articles/catching-systemwebowin-cookie
I would assume the second one would work for you, but it looks like that's what you're doing. Can you test that on its own? Comment out your array and confirm that that works or doesn't.
To be honest, I don't know enough about OWIN to know about the Passive Authentication mode, however.
I worked on this for days. Here is what finally worked for me. First thing I do is clear the token cache. Next, I create an array of Auth Application Types. I added these 4. You can add more, if you are using them. To my knowledge, I'm only using Cookies and OpenIdConnect, but I added Bearer and Application to be safe. The final step is to clear all remaining Cookies, if any, and any remaining Sessions, if any. Again, I worked on this for days. It was so frustrating. I'm currently using 4.0.1 of these packages.
Install-Package Microsoft.Owin.Security.OpenIdConnect
Install-Package Microsoft.Owin.Security.Cookies
Install-Package Microsoft.Owin.Host.SystemWeb
public ActionResult SignOut()
{
if (Request.IsAuthenticated)
{
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
if (!string.IsNullOrEmpty(userId))
{
// Get the user's token cache and clear it
SessionTokenCache tokenCache = new SessionTokenCache(userId, HttpContext);
string sessionID = HttpContext.Session.SessionID;
tokenCache.Clear(sessionID);
}
}
var authTypeNames = new List<string>();
authTypeNames.Add("Cookies");
authTypeNames.Add("Application");
authTypeNames.Add("Bearer");
authTypeNames.Add("OpenIdConnect");
// Send a sign-out request.
HttpContext.GetOwinContext().Authentication.SignOut(authTypeNames.ToArray());
Request.Cookies.Clear();
Session.RemoveAll();
return RedirectToAction("Index", "Home");
}
If you have any master page then please add the below tag. May be this would be helpful.
<meta http-equiv="Cache-control" content="no-cache" />

WIF: How to specify which claims to return upon authentication?

Similar to this question, except I need to get additional claims at the moment of authentication, not later.
I'm implementing my RP as an authentication plugin to another website, so I can't (or rather would like to avoid if at all possible) do such things as alter the web.config file or add FederationMetadata.xml to my RP.
I've managed to sucessfully authenticate against the STS, now I need to get some more claims besides the very basics that it sends me. The STS is public (or near it), out of my control, and there will be many different RP's authenticating against it, so I don't expect that every RP will receive special treatment. I thus assume that the STS doesn't know anything about my RP until I perform an authentication, and that it will forget all about it after the authentication is complete.
As stated, I'm using WIF and I'm doing everything in code. Where do I specify which claims to send? Here's my code so far:
// Init configuration
var config = new ServiceConfiguration();
config.AudienceRestriction.AllowedAudienceUris.Add(new Uri("https://MyAudienceURI/"));
config.CertificateValidator = System.IdentityModel.Selectors.X509CertificateValidator.None;
var issuers = new ConfigurationBasedIssuerNameRegistry();
issuers.AddTrustedIssuer("08F81147C44D95CDA617963AFF0650EF26578E4A", "http://STSIssuer/trust");
config.IssuerNameRegistry = issuers;
// Create the FAM
var fam = new WSFederationAuthenticationModule();
fam.ServiceConfiguration = config;
fam.PassiveRedirectEnabled = true;
fam.Issuer = "https://STSUrl/Default.aspx";
fam.Realm = "https://MyAudienceURI/";
fam.Reply = Request.Url.ToString();
fam.RequireHttps = false;
// Check the current request
var req = System.Web.HttpContext.Current.Request;
if (!fam.CanReadSignInResponse(req, true))
{
fam.RedirectToIdentityProvider("Nop.Plugin.ExternalAuth.WIF", Request.Url.ToString(), false);
Response.End();
}
var principal = ClaimsPrincipal.CreateFromIdentities(config.SecurityTokenHandlers.ValidateToken(fam.GetSecurityToken(fam.GetSignInResponseMessage(req))));
Normally, the STS is configured to provide the claims. The configuration is on a per RP basis so different RP can get different claims.
You can augment this using WIF.
Use the ClaimsAuthenticationManager and override Authenticate.
and then something like:
((IClaimsIdentity)incomingPrincipal.Identity).Claims.Add(new Claim(...))
If the claims are external, you have to get them yourself e.g. accessing AD?

Categories

Resources