Abc.IdentityServer4.Saml2 1.0.0-dev66

This is a prerelease version of Abc.IdentityServer4.Saml2.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Abc.IdentityServer4.Saml2 --version 1.0.0-dev66
NuGet\Install-Package Abc.IdentityServer4.Saml2 -Version 1.0.0-dev66
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Abc.IdentityServer4.Saml2" Version="1.0.0-dev66" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Abc.IdentityServer4.Saml2 --version 1.0.0-dev66
#r "nuget: Abc.IdentityServer4.Saml2, 1.0.0-dev66"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Abc.IdentityServer4.Saml2 as a Cake Addin
#addin nuget:?package=Abc.IdentityServer4.Saml2&version=1.0.0-dev66&prerelease

// Install Abc.IdentityServer4.Saml2 as a Cake Tool
#tool nuget:?package=Abc.IdentityServer4.Saml2&version=1.0.0-dev66&prerelease

Abc.IdentityServer4.Saml2

Overview

Implementation SAML2 IdP support for IdentityServer4 with .NET core.

This is useful for connecting older relying parties to IdentityServer4.

.NET Support

The underlying SAML2 classes use .NET Core.

SAML2 endpoint

The SAML2 endpoints is implemented via an IdentityServer4.Hosting.IEndpointHanlder. Endpoint ~/saml2/metadata returns SAML2 metadata, ~/saml2 process SAML2 sing-in and sign-out requests. This endpoints handles the SAML2P protocol requests and redirects the user to the login page if needed.

The login page will then use the normal return URL mechanism to redirect back to the SAML2 endpoint to create the protocol response.

Configuration

For most parts, the SAML2 endpoint can use the standard IdentityServer4 client configuration for relying parties. But there are also options available for setting SAML2 specific options.

Defaults

You can configure global defaults in the Saml2SPOptions class, e.g.:

  • default hashing and digest algorithms
  • default SAML name identifier format
  • default encryption and keywrap algorithms
  • default mappings from "short" claim types to WS-* claim types
  • specify Saml2SecurityTokenHandler

Relying party configuration

The following client settings are used by the SAML2 endpoint:

public static IEnumerable<Client> GetClients()
{
    return new[]
    {
        new Client
        {
            // realm identifier
            ClientId = "urn:owinrp",
            
            // must be set to SAML2
            ProtocolType = ProtocolTypes.Saml2p,

            // reply URL
            RedirectUris = { "http://localhost:10313/" },
            
            // signout cleanup url
            LogoutUri = "http://localhost:10313/home/signoutcleanup",
            
            // lifetime of SAML token
            AccessTokenLifetime = 36000,

            // identity scopes - the associated claims will be used to call the profile service
            AllowedScopes = { "openid", "profile" }
        }
    };
}

SAML2 specific relying party settings

If you want to deviate from the global defaults (e.g. set a different token type or claim mapping) for a specific relying party, you can define a RelyingParty object that uses the same realm name as the client ID used above.

This sample contains an in-memory relying party store that you can use to make these relying party specific settings available to the SAML2 engine (using the AddInMemoryRelyingParty extension method). Otherwise, if you want to use your own store, you will need an implementation of IRelyingPartyStore.

Configuring IdentityServer

This repo contains an extension method for the IdentityServer builder object to register all the necessary services in DI, e.g.:

services.AddDistributedMemoryCache();
services.AddIdentityServer()
    .AddSigningCredential(cert)
    .AddInMemoryIdentityResources(Config.GetIdentityResources())
    .AddInMemoryApiResources(Config.GetApiResources())
    .AddInMemoryClients(Config.GetClients())
    .AddTestUsers(TestUsers.Users)
    .AddSaml2()
    .AddAuthorizationParametersMessageStore<DistributedCacheAuthorizationParametersMessageStore>()
    .AddInMemoryRelyingParties(Config.GetRelyingParties());

Enable encrypted SAML2.0 token

Add to project Abc.IdentityModel.Tokens.Saml via nuget and change SecurityTokenHandlers, e.g.:

builder.AddSaml2(options => {
    // Add encrypted SAML2.0 tokens support
    options.SecurityTokenHandler = new Abc.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler()
    };
});

Connecting a relying party to the SAML2 endpoint

Using .NET Core

Use the .NET Core SAML2 middleware to point to the SAML2 endpoint, e.g.:

