ComponentSpace
SAML for ASP.NET Core
Examples Guide

Copyright © ComponentSpace Pty Ltd 2017-2023. All rights reserved.
www.componentspace.com

ComponentSpace SAML for ASP.NET Core Examples Guide

Contents
Introduction ............................................................................................................................................ 1
Visual Studio Solution Files ..................................................................................................................... 1
Setting the Startup Projects ................................................................................................................ 1
Example Identity Provider....................................................................................................................... 2
Building and Running .......................................................................................................................... 2
IdP-initiated SSO ................................................................................................................................. 2
IdP-initiated SLO.................................................................................................................................. 6
Example Service Provider........................................................................................................................ 7
Building and Running .......................................................................................................................... 7
SP-initiated SSO................................................................................................................................... 8
SP-initiated SLO ................................................................................................................................. 10
Middleware Identity Provider ............................................................................................................... 11
Building and Running ........................................................................................................................ 11
IdP-initiated SSO ............................................................................................................................... 12
IdP-initiated SLO................................................................................................................................ 15
Middleware Service Provider ................................................................................................................ 16
Building and Running ........................................................................................................................ 16
SP-initiated SSO................................................................................................................................. 17
SP-initiated SLO ................................................................................................................................. 19
Blazor Server Identity Provider ............................................................................................................. 21
Building and Running ........................................................................................................................ 21
IdP-initiated SSO ............................................................................................................................... 21
IdP-initiated SLO................................................................................................................................ 26
Blazor Server Service Provider .............................................................................................................. 28
Building and Running ........................................................................................................................ 28
SP-initiated SSO................................................................................................................................. 29
SP-initiated SLO ................................................................................................................................. 31
Example Web API .................................................................................................................................. 33
Building and Running ........................................................................................................................ 33
Unauthorized API Access .................................................................................................................. 34
SP-initiated SSO................................................................................................................................. 34
Authorized API Access....................................................................................................................... 35
SP-initiated SLO ................................................................................................................................. 36
Example Angular SPA ............................................................................................................................ 36iComponentSpace SAML for ASP.NET Core Examples Guide
Building and Running ........................................................................................................................ 36
SP-initiated SSO................................................................................................................................. 37
SP-initiated SLO ................................................................................................................................. 40
SAML Proxy ........................................................................................................................................... 41
Building and Running ........................................................................................................................ 41
IdP-initiated SSO ............................................................................................................................... 42
IdP-initiated SLO................................................................................................................................ 44
SP-initiated SSO................................................................................................................................. 46
SP-initiated SLO ................................................................................................................................. 49
Code Walkthrough ................................................................................................................................ 51
Example Identity Provider................................................................................................................. 51
Configuration ................................................................................................................................ 51
Startup .......................................................................................................................................... 51
SamlController.InitiateSingleSignOn ............................................................................................. 52
Identity/Account/Logout Page...................................................................................................... 52
SamlController.SingleSignOnService............................................................................................. 53
SamlController.SingleLogoutService ............................................................................................. 54
SamlController.ArtifactResolutionService .................................................................................... 55
Example Service Provider.................................................................................................................. 55
Configuration ................................................................................................................................ 55
Startup .......................................................................................................................................... 55
SamlController.SingleSignOn ........................................................................................................ 56
Identity/Account/Logout Page...................................................................................................... 56
SamlController.AssertionConsumerService .................................................................................. 57
SamlController.SingleLogoutService ............................................................................................. 58
SamlController.ArtifactResolutionService .................................................................................... 59
JWT Bearer Token Support ........................................................................................................... 59
Middleware Identity Provider ........................................................................................................... 60
Configuration ................................................................................................................................ 60
Startup .......................................................................................................................................... 60
Index Page ..................................................................................................................................... 61
Identity/Account/Logout Page...................................................................................................... 61
Middleware Service Provider ............................................................................................................ 62
Configuration ................................................................................................................................ 62
Startup .......................................................................................................................................... 62
Identity/Account/Logout .............................................................................................................. 63

ii

ComponentSpace SAML for ASP.NET Core Examples Guide
Blazor Server Identity Provider ......................................................................................................... 63
Configuration ................................................................................................................................ 63
Startup .......................................................................................................................................... 63
SamlController.InitiateSingleSignOn ............................................................................................. 64
Identity/Account/Logout Page...................................................................................................... 65
SamlController.InitiateSingleLogout ............................................................................................. 65
SamlController.SingleSignOnService............................................................................................. 65
SamlController.SingleLogoutService ............................................................................................. 67
SamlController.ArtifactResolutionService .................................................................................... 67
Blazor Server Service Provider .......................................................................................................... 68
Configuration ................................................................................................................................ 68
Startup .......................................................................................................................................... 68
SamlController.SingleSignOn ........................................................................................................ 68
Identity/Account/Logout Page...................................................................................................... 69
SamlController.InitiateSingleLogout ............................................................................................. 69
SamlController.AssertionConsumerService .................................................................................. 69
SamlController.SingleLogoutService ............................................................................................. 71
SamlController.ArtifactResolutionService .................................................................................... 72
Example Web API .............................................................................................................................. 72
Configuration ................................................................................................................................ 72
Startup .......................................................................................................................................... 72
SamlController.InitiateSingleSignOn ............................................................................................. 73
SamlController.InitiateSingleLogout ............................................................................................. 74
SamlController.AssertionConsumerService .................................................................................. 75
SamlController.SingleLogoutService ............................................................................................. 75
Example Angular SPA ........................................................................................................................ 76
Configuration ................................................................................................................................ 77
Auth Service .................................................................................................................................. 77
App Component ............................................................................................................................ 77
SAML Proxy ....................................................................................................................................... 78
Configuration ................................................................................................................................ 78
Startup .......................................................................................................................................... 78
IdentityProviderController.SingleSignOnService .......................................................................... 78
IdentityProviderController.SingleLogoutService .......................................................................... 79
IdentityProviderController.ArtifactResolutionService .................................................................. 79
ServiceProviderController.AssertionConsumerService ................................................................ 80

iii

ComponentSpace SAML for ASP.NET Core Examples Guide
ServiceProviderController.SingleLogoutService ........................................................................... 80
ServiceProviderController.ArtifactResolutionService ................................................................... 81
Error Handling ....................................................................................................................................... 81
Running the Examples on IIS ................................................................................................................. 81
Connection String.............................................................................................................................. 81
Database Creation............................................................................................................................. 82
Database Permissions ....................................................................................................................... 82
IIS Publication.................................................................................................................................... 84
Update SAML Configuration ............................................................................................................. 85

iv

ComponentSpace SAML for ASP.NET Core Examples Guide

Introduction
This document describes the example projects shipped with the product.
Refer to the SAML for ASP.NET Core Installation Guide for instructions on installing the product.
The example projects include SAML configurations. Refer to the SAML for ASP.NET Core
Configuration Guide for information on SAML configuration.
The SAML for ASP.NET Core Developer Guide describes the SAML APIs called by the example
projects.

Visual Studio Solution Files
Solution files for the various .NET Core releases and versions of Visual Studio are included.
Select the appropriate solution file to open the example projects in Visual Studio.
No changes are required for the example projects to build cleanly and run without error in Visual
Studio.

Setting the Startup Projects
Open the Visual Studio solution properties to edit the start-up project to ensure the required
projects are run.
For example, start the ExampleIdentityProvider, MiddlewareServiceProvider andExampleServiceProvider projects for SSO between these applications.

Figure 1 Startup Projects

1ComponentSpace SAML for ASP.NET Core Examples Guide

