Table of Contents
Last updated: 2024-06-26

OpenID Connect / Trusted identity provider


It is possible to setup a trust to an external identity provider in ShareAspace using OpenID Connect. Using this functionality will allow you to opt-out of using the ShareAspace Identity Server and ShareAspace Authorization Server for the OAuth 2.0 authorization flows and instead use a third party authentication/authorization provider.

Deployment setup

In this setup the ShareAspace Host is configured to trust tokens signed by an external identity provider while ShareAspace Web is configured to use the external identity provider for the OAuth 2.0 code flow.

A user will retrieve the JSON Web Tokens (JWTs) from the external identity provider. When the token is used with the ShareAspace REST APIs, ShareAspace will validate the token signature using the keys provided from the trust configuration.

One example is the Microsoft identity platform that lets you configure the OAuth 2.0 flows using:

  • App Registrations in Microsoft Entra ID (Azure AD)
  • App Registrations in Microsoft Azure B2C
  • Microsoft Server 2019/2022 AD FS

Setting up the trust


The trust can be setup directly in the Collection bootstrap settings and/or using the ShareAspace Admin APIs.

Via the APIs it is possible to edit the configuration.

Payload

Parameter Descriptions
id The unique id for the configuration. It is possible to setup multiple trusts.
issuerUrl The OpenID connect metadata document endpoint. This can be configured with our without the last .well-known/openid-configuration bit. e.g. for Entra Id (Azure AD), both https://login.microsoftonline.com/{tenant}/v2.0 and https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration works. Read more about the Microsoft identity platform and the OpenID connect protocol here.
audience (Optional) The audience value used in the signed tokens. This is same as the application id in the Entra Id (Azure AD) / B2C case.
jwksUri (Optional) used for configuring an additional source of public keys for validating an issued access_token. This source will be used together with the key source provided in the metadata exchange.
overrideIssuer (Optional) used for providing an override value on what issuer the access_token should be validated against.
refreshInterval (Optional) the number of hours between ShareAspace requesting a new open id configuration from the trust. Default value is 24h.

Example:

{
  "id": "external-identity",
  "issuerUrl":"https://login.microsoftonline.com/1b90b763-828c-4aa4-885c-58aa98585460/v2.0",
  "audience": "6626e882-9310-4193-b82b-ce95e4e43268",
  "refreshInterval": 24
}

When the trust is registered ShareAspace will use the OpenID Connect metadata document endpoint to fetch the information required from the trust, like the public keys used for validating the tokens. ShareAspace will automatically refresh the metadata in order to support the rolling changes of the signing keys etc.

Bootstrap

The bootstrap payload has an array trustedIdentityProviders

Example:

{
  "trustedIdentityProviders": [
    {
      "id": "external-identity",
      "issuerUrl":"https://login.microsoftonline.com/1b90b763-828c-4aa4-885c-58aa98585460/v2.0",
      "audience": "6626e882-9310-4193-b82b-ce95e4e43268",
      "refreshInterval": 24
    }
  ]
}

Using the Admin APIs

To read and update a configuration.

GET, PUT /admin/trustedIdentityProvider/{id}
Authorization: Bearer ky...
Content-Type: application/json

To register a configuration.

POST /admin/trustedIdentityProvider
Authorization: Bearer ky...
Content-Type: application/json

Example: Creating a configuration using PowerShell.

function GetAuthorizationHeader ($key, $path){
    $encodedPath = [Text.Encoding]::ASCII.GetBytes($path)
    $sha = New-Object System.Security.Cryptography.HMACSHA512
    $sha.key = [Convert]::FromBase64String($key)
    $hash = $sha.ComputeHash($encodedPath)
    $hashString = [Convert]::ToBase64String($hash)
    $bearerToken = $hashString.Split('=')[0]
    $bearerToken = $bearerToken.Replace('+', '-')
    $bearerToken = $bearerToken.Replace('/', '_')
    return @{"Authorization" = ("Bearer", $bearerToken -join " ")}
}

$AdminAPIkey = "6o6aMeh...C7hEPsYMeg=="
$path = "/admin/trustedIdentityProvider"

$uri = "https://localhost:5001" + $path
$headers = GetAuthorizationHeader $AdminAPIkey $path