public void ConfigureServices(IServiceCollection services) 
{
        services.AddRazorPages();

        services.Configure<Saml2Configuration>(saml2Configuration => {
            saml2Configuration.Issuer = Configuration["saml2:issuer"];
            saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);
            saml2Configuration.SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
            saml2Configuration.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.ChainTrust;
            // !!! REMOVE for production
            saml2Configuration.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
            // !!! for TEST only
            saml2Configuration.SaveBootstrapContext = true;

            var entityDescriptor = new EntityDescriptor();
            entityDescriptor.ReadIdPSsoDescriptorFromUrl(new Uri(Configuration["saml2:metadata"]));
            if (entityDescriptor.IdPSsoDescriptor != null) {
                saml2Configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
                saml2Configuration.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
                saml2Configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
            }
            else {
                throw new Exception("IdPSsoDescriptor not loaded from metadata.");
            }

            // !!! for ADFS
            saml2Configuration.SignAuthnRequest = true;

            var certPath = Path.Combine(Directory.GetCurrentDirectory(), "saml2.sample.pfx");
            if (!File.Exists(certPath)) {
                throw new InvalidOperationException($"{certPath} not found");
            }

            saml2Configuration.SigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, "abc", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet);
        });

        services.AddSaml2();
}

Using Katana

Use the Katana SAML2 middleware to point to the SAML2 endpoint, e.g.:

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions() {
        CookiePath = HostingEnvironment.ApplicationVirtualPath,
        CookieSameSite = Microsoft.Owin.SameSiteMode.None, 
    });

    app.UseSaml2Authentication(CreateSaml2Options())
}

private static Saml2AuthenticationOptions CreateSaml2Options() {
    var spOptions = new SPOptions {
        EntityId = new EntityId(realm),
        AuthenticateRequestSigningBehavior = SigningBehavior.IfIdpWantAuthnRequestsSigned,
        ReturnUrl = new Uri(System.Web.VirtualPathUtility.ToAbsolute("~/Home"), UriKind.Relative),
    };

    spOptions.ServiceCertificates.Add(new X509Certificate2(
        AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "/App_Data/saml2.sample.pfx", "abc"));

    var saml2Options = new Saml2AuthenticationOptions(false) {
        SPOptions = spOptions
    };

    var ed = MetadataLoader.LoadIdp(adfsMetadata, false);

    var idp = new IdentityProvider(ed.EntityId, spOptions) {
        AllowUnsolicitedAuthnResponse = true,
    };
            
    idp.ReadMetadata(ed);
    saml2Options.IdentityProviders.Add(idp);

    return saml2Options;
}

Using ASP.NET WebForms

Use the WebForms SAML2 module to point to the SAML2 endpoint, e.g.:

<configuration>
  <configSections>
    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <section name="microsoft.identityModel.saml" type="Microsoft.IdentityModel.Web.Configuration.MicrosoftIdentityModelSamlSection, Microsoft.IdentityModel.Protocols" />
  </configSections>
  <system.webServer>
    <modules>
        <remove name="FormsAuthentication" />
        <add name="Saml2AuthenticationModule" type="ServiceProvider.MySaml2AuthenticationModule" />
        <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule" />
    </modules>
  </system.webServer>
  <microsoft.identityModel>
    <service>
      
      <audienceUris>
        <add value="urn:sample:saml2:fx" />
      </audienceUris>
      
      <serviceCertificate>
        <certificateReference x509FindType="FindBySubjectDistinguishedName" findValue="CN=localhost" storeLocation="LocalMachine" storeName="My"/>
      </serviceCertificate>
      
      <certificateValidation certificateValidationMode="None" />
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry">
        
        <trustedIssuers>
          <add thumbprint="72 49 4c 3a d3 6f 3a 1d 94 7b 38 d1 7e b2 50 57 4c d3 ef 92" name="LVP.STS" />
        </trustedIssuers>
      </issuerNameRegistry>
      
      <serviceTokenResolver type="Samples.Saml.Utilities.SampleServiceProviderSecurityTokenResolver" />
      
      <securityTokenHandlers>
        <securityTokenHandlerConfiguration saveBootstrapTokens="true">
        </securityTokenHandlerConfiguration>
      </securityTokenHandlers>
      <federatedAuthentication>
        <cookieHandler requireSsl="true" />
      </federatedAuthentication>
    </service>
  </microsoft.identityModel>
</configuration>
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.1 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0-dev75 125 1/23/2023
1.0.0-dev74 105 11/23/2022
1.0.0-dev70 109 10/25/2022
1.0.0-dev67 138 9/15/2022
1.0.0-dev66 97 8/29/2022