diff --git a/.deployment/module/cloudDeploy.json b/.deployment/module/cloudDeploy.json
index 11081d4..151703d 100644
--- a/.deployment/module/cloudDeploy.json
+++ b/.deployment/module/cloudDeploy.json
@@ -1,5 +1,5 @@
{
- "artifactKey": "VirtoCommerce.Customer",
+ "artifactKey": "VirtoCommerce.OpenIdConnectModule",
"deployRepo": "vc-deploy-dev",
"cmPath": "backend/packages.json",
"dev": {
diff --git a/.editorconfig b/.editorconfig
index 52a5b14..d467f1b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -102,7 +102,7 @@ csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
-csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_expression_bodied_lambdas = true:silent
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f9421a3..22e3547 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,8 +1,8 @@
# Common settings
-.github/* @mvktsk @Vectorfield4
-.gitignore @mvktsk @Vectorfield4
-.dockerignore @mvktsk @Vectorfield4
+.github/* @VirtoCommerce/platform
+.gitignore @VirtoCommerce/platform
+.dockerignore @VirtoCommerce/platform
# Main Code and Tests
@@ -13,4 +13,4 @@ tests/* @VirtoCommerce/platform
VirtoCommerce.Platform.sln @VirtoCommerce/platform
# Docs
-docs/* @zashchitnik-kuka
+docs/* @VirtoCommerce/platform
diff --git a/.github/workflows/module-ci.yml b/.github/workflows/module-ci.yml
index 1634061..d7b89cd 100644
--- a/.github/workflows/module-ci.yml
+++ b/.github/workflows/module-ci.yml
@@ -1,5 +1,5 @@
-# v3.800.6
-# https://virtocommerce.atlassian.net/browse/VCST-915
+# v3.800.10
+# https://virtocommerce.atlassian.net/browse/VCST-1738
name: Module CI
on:
@@ -239,9 +239,9 @@ jobs:
module-katalon-tests:
if: ${{ ((github.ref == 'refs/heads/dev') && (github.event_name == 'push') && (needs.ci.outputs.run-e2e == 'true')) ||
- (github.event_name == 'workflow_dispatch')}}
+ (github.event_name == 'workflow_dispatch') || (github.base_ref == 'dev') && (github.event_name == 'pull_request') }}
needs: 'ci'
- uses: VirtoCommerce/.github/.github/workflows/e2e.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/e2e.yml@v3.800.10
with:
katalonRepo: 'VirtoCommerce/vc-quality-gate-katalon'
@@ -260,7 +260,7 @@ jobs:
deploy-cloud:
if: ${{ (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' }}
needs: ci
- uses: VirtoCommerce/.github/.github/workflows/deploy-cloud.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/deploy-cloud.yml@v3.800.10
with:
releaseSource: module
moduleId: ${{ needs.ci.outputs.moduleId }}
diff --git a/.github/workflows/module-release-hotfix.yml b/.github/workflows/module-release-hotfix.yml
index 42ed2a1..b5a3dae 100644
--- a/.github/workflows/module-release-hotfix.yml
+++ b/.github/workflows/module-release-hotfix.yml
@@ -1,5 +1,5 @@
-# v3.800.6
-# https://virtocommerce.atlassian.net/browse/VCST-915
+# v3.800.10
+# https://virtocommerce.atlassian.net/browse/VCST-1738
name: Release hotfix
on:
@@ -13,12 +13,12 @@ on:
jobs:
test:
- uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.10
secrets:
sonarToken: ${{ secrets.SONAR_TOKEN }}
build:
- uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.10
with:
uploadPackage: 'true'
uploadDocker: 'false'
@@ -46,7 +46,7 @@ jobs:
publish-github-release:
needs:
[build, test, get-metadata]
- uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.10
with:
fullKey: ${{ needs.build.outputs.packageFullKey }}
changeLog: '${{ needs.get-metadata.outputs.changeLog }}'
diff --git a/.github/workflows/publish-nugets.yml b/.github/workflows/publish-nugets.yml
index c683367..8c52109 100644
--- a/.github/workflows/publish-nugets.yml
+++ b/.github/workflows/publish-nugets.yml
@@ -1,5 +1,5 @@
-# v3.800.6
-# https://virtocommerce.atlassian.net/browse/VCST-915
+# v3.800.10
+# https://virtocommerce.atlassian.net/browse/VCST-1738
name: Publish nuget
on:
@@ -13,12 +13,12 @@ on:
jobs:
test:
- uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.10
secrets:
sonarToken: ${{ secrets.SONAR_TOKEN }}
build:
- uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.10
with:
uploadPackage: 'true'
uploadDocker: 'false'
@@ -29,7 +29,7 @@ jobs:
publish-nuget:
needs:
[build, test]
- uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.10
with:
fullKey: ${{ needs.build.outputs.packageFullKey }}
forceGithub: false
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ee43ae2..17e5d39 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,5 +1,5 @@
-# v3.800.6
-# https://virtocommerce.atlassian.net/browse/VCST-915
+# v3.800.10
+# https://virtocommerce.atlassian.net/browse/VCST-1738
name: Release
on:
@@ -7,6 +7,6 @@ on:
jobs:
release:
- uses: VirtoCommerce/.github/.github/workflows/release.yml@v3.800.6
+ uses: VirtoCommerce/.github/.github/workflows/release.yml@v3.800.10
secrets:
envPAT: ${{ secrets.REPO_TOKEN }}
\ No newline at end of file
diff --git a/README.md b/README.md
index 808385b..bfdc000 100644
--- a/README.md
+++ b/README.md
@@ -11,49 +11,114 @@ OpenID Connect is an identity module on top of the OAuth 2.0 protocol, allowing
## Configuration
The module configuration for OpenID Connect (OIDC) authentication is defined in the appsettings.json file under the `oidc` section. This configuration enables the application to authenticate users using the OIDC protocol. Below are the parameters and their descriptions:
-* Enabled: A boolean value indicating whether OIDC authentication is enabled. Set to true to enable.
-* AuthenticationType: Specifies the type of authentication. For OIDC, this should be set to "oidc".
-* Authority: The URL of the OIDC provider. This is the base address of the identity provider, e.g., https://localhost:5001.
-* AuthenticationCaption: A user-friendly name for the authentication method, e.g., "OpenID Connect".
-* ApplicationId: The unique identifier for the application registered with the OIDC provider.
-* ClientId: The client identifier issued to the application by the OIDC provider.
-* ClientSecret: The client secret issued to the application by the OIDC provider. This should be kept confidential.
-* DefaultUserType: Specifies the default user type upon successful authentication, e.g., "Manager".
-* ResponseMode: Defines how the authorization response is returned. Common values are "query" or "fragment".
-* ResponseType: Specifies the type of response expected from the OIDC provider. For example, "code" for authorization code flow.
-* RequireHttpsMetadata: A boolean value indicating whether HTTPS metadata is required. Set to false for development environments.
-* SaveTokens: A boolean value indicating whether to save the tokens received from the OIDC provider.
-* UseTokenLifetime: A boolean value indicating whether to use the token’s lifetime as provided by the OIDC provider.
-* Scope: An array of strings specifying the scopes requested from the OIDC provider, e.g., ["profile", "email"].
-* GetClaimsFromUserInfoEndpoint: A boolean value indicating whether to retrieve additional claims from the user info endpoint.
-* CallbackPath: The path to which the OIDC provider will redirect after authentication, by default "/signin-openid-connect"
+* `Enabled`: A boolean value indicating whether OIDC authentication is enabled. Set to `true` to enable. Default value is `false`.
+* `AuthenticationType`: Specifies the unique name of the authentication method. Default value is `"oidc"`.
+* `AuthenticationCaption`: A user-friendly name for the authentication method. Default value is `"OpenID Connect"`.
+* `AllowCreateNewUser`: A boolean value indicating whether a new user should be created upon successful authentication. Default value is `true`.
+* `DefaultUserType`: Specifies the user type of a new user. Default value is `"Manager"`.
+* `DefaultUserRoles`: Specifies the list of user roles of a new user. Default value is `[]`.
+* `UserNameClaimType`: Specifies the claim type used to retrieve the username. Default value is `"name"`.
+* `EmailClaimType`: Specifies the claim type used to retrieve the email address. Default value is `"email"`.
+* `HasLoginForm`: A boolean value indicating whether to display a dedicated login form or not. Default value is `true`.
+* `Priority`: An integer value specifying the sorting order of the authentication method. Default value is `1`.
+* `LogoUrl`: URL of the logo for the OpenId Connect authentication provider.
+* `Authority`: The URL of the OIDC provider. This is the base address of the identity provider, e.g., https://localhost:5001.
+* `ClientId`: The client identifier issued to the application by the OIDC provider.
+* `ClientSecret`: The client secret issued to the application by the OIDC provider. This should be kept confidential.
+* `Scope`: An array of strings specifying the scopes requested from the OIDC provider. Default value is `["openid", "profile", "email"]`.
+* `ResponseMode`: Defines how the authorization response is returned. Default value is `"form_post"`.
+* `ResponseType`: Specifies the type of response expected from the OIDC provider. Default value is `"id_token"`.
+* `GetClaimsFromUserInfoEndpoint`: A boolean value indicating whether to retrieve additional claims from the user info endpoint.
+* `CallbackPath`: The path to which the OIDC provider will redirect after authentication. Default value is `"/signin-oidc"`.
+* `SignedOutCallbackPath`: The path to which the OIDC provider will redirect after signing out. Default value is `"/signout-callback-oidc"`.
-> Note: If you other external sign-in providers installed (Microsoft Entra ID or Google SSO) you need to make sure to use unique callback paths for each provider.
+The list of other parameters can be found in the [OpenIdConnectOptions](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.openidconnectoptions?view=aspnetcore-1.1&viewFallbackFrom=aspnetcore-8.0) documentation.
+> [!IMPORTANT]
+> If you have other external sign-in providers installed (Microsoft Entra ID or Google SSO) you need to make sure to use unique authentication types and callback paths for each provider.
+
+> [!NOTE]
+> The module was designed and tested with this version of the platform [VCST-1415: Platform as authorization server](https://github.com/VirtoCommerce/vc-platform/pull/2809)
+
+### Example settings for Virto Commerce
```json
"oidc": {
"Enabled": true,
- "AuthenticationType": "oidc",
+ "AuthenticationType": "virto",
+ "AuthenticationCaption": "Virto Commerce",
"Authority": "https://localhost:5001",
- "AuthenticationCaption": "OpenID Connect",
- "ApplicationId": "cf4cb5a0-17c8-4cde-91fd-f23f0891ae20",
- "ClientId": "cf4cb5a0-17c8-4cde-91fd-f23f0891ae20",
- "ClientSecret": "ad724695-ca42-4271-a9ba-636a2d50f7ec",
- "DefaultUserType": "Manager",
- "ResponseMode" : "query",
- "ResponseType" : "code",
- "RequireHttpsMetadata" : false,
- "SaveTokens" : true,
- "UseTokenLifetime" : true,
- "Scope" : ["profile", "email"],
- "GetClaimsFromUserInfoEndpoint" : true,
- "CallbackPath": "/signin-openid-connect"
+ "ClientId": "your-client-id",
+ "ClientSecret": "your-client-secret",
+ "ResponseMode": "query",
+ "ResponseType": "code",
+ "GetClaimsFromUserInfoEndpoint": true
+ }
+```
+
+### Example settings for Google
+```json
+ "oidc": {
+ "Enabled": true,
+ "AuthenticationType": "google",
+ "AuthenticationCaption": "Google",
+ "Authority": "https://accounts.google.com",
+ "ClientId": "your-client-id",
+ "ClientSecret": "your-client-secret",
+ "UserNameClaimType": "email"
}
```
-## Known limitation
-1. The module was designed and tested with this version of the platform [VCST-1415: Platform as authorization server](https://github.com/VirtoCommerce/vc-platform/pull/2809)
-2. Supports ResponseMode query only.
+### Example settings for Microsoft
+```json
+ "oidc": {
+ "Enabled": true,
+ "AuthenticationType": "microsoft",
+ "AuthenticationCaption": "Microsoft",
+ "Authority": "https://login.microsoftonline.com/your-tenant-id/v2.0",
+ "ClientId": "your-application-id",
+ "UserNameClaimType": "preferred_username"
+ }
+```
+
+### Example settings for multiple configurations
+```json
+ "oidc": [
+ {
+ "Enabled": true,
+ "AuthenticationType": "virto",
+ "AuthenticationCaption": "Virto Commerce",
+ "Authority": "https://localhost:5001",
+ "ClientId": "your-client-id",
+ "ClientSecret": "your-client-secret",
+ "ResponseMode": "query",
+ "ResponseType": "code",
+ "GetClaimsFromUserInfoEndpoint": true,
+ "CallbackPath": "/signin-virto",
+ "SignedOutCallbackPath": "/signout-virto"
+ },
+ {
+ "Enabled": true,
+ "AuthenticationType": "google",
+ "AuthenticationCaption": "Google",
+ "Authority": "https://accounts.google.com",
+ "ClientId": "your-client-id",
+ "ClientSecret": "your-client-secret",
+ "UserNameClaimType": "email",
+ "CallbackPath": "/signin-google",
+ "SignedOutCallbackPath": "/signout-google"
+ },
+ {
+ "Enabled": true,
+ "AuthenticationType": "microsoft",
+ "AuthenticationCaption": "Microsoft",
+ "Authority": "https://login.microsoftonline.com/your-tenant-id/v2.0",
+ "ClientId": "your-application-id",
+ "UserNameClaimType": "preferred_username",
+ "CallbackPath": "/signin-microsoft",
+ "SignedOutCallbackPath": "/signout-microsoft"
+ }
+ ]
+```
## License
Copyright (c) Virto Solutions LTD. All rights reserved.
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/Events/.keep b/src/VirtoCommerce.OpenIdConnectModule.Core/Events/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/Models/OidcOptions.cs b/src/VirtoCommerce.OpenIdConnectModule.Core/Models/OidcOptions.cs
index d74c860..758d905 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Core/Models/OidcOptions.cs
+++ b/src/VirtoCommerce.OpenIdConnectModule.Core/Models/OidcOptions.cs
@@ -1,133 +1,59 @@
-using System.Collections.Generic;
+namespace VirtoCommerce.OpenIdConnectModule.Core.Models;
-namespace VirtoCommerce.OpenIdConnectModule.Core.Models
+public class OidcOptions
{
- public class OidcOptions
- {
- ///
- /// Determines whether the user authentication via OpenId Connect is enabled.
- ///
- public bool Enabled { get; set; }
-
- ///
- /// Sets AuthenticationType value for OpenId Connect authentication provider.
- ///
- public string AuthenticationType { get; set; }
-
- ///
- /// Sets human-readable caption for OpenId Connect authentication provider. It is visible on sign-in page.
- ///
- public string AuthenticationCaption { get; set; }
-
- ///
- /// Application ID of the VirtoCommerce platform application registered in OpenId Connect.
- ///
- public string ApplicationId { get; set; }
-
- ///
- /// URL of the OpenId Connect endpoint used for authentication.
- ///
- public string Authority { get; set; }
-
- ///
- /// Default user type for users created by OpenId Connect accounts.
- ///
- public string DefaultUserType { get; set; }
-
- ///
- /// Default user roles for users created by OpenId Connect accounts.
- ///
- public string[] DefaultUserRoles { get; set; }
-
- ///
- /// Allow creating new user when a user authenticates via IDP for the first time
- ///
- public bool AllowCreateNewUser { get; set; } = true;
-
- ///
- /// Display dedicated login form or not
- ///
- public bool HasLoginForm { get; set; } = true;
-
- ///
- /// Gets or sets the discovery endpoint for obtaining metadata
- ///
- public string MetadataAddress { get; set; }
-
- ///
- /// Client Id
- ///
- public string ClientId { get; set; }
-
- ///
- /// Client Id
- ///
- public string ClientSecret { get; set; }
-
- ///
- /// Client Id
- ///
- public string CallbackPath { get; set; } = "/signin-openid-connect";
-
- ///
- /// Response type
- ///
- public string ResponseType { get; set; }
-
- ///
- /// Response mode
- ///
- public string ResponseMode { get; set; }
-
- ///
- /// Indicates that the authentication session lifetime (e.g. cookies) should match that of the authentication token.
- /// If the token does not provide lifetime information then normal session lifetimes will be used.
- /// This is disabled by default.
- ///
- public bool UseTokenLifetime { get; set; }
-
- ///
- /// Defines whether access and refresh tokens should be stored in the AuthenticationProperties after a successful authorization.
- /// This property is set to false by default to reduce the size of the final authentication cookie.
- ///
- public bool SaveTokens { get; set; }
-
- ///
- /// Gets or sets if HTTPS is required for the metadata address or authority. The default is true.
- /// This should be disabled only in development environments.
- ///
- public bool RequireHttpsMetadata { get; set; }
-
- ///
- /// Gets or sets the authentication scheme corresponding to the middleware responsible of persisting user's identity after a successful authentication.
- /// This value typically corresponds to a cookie middleware registered in the Startup class. When omitted, SignInScheme is used as a fallback value.
- ///
- public string SignInScheme { get; set; }
-
- ///
- /// Gets the list of permissions to request.
- ///
- public List Scope { get; set; }
-
- ///
- /// Boolean to set whether the middleware should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint.
- /// The default is 'false'.
- ///
- public bool GetClaimsFromUserInfoEndpoint { get; set; }
-
- ///
- ///
- ///
- public string SignedOutCallbackPath { get; set; }
-
- ///
- ///
- ///
- public string SignedOutRedirectUri { get; set; }
-
- ///
- ///
- ///
- public string SignOutScheme { get; set; }
- }
+ ///
+ /// Determines whether the user authentication via OpenId Connect is enabled.
+ ///
+ public bool Enabled { get; set; } = false;
+
+ ///
+ /// Sets AuthenticationType value for OpenId Connect authentication provider.
+ ///
+ public string AuthenticationType { get; set; } = "oidc";
+
+ ///
+ /// Sets human-readable caption for OpenId Connect authentication provider. It is visible on sign-in page.
+ ///
+ public string AuthenticationCaption { get; set; } = "OpenID Connect";
+
+ ///
+ /// Allow creating new user when a user authenticates via IDP for the first time
+ ///
+ public bool AllowCreateNewUser { get; set; } = true;
+
+ ///
+ /// Default user type for users created by OpenId Connect accounts.
+ ///
+ public string DefaultUserType { get; set; } = "Manager";
+
+ ///
+ /// Default user roles for users created by OpenId Connect accounts.
+ ///
+ public string[] DefaultUserRoles { get; set; } = [];
+
+ ///
+ /// Specifies the claim type used to retrieve the username.
+ ///
+ public string UserNameClaimType { get; set; } = "name";
+
+ ///
+ /// Specifies the claim type used to retrieve the email address.
+ ///
+ public string EmailClaimType { get; set; } = "email";
+
+ ///
+ /// Display dedicated login form or not
+ ///
+ public bool HasLoginForm { get; set; } = true;
+
+ ///
+ /// The sorting order of the external sign-in provider.
+ ///
+ public int Priority { get; set; } = 1;
+
+ ///
+ /// URL of the logo for the OpenId Connect authentication provider.
+ ///
+ public string LogoUrl { get; set; } = "Modules/$(VirtoCommerce.OpenIdConnectModule)/Content/openid-icon.webp";
}
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/ModuleConstants.cs b/src/VirtoCommerce.OpenIdConnectModule.Core/ModuleConstants.cs
deleted file mode 100644
index d454949..0000000
--- a/src/VirtoCommerce.OpenIdConnectModule.Core/ModuleConstants.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace VirtoCommerce.OpenIdConnectModule.Core;
-
-public static class ModuleConstants
-{
- public const string OidcAuthenticationType = "oidc";
- public const int ProviderPriority = 200;
- public const string JsonKeyName = "name";
- public const string JsonKeyEmail = "email";
-}
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/Notifications/.keep b/src/VirtoCommerce.OpenIdConnectModule.Core/Notifications/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/Services/.keep b/src/VirtoCommerce.OpenIdConnectModule.Core/Services/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Core/VirtoCommerce.OpenIdConnectModule.Core.csproj b/src/VirtoCommerce.OpenIdConnectModule.Core/VirtoCommerce.OpenIdConnectModule.Core.csproj
index c07fcda..559727b 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Core/VirtoCommerce.OpenIdConnectModule.Core.csproj
+++ b/src/VirtoCommerce.OpenIdConnectModule.Core/VirtoCommerce.OpenIdConnectModule.Core.csproj
@@ -7,6 +7,6 @@
false
-
+
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Data/Models/.keep b/src/VirtoCommerce.OpenIdConnectModule.Data/Models/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Data/Services/OidcExternalSignInProvider.cs b/src/VirtoCommerce.OpenIdConnectModule.Data/Services/OidcExternalSignInProvider.cs
index 0ec132c..02920bd 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Data/Services/OidcExternalSignInProvider.cs
+++ b/src/VirtoCommerce.OpenIdConnectModule.Data/Services/OidcExternalSignInProvider.cs
@@ -1,42 +1,46 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Identity;
-using Microsoft.Extensions.Options;
-using VirtoCommerce.OpenIdConnectModule.Core;
using VirtoCommerce.OpenIdConnectModule.Core.Models;
using VirtoCommerce.Platform.Security.ExternalSignIn;
-namespace VirtoCommerce.OpenIdConnectModule.Data.Services
+namespace VirtoCommerce.OpenIdConnectModule.Data.Services;
+
+public class OidcExternalSignInProvider : IExternalSignInProvider
{
- public class OidcExternalSignInProvider : IExternalSignInProvider
+ private readonly OidcOptions _oidcOptions;
+
+ public OidcExternalSignInProvider(OidcOptions oidcOptions)
{
- private readonly OidcOptions _oidcOptions;
+ _oidcOptions = oidcOptions;
+ }
- public OidcExternalSignInProvider(IOptions oidcOptions)
- {
- _oidcOptions = oidcOptions.Value;
- }
+ public int Priority => _oidcOptions.Priority;
- public int Priority => ModuleConstants.ProviderPriority;
+ public bool HasLoginForm => _oidcOptions.HasLoginForm;
- public bool HasLoginForm => _oidcOptions.HasLoginForm;
+ public bool AllowCreateNewUser => _oidcOptions.AllowCreateNewUser;
- public bool AllowCreateNewUser => _oidcOptions.AllowCreateNewUser;
+ public string GetUserName(ExternalLoginInfo externalLoginInfo)
+ {
+ var userName = externalLoginInfo.Principal.FindFirstValue(_oidcOptions.UserNameClaimType);
- public string GetUserName(ExternalLoginInfo externalLoginInfo)
- {
- var userName = externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Name);
+ return userName;
+ }
- return userName;
- }
+ public string GetEmail(ExternalLoginInfo externalLoginInfo)
+ {
+ var email = externalLoginInfo.Principal.FindFirstValue(_oidcOptions.EmailClaimType);
- public string[] GetUserRoles()
- {
- return _oidcOptions.DefaultUserRoles;
- }
+ return email;
+ }
- public string GetUserType()
- {
- return _oidcOptions.DefaultUserType;
- }
+ public string[] GetUserRoles()
+ {
+ return _oidcOptions.DefaultUserRoles;
+ }
+
+ public string GetUserType()
+ {
+ return _oidcOptions.DefaultUserType;
}
}
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Data/VirtoCommerce.OpenIdConnectModule.Data.csproj b/src/VirtoCommerce.OpenIdConnectModule.Data/VirtoCommerce.OpenIdConnectModule.Data.csproj
index e092520..7797f10 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Data/VirtoCommerce.OpenIdConnectModule.Data.csproj
+++ b/src/VirtoCommerce.OpenIdConnectModule.Data/VirtoCommerce.OpenIdConnectModule.Data.csproj
@@ -1,4 +1,4 @@
-
+
net8.0
@@ -7,7 +7,7 @@
false
-
+
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Web/Module.cs b/src/VirtoCommerce.OpenIdConnectModule.Web/Module.cs
index 6f72e5e..4af3e76 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Web/Module.cs
+++ b/src/VirtoCommerce.OpenIdConnectModule.Web/Module.cs
@@ -1,11 +1,11 @@
+using System;
using System.Linq;
-using System.Security.Claims;
using System.Threading.Tasks;
+using System.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using VirtoCommerce.OpenIdConnectModule.Core;
using VirtoCommerce.OpenIdConnectModule.Core.Models;
using VirtoCommerce.OpenIdConnectModule.Data.Services;
using VirtoCommerce.Platform.Core.Modularity;
@@ -21,62 +21,83 @@ public class Module : IModule, IHasConfiguration
public void Initialize(IServiceCollection serviceCollection)
{
- Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear();
-
- var OidcSection = Configuration.GetSection(ModuleConstants.OidcAuthenticationType);
- if (OidcSection.GetChildren().Any())
+ var oidcSection = Configuration.GetSection("oidc");
+ if (!oidcSection.GetChildren().Any())
{
- var options = new OidcOptions();
- OidcSection.Bind(options);
- serviceCollection.Configure(OidcSection);
+ return;
+ }
- if (options.Enabled)
+ // Support both single and multiple configurations
+ // Single: "oidc": {...}
+ // Multiple: "oidc": [{...}, {...}]
+ if (oidcSection.GetSection("0").Exists())
+ {
+ foreach (var section in oidcSection.GetChildren())
{
- var authBuilder = new AuthenticationBuilder(serviceCollection);
+ RegisterOidcProvider(serviceCollection, section);
+ }
+ }
+ else
+ {
+ RegisterOidcProvider(serviceCollection, oidcSection);
+ }
+ }
- authBuilder.AddOpenIdConnect(options.AuthenticationType, options.AuthenticationCaption,
- openIdConnectOptions =>
- {
- openIdConnectOptions.ClientId = options.ClientId;
- openIdConnectOptions.ClientSecret = options.ClientSecret;
- openIdConnectOptions.Authority = options.Authority;
- openIdConnectOptions.UseTokenLifetime = options.UseTokenLifetime;
- openIdConnectOptions.SaveTokens = options.SaveTokens;
- openIdConnectOptions.ResponseMode = options.ResponseMode;
- openIdConnectOptions.ResponseType = options.ResponseType;
- openIdConnectOptions.MetadataAddress = options.MetadataAddress;
- openIdConnectOptions.RequireHttpsMetadata = options.RequireHttpsMetadata;
- openIdConnectOptions.SignInScheme = options.SignInScheme;
- openIdConnectOptions.SignOutScheme = options.SignOutScheme;
- openIdConnectOptions.CallbackPath = options.CallbackPath;
- openIdConnectOptions.SignedOutCallbackPath = options.SignedOutCallbackPath;
- openIdConnectOptions.SignedOutRedirectUri = options.SignedOutRedirectUri;
- openIdConnectOptions.GetClaimsFromUserInfoEndpoint = options.GetClaimsFromUserInfoEndpoint;
- options.Scope.ForEach(scope => openIdConnectOptions.Scope.Add(scope));
-
- openIdConnectOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, ModuleConstants.JsonKeyName);
- openIdConnectOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, ModuleConstants.JsonKeyEmail);
-
- openIdConnectOptions.Events.OnRedirectToIdentityProvider = context =>
- {
- var oidcUrl = context.Properties.GetOidcUrl();
- if (!string.IsNullOrEmpty(oidcUrl))
- {
- context.ProtocolMessage.RedirectUri = oidcUrl;
- }
- return Task.CompletedTask;
- };
- });
-
- // register default external provider implementation
- serviceCollection.AddSingleton();
- serviceCollection.AddSingleton(provider => new ExternalSignInProviderConfiguration
+ private static void RegisterOidcProvider(IServiceCollection serviceCollection, IConfigurationSection oidcSection)
+ {
+ var options = new OidcOptions();
+ oidcSection.Bind(options);
+
+ if (options.Enabled)
+ {
+ var authBuilder = new AuthenticationBuilder(serviceCollection);
+
+ authBuilder.AddOpenIdConnect(options.AuthenticationType, options.AuthenticationCaption,
+ openIdConnectOptions =>
{
- AuthenticationType = ModuleConstants.OidcAuthenticationType,
- Provider = provider.GetService(),
- LogoUrl = "Modules/$(VirtoCommerce.OpenIdConnectModule)/Content/openid-icon.webp"
+ openIdConnectOptions.MapInboundClaims = false;
+
+ openIdConnectOptions.Scope.Clear();
+ if (!oidcSection.GetSection("Scope").Exists())
+ {
+ openIdConnectOptions.Scope.Add("openid");
+ openIdConnectOptions.Scope.Add("profile");
+ openIdConnectOptions.Scope.Add("email");
+ }
+
+ oidcSection.Bind(openIdConnectOptions);
+
+ openIdConnectOptions.Events.OnRedirectToIdentityProvider = context =>
+ {
+ var oidcUrl = context.Properties.GetOidcUrl();
+ if (!string.IsNullOrEmpty(oidcUrl))
+ {
+ context.ProtocolMessage.RedirectUri = oidcUrl;
+ }
+
+ return Task.CompletedTask;
+ };
+
+ openIdConnectOptions.Events.OnAccessDenied = context =>
+ {
+ // Need a base URI (any) to work with relative URLs
+ var baseUri = new Uri("https://localhost");
+ var uri = new Uri(baseUri, context.ReturnUrl);
+ var returnUrl = HttpUtility.ParseQueryString(uri.Query).GetValues(context.ReturnUrlParameter)?.FirstOrDefault();
+
+ context.Response.Redirect(returnUrl ?? "/");
+ context.HandleResponse();
+
+ return Task.CompletedTask;
+ };
});
- }
+
+ serviceCollection.AddSingleton(new ExternalSignInProviderConfiguration
+ {
+ AuthenticationType = options.AuthenticationType,
+ Provider = new OidcExternalSignInProvider(options),
+ LogoUrl = options.LogoUrl,
+ });
}
}
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Web/VirtoCommerce.OpenIdConnectModule.Web.csproj b/src/VirtoCommerce.OpenIdConnectModule.Web/VirtoCommerce.OpenIdConnectModule.Web.csproj
index 233ca1d..d921069 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Web/VirtoCommerce.OpenIdConnectModule.Web.csproj
+++ b/src/VirtoCommerce.OpenIdConnectModule.Web/VirtoCommerce.OpenIdConnectModule.Web.csproj
@@ -14,9 +14,7 @@
-
-
-
+
diff --git a/src/VirtoCommerce.OpenIdConnectModule.Web/module.manifest b/src/VirtoCommerce.OpenIdConnectModule.Web/module.manifest
index e5cfe50..19c361a 100644
--- a/src/VirtoCommerce.OpenIdConnectModule.Web/module.manifest
+++ b/src/VirtoCommerce.OpenIdConnectModule.Web/module.manifest
@@ -4,16 +4,15 @@
3.800.0
- 3.849.0
-
-
-
+ 3.865.0
+
VirtoCommerce OpenIdConnect module
VirtoCommerce OpenId Connect module
Igoris Berniukevicius
+ Artem Dudarev
VirtoCommerce
diff --git a/tests/VirtoCommerce.OpenIdConnectModule.Tests/VirtoCommerce.OpenIdConnectModule.Tests.csproj b/tests/VirtoCommerce.OpenIdConnectModule.Tests/VirtoCommerce.OpenIdConnectModule.Tests.csproj
index ac1ce94..be90d1f 100644
--- a/tests/VirtoCommerce.OpenIdConnectModule.Tests/VirtoCommerce.OpenIdConnectModule.Tests.csproj
+++ b/tests/VirtoCommerce.OpenIdConnectModule.Tests/VirtoCommerce.OpenIdConnectModule.Tests.csproj
@@ -12,9 +12,12 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+