$body = @{
    "id" = "external-identity";
    "issuerUrl" = "https://login.microsoftonline.com/1b90b763-828c-4aa4-885c-58aa98585460/v2.0";
    "audience" = "6626e882-9310-4193-b82b-ce95e4e43268"
} | ConvertTo-Json

$response = Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -ContentType "application/json" -Body $body 

Configuring ShareAspace web


config.json

To configure ShareAspace web to use the OAuth 2.0 code flow with the trusted identity provider, the config.json file must be configured.

Setting Description
apiPath The url to the ShareAspace API (reverse proxy). On a vanilla installation when ShareAspace web is hosted on the same server as the reverse proxy, this can be set to /api.
client_id The id of the registered client (i.e. the client configuration used for SAs Web).
scope The requested authorization scope.
response-type The type of token(s) expected back. Should always be set to code.
authorizationUrl The OAuth 2.0 authorization endpoint that ShareAspace should redirect to in order to start the OAuth 2.0 flow.
tokenUrl The OAuth 2.0 token endpoint where the callback handler will request the access token and id token from.
redirect_uri The url where ShareAspace will pickup the code that will be used to request the access token. This value must be configured on the trusted provider side. For a vanilla ShareAspace Web installation the url is always https://{fqdn}/sasweb/callback.html.
signOut_uri (Optional) The trusted providers logout endpoint (if applicable).
signOut_queryParam (Optional) If applicable, the name of the query parameter that contains the redirect link after a logout has been done. ShareAspace will pass the link to the ShareAspace start page https://{fqdn}/sasweb.
response_mode The response mode used with the redirect_uri.
changePasswordUri (Optional) The OAuth 2.0 authorization endpoint that ShareAspace should redirect to in order to start the OAuth 2 flow for resetting password. Only applicable to Microsoft Azure B2C.
changePasswordTokenUrl (Optional, required if changePasswordUri is used). The OAuth 2.0 token endpoint where the callback handler will request the access token and id token from (for the reset password flow). Only applicable to Microsoft Azure B2C.
externalIdentity (Optional) Should be set to true when using external providers. The invite emails sent to invited users will not contain a link to the password registration on the ShareAspace Identity server. Instead the link in the email message will be https://{fqdn}/sasweb.
ignoreIdTokenToAccessToken (Optional) Boolean parameter, If set to true, the access_token issued by the identity provider will be used as the ShareAspace access_token.
accessTokenExpireWarningTimeMinutes (Optional, default 10) The number of minutes before the access token expires that ShareAspace web should warn the user about the toke expiration.

Example using Microsoft Azure B2C

{
  "apiPath": "/api",
  "client_id": "740aa397-ef86-46ce-a330-5dbeeeea2829",
  "scope": "openid email",
  "response_type": "code",
  "authorizationUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/authorize",
  "tokenUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/token",
  "redirect_uri": "https://esaz918.eurostep.com/sasweb/callback.html",
  "signOut_uri": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/logout",
  "changePasswordUri": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_reset_v2/oauth2/v2.0/authorize",
  "changePasswordTokenUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_reset_v2/oauth2/v2.0/token",
  "application_id": "a379f5b8-2625-4972-8493-77358d53wf44",
  "signOut_queryParam": "post_logout_redirect_uri",
  "response_mode": "query",
  "externalIdentity": true,
  "accessTokenExpireWarningTimeMinutes": 10
}

web.config

In order for ShareAspace web to request access token and id token using the code provided in the OAuth 2.0 flow, the Content-Security-Policy in the configuration file web.config of ShareAspace web must be updated to include the domain of the identity provider. The domain is added after default-src 'self'.

Example using Microsoft Entra Id (Azure AD) (login.microsoftonline.com)

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Content-Security-Policy" value="default-src 'self' login.microsoftonline.com; ..." />

Step-by-step guides


Microsoft Entra Id (Azure AD)

This guide will go through the steps required to use the Microsoft identity platform in Entra Id (Azure AD) with ShareAspace. The guide uses the Azure portal UI for the setup. Note that it is possible to script all these steps.

Register App

There is a set of values that we will extract during this process.

Value Example
Application (client) ID {application-client-guid}
Directory (tenant) ID {tenant-guid}
OAuth 2.0 authorization endpoint (v2) https://login.microsoftonline.com/{tenant-guid}/oauth2/v2.0/authorize
OAuth 2.0 token endpoint (v2) https://login.microsoftonline.com/{tenant-guid}/oauth2/v2.0/token
OpenID Connect metadata document https://login.microsoftonline.com/{tenant-guid}/v2.0/.well-known/openid-configuration

Using the Azure portal, search for or navigate to the App registrations service.

App registrations

Click the New registration button. Give the configuration a name, decide on what type of account types that should be supported.

Select Single-page application (SPA) under Redirect URI and provide the ShareAspace callback to be used https://[fqdn]/sasweb/callback.html.

New app

Click Register.

Copy the values for Application (client) ID and Directory (tenant) ID from the Essentials section. Save these for later.

Client and Tenant

Click Endpoints.

Endpoints

Copy the values for OAuth 2.0 authorization endpoint (v2), OAuth 2.0 token endpoint (v2), and OpenID Connect metadata document. Save these for later.

These are the minimum requirements for setting up the trust and configuring ShareAspace Web. For any further configuration of the app registration please refer to the Microsoft Azure documentation.

Configuring ShareAspace

Using the values from the previous section it is possible to configure ShareAspace.

Setup trust

Register the trust by either using the collection bootstrap file or the Admin APIs.

Value Description
issuerUrl Contains the Directory (tenant) ID (tenant-guid) that was saved earlier.
audience Is the Application (client) ID (application-client-guid) saved earlier.
{
  "id": "azure-ad",
  "issuerUrl":"https://login.microsoftonline.com/{tenant-guid}/v2.0",
  "audience": "{application-client-guid}"
}
Configure ShareAspace Web

Open config.json under the ShareAspace Web installation folder.

Value Description
client_id Is the Application (client) ID (application-client-guid) saved earlier.
scope Set to "openid email".
response_type Set to "code".
authorizationUrl Is the OAuth 2.0 authorization endpoint (v2) saved earlier.
tokenUrl Is the OAuuth 2.0 token endpoint (v2) saved earlier.
signOut_uri Contains the Directory (tenant) ID (tenant-guid) that was saved earlier.
signOut_queryParam Set to "post_logout_redirect_uri".
externalIdentity Added and set to true.
{
  "apiPath": "/api",
  "client_id": "{application-guid}",
  "scope": "openid email",
  "response_type": "code",
  "authorizationUrl": "https://login.microsoftonline.com/{tenant-guid}/oauth2/v2.0/authorize",
  "tokenUrl": "https://login.microsoftonline.com/{tenant-guid}/oauth2/v2.0/token",
  "redirect_uri": "https://{fqdn}/sasweb/callback.html",
  "signOut_uri": "https://login.microsoftonline.com/{tenant-guid}/oauth2/v2.0/logout",
  "application_id": "{tenant-guid}",
  "signOut_queryParam": "post_logout_redirect_uri",
  "response_mode": "query",
  "externalIdentity": true
}

Open web.config under the ShareAspace Web installation folder. Add login.microsoftonline.com to the content security policy.

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Content-Security-Policy" value="default-src 'self' login.microsoftonline.com; ..." />

The setup is now completed.

Microsoft Azure B2C

Configuring app registrations for Microsoft Azure B2C is similar to configuring the Azure AD. The main difference is the user flows available in Azure B2C. Please refer to the Microsoft Azure B2C documentation on how to mange these.

Configuration examples

Trusted identity provider:

{
  "id": "azure-b2c",
  "issuerUrl": "https://example.b2clogin.com/example.onmicrosoft.com/b2c_1_susi_v2/v2.0/",
  "audience": "d579c6e8-f567-4dfc-9739-d3c34b12b164"
},
{
  "id": "azure-b2c2",
  "issuerUrl": "https://example.b2clogin.com/example.onmicrosoft.com/b2c_1_reset_v2/v2.0/",
  "audience": "d579c6e8-f567-4dfc-9739-d3c34b12b164"
}

config.json:

{
  "apiPath": "/api",
  "client_id": "740aa397-ef86-46ce-a330-5dbeeeea2829",
  "scope": "openid email",
  "response_type": "code",
  "authorizationUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/authorize",
  "tokenUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/token",
  "redirect_uri": "https://esaz918.eurostep.com/sasweb/callback.html",
  "signOut_uri": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_susi_v2/oauth2/v2.0/logout",
  "changePasswordUri": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_reset_v2/oauth2/v2.0/authorize",
  "changePasswordTokenUrl": "https://EXAMPLE_123.b2clogin.com/eurostepcloudservices.onmicrosoft.com/b2c_1_reset_v2/oauth2/v2.0/token",
  "application_id": "a379f5b8-2625-4972-8493-77358d53wf44",
  "signOut_queryParam": "post_logout_redirect_uri",
  "response_mode": "query",
  "externalIdentity": true,
  "accessTokenExpireWarningTimeMinutes": 10
}
Note

b2c_1_susi_v2 and b2c_1_reset_v2 in the example above are the ids of the user flows configured in Azure B2C.

web.config:

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Content-Security-Policy" value="default-src 'self' EXAMPLE_123.b2clogin.com; ..." />

Microsoft AD FS


An OpenID Connect trust can also be setup using Active Directory Federation Services (AD FS) on Microsoft Server 2016/2019/2022.

AD FS configuration

Start the AD FS Management Console and select the Application Groups section.

Application Groups

Click Add Application Group to start the setup wizard. Give the configuration a name, e.g. "ShareAspace", and select the Web browser accessing a web application template.

Add Application Group Wizard

Click Next.

In the next step:

  • Copy the Client Identifier value and save this for later.
  • Add the ShareAspace Web callback address under Redirect URI and click Add.

Native application

Click Next.

In the Apply Access Control Policy step make the configurations that are needed (please refer to the Microsoft AD FS documentation). In this example we will use Permit everyone.

Apply Access Control Policy

Click Next twice, the click Close. The initial configuration is now done. The final step on the AD FS side of the configuration is to map the email claims for ShareAspace.

Right click on the application group that has just been created (e.g. "ShareAspace") then click Properties.

Application Group Properties

Select the Web application (e.g. "ShareAspace - Web application") and click Edit. Open the Issuance Transform Rules tab.

Issuance Transform Rules

  • Click Add Rule.
  • Select Send LDAP Attributes as Claims under Claim rule template.
  • Click Next.
  • Set the Claim rule name to "email".
  • Select Active Directory under Attribute store.
  • Select E-Mail-Addresses under LDAP Attribute.
  • Select E-Mail Address under Outgoing Claim Type.

Issuance Transform Rules, email

  • Click Finish then click OK twice.
Cross domain configuration

As the final step in the authentication/authroization flow ShareAspace web will make a POST call to AD FS in order to exchange the authorization code for the id token. This POST is made from one domain (server hosting ShareAspace web) to a second domain (domain of AD FS). Microsoft Windows Server 2019/2022 supports CORS configuration.

Enable CORS:

> Set-AdfsResponseHeaders -EnableCORS $true

Register ShareAspace web domain:

> Set-AdfsResponseHeaders -CORSTrustedOrigins https://<sas web server fqdn>
Note

If AD FS is running on Windows Server 2016 or if for some reason the CORS configuration is not allowed to be configured on AD FS it is possible to route the code exchange POST via the ShareAspace Reverse proxy. Read more here.

The AD FS configuration is done.

Configuring ShareAspace

Using the values from the previous section it is possible to configure ShareAspace.

Setup trust

Register the trust by either using the collection bootstrap file or the Admin APIs.

Value Description
issuerUrl The OpenID Connect URL for AD FS https://<adfs server fqdn>/adfs/.well-known/openid-configuration.
audience The Client Identifier (client-identifier) saved earlier.
{
  "id": "adfs",
  "issuerUrl":"https://<adfs server fqdn>/adfs/.well-known/openid-configuration",
  "audience": "{client-identifier}"
}
Configure ShareAspace Web

Open config.json under the ShareAspace Web installation folder.

Value Description
client_id Is the Client Identifier (client-identifier) saved earlier.
scope Set to "openid email".
response_type Set to "code".
authorizationUrl The AD FS authorization URL https://<adfs server fqdn>/adfs/oauth2/authorize.
tokenUrl The AD FS token URL https://<adfs server fqdn>/adfs/oauth2/token.
signOut_uri The AD FS logout URL https://<adfs server fqdn>/adfs/oauth2/logout.
signOut_queryParam Set to "post_logout_redirect_uri".
externalIdentity Added and set to true.
{
  "apiPath": "/api",
  "client_id": "{client-identifier}",
  "scope": "openid email",
  "response_type": "code",
  "authorizationUrl": "https://<adfs server fqdn>/adfs/oauth2/authorize",
  "tokenUrl": "https://<adfs server fqdn>/adfs/oauth2/token",
  "redirect_uri": "https://<sas web server fqdn>/sasweb/callback.html",
  "signOut_uri": "https://<adfs server fqdn>/adfs/oauth2/logout",
  "application_id": "{client-identifier}",
  "signOut_queryParam": "post_logout_redirect_uri",
  "response_mode": "query",
  "externalIdentity": true,
  "accessTokenExpireWarningTimeMinutes": 10
}

Open web.config under the ShareAspace Web installation folder. Add the AD FS server fully qualified domain name (FQDN) to the content security policy.

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Content-Security-Policy" value="default-src 'self' <adfs server fqdn>; ..." />

Route tokenUrl via ShareAspace reverse proxy

If ShareAspace web and the ShareAspace reverse proxy are both hosted on the same domain it is possible to avoid a cross domain call from ShareAspace web to the ADFS domain by routing the token request via the ShareAspace reverse proxy.

In the appsettings.json of the ShareAspace reverse proxy - add a new route under ReverseProxy/Routes.

"ADFSServiceRoute": {
  "ClusterId": "ADFSService",
  "Match": {
    "Path": "/adfs-proxy/{**catch-all}"
  },
  "Transforms": [
    {
      "PathRemovePrefix": "/adfs-proxy"
    }
  ]
}

Proxy the request by adding a new cluster under ReverseProxy/Clusters.

"ADFSService": {
      "Destinations": {
        "destination1": {
          "Address": "https://<adfs server fqdn>"
        }
      }
    }

Full example:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Trace",
      "Microsoft.Hosting.Lifetime": "Trace",
      "Eurostep": "Trace"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "https": {
        "Url": "https://localhost:6001"
      }
    }
  },
  "ReverseProxy": {
    "Routes": {
      "ShareAspaceRoute": {
        "ClusterId": "ShareAspaceCluster",
        "Match": {
          "Path": "{**catch-all}"
        },
        "Transforms": [
          {
            "PathRemovePrefix": "/api"
          },
          {
            "RequestHeadersCopy": "true"
          },
          {
            "RequestHeaderOriginalHost": "true"
          },
          {
            "SAs-Route": "true"
          }
        ]
      },
      "ADFSServiceRoute": {
        "ClusterId": "ADFSService",
        "Match": {
          "Path": "/adfs-proxy/{**catch-all}"
        },
        "Transforms": [
          {
            "PathRemovePrefix": "/adfs-proxy"
          }
        ]
      }
    },
    "Clusters": {
      "ShareAspaceCluster": {
        "LoadBalancingPolicy": "FirstAlphabetical",
        "HttpClient": {
          "DangerousAcceptAnyServerCertificate": true
        },
        "HealthCheck": {
          "Active": {
            "Enabled": "true",
            "Interval": "00:00:10",
            "Timeout": "00:00:10",
            "Policy": "PrimarySecondary",
            "Path": "/health"
          }
        },
        "Metadata": {
          "ConsecutiveFailuresHealthPolicy.Threshold": "3"
        },
        "Destinations": {
          "ShareAspaceCluster/destination1": {
            "Address": "https://esaz951web:5001"
          }
        }
      },
      "ADFSService": {
        "Destinations": {
          "destination1": {
            "Address": "https://adfs-server-address"
          }
        }
      }
    }
  }
}

Update the tokenUrl parameter in the ShareAspace web config.json. Instead of requesting the token from AD FS call the configured proxy at https://<sas web server fqdn>/api/adfs-proxy/adfs/oauth2/token.

{
  ...
  "tokenUrl": "https://<sas web server fqdn>/api/adfs-proxy/adfs/oauth2/token",
  ...
}
Note

That with the proxy configuration it is no longer required to set the AD FS address as default-source in the Content-Security-Policy of the ShareAspace web web.config file.

The setup is now completed.