Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for dynamic userinfo subdomains #756

Merged
merged 2 commits into from
Apr 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ If a provider you're looking for does not exist, consider making a PR to add one
| Stack Exchange | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.StackExchange?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.StackExchange/ "Download AspNet.Security.OAuth.StackExchange from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.StackExchange?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.StackExchange "Download AspNet.Security.OAuth.StackExchange from MyGet.org") | [Documentation](https://api.stackexchange.com/docs/authentication "Stack Exchange developer documentation") |
| Strava | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Strava?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Strava/ "Download AspNet.Security.OAuth.Strava from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Strava?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Strava "Download AspNet.Security.OAuth.Strava from MyGet.org") | [Documentation](https://developers.strava.com/docs/authentication/ "Strava developer documentation") |
| Streamlabs | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Streamlabs?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Streamlabs/ "Download AspNet.Security.OAuth.Streamlabs from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Streamlabs?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Streamlabs "Download AspNet.Security.OAuth.Streamlabs from MyGet.org") | [Documentation](https://dev.streamlabs.com/reference#authorize "Streamlabs developer documentation") |
| SuperOffice | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.SuperOffice?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.SuperOffice/ "Download AspNet.Security.OAuth.SuperOffice from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.SuperOffice?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.SuperOffice "Download AspNet.Security.OAuth.SuperOffice from MyGet.org") | [Documentation](https://community.superoffice.com/en/developer/create-apps/concepts/authentication/ "SuperOffice developer documentation") |
| SuperOffice | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.SuperOffice?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.SuperOffice/ "Download AspNet.Security.OAuth.SuperOffice from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.SuperOffice?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.SuperOffice "Download AspNet.Security.OAuth.SuperOffice from MyGet.org") | [Documentation](https://docs.superoffice.com/en/authentication/online/index.html "SuperOffice developer documentation") |
| Trakt | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Trakt?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Trakt/ "Download AspNet.Security.OAuth.Trakt from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Trakt?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Trakt "Download AspNet.Security.OAuth.Trakt from MyGet.org") | [Documentation](https://trakt.docs.apiary.io/ "Trakt developer documentation") |
| Trovo | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Trovo?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Trovo/ "Download AspNet.Security.OAuth.Trovo from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Trovo?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Trovo "Download AspNet.Security.OAuth.Trovo from MyGet.org") | [Documentation](https://developer.trovo.live/docs/APIs.html "Trovo developer documentation") |
| Twitch | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Twitch?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Twitch/ "Download AspNet.Security.OAuth.Twitch from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Twitch?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Twitch "Download AspNet.Security.OAuth.Twitch from MyGet.org") | [Documentation](https://dev.twitch.tv/docs/authentication/ "Twitch developer documentation") |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ internal static class FormatStrings
/// </summary>
/// <remarks>The final user information URL contains the protocol, host and tenant.</remarks>
/// <example>https://sod.superoffice.com/Cust12345/api/v1/user/currentPrincipal</example>
public const string UserInfoEndpoint = "/{0}/api/v1/user/currentPrincipal";
public const string UserInfoEndpoint = "{0}v1/user/currentPrincipal";
}

public static class PrincipalNames
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,22 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
[NotNull] AuthenticationProperties properties,
[NotNull] OAuthTokenResponse tokens)
{
var contextId = await ProcessIdTokenAndGetContactIdentifierAsync(tokens, properties, identity);
(string tenantId, string webApiUrl) = await ProcessIdTokenAndGetContactIdentifierAsync(tokens, properties, identity);

if (string.IsNullOrEmpty(contextId))
if (string.IsNullOrEmpty(tenantId))
{
throw new InvalidOperationException("An error occurred trying to obtain the context identifier from the current user's identity claims.");
}

// Add contextId to the Options.UserInformationEndpoint (https://sod.superoffice.com/{0}/api/v1/user/currentPrincipal).
var userInfoEndpoint = string.Format(CultureInfo.InvariantCulture, Options.UserInformationEndpoint, contextId);
if (string.IsNullOrEmpty(webApiUrl))
{
throw new InvalidOperationException("An error occurred trying to obtain the WebApi from the current user's identity claims.");
martincostello marked this conversation as resolved.
Show resolved Hide resolved
}

// UserInfo endpoint must support multiple subdomains, i.e. sod, sod1, online, online1, online2, ...
// - subdomain only becomes known from id token
// Example WebApi Url https://sod.superoffice.com/Cust12345/api/
var userInfoEndpoint = string.Format(CultureInfo.InvariantCulture, SuperOfficeAuthenticationConstants.FormatStrings.UserInfoEndpoint, webApiUrl);

// Get the SuperOffice user principal.
using var request = new HttpRequestMessage(HttpMethod.Get, userInfoEndpoint);
Expand All @@ -69,7 +76,7 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
}

private async Task<string> ProcessIdTokenAndGetContactIdentifierAsync(
private async Task<(string TenantId, string WebApiUrl)> ProcessIdTokenAndGetContactIdentifierAsync(
[NotNull] OAuthTokenResponse tokens,
[NotNull] AuthenticationProperties properties,
[NotNull] ClaimsIdentity identity)
Expand All @@ -85,6 +92,7 @@ private async Task<string> ProcessIdTokenAndGetContactIdentifierAsync(
var tokenValidationResult = await ValidateAsync(idToken, Options.TokenValidationParameters.Clone());

var contextIdentifier = string.Empty;
var webApiUrl = string.Empty;

foreach (var claim in tokenValidationResult.ClaimsIdentity.Claims)
{
Expand All @@ -93,6 +101,11 @@ private async Task<string> ProcessIdTokenAndGetContactIdentifierAsync(
contextIdentifier = claim.Value;
}

if (claim.Type == SuperOfficeAuthenticationConstants.ClaimNames.WebApiUrl)
{
webApiUrl = claim.Value;
}

if (claim.Type == SuperOfficeAuthenticationConstants.ClaimNames.SubjectIdentifier)
{
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, claim.Value));
Expand All @@ -109,7 +122,7 @@ private async Task<string> ProcessIdTokenAndGetContactIdentifierAsync(
}
}

return contextIdentifier;
return (contextIdentifier, webApiUrl);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,6 @@ private void UpdateEndpoints()
FormatStrings.ClaimsIssuer,
env);

// UserInformationEndpoint will include context identifier after authentication in SuperOfficeAuthenticationHandler.CreateTicketAsync
UserInformationEndpoint = string.Concat(ClaimsIssuer, FormatStrings.UserInfoEndpoint);

MetadataAddress = string.Format(CultureInfo.InvariantCulture,
FormatStrings.MetadataEndpoint,
env);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"contentJson": {
"access_token": "8A:Cust12345.secret-access-token",
"expires_in": "300",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2htLmRlbW8uc21pdGhAc3VwZXJvZmZpY2UuY29tIiwibmFtZSI6IkpvaG4gU21pdGgiLCJpc3MiOiJodHRwczovL3NvZC5zdXBlcm9mZmljZS5jb20iLCJpYXQiOjE5MjQzOTA4MDAsImV4cCI6MTkyNDM5MDgwMCwiYXVkIjoiZ2c0NTQ5MThkNzViMWI1MzEwMTA2NWMxNmVlNTExMjMiLCJodHRwOi8vc2NoZW1lcy5zdXBlcm9mZmljZS5uZXQvaWRlbnRpdHkvY3R4IjoiQ3VzdDEyMzQ1In0.XhHllwP6aRR4ZfXj1GlBxCEKKBldYkXef70eX4cjrvlYNLopk62nPnGl6-MxLqjrGHyDIHUo79K3p4_TbDnik2S6FYTeQS_BGNfXC9IuLxuuXnSjU-qhuHpUp1bMt9SBZkz91xDERkqEaTE3E6Q7WLmKAvKapXyJRas3DgAWUfc",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2htLmRlbW8uc21pdGhAc3VwZXJvZmZpY2UuY29tIiwibmFtZSI6IkpvaG4gU21pdGgiLCJpc3MiOiJodHRwczovL3NvZC5zdXBlcm9mZmljZS5jb20iLCJpYXQiOiIxOTI0MzkwODAwIiwiZXhwIjoxODMxODMyNDEwLCJhdWQiOlsiZ2c0NTQ5MThkNzViMWI1MzEwMTA2NWMxNmVlNTExMjMiLCJnZzQ1NDkxOGQ3NWIxYjUzMTAxMDY1YzE2ZWU1MTEyMyJdLCJodHRwOi8vc2NoZW1lcy5zdXBlcm9mZmljZS5uZXQvaWRlbnRpdHkvY3R4IjoiQ3VzdDEyMzQ1IiwiaHR0cDovL3NjaGVtZXMuc3VwZXJvZmZpY2UubmV0L2lkZW50aXR5L3RpY2tldCI6IjdUOlpRQTVBRElBTkFBM0FETUFNUUJoQURFQVpBQmpBRFlBTXdBM0FEVUFZUUF6QURjQU9RQmpBRGdBTmdBNUFEUUFOUUF6QURVQU9RQTRBR0VBWmdBekFEc0FPUUF5QURFQU5BQXhBRFVBTWdBM0FEVUFPd0JEQUhVQWN3QjBBRElBTmdBM0FEVUFPUUE9IiwiaHR0cDovL3NjaGVtZXMuc3VwZXJvZmZpY2UubmV0L2lkZW50aXR5L3NlcmlhbCI6IjEyMzQ1Njc4OSIsImh0dHA6Ly9zY2hlbWVzLnN1cGVyb2ZmaWNlLm5ldC9pZGVudGl0eS93ZWJhcGlfdXJsIjoiaHR0cHM6Ly9zb2Quc3VwZXJvZmZpY2UuY29tL0N1c3QxMjM0NS9hcGkvIiwibmJmIjoxNjc0MDY2MDEwfQ.kbqiDpeOmP0BzoeAxygefMlvkc_ZjoOkPW5luSdR7qKVRviypikg8joZhGpcgKFnx5lpN2hcAX8LR1Jm-g8IBHHNZtj1LU56OwQiDbradMjn_T4Ysqkyus50VBusVUnuOJUNoVZdUj-fwj8SdtLCPfFLGRS2y0EnOZFwvouB0szqybHM_XevSJe54JjSECHOlICXLvaZROvs8n4ZfoCKOIVMIObJ_wlEOHOJu3rnEk2t0srlE5uGbn-Xl-adNlOUM49Mffh6kcAGvjIxCNi2Pzx3_8k3UzdSwTDxef8E2nb20bbh_5qLch_m6rw_EYrJWEuJSQ_dOmd1MqBWoq-VDA",
"refresh_token": "secret-refresh-token",
"token_type": "bearer"
}
Expand Down Expand Up @@ -88,10 +88,12 @@
"kty": "RSA",
"use": "sig",
"alg": "RS256",
"n": "o91XgZtL5WFwiz3jJAEhn2qWsMXRD1f9QJESXro2JIGeAr6jWRvFO8PC0J78PMe46abHDtYKSo49rJZNumADsrYEzUF_FWmvcB9yhEEAQoG9478SYatzzhgUUEebZ4ob5jJpAxNMCzbDJ_8w5rMXJJqy0lI4vUl6rj9akr29nrM",
"kid": "B0AD4C0BFD8913B8040F3E8AD16A91F585222C33",
"x5t": "sK1MC_2JE7gEDz6K0WqR9YUiLDM",
"n": "we8Rh2LfdASEFRgE4VoLZomLl_9ZMowkXn7cjL23s2HYB5pG-ZldhSDyNXzGjNt6xpczhtfNy6Qo7nrleJM40_iXmcqUbIWHGqEPycixYyJVVgEcWXUujX12Xcnm8ZbgDlONXKday3rpAZBO909QzsxQtkcraToriQnOHgTPnbGMJC6kOIC_9qZv5u5wasMd97W21hhzQNVIpO5MlFT7YascGXJa95gjJ2kc975S1soTSOJrhkTe-osBO3fubSXlbyQfkF8HLqbBY2ds3HnV24QAusb7jVeQhiowSReiOoEcG-m6kFZQu3Tc3__1mWe1zeaGfDmuTNQsa2YZHeRLlQ",
"e": "AQAB",
"x5c": [
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCj3VeBm0vlYXCLPeMkASGfapawxdEPV/1AkRJeujYkgZ4CvqNZG8U7w8LQnvw8x7jppscO1gpKjj2slk26YAOytgTNQX8Vaa9wH3KEQQBCgb3jvxJhq3POGBRQR5tnihvmMmkDE0wLNsMn/zDmsxckmrLSUji9SXquP1qSvb2eswIDAQAB"
"MIIDyTCCArECFA/Y63b+pAFzyYckrH2eTPywxz2QMA0GCSqGSIb3DQEBCwUAMIGgMQswCQYDVQQGEwJOTzERMA8GA1UECAwIQWtlcmh1cnMxDTALBgNVBAcMBE9zbG8xGzAZBgNVBAoMElN1cGVyT2ZmaWNlIERldk5ldDEhMB8GA1UECwwYUmVzZWFyY2ggYW5kIERldmVsb3BtZW50MQswCQYDVQQDDAJEWDEiMCAGCSqGSIb3DQEJARYTc2RrQHN1cGVyb2ZmaWNlLmNvbTAeFw0yMTEyMTMyMDMzMDJaFw0yMjEyMTMyMDMzMDJaMIGgMQswCQYDVQQGEwJOTzERMA8GA1UECAwIQWtlcmh1cnMxDTALBgNVBAcMBE9zbG8xGzAZBgNVBAoMElN1cGVyT2ZmaWNlIERldk5ldDEhMB8GA1UECwwYUmVzZWFyY2ggYW5kIERldmVsb3BtZW50MQswCQYDVQQDDAJEWDEiMCAGCSqGSIb3DQEJARYTc2RrQHN1cGVyb2ZmaWNlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMHvEYdi33QEhBUYBOFaC2aJi5f/WTKMJF5+3Iy9t7Nh2AeaRvmZXYUg8jV8xozbesaXM4bXzcukKO565XiTONP4l5nKlGyFhxqhD8nIsWMiVVYBHFl1Lo19dl3J5vGW4A5TjVynWst66QGQTvdPUM7MULZHK2k6K4kJzh4Ez52xjCQupDiAv/amb+bucGrDHfe1ttYYc0DVSKTuTJRU+2GrHBlyWveYIydpHPe+UtbKE0jia4ZE3vqLATt37m0l5W8kH5BfBy6mwWNnbNx51duEALrG+41XkIYqMEkXojqBHBvpupBWULt03N//9Zlntc3mhnw5rkzULGtmGR3kS5UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAjBIAR7cG6r4gReI7S2Qs2zuD4Ghs6wTkPg0BHxoMnHYNN8E1Qig3KzE7BsZzO4gSA6w4kGx1nMSnAEStZMJSalU6LpUdf3xsl9XvM3EyNumk6r07mcphknNo0NFKc5DslITBImEteVcCK1qjWKZDrvH4Qf6VCItbn9v/jDkdzMsCBwA95FLvt0PI3J86rrHAYI9aqMb0q6qx5NbvPlsCTdVSJfqYYjY2acfTGkc3Bi9/phw8xR02gcU080SapftV+T/O0dd0bWL9XnLtHoioRMqIKbl4MRgDDszxV8jfAD3APbQCkHtiFcIU6PlLzU+Lc41Lxktre7JBKY3W3aHd0Q=="
]
}
]
Expand Down