Very short and simple SAML 2.0 "consumer" implementation in C#.
It's a SAML client library, not a SAML server. As in - allows adding SAML single-sign-on to your ASP.NET app, but not to provide auth services to other apps. In other words, it's a library for "service-providers" not for "identity providers".
Install-Package AspNetSaml
Adds a very small .NET Standard 2.0 library (11KB dll) that works with both ASP.NET Core and the "old" ASP.NET Framework. Please refer to releases for the change log.
SAML workflow has 2 steps:
- User is redirected to the SAML provider (with some magic in the query-string) where he authenticates
- User is redirected back to your app, where you validate the payload
Here's how you do it (this example is for ASP.NET Core MVC):
//this example is an ASP.NET Core MVC action methodpublicIActionResultLogin(){//TODO: specify the SAML provider url here, aka "Endpoint"varsamlEndpoint="http://saml-provider-that-we-use.com/login/";varrequest=newAuthRequest("http://www.myapp.com",//TODO: put your app's "entity ID" here"http://www.myapp.com/SamlConsume"//TODO: put Assertion Consumer URL (where the provider should redirect users after authenticating));//now send the user to the SAML providerreturnRedirect(request.GetRedirectUrl(samlEndpoint));}User is sent back to your app - you need to validate the SAML response ("assertion") that you recieved via POST.
Here's an example of how you do it in ASP.NET Core MVC
//ASP.NET Core MVC action method... But you can easily modify the code for old .NET Framework, minimal API etc.publicasyncTask<IActionResult>SamlConsume(){// 1. TODO: specify the certificate that your SAML provider gave youstringsamlCertificate=@"-----BEGIN CERTIFICATE-----BLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAH123543==-----END CERTIFICATE-----";// 2. Let's read the data - SAML providers usually POST it into the "SAMLResponse" varvarsamlResponse=newResponse(samlCertificate,Request.Form["SAMLResponse"]);// 3. Validate the response. "audienceEntityId" is your app's EntityID.varaudienceEntityId="http://www.myapp.com";if(samlResponse.IsValid(audienceEntityId))//all good?{//WOOHOO!!! the user is logged invarusername=samlResponse.GetNameID();//let's get the username//the user has been authenticated, now what?//we can call context.SignInAsync() for ASP.NET Core//or call FormsAuthentication.SetAuthCookie() for .NET Framework//or do something else, like set a cookie or something...//FOR EXAMPLE this is how you sign-in a user in ASP.NET Core 3,5,6,7,8awaitcontext.SignInAsync(newClaimsPrincipal(newClaimsIdentity(new[]{newClaim(ClaimTypes.Name,username)},CookieAuthenticationDefaults.AuthenticationScheme)));//Yeah, it's a mouthful, sorry, not my faultreturnRedirect("~/");//redirect authenticated user back to homapage for example}returnContent("Unauthorized");}SAML providers usually send more data with their response: username, first/last names etc. Here's how to get it:
if(samlResponse.IsValid("http://www.myapp.com"))//your app's EntityID{//WOOHOO!!! user is logged in//Some more optional stuff//let's extract username/firstname etctry{varusername=samlResponse.GetNameID();varemail=samlResponse.GetEmail();varfirstname=samlResponse.GetFirstName();varlastname=samlResponse.GetLastName();//or read some custom-named data that you know the IdP sendsvarofficeLocation=samlResponse.GetCustomAttribute("OfficeAddress");}catch(Exceptionex){//insert error handling code//in case some extra attributes are not present in XML, for examplereturnnull;}}All the functionality sits in one single short file Saml.cs other stuff in this repo are just unit tests, nuget-packaging etc. You can take that file and throw it in your project, it should work just fine.
P.S. This library has been battle-tested for years in production in our helpdesk app please check it out if you're looking for a ticketing system for your team. Cheers.