Example Identity Provider
The ExampleIdentityProvider project is an ASP.NET Core web application based off the Visual Studio
template.
It demonstrates acting as a SAML identity provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The ExampleIdentityProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.
The application is configured to run at https://localhost:44313/.
If this is changed, the ExampleServiceProvider’s SAML configuration must be updated to match the
new URLs.
To demonstrate SAML SSO, both the ExampleIdentityProvider and ExampleServiceProvider must berun.

IdP-initiated SSO
Browse to the example identity provider’s home page at http://localhost:44313/.

2

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the SSO to the Service Provider button.
As you haven’t been authenticated at the ExampleIdentityProvider, you are prompted to login orregister.

3

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the link to register as a new user.
Complete the registration process.

4ComponentSpace SAML for ASP.NET Core Examples Guide
If you’ve previously registered, simply login.

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

5

ComponentSpace SAML for ASP.NET Core Examples Guide

IdP-initiated SLO
Having completed SSO, in the same browser window, browse to the example identity provider’shome page at https://localhost:44313/.

6

ComponentSpace SAML for ASP.NET Core Examples Guide
Click the Log out link. Logout occurs at both the identity provider and service provider.

Example Service Provider
The ExampleServiceProvider project is an ASP.NET Core web application based off the Visual Studio
template.
It demonstrates acting as a SAML service provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The ExampleServiceProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.
The application is configured to run at https://localhost:44360/.

7

ComponentSpace SAML for ASP.NET Core Examples Guide
If this is changed, the ExampleIdentityProvider’s SAML configuration must be updated to match the
new URLs.
To demonstrate SAML SSO, both the ExampleIdentityProvider and ExampleServiceProvider must berun.

SP-initiated SSO
Browse to the example service provider’s home page at https://localhost:44360/.

Click the SSO to the Identity Provider button.
You are prompted to login at the identity provider.

8

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

9

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SLO
Having completed SSO, in the same browser window, browse to the example service provider’shome page at https://localhost:44360/.

Click the Log out link. Logout occurs at both the identity provider and service provider.

10

ComponentSpace SAML for ASP.NET Core Examples Guide

Middleware Identity Provider
The MiddlewareIdentityProvider project is an ASP.NET Core web application based off the Visual
Studio template.
It demonstrates acting as a SAML identity provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Rather than making explicit SAML API calls, the SAML middleware is used to support SSO.
Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The MiddlewareIdentityProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.
The application is configured to run at https://localhost:44377/.

11

ComponentSpace SAML for ASP.NET Core Examples Guide
If this is changed, the MiddlewareServiceProvider’s SAML configuration must be updated to matchthe new URLs.
To demonstrate SAML SSO, both the MiddlewareIdentityProvider and MiddlewareServiceProvider
must be run.

IdP-initiated SSO
Browse to the middleware identity provider’s home page at http://localhost:44377/.

Click the SSO to the Service Provider button.
As you haven’t been authenticated at the MiddlewareIdentityProvider, you are prompted to login orregister.

12

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the link to register as a new user.
Complete the registration process.

13ComponentSpace SAML for ASP.NET Core Examples Guide
If you’ve previously registered, simply login.

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

14

ComponentSpace SAML for ASP.NET Core Examples Guide

IdP-initiated SLO
Having completed SSO, in the same browser window, browse to the example identity provider’shome page at https://localhost:44377/.

15

ComponentSpace SAML for ASP.NET Core Examples Guide
Click the Log out link. Logout occurs at both the identity provider and service provider.

Middleware Service Provider
The MiddlewareServiceProvider project is an ASP.NET Core web application based off the Visual
Studio template.
It demonstrates acting as a SAML service provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Rather than making explicit SAML API calls, the SAML authentication handler is used to support SSO.
Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The MiddlewareServiceProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.

16

ComponentSpace SAML for ASP.NET Core Examples Guide
The application is configured to run at https://localhost:44374/.
If this is changed, the corresponding MiddlewareIdentityProvider’s SAML configuration must be
updated to match the new URLs.
To demonstrate SAML SSO, both the MiddlewareIdentityProvider and MiddlewareServiceProvider
must be run.

SP-initiated SSO
Browse to the middleware service provider’s home page at https://localhost:44374/.

Click the SSO to the Identity Provider button.
Alternatively, click the Log in link and then the SAML button.

17

ComponentSpace SAML for ASP.NET Core Examples Guide

You are prompted to login at the identity provider.

18

ComponentSpace SAML for ASP.NET Core Examples Guide
SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

SP-initiated SLO
Having completed SSO, in the same browser window, browse to the middleware service provider’shome page at https://localhost:44374/.

19

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the Log out link. Logout occurs at both the identity provider and service provider.

20

ComponentSpace SAML for ASP.NET Core Examples Guide

Blazor Server Identity Provider
The BlazorServerIdentityProvider project is a Blazor Server web application based off the Visual
Studio template.
It demonstrates acting as a SAML identity provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The BlazorServerIdentityProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.
The application is configured to run at https://localhost:44361/.
If this is changed, the BlazorServerServiceProvider’s SAML configuration must be updated to matchthe new URLs.
To demonstrate SAML SSO, both the BlazorServerIdentityProvider and BlazorServerServiceProvider
must be run.

IdP-initiated SSO
Browse to the example identity provider’s home page at http://localhost:44361/.

21

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the SSO to the Service Provider button.
As you haven’t been authenticated at the BlazorServerIdentityProvider, you are prompted to login orregister.

22

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the link to register as a new user.
Complete the registration process.

23ComponentSpace SAML for ASP.NET Core Examples Guide

If you’ve previously registered, simply login.

24

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

25

ComponentSpace SAML for ASP.NET Core Examples Guide

IdP-initiated SLO
Having completed SSO, in the same browser window, browse to the example identity provider’shome page at https://localhost:44361/.

26

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the Log out link. Logout occurs at both the identity provider and service provider.

27

ComponentSpace SAML for ASP.NET Core Examples Guide

Blazor Server Service Provider
The BlazorServerServiceProvider project is a Blazor Server web application based off the Visual
Studio template.
It demonstrates acting as a SAML service provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The BlazorServerServiceProvider should build without any errors or warnings.
As it is configured to use the default LocalDB connection string, the simplest approach is to run theapplication on IIS Express through the Visual Studio debugger.
Note that this database is not used by the SAML API but is the application’s user registry.
To run on IIS, the application must be configured in and published to IIS. It should use a databaseprovider other than LocalDB.
The application is configured to run at https://localhost:44326/.

28

ComponentSpace SAML for ASP.NET Core Examples Guide
If this is changed, the BlazorServerIdentityProvider’s SAML configuration must be updated to matchthe new URLs.
To demonstrate SAML SSO, both the BlazorServerIdentityProvider and BlazorServerServiceProvider
must be run.

SP-initiated SSO
Browse to the example service provider’s home page at https://localhost:44326/.

Click the SSO to the Identity Provider button.
You are prompted to login at the identity provider.

29

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

30

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SLO
Having completed SSO, in the same browser window, browse to the example service provider’shome page at https://localhost:44326/.

31ComponentSpace SAML for ASP.NET Core Examples Guide

Click the Log out link. Logout occurs at both the identity provider and service provider.

32

ComponentSpace SAML for ASP.NET Core Examples Guide

Example Web API
The ExampleWebApi project is an ASP.NET Core web application based off the Visual Studio
template.
It demonstrates a web API acting as a SAML service provider and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.
In conjunction with a JavaScript SPA, the ExampleWebApi demonstrates authentication throughSAML SSO and web API authorization through JWT bearer tokens.
It doesn’t demonstrate revoking JWT bearer tokens on logout but this functionality could be added.

Building and Running
The ExampleWebApi should build without any errors or warnings.
The application is configured to run at https://localhost:44319/.

33

ComponentSpace SAML for ASP.NET Core Examples Guide
If this is changed, the ExampleIdentityProvider’s SAML configuration must be updated to match the
new URLs.
To demonstrate SAML SSO, both the ExampleIdentityProvider and ExampleWebApi must be run.

Unauthorized API Access
Access the secured API at https://localhost:44319/api/samllicense.
A 401 error is returned as only requests with a valid JWT bearer token are permitted access.

SP-initiated SSO
Browse to https://localhost:44319/Saml/InitiateSingleSignOn.
You are prompted to login at the identity provider.

34

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes.

Authorized API Access
Access the secured API at https://localhost:44319/api/samllicense.
The API returns successfully.

35

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SLO
Having completed SSO, in the same browser window, browse tohttps://localhost:44319/Saml/InitiateSingleLogout.
Logout occurs at both the identity provider and service provider.

Example Angular SPA
The ExampleAngularSpa project is an Angular application created using the Angular CLI(https://cli.angular.io/).
In conjunction with the ExampleWebApi, it demonstrates authentication through SAML SSO and web
API authorization through JWT bearer tokens.

Building and Running
The ExampleAngularSpa should build without any errors or warnings.
From the application’s top-level folder, restore the packages.
npm install

From the application’s top-level folder, run the application.
ng serve

The application is configured to run at http://localhost:4200/.

36

ComponentSpace SAML for ASP.NET Core Examples Guide
The application also may be run over HTTPS using the “https” script configured in package.json.
From the application’s top-level folder, run the application.
npm run https

The application is configured to run at https://localhost:4200/.
To demonstrate SAML SSO, both the ExampleIdentityProvider and ExampleWebApi must be run.

SP-initiated SSO
Browse to the Angular application at http://localhost:4200/.

Click the SSO to the Identity Provider button.

37

ComponentSpace SAML for ASP.NET Core Examples Guide

You are prompted to login at the identity provider.

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

38

ComponentSpace SAML for ASP.NET Core Examples Guide
For informational purposes only, the returned JWT is displayed.

Click the Call WebAPI button.
A web API is called with the JWT bearer token and the returned SAML product information isdisplayed.

39

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SLO
Having completed SSO, in the same browser window, browse to the Angular application at
http://localhost:4200/.
Click the Log out link. Logout occurs at both the identity provider and service provider.

40

ComponentSpace SAML for ASP.NET Core Examples Guide

SAML ProxyThe SamlProxy project is an ASP.NET Core web application based off the Visual Studio template.
It demonstrates acting as a SAML proxy for identity providers and service providers and supports:••••

IdP-initiated SSO
SP-initiated SSO
IdP-initiated SLO
SP-initiated SLO

An IdP-initiated SSO from an identity provider results in a new IdP-initiated SSO to the target service
provider.
An SP-initiated SSO from a service provider results in a new SP-initiated SSO to the target identity
provider.
The advantage of a SAML proxy is that it’s a single access point for external identity providers orservices providers single signing onto one or more internal identity providers or services providers.
For example, an external identity provider needs to know about a single service provider only (i.e.
the SAML Proxy) which acts on behalf of multiple internal service providers. This minimizes theconfiguration required at the identity provider and makes configuration changes easier to manage.
Through changes to its SAML configuration, it can support all SAML v2.0 compliant third-party
offerings.

Building and Running
The SamlProxy should build without any errors or warnings.

41

ComponentSpace SAML for ASP.NET Core Examples Guide
To run on IIS, the application must be configured in and published to IIS.
The application is configured to run at https://localhost:44361/.
If this is changed, the SAML configurations must be updated to match the new URLs.
To demonstrate SAML SSO, the ExampleIdentityProvider, ExampleServiceProvider and SamlProxymust be run.
Update the PartnerName in both the ExampleIdentityProvider’s and ExampleServiceProvider’sappsettings.json to specify https://SamlProxy.

IdP-initiated SSO
Browse to the example identity provider’s home page at http://localhost:44313/.

Click the SSO to the Service Provider button.
As you haven’t been authenticated at the ExampleIdentityProvider, you are prompted to login.

42

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

43

ComponentSpace SAML for ASP.NET Core Examples Guide

IdP-initiated SLO
Having completed SSO, in the same browser window, browse to the example identity provider’shome page at https://localhost:44313/.

44

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the Log out link. Logout occurs at both the identity provider and service provider.

45

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SSO
Browse to the example service provider’s home page at https://localhost:44360/.

46

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the SSO to the Identity Provider button.
You are prompted to login at the identity provider.

47

ComponentSpace SAML for ASP.NET Core Examples Guide

SSO completes with automatic login at the service provider. The user identity is that specified by theidentity provider.

48

ComponentSpace SAML for ASP.NET Core Examples Guide

SP-initiated SLO
Having completed SSO, in the same browser window, browse to the example service provider’shome page at https://localhost:44360/.

49

ComponentSpace SAML for ASP.NET Core Examples Guide

Click the Log out link. Logout occurs at both the identity provider and service provider.

50

ComponentSpace SAML for ASP.NET Core Examples Guide

Code WalkthroughExample Identity Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local identity provider
and multiple partner service providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "ExampleIdentityProvider.Identity";});// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));

51

ComponentSpace SAML for ASP.NET Core Examples Guide
To avoid the sharing of identity cookies between the ExampleIdentityProvider andExampleServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

SamlController.InitiateSingleSignOn
The SAML controller includes the following action to support IdP-initiated SSO.
[Authorize]
public async Task<IActionResult> InitiateSingleSignOn(){// Get the name of the logged in user.
var userName = User.Identity.Name;// For demonstration purposes, include some claims.
var attributes = new List<SamlAttribute>(){new SamlAttribute(ClaimTypes.Email, User.FindFirst(ClaimTypes.Email)?.Value),
new SamlAttribute(ClaimTypes.GivenName, User.FindFirst(ClaimTypes.GivenName)?.Value),
new SamlAttribute(ClaimTypes.Surname, User.FindFirst(ClaimTypes.Surname)?.Value),};// Initiate single sign-on to the service provider (IdP-initiated SSO)// by sending a SAML response containing a SAML assertion to the SP.
// The optional relay state normally specifies the target URL once SSO completes.
var partnerName = _configuration["PartnerName"];var relayState = _configuration["RelayState"];await _samlIdentityProvider.InitiateSsoAsync(partnerName, userName, attributes, relayState);
return new EmptyResult();}

The authorize attribute on the method ensures only authenticated users can initiate SSO.
The user’s name and some associated claims, to be included in the SAML assertion sent to theservice provider, are retrieved. The user ID and attributes, if any, sent to the service provider may bedifferent depending on your business requirements.
The partner service provider name is retrieved from the application configuration. The method for
determining which service provider to select may be different depending on your business
requirements.
InitiateSsoAsync is called to construct and send a SAML response to the service provider.
Control now moves to the service provider site.

Identity/Account/Logout Page
The logout page includes the following code to support IdP-initiated SLO.
var ssoState = await _samlIdentityProvider.GetStatusAsync();52

ComponentSpace SAML for ASP.NET Core Examples Guideif (await ssoState.CanSloAsync()){// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();}

If the user clicks the log out link, a check is made to see whether the user has completed SSO and, if
so, InitiateSloAsync is called to construct and send a logout request to the service provider(s).
Control now moves to the service provider site.

SamlController.SingleSignOnService
The SAML controller includes the following code to support SP-initiated SSO.
public async Task<IActionResult> SingleSignOnService(){// Receive the authn request from the service provider (SP-initiated SSO).
await _samlIdentityProvider.ReceiveSsoAsync();// If the user is logged in at the identity provider, complete SSO immediately.
// Otherwise have the user login before completing SSO.
if (User.Identity.IsAuthenticated){await CompleteSsoAsync();
return new EmptyResult();}
else{
return RedirectToAction("SingleSignOnServiceCompletion");}}ReceiveSsoAsync receives and processes the SAML authentication request from the service provider.
An internal redirect to the SingleSignOnServiceCompletion action is performed to ensure the user islogged in.
[Authorize]
public async Task<ActionResult> SingleSignOnServiceCompletion(){
await CompleteSsoAsync();
return new EmptyResult();}

The authorize attribute on the method ensures only authenticated users can respond to the SSO
request.

53

ComponentSpace SAML for ASP.NET Core Examples Guide

private Task CompleteSsoAsync(){// Get the name of the logged in user.
var userName = User.Identity.Name;// For demonstration purposes, include some claims.
var attributes = new List<SamlAttribute>(){new SamlAttribute(ClaimTypes.Email, User.FindFirst(ClaimTypes.Email)?.Value),
new SamlAttribute(ClaimTypes.GivenName, User.FindFirst(ClaimTypes.GivenName)?.Value),
new SamlAttribute(ClaimTypes.Surname, User.FindFirst(ClaimTypes.Surname)?.Value),};// The user is logged in at the identity provider.
// Respond to the authn request by sending a SAML response containing a SAML assertion to the SP.
return _samlIdentityProvider.SendSsoAsync(userName, attributes);}

The user’s name and some associated claims, to be included in the SAML assertion sent to theservice provider, are retrieved. The user ID and attributes, if any, sent to the service provider may bedifferent depending on your business requirements.
SendSsoAsync is called to construct and send a SAML response to the service provider.
Control now returns to the service provider site.

SamlController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive the single logout request or response.
// If a request is received then single logout is being initiated by a partner service provider.
// If a response is received then this is in response to single logout having been initiated by the identity
provider.
var sloResult = await _samlIdentityProvider.ReceiveSloAsync();
if (sloResult.IsResponse){
if (sloResult.HasCompleted){// IdP-initiated SLO has completed.
if (!string.IsNullOrEmpty(sloResult.RelayState)){
return LocalRedirect(sloResult.RelayState);}
return RedirectToPage("/Index");
}
}
else
{

54

ComponentSpace SAML for ASP.NET Core Examples Guide// Logout locally.
await _signInManager.SignOutAsync();// Respond to the SP-initiated SLO request indicating successful logout.
await _samlIdentityProvider.SendSloAsync();}
return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the service provider.
For IdP-initiated SLO, a logout response is received. If the results indicate SLO has completed, theuser is redirected to the home page.
For SP-initiated SLO, a logout request is received. The user is logged out locally and SendSloAsync iscalled to construct and send a SAML logout response to the service provider. Control now returns tothe service provider site.

SamlController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){// Resolve the HTTP artifact.
// This is only required if supporting the HTTP-Artifact binding.
await _samlIdentityProvider.ResolveArtifactAsync();
return new EmptyResult();}

Example Service Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local service provider
and multiple partner identity providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "ExampleServiceProvider.Identity";});// Add SAML SSO services.

55

ComponentSpace SAML for ASP.NET Core Examples Guide

services.AddSaml(Configuration.GetSection("SAML"));To avoid the sharing of identity cookies between the ExampleIdentityProvider andExampleServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

SamlController.SingleSignOn
The SAML controller includes the following action to support SP-initiated SSO.
public async Task<IActionResult> InitiateSingleSignOn(string returnUrl = null){// To login automatically at the service provider, initiate single sign-on to the identity provider (SPinitiated SSO).
// The return URL is remembered as SAML relay state.
var partnerName = _configuration["PartnerName"];await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);
return new EmptyResult();}

The partner identity provider name is retrieved from the application configuration. The method for
determining which identity provider to select may be different depending on your business
requirements.
InitiateSSOAsync is called to construct and send a SAML authentication request to the identity
provider.
Control now moves to the identity provider site.

Identity/Account/Logout Page
The logout page includes the following code to support SP-initiated SLO.
var ssoState = await _samlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync()){// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();}

If the user clicks the log out link, a check is made to see whether the user has completed SSO and, if
so, InitiateSloAsync is called to construct and send a logout request to the identity provider.
Control now moves to the identity provider site.

56

ComponentSpace SAML for ASP.NET Core Examples Guide

SamlController.AssertionConsumerService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SSO.
public async Task<IActionResult> AssertionConsumerService(){// Receive and process the SAML assertion contained in the SAML response.
// The SAML response is received either as part of IdP-initiated or SP-initiated SSO.
var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();// Automatically provision the user.
// If the user doesn't exist locally then create the user.
// Automatic provisioning is an optional step.
var user = await _userManager.FindByNameAsync(ssoResult.UserID);
if (user == null){user = new IdentityUser { UserName = ssoResult.UserID, Email = ssoResult.UserID };var result = await _userManager.CreateAsync(user);if (!result.Succeeded){
throw new Exception($"The user {ssoResult.UserID} couldn't be created - {result}");}// For demonstration purposes, create some additional claims.
if (ssoResult.Attributes != null){var samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.Email);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, samlAttribute.ToString()));}
samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.GivenName);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.GivenName,
samlAttribute.ToString()));}
samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.Surname);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Surname,samlAttribute.ToString()));}}}// Automatically login using the asserted identity.
await _signInManager.SignInAsync(user, isPersistent: false);

57

ComponentSpace SAML for ASP.NET Core Examples Guide// Redirect to the target URL if specified.
if (!string.IsNullOrEmpty(ssoResult.RelayState)){
return LocalRedirect(ssoResult.RelayState);}
return RedirectToPage("/Index");}

ReceiveSsoAsync receives and processes the SAML response from the identity provider. The SAML
response is either the result of IdP-initiated or SP-initiated SSO.
If the user doesn’t exist in the user database, they’re automatically provisioned. You may or may notsupport automatic provisioning depending on your business requirements.
The user is logged in automatically at the service provider using information retrieved from the
SAML assertion. The user ID and attributes, if any, received by the service provider may be different
depending on your business requirements.
For IdP-initiated SSO, the optional relay state sent by the identity provider specifies a URL to support
deep web linking. If specified, the user is redirected to this page. Otherwise, the user is redirected tothe home page.

SamlController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive the single logout request or response.
// If a request is received then single logout is being initiated by the identity provider.
// If a response is received then this is in response to single logout having been initiated by the service
provider.
var sloResult = await _samlServiceProvider.ReceiveSloAsync();
if (sloResult.IsResponse){// SP-initiated SLO has completed.
if (!string.IsNullOrEmpty(sloResult.RelayState)){
return LocalRedirect(sloResult.RelayState);}
return RedirectToPage("/Index");}else{// Logout locally.
await _signInManager.SignOutAsync();// Respond to the IdP-initiated SLO request indicating successful logout.
await _samlServiceProvider.SendSloAsync();}58

ComponentSpace SAML for ASP.NET Core Examples Guide

return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the identity provider.
For SP-initiated SLO, a logout response is received. The user is redirected to the home page.
For IdP-initiated SLO, a logout request is received. The user is logged out locally and SendSloAsync iscalled to construct and send a SAML logout response to the identity provider. Control now returns to
the identity provider site.

SamlController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){// Resolve the HTTP artifact.
// This is only required if supporting the HTTP-Artifact binding.
await _ _samlServiceProvider.ResolveArtifactAsync();
return new EmptyResult();}

ResolveArtifactAsync is called to receive and process the artifact resolve request from the identity
provider.

JWT Bearer Token Support
The ExampleServiceProvider project demonstrates authorizing access to a web API using JWT tokens.
The claims page calls a web API to return a JWT bearer token. This token includes claims originatingfrom the SAML assertion received as part of SSO.
The claim page then presents the JWT bearer token when accessing a web API that returns theuser’s claims for display.
None of this code is SAML SSO specific but is does demonstrate using SAML SSO for authenticationof the user, creating a JWT bearer token, and presenting this token for authorized access to a web
API.

59

ComponentSpace SAML for ASP.NET Core Examples Guide

Middleware Identity Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local identity provider
and multiple partner service providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "MiddlewareIdentityProvider.Identity";});// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));// Add the SAML middleware services.
services.AddSamlMiddleware(options =>{options.PartnerName = () => Configuration["PartnerName"];});60

ComponentSpace SAML for ASP.NET Core Examples Guide
To avoid the sharing of identity cookies between the MiddlewareIdentityProvider andExampleServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Finally, the SAML middleware is added.
The SAML options specify the name of a configured partner service provider.
The Configure method includes the following code.
app.UseAuthentication();// Use SAML middleware.
app.UseSaml();

The authentication middleware and SAML middles are enabled.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

Index Page
The index page includes the following code to support IdP-initiated SSO.
public IActionResult OnGetInitiateSingleSignOn(){// Pass control to the SAML middleware for IdP-initiated SSO.
return LocalRedirect(SamlMiddlewareDefaults.InitiateSingleSignOnPath);}

A redirect to the InitiateSingleSignOnPath initiates SSO.
The SAML middleware constructs a SAML response and sends it to the service provider.
Control now moves to the service provider site.

Identity/Account/Logout Page
The logout page includes the following code to support SP-initiated SLO.
public async Task<IActionResult> OnGet(string returnUrl = null){// If a redirect URL is included, this was invoked by the SAML middleware as part of SP-initiated SLO.
if (returnUrl != null){// Logout the user locally.
await _signInManager.SignOutAsync();_logger.LogInformation("User logged out.");// Return control to the SAML middleware.
return LocalRedirect(returnUrl);}
return Page();61

ComponentSpace SAML for ASP.NET Core Examples Guide}

The user is logged out locally and control is returned to the SAML middleware to complete SLO.
Control now moves to the service provider site.
The logout page includes the following code to support IdP-initiated SLO.
public async Task<IActionResult> OnPost(string returnUrl = null){// Logout the user locally.
await _signInManager.SignOutAsync();_logger.LogInformation("User logged out.");// Pass control to the SAML middleware for IdP-initiated SLO.
return LocalRedirect(
QueryHelpers.AddQueryString(
SamlMiddlewareDefaults.InitiateSingleLogoutPath,
SamlMiddlewareDefaults.ReturnUrlParameter,
returnUrl));}

A redirect to the InitiateSingleLogoutPath initiates SLO.
The SAML middleware constructs a SAML logout request and sends it to the service provider.
Control now moves to the service provider site.

Middleware Service Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local service provider
and multiple partner identity providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "MiddlewareServiceProvider.Identity";});// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));// Add SAML authentication middleware.
services.AddAuthentication().AddSaml(options =>{62

ComponentSpace SAML for ASP.NET Core Examples Guide

options.PartnerName = () => Configuration["PartnerName"];});To avoid the sharing of identity cookies between the ExampleIdentityProvider andMiddlewareServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Finally, the SAML authentication is added.
The SAML options specify the name of a configured partner identity provider.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services and middleware.

Identity/Account/Logout
The logout page includes the following code to support SP-initiated SLO.
public async Task<IActionResult> OnPost(string returnUrl = null){// Logout the user locally.
await _signInManager.SignOutAsync();_logger.LogInformation("User logged out.");// Explicitly logout SAML as this isn't done by the SignInManager.
await HttpContext.SignOutAsync(
SamlAuthenticationDefaults.AuthenticationScheme,
new AuthenticationProperties(){
RedirectUri = returnUrl});
return new EmptyResult();}

HttpContext.SignOutAsync initiates SLO.
The SAML authentication handler constructs a SAML logout request and sends it to the identity
provider.
Control now moves to the identity provider site.

Blazor Server Identity Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local identity provider
and multiple partner service providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
63ComponentSpace SAML for ASP.NET Core Examples Guide// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "BlazorServerIdentityProvider.Identity";});// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));To avoid the sharing of identity cookies between the BlazorServerIdentityProvider andBlazorServerServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

SamlController.InitiateSingleSignOn
The SAML controller includes the following action to support IdP-initiated SSO.
[Authorize]
public async Task<IActionResult> InitiateSingleSignOn(){// Get the name of the logged in user.
var userName = User.Identity.Name;// For demonstration purposes, include some claims.
var attributes = new List<SamlAttribute>(){new SamlAttribute(ClaimTypes.Email, User.FindFirst(ClaimTypes.Email)?.Value),
new SamlAttribute(ClaimTypes.GivenName, User.FindFirst(ClaimTypes.GivenName)?.Value),
new SamlAttribute(ClaimTypes.Surname, User.FindFirst(ClaimTypes.Surname)?.Value),};
var partnerName = _configuration["PartnerName"];var relayState = _configuration["RelayState"];// Initiate single sign-on to the service provider (IdP-initiated SSO)// by sending a SAML response containing a SAML assertion to the SP.
// The optional relay state normally specifies the target URL once SSO completes.
await _samlIdentityProvider.InitiateSsoAsync(partnerName, userName, attributes, relayState);
return new EmptyResult();}

The authorize attribute on the method ensures only authenticated users can initiate SSO.
The user’s name and some associated claims, to be included in the SAML assertion sent to theservice provider, are retrieved. The user ID and attributes, if any, sent to the service provider may bedifferent depending on your business requirements.

64

ComponentSpace SAML for ASP.NET Core Examples Guide
The partner service provider name is retrieved from the application configuration. The method for
determining which service provider to select may be different depending on your business
requirements.
InitiateSsoAsync is called to construct and send a SAML response to the service provider.
Control now moves to the service provider site.

Identity/Account/Logout Page
The logout page includes the following code to support IdP-initiated SLO.
var ssoState = await _samlIdentityProvider.GetStatusAsync();
if (await ssoState.CanSloAsync()){// Request logout at the service provider(s).
return RedirectToAction("InitiateSingleLogout", "Saml");
return new EmptyResult();}

If the user clicks the log out link, a check is made to see whether the user has completed SSO and, if
so, single logout is initiated.

SamlController.InitiateSingleLogout
The SAML controller includes the following action to support IdP-initiated SLO.
public async Task<IActionResult> InitiateSingleLogout(string returnUrl = null){// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();}

InitiateSloAsync is called to construct and send a logout request to the service provider(s).
Control now moves to the service provider site.

SamlController.SingleSignOnService
The SAML controller includes the following code to support SP-initiated SSO.
public async Task<IActionResult> SingleSignOnService(){// Receive the authn request from the service provider (SP-initiated SSO).
await _samlIdentityProvider.ReceiveSsoAsync();// If the user is logged in at the identity provider, complete SSO immediately.
// Otherwise have the user login before completing SSO.
if (User.Identity.IsAuthenticated){await CompleteSsoAsync();65

ComponentSpace SAML for ASP.NET Core Examples Guide

return new EmptyResult();}
else{
return RedirectToAction("SingleSignOnServiceCompletion");}}ReceiveSsoAsync receives and processes the SAML authentication request from the service provider.
An internal redirect to the SingleSignOnServiceCompletion action is performed to ensure the user islogged in.
[Authorize]
public async Task<ActionResult> SingleSignOnServiceCompletion(){
await CompleteSsoAsync();
return new EmptyResult();}

The authorize attribute on the method ensures only authenticated users can respond to the SSO
request.

private Task CompleteSsoAsync(){// Get the name of the logged in user.
var userName = User.Identity.Name;// For demonstration purposes, include some claims.
var attributes = new List<SamlAttribute>(){new SamlAttribute(ClaimTypes.Email, User.FindFirst(ClaimTypes.Email)?.Value),
new SamlAttribute(ClaimTypes.GivenName, User.FindFirst(ClaimTypes.GivenName)?.Value),
new SamlAttribute(ClaimTypes.Surname, User.FindFirst(ClaimTypes.Surname)?.Value),};// The user is logged in at the identity provider.
// Respond to the authn request by sending a SAML response containing a SAML assertion to the SP.
return _samlIdentityProvider.SendSsoAsync(userName, attributes);}

The user’s name and some associated claims, to be included in the SAML assertion sent to theservice provider, are retrieved. The user ID and attributes, if any, sent to the service provider may bedifferent depending on your business requirements.
SendSsoAsync is called to construct and send a SAML response to the service provider.

66

ComponentSpace SAML for ASP.NET Core Examples Guide
Control now returns to the service provider site.

SamlController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive the single logout request or response.
// If a request is received then single logout is being initiated by a partner service provider.
// If a response is received then this is in response to single logout having been initiated by the identity
provider.
var sloResult = await _samlIdentityProvider.ReceiveSloAsync();
if (sloResult.IsResponse){
if (sloResult.HasCompleted){// IdP-initiated SLO has completed.
if (!string.IsNullOrEmpty(sloResult.RelayState)){
return LocalRedirect(sloResult.RelayState);}
return LocalRedirect("~/");
}
}
else
{
// Logout locally.
await _signInManager.SignOutAsync();// Respond to the SP-initiated SLO request indicating successful logout.
await _samlIdentityProvider.SendSloAsync();}
return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the service provider.
For IdP-initiated SLO, a logout response is received. If the results indicate SLO has completed, theuser is redirected to the home page.
For SP-initiated SLO, a logout request is received. The user is logged out locally and SendSloAsync iscalled to construct and send a SAML logout response to the service provider. Control now returns tothe service provider site.

SamlController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){// Resolve the HTTP artifact.

67

ComponentSpace SAML for ASP.NET Core Examples Guide// This is only required if supporting the HTTP-Artifact binding.
await _samlIdentityProvider.ResolveArtifactAsync();
return new EmptyResult();}

Blazor Server Service Provider
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local service provider
and multiple partner identity providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
services.ConfigureApplicationCookie(options =>{options.Cookie.Name = "BlazorServerServiceProvider.Identity";});// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));To avoid the sharing of identity cookies between the BlazorServerIdentityProvider andBlazorServerServiceProvider, unique cookie names are specified.
The SAML services are added using the SAML configurations stored in the appsettings.json.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

SamlController.SingleSignOn
The SAML controller includes the following action to support SP-initiated SSO.
public async Task<IActionResult> InitiateSingleSignOn(string returnUrl = null){// To login automatically at the service provider, initiate single sign-on to the identity provider (SPinitiated SSO).
// The return URL is remembered as SAML relay state.
var partnerName = _configuration["PartnerName"];await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);
return new EmptyResult();}

68

ComponentSpace SAML for ASP.NET Core Examples Guide
The partner identity provider name is retrieved from the application configuration. The method for
determining which identity provider to select may be different depending on your business
requirements.
InitiateSSOAsync is called to construct and send a SAML authentication request to the identity
provider.
Control now moves to the identity provider site.

Identity/Account/Logout Page
The logout page includes the following code to support SP-initiated SLO.
var ssoState = await _samlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync()){// Initiate SAML logout.
return RedirectToAction("InitiateSingleLogout", "Saml");}If the user clicks the log out link, a check is made to see whether the user has completed SSO and, if
so, single logout is initiated.

SamlController.InitiateSingleLogout
The SAML controller includes the following action to support SP-initiated SLO.
public async Task<IActionResult> InitiateSingleLogout(string returnUrl = null){// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();}

InitiateSloAsync is called to construct and send a logout request to the identity provider.
Control now moves to the identity provider site.

SamlController.AssertionConsumerService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SSO.
public async Task<IActionResult> AssertionConsumerService(){// Receive and process the SAML assertion contained in the SAML response.
// The SAML response is received either as part of IdP-initiated or SP-initiated SSO.
var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();// Automatically provision the user.
// If the user doesn't exist locally then create the user.
// Automatic provisioning is an optional step.
var user = await _userManager.FindByNameAsync(ssoResult.UserID);

69

ComponentSpace SAML for ASP.NET Core Examples Guideif (user == null){user = new IdentityUser { UserName = ssoResult.UserID, Email = ssoResult.UserID };var result = await _userManager.CreateAsync(user);if (!result.Succeeded){
throw new Exception($"The user {ssoResult.UserID} couldn't be created - {result}");}// For demonstration purposes, create some additional claims.
if (ssoResult.Attributes != null){var samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.Email);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, samlAttribute.ToString()));}
samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.GivenName);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.GivenName,
samlAttribute.ToString()));}
samlAttribute = ssoResult.Attributes.SingleOrDefault(a => a.Name == ClaimTypes.Surname);if (samlAttribute != null){
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Surname,samlAttribute.ToString()));}}}// Automatically login using the asserted identity.
await _signInManager.SignInAsync(user, isPersistent: false);// Redirect to the target URL if specified.
if (!string.IsNullOrEmpty(ssoResult.RelayState)){
return LocalRedirect(ssoResult.RelayState);}
return LocalRedirect("~/");}

ReceiveSsoAsync receives and processes the SAML response from the identity provider. The SAML
response is either the result of IdP-initiated or SP-initiated SSO.

70

ComponentSpace SAML for ASP.NET Core Examples Guide
If the user doesn’t exist in the user database, they’re automatically provisioned. You may or may notsupport automatic provisioning depending on your business requirements.
The user is logged in automatically at the service provider using information retrieved from the
SAML assertion. The user ID and attributes, if any, received by the service provider may be different
depending on your business requirements.
For IdP-initiated SSO, the optional relay state sent by the identity provider specifies a URL to support
deep web linking. If specified, the user is redirected to this page. Otherwise, the user is redirected tothe home page.

SamlController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive the single logout request or response.
// If a request is received then single logout is being initiated by the identity provider.
// If a response is received then this is in response to single logout having been initiated by the service
provider.
var sloResult = await _samlServiceProvider.ReceiveSloAsync();
if (sloResult.IsResponse){// SP-initiated SLO has completed.
if (!string.IsNullOrEmpty(sloResult.RelayState)){
return LocalRedirect(sloResult.RelayState);}
return LocalRedirect("~/");}
else{// Logout locally.
await _signInManager.SignOutAsync();// Respond to the IdP-initiated SLO request indicating successful logout.
await _samlServiceProvider.SendSloAsync();}
return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the identity provider.
For SP-initiated SLO, a logout response is received. The user is redirected to the home page.
For IdP-initiated SLO, a logout request is received. The user is logged out locally and SendSloAsync iscalled to construct and send a SAML logout response to the identity provider. Control now returns to
the identity provider site.

71

ComponentSpace SAML for ASP.NET Core Examples Guide

SamlController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){// Resolve the HTTP artifact.
// This is only required if supporting the HTTP-Artifact binding.
await _samlServiceProvider.ResolveArtifactAsync();
return new EmptyResult();}

ResolveArtifactAsync is called to receive and process the artifact resolve request from the identity
provider.

Example Web API
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local service provider
and multiple partner identity providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The startup includes the following code.
// Optionally add support for JWT bearer tokens.
// This is required only if JWT bearer tokens are used to authorize access to a web API.
// It's not required for SAML SSO.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.Events = new JwtBearerEvents(){
OnMessageReceived = context =>{if (context.Request.Cookies.ContainsKey(builder.Configuration["JWT:CookieName"])){context.Token = context.Request.Cookies[builder.Configuration["JWT:CookieName"]];}return Task.CompletedTask;},
OnAuthenticationFailed = context =>{if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)){// Send a signal to the client that the JWT has expired:// - Add a header to the response to indicate the token has expired// - Use it to perform a desired action on the client

72

ComponentSpace SAML for ASP.NET Core Examples Guide// This is just an example of one approach to handle this event on the client.
context.Response.Headers.Add("token-expired", "true");context.Response.Headers.Add("access-control-expose-headers", "token-expired");}return Task.CompletedTask;}};
options.TokenValidationParameters = new TokenValidationParameters(){
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidAudience = builder.Configuration["JWT:Issuer"],
IssuerSigningKey = newSymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))};});// Optionally add cross-origin request sharing services.
// This is only required for the web API.
// It's not required for SAML SSO.
builder.Services.AddCors(options =>{options.AddPolicy(DefaultCorsPolicyName,builder =>{builder.WithOrigins("http://localhost:4200", "https://localhost:4200");
builder.AllowAnyMethod();builder.AllowAnyHeader();builder.AllowCredentials();});});// Add SAML SSO services.
builder.Services.AddSaml(builder.Configuration.GetSection("SAML"));JWT bearer token support is configured. The token is transmitted as a cookie rather than as an HTTP
header.
CORS support is configured for the web API.
The SAML services are added using the SAML configurations stored in the appsettings.json.

SamlController.InitiateSingleSignOn
The SAML controller includes the following action to support SP-initiated SSO.
public async Task<IActionResult> InitiateSingleSignOn(string returnUrl){
if (string.IsNullOrEmpty(returnUrl)){
returnUrl = "/";

73

ComponentSpace SAML for ASP.NET Core Examples Guide}if (!IsWhitelisted(returnUrl)){
return BadRequest();}// To login automatically at the service provider, initiate single sign-on to the identity provider (SPinitiated SSO).
var partnerName = _configuration["PartnerName"];await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);
return new EmptyResult();}

The partner identity provider name is retrieved from the application configuration. The method for
determining which identity provider to select may be different depending on your business
requirements.
InitiateSSOAsync is called to construct and send a SAML authentication request to the identity
provider.
Control now moves to the identity provider site.

SamlController.InitiateSingleLogout
The SAML controller includes the following action to support SP-initiated SLO.
public async Task<IActionResult> InitiateSingleLogout(string returnUrl){
if (string.IsNullOrEmpty(returnUrl)){
returnUrl = "/";}
if (!IsWhitelisted(returnUrl)){
return BadRequest();}Response.Cookies.Delete(_configuration["JWT:CookieName"], _cookieOptions);
var ssoState = await _samlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync()){// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();}
if (!string.IsNullOrEmpty(returnUrl)){

74

ComponentSpace SAML for ASP.NET Core Examples Guide

return Redirect(returnUrl);}
return new EmptyResult();}

The JWT cookie is deleted.
A check is made to see whether the user has completed SSO and, if so, InitiateSloAsync is called toconstruct and send a logout request to the identity provider.
Control now moves to the identity provider site.

SamlController.AssertionConsumerService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SSO.
public async Task<IActionResult> AssertionConsumerService(){// Receive and process the SAML assertion contained in the SAML response.
// The SAML response is received either as part of IdP-initiated or SP-initiated SSO.
var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();// Create and save a JWT as a cookie.
var jwt = new JwtSecurityTokenHandler().WriteToken(CreateJwtSecurityToken(ssoResult));
Response.Cookies.Append(_configuration["JWT:CookieName"], jwt, _cookieOptions);// Redirect to the specified URL.
if (!string.IsNullOrEmpty(ssoResult.RelayState)){if (!IsWhitelisted(ssoResult.RelayState)){
return BadRequest();}return Redirect(ssoResult.RelayState);}
return new EmptyResult();}

ReceiveSsoAsync receives and processes the SAML response from the identity provider.
A JWT security token is generated and saved as a cookie.

SamlController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){
Response.Cookies.Delete(_configuration["JWT:CookieName"], _cookieOptions);

75

ComponentSpace SAML for ASP.NET Core Examples Guide// Receive the single logout request or response.
// If a request is received then single logout is being initiated by the identity provider.
// If a response is received then this is in response to single logout having been initiated by the service
provider.
var sloResult = await _samlServiceProvider.ReceiveSloAsync();
if (sloResult.IsResponse){// SP-initiated SLO has completed.
if (!string.IsNullOrEmpty(sloResult.RelayState)){if (!IsWhitelisted(sloResult.RelayState)){
return BadRequest();}return Redirect(sloResult.RelayState);
}
}
else
{
// Respond to the IdP-initiated SLO request indicating successful logout.
await _samlServiceProvider.SendSloAsync();}
return new EmptyResult();}

The JWT cookie is deleted.
ReceiveSloAsync is called to receive and process the logout message from the identity provider.
For SP-initiated SLO, a logout response is received. The user is redirected to the application that
initiated SLO.
For IdP-initiated SLO, a logout request is received. The user is logged out locally and SendSloAsync iscalled to construct and send a SAML logout response to the identity provider. Control now returns to
the identity provider site.

Example Angular SPA
SAML SSO is initiated by sending an HTTP Get to the example web API (e.g.
https://localhost:44319/Saml/InitiateSingleSignOn?returnurl=http://localhost:4200).
The returnUrl query string parameter specifies where control should return to once SSO completes.
Similarly, SLO is initiated by sending an HTTP Get to the example web API (e.g.
https://localhost:44319/Saml/InitiateSingleLogout?returnurl=http://localhost:4200).
The returnUrl query string parameter specifies where control should return to once SLO completes.
SAML SSO and SLO flows cannot be initiated through web API calls as these flows must be throughthe browser, as required by the SAML protocol, and typically involve prompting the user to login or
logoff.

76

ComponentSpace SAML for ASP.NET Core Examples Guide

Configuration
The environment specifies the ExampleWebApi URLs for initiating SSO, initiating SLO, retrieving the
JWT and invoking the web API.
export const environment = {production: false,
samlSsoUrl: 'https://localhost:44319/Saml/InitiateSingleSignOn',
samlSloUrl: 'https://localhost:44319/Saml/InitiateSingleLogout',samlAuthUrl: 'https://localhost:44319/api/Authorization',
apiUrl: 'https://localhost:44319/api',
jwtCookieName: 'JWT'};

Auth Service
The auth service includes the following code to check if the JWT cookie is present.
export class AuthService {constructor(private util: UtilService) { }// Determine if a user is Authenticatedpublic get isAuthenticated(): boolean {const userCookie = this.util.getCookieByName(environment.jwtCookieName);// The JWT cookie is provided by the server during the SAML authentication process,// so if it's present then the user is authenticated.
return (userCookie != null && userCookie != undefined);}}

App Component
The app component includes the following code to call the web API. Setting withCredentials is
required to include the JWT cookie with the request.
// Button click event handler to call WebAPI
onClick() {this.isSpinnerVisible = true;
this.apiResult = "";this.resultStatus = undefined;
this.resultStatusText = "";this.resultMessage = "";const url = `${environment.apiUrl}/samllicense`;
this.apiResult = `Calling api "${url}". JWT will be sent in cookie...`;
setTimeout(() => {this.http.get<any>(url, { withCredentials:true }).subscribe({
next: (data) => {77

ComponentSpace SAML for ASP.NET Core Examples Guide

this.apiResult += " done.";this.resultStatus = 200;
this.resultStatusText = "OK";this.resultMessage = data.displayMessage;
this.isSpinnerVisible = false;},
error: (err: HttpErrorResponse) => {this.apiResult += " done.";this.resultStatus = err.status;
this.resultStatusText = err.statusText;
this.resultMessage = "Error";this.isSpinnerVisible = false;}});}, 2000);}

SAML Proxy
Configuration
The appsettings.json includes the SAML configuration.
The configuration consists of a single SAML configuration specifying a single local identity provider, asingle local service provider and multiple partner identity and service providers.
Refer to the SAML for ASP.NET Core Configuration Guide for more information.

Startup
The ConfigureServices method includes the following code.
// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));The SAML services are added using the SAML configurations stored in the appsettings.json.
Although some of this code is specific to this example, most applications will include code to register
the SAML configuration and add the SAML services.

IdentityProviderController.SingleSignOnService
The identity provider SAML controller includes the following code to support SP-initiated SSO.
public async Task<IActionResult> SingleSignOnService(){// Receive an authn request from a service provider (SP-initiated SSO).
var idpSsoResult = await _samlIdentityProvider.ReceiveSsoAsync();// Determine the identity provider name.
var partnerName = GetIdentityProviderName();// Initiate SSO to the identity provider.
await _samlServiceProvider.InitiateSsoAsync(partnerName, null, idpSsoResult.SsoOptions);

78

ComponentSpace SAML for ASP.NET Core Examples Guide

return new EmptyResult();}

ReceiveSsoAsync receives and processes the SAML authentication request from the service provider.
InitiateSsoAsync creates and sends a SAML authentication request to the identity provider.

IdentityProviderController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive a single logout request or response from a service provider.
// If a request is received then initiate SLO to the identity provider.
// If a response is received then complete the SP-initiated SLO.
var sloResult = await _samlIdentityProvider.ReceiveSloAsync();
if (sloResult.IsResponse){
if (sloResult.HasCompleted){// SP-initiated SLO has completed.
await _samlServiceProvider.SendSloAsync();
}
}
else
{
// Determine the identity provider name.
var partnerName = GetIdentityProviderName();// Initiate SLO to the identity provider.
await _samlServiceProvider.InitiateSloAsync(partnerName, sloResult.LogoutReason,
sloResult.RelayState);}
return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the service provider.
For IdP-initiated SLO, a logout response is received. A SAML logout response is sent to the identity
provider.
For SP-initiated SLO, a logout request is received. A SAML logout request is sent to the identity
provider.

IdentityProviderController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){

79ComponentSpace SAML for ASP.NET Core Examples Guide// Resolve the HTTP artifact.
// This is only required if supporting the HTTP-Artifact binding.
await _samlIdentityProvider.ResolveArtifactAsync();
return new EmptyResult();}

ServiceProviderController.AssertionConsumerService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SSO.
public async Task<IActionResult> AssertionConsumerService(){// Receive a SAML response from an identity provider either as part of IdP-initiated or SP-initiated SSO.
var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();
if (ssoResult.IsInResponseTo){// Complete SP-initiated SSO to the service provider.
await _samlIdentityProvider.SendSsoAsync(ssoResult.UserID, ssoResult.Attributes,
ssoResult.AuthnContext);}
else{// Determine the service provider name.
var partnerName = GetServiceProviderName();// Initiate SSO to the service provider.
await _samlIdentityProvider.InitiateSsoAsync(partnerName, ssoResult.UserID, ssoResult.Attributes,
ssoResult.RelayState, ssoResult.AuthnContext);}
return new EmptyResult();}

ReceiveSsoAsync receives and processes the SAML response from the identity provider. The SAML
response is either the result of IdP-initiated or SP-initiated SSO. A SAML response is sent to theservice provider.

ServiceProviderController.SingleLogoutService
The SAML controller includes the following code to support IdP-initiated and SP-initiated SLO.
public async Task<IActionResult> SingleLogoutService(){// Receive a single logout request or response from an identity provider.
// If a request is received then initiate SLO to the identity provider.
// If a response is received then complete the SP-initiated SLO.
var sloResult = await _samlServiceProvider.ReceiveSloAsync();
if (sloResult.IsResponse){// Respond to the SP-initiated SLO request indicating successful logout.
await _samlIdentityProvider.SendSloAsync();80ComponentSpace SAML for ASP.NET Core Examples Guide

}
else
{
// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync(sloResult.LogoutReason, sloResult.RelayState);}
return new EmptyResult();}

ReceiveSloAsync is called to receive and process the logout message from the identity provider.
For SP-initiated SLO, a logout response is received. A SAML logout response is sent to the service
provider.
For IdP-initiated SLO, a logout request is received. A SAML logout request is sent to the service
provider.

ServiceProviderController.ArtifactResolutionService
The SAML controller includes the following code to support SAML artifact resolution as part of the
HTTP-Artifact binding. If the HTTP-Artifact binding is not supported, this code may be omitted.
public async Task<IActionResult> ArtifactResolutionService(){// Resolve the HTTP artifact.
// This is only required if supporting the HTTP-Artifact binding.
await _ _samlServiceProvider.ResolveArtifactAsync();
return new EmptyResult();}

ResolveArtifactAsync is called to receive and process the artifact resolve request from the identity
provider.

Error HandlingAs these are example applications, no error handling is included. Exceptions are not caught andtherefore are displayed in the browser.
In a production application, exceptions should be caught and processed.
Refer to the SAML for ASP.NET Core Developer Guide for more information.

Running the Examples on IIS
Connection String
Update the connection string in appsettings.json to specify a database server such as SQL Server.
The following is one example of a connection string to SQL Server running on localhost and using
Windows authentication.

81

ComponentSpace SAML for ASP.NET Core Examples Guide"DefaultConnection": "Server=localhost;Database=aspnetExampleIdentityProvider;Trusted_Connection=True;MultipleActiveResultSets=true"

Database Creation
Refer to the following tutorial for information on creating the database.
https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/migrations
From the command line, change to the project’s folder and run the following commands.
dotnet ef migrations add InitialCreate

dotnet ef database update

Database Permissions
The account under which the application runs must have permission to access the database.
For a SQL Server database and if Trusted_Connection is specified in the connection string, use theMicrosoft SQL Server Management Studio and create a new login by selecting the Security > Logins
node and clicking New Login.
In the example below, IIS APPPOOL\DefaultAppPool is specified as this is the account under which
the application runs in IIS.

82

ComponentSpace SAML for ASP.NET Core Examples Guide

Ensure the account has read and write access to the database.

83ComponentSpace SAML for ASP.NET Core Examples Guide

IIS Publication
Publish the application to IIS.

84

ComponentSpace SAML for ASP.NET Core Examples Guide

Update SAML Configuration
Ensure all URLs in the SAML configuration are updated as required.

85