diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fc8f1dd..1a74b77 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,14 +9,14 @@ # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # -name: "CodeQL" +name: 'CodeQL' on: push: - branches: [ master ] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [master] schedule: - cron: '42 23 * * 3' @@ -32,57 +32,56 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'csharp', 'javascript' ] + language: ['csharp', 'javascript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 - - name: Setup NodeJS version - uses: actions/setup-node@v2-beta - with: - node-version: '14' + - name: Setup NodeJS version + uses: actions/setup-node@v2-beta + with: + node-version: '14' - - name: Setup dotnet version - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '6.0.x' + - name: Setup dotnet version + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '6.0.x' - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - if: ${{ matrix.language == 'javascript' }} - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + if: ${{ matrix.language == 'javascript' }} + uses: github/codeql-action/autobuild@v1 + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + - name: CS Build + if: ${{ matrix.language == 'csharp' }} + run: | + curl -L https://raw.githubusercontent.com/DuendeSoftware/IdentityServer.Quickstart.UI/main/getmain.sh | bash + dotnet clean OpenIdConnectServerMock.csproj + dotnet restore OpenIdConnectServerMock.csproj + dotnet build --no-incremental /p:UseSharedCompilation=false OpenIdConnectServerMock.csproj + working-directory: ./src - - name: CS Build - if: ${{ matrix.language == 'csharp' }} - run: | - ./getmain.sh - dotnet clean OpenIdConnectServerMock.csproj - dotnet restore OpenIdConnectServerMock.csproj - dotnet build --no-incremental /p:UseSharedCompilation=false OpenIdConnectServerMock.csproj - working-directory: ./src - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.gitignore b/.gitignore index dc20bd2..694d86e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,5 @@ obj .docker # UI -Quickstart -Views -wwwroot +src/Pages +src/wwwroot diff --git a/README.md b/README.md index 33ee1a5..c05519b 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,11 @@ services: "CheckSessionCookieSameSiteMode": "Lax" } } - ACCOUNT_OPTIONS_INLINE: | + LOGIN_OPTIONS_INLINE: | + { + "AllowRememberLogin": false + } + LOGOUT_OPTIONS_INLINE: | { "AutomaticRedirectAfterSignOut": true } @@ -121,7 +125,8 @@ Clients configuration should be provided. Test user configuration is optional (u There are two ways to provide configuration for supported scopes, clients and users. You can either provide it inline as environment variable: - `SERVER_OPTIONS_INLINE` -- `ACCOUNT_OPTIONS_INLINE` +- `LOGIN_OPTIONS_INLINE` +- `LOGOUT_OPTIONS_INLINE` - `API_SCOPES_INLINE` - `USERS_CONFIGURATION_INLINE` - `CLIENTS_CONFIGURATION_INLINE` @@ -131,7 +136,8 @@ There are two ways to provide configuration for supported scopes, clients and us or mount volume and provide the path to configuration json as environment variable: - `SERVER_OPTIONS_PATH` -- `ACCOUNT_OPTIONS_PATH` +- `LOGIN_OPTIONS_PATH` +- `LOGOUT_OPTIONS_PATH` - `API_SCOPES_PATH` - `USERS_CONFIGURATION_PATH` - `CLIENTS_CONFIGURATION_PATH` diff --git a/e2e/config/account-options.json b/e2e/config/account-options.json deleted file mode 100644 index 3eb27a6..0000000 --- a/e2e/config/account-options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "AutomaticRedirectAfterSignOut": true -} diff --git a/e2e/config/clients.json b/e2e/config/clients.json index 618efaf..2303269 100644 --- a/e2e/config/clients.json +++ b/e2e/config/clients.json @@ -19,11 +19,12 @@ "Claims": [ { "Type": "string_claim", - "Value": "string_claim_value" + "Value": "string_claim_value", + "ValueType": "string" }, { "Type": "json_claim", - "Value": "['value1', 'value2']", + "Value": "[\"value1\", \"value2\"]", "ValueType": "json" } ] @@ -38,7 +39,8 @@ "Claims": [ { "Type": "string_claim", - "Value": "string_claim_value" + "Value": "string_claim_value", + "ValueType": "string" }, { "Type": "json_claim", diff --git a/e2e/config/users.yaml b/e2e/config/users.yaml index 3801020..d394e85 100644 --- a/e2e/config/users.yaml +++ b/e2e/config/users.yaml @@ -1,95 +1,58 @@ [ + { 'SubjectId': 'simple_user', 'Username': 'simple_user', 'Password': 'pwd' }, { - "SubjectId": "simple_user", - "Username": "simple_user", - "Password": "pwd" + 'SubjectId': 'user_with_standard_claims', + 'Username': 'user_with_standard_claims', + 'Password': 'pwd', + 'Claims': + [ + { 'Type': 'name', 'Value': 'John Smith', 'ValueType': 'string' }, + { 'Type': 'email', 'Value': 'john.smith@gmail.com', 'ValueType': 'emailaddress' }, + { 'Type': 'email_verified', 'Value': 'true', 'ValueType': 'boolean' }, + ], }, { - "SubjectId": "user_with_standard_claims", - "Username": "user_with_standard_claims", - "Password": "pwd", - "Claims": [ - { - "Type": "name", - "Value": "John Smith" - }, - { - "Type": "email", - "Value": "john.smith@gmail.com" - }, - { - "Type": "email_verified", - "Value": "true" - } - ] + 'SubjectId': 'user_with_custom_identity_claims', + 'Username': 'user_with_custom_identity_claims', + 'Password': 'pwd', + 'Claims': + [ + { 'Type': 'name', 'Value': 'Jack Sparrow', 'ValueType': 'string' }, + { 'Type': 'email', 'Value': 'jack.sparrow@gmail.com', 'ValueType': 'emailaddress' }, + { 'Type': 'some-custom-identity-user-claim', 'Value': "Jack's Custom User Claim", 'ValueType': 'string' }, + ], }, { - "SubjectId": "user_with_custom_identity_claims", - "Username": "user_with_custom_identity_claims", - "Password": "pwd", - "Claims": [ - { - "Type": "name", - "Value": "Jack Sparrow" - }, - { - "Type": "email", - "Value": "jack.sparrow@gmail.com" - }, - { - "Type": "some-custom-identity-user-claim", - "Value": "Jack's Custom User Claim" - } - ] + 'SubjectId': 'user_with_custom_api_resource_claims', + 'Username': 'user_with_custom_api_resource_claims', + 'Password': 'pwd', + 'Claims': + [ + { 'Type': 'name', 'Value': 'Sam Tailor', 'ValueType': 'string' }, + { 'Type': 'email', 'Value': 'sam.tailor@gmail.com', 'ValueType': 'emailaddress' }, + { 'Type': 'some-app-user-custom-claim', 'Value': "Sam's Custom User Claim", 'ValueType': 'string' }, + { + 'Type': 'some-app-scope-1-custom-user-claim', + 'Value': "Sam's Scope Custom User Claim", + 'ValueType': 'string', + }, + ], }, { - "SubjectId": "user_with_custom_api_resource_claims", - "Username": "user_with_custom_api_resource_claims", - "Password": "pwd", - "Claims": [ - { - "Type": "name", - "Value": "Sam Tailor" - }, - { - "Type": "email", - "Value": "sam.tailor@gmail.com" - }, - { - "Type": "some-app-user-custom-claim", - "Value": "Sam's Custom User Claim" - }, - { - "Type": "some-app-scope-1-custom-user-claim", - "Value": "Sam's Scope Custom User Claim" - } - ] + 'SubjectId': 'user_with_all_claim_types', + 'Username': 'user_with_all_claim_types', + 'Password': 'pwd', + 'Claims': + [ + { 'Type': 'name', 'Value': 'Oliver Hunter', 'ValueType': 'string' }, + { 'Type': 'email', 'Value': 'oliver.hunter@gmail.com', 'ValueType': 'emailaddress' }, + { 'Type': 'some-app-user-custom-claim', 'Value': "Oliver's Custom User Claim", 'ValueType': 'string' }, + { + 'Type': 'some-app-scope-1-custom-user-claim', + 'Value': "Oliver's Scope Custom User Claim", + 'ValueType': 'string', + }, + { 'Type': 'some-custom-identity-user-claim', 'Value': "Oliver's Custom User Claim", 'ValueType': 'string' }, + ], }, - { - "SubjectId": "user_with_all_claim_types", - "Username": "user_with_all_claim_types", - "Password": "pwd", - "Claims": [ - { - "Type": "name", - "Value": "Oliver Hunter" - }, - { - "Type": "email", - "Value": "oliver.hunter@gmail.com" - }, - { - "Type": "some-app-user-custom-claim", - "Value": "Oliver's Custom User Claim" - }, - { - "Type": "some-app-scope-1-custom-user-claim", - "Value": "Oliver's Scope Custom User Claim" - }, - { - "Type": "some-custom-identity-user-claim", - "Value": "Oliver's Custom User Claim" - } - ] - } ] diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index d7a19b7..83b9b71 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -10,7 +10,14 @@ services: ASPNETCORE_Kestrel__Certificates__Default__Password: oidc-server-mock-pwd ASPNETCORE_Kestrel__Certificates__Default__Path: /https/aspnetapp.pfx SERVER_OPTIONS_PATH: /config/server-options.json - ACCOUNT_OPTIONS_PATH: /config/account-options.json + LOGIN_OPTIONS_INLINE: | + { + "AllowRememberLogin": false + } + LOGOUT_OPTIONS_INLINE: | + { + "AutomaticRedirectAfterSignOut": true + } API_RESOURCES_PATH: /config/api-resources.yaml API_SCOPES_INLINE: | - Name: some-app-scope-1 diff --git a/e2e/helpers/authorization-endpoint.ts b/e2e/helpers/authorization-endpoint.ts index 9494a2c..0d18025 100644 --- a/e2e/helpers/authorization-endpoint.ts +++ b/e2e/helpers/authorization-endpoint.ts @@ -7,9 +7,9 @@ export default async (page: Page, parameters: URLSearchParams, user: User, redir const response = await page.goto(url); expect(response.ok()).toBeTruthy(); - await page.waitForSelector('#Username'); - await page.type('#Username', user.Username); - await page.type('#Password', user.Password); + await page.waitForSelector('[id=Input_Username]'); + await page.type('[id=Input_Username]', user.Username); + await page.type('[id=Input_Password]', user.Password); await page.keyboard.press('Enter'); await page.waitForNavigation(); const redirectedUrl = new URL(page.url()); diff --git a/e2e/helpers/grants.ts b/e2e/helpers/grants.ts index ac395ea..faa5b3e 100644 --- a/e2e/helpers/grants.ts +++ b/e2e/helpers/grants.ts @@ -6,9 +6,9 @@ export default async (page: Page, user: User): Promise => { const response = await page.goto(process.env.OIDC_GRANTS_URL); expect(response.ok()).toBeTruthy(); - await page.waitForSelector('#Username'); - await page.type('#Username', user.Username); - await page.type('#Password', user.Password); + await page.waitForSelector('[id=Input_Username]'); + await page.type('[id=Input_Username]', user.Username); + await page.type('[id=Input_Password]', user.Password); await page.keyboard.press('Enter'); await page.waitForNavigation(); expect(await page.content()).toMatchSnapshot(); diff --git a/e2e/tests/custom-endpoints/__snapshots__/user-management.spec.ts.snap b/e2e/tests/custom-endpoints/__snapshots__/user-management.spec.ts.snap index 0418847..1069200 100644 --- a/e2e/tests/custom-endpoints/__snapshots__/user-management.spec.ts.snap +++ b/e2e/tests/custom-endpoints/__snapshots__/user-management.spec.ts.snap @@ -4,6 +4,7 @@ exports[`User management Introspection Endpoint 1`] = ` { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": { "inverse": false @@ -15,7 +16,6 @@ exports[`User management Introspection Endpoint 1`] = ` "some-app-scope-1-custom-user-claim": { "inverse": false }, - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -27,6 +27,16 @@ exports[`User management Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", + "scope": [ + "email", + "openid", + "profile", + "some-app-scope-1", + "some-custom-identity" + ], + "amr": [ + "pwd" + ], "client_id": "password-flow-client-id", "sub": { "inverse": false @@ -37,17 +47,7 @@ exports[`User management Token Endpoint 1`] = ` }, "some-app-scope-1-custom-user-claim": { "inverse": false - }, - "scope": [ - "email", - "openid", - "profile", - "some-app-scope-1", - "some-custom-identity" - ], - "amr": [ - "pwd" - ] + } } `; diff --git a/e2e/tests/custom-endpoints/user-management.spec.ts b/e2e/tests/custom-endpoints/user-management.spec.ts index afb9fbf..cf70808 100644 --- a/e2e/tests/custom-endpoints/user-management.spec.ts +++ b/e2e/tests/custom-endpoints/user-management.spec.ts @@ -111,7 +111,7 @@ describe('User management', () => { email: expect.any(String), ['some-custom-identity-user-claim']: expect.any(String), }); - }); + }, 10000); test('Introspection Endpoint', async () => { await introspectEndpoint(token, 'some-app', { diff --git a/e2e/tests/flows/__snapshots__/authorization-code-pkce.e2e-spec.ts.snap b/e2e/tests/flows/__snapshots__/authorization-code-pkce.e2e-spec.ts.snap index d234ded..2920e1b 100644 --- a/e2e/tests/flows/__snapshots__/authorization-code-pkce.e2e-spec.ts.snap +++ b/e2e/tests/flows/__snapshots__/authorization-code-pkce.e2e-spec.ts.snap @@ -4,10 +4,10 @@ exports[`Authorization Code Flow (with PKCE) - simple_user - Introspection Endpo { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-with-pkce-client-id", "sub": "simple_user", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -19,9 +19,6 @@ exports[`Authorization Code Flow (with PKCE) - simple_user - Token Endpoint 1`] "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-with-pkce-client-id", - "sub": "simple_user", - "idp": "local", "scope": [ "openid", "profile", @@ -31,7 +28,10 @@ exports[`Authorization Code Flow (with PKCE) - simple_user - Token Endpoint 1`] ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-with-pkce-client-id", + "sub": "simple_user", + "idp": "local" } `; @@ -45,12 +45,12 @@ exports[`Authorization Code Flow (with PKCE) - user_with_all_claim_types - Intro { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-with-pkce-client-id", "sub": "user_with_all_claim_types", "idp": "local", "some-app-user-custom-claim": "Oliver's Custom User Claim", "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -62,11 +62,6 @@ exports[`Authorization Code Flow (with PKCE) - user_with_all_claim_types - Token "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-with-pkce-client-id", - "sub": "user_with_all_claim_types", - "idp": "local", - "some-app-user-custom-claim": "Oliver's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -76,7 +71,12 @@ exports[`Authorization Code Flow (with PKCE) - user_with_all_claim_types - Token ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-with-pkce-client-id", + "sub": "user_with_all_claim_types", + "idp": "local", + "some-app-user-custom-claim": "Oliver's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim" } `; @@ -93,12 +93,12 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_api_resource_cla { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-with-pkce-client-id", "sub": "user_with_custom_api_resource_claims", "idp": "local", "some-app-user-custom-claim": "Sam's Custom User Claim", "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -110,11 +110,6 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_api_resource_cla "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-with-pkce-client-id", - "sub": "user_with_custom_api_resource_claims", - "idp": "local", - "some-app-user-custom-claim": "Sam's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -124,7 +119,12 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_api_resource_cla ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-with-pkce-client-id", + "sub": "user_with_custom_api_resource_claims", + "idp": "local", + "some-app-user-custom-claim": "Sam's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim" } `; @@ -140,10 +140,10 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_identity_claims { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-with-pkce-client-id", "sub": "user_with_custom_identity_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -155,9 +155,6 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_identity_claims "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-with-pkce-client-id", - "sub": "user_with_custom_identity_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -167,7 +164,10 @@ exports[`Authorization Code Flow (with PKCE) - user_with_custom_identity_claims ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-with-pkce-client-id", + "sub": "user_with_custom_identity_claims", + "idp": "local" } `; @@ -184,10 +184,10 @@ exports[`Authorization Code Flow (with PKCE) - user_with_standard_claims - Intro { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-with-pkce-client-id", "sub": "user_with_standard_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -199,9 +199,6 @@ exports[`Authorization Code Flow (with PKCE) - user_with_standard_claims - Token "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-with-pkce-client-id", - "sub": "user_with_standard_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -211,7 +208,10 @@ exports[`Authorization Code Flow (with PKCE) - user_with_standard_claims - Token ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-with-pkce-client-id", + "sub": "user_with_standard_claims", + "idp": "local" } `; diff --git a/e2e/tests/flows/__snapshots__/authorization-code.e2e-spec.ts.snap b/e2e/tests/flows/__snapshots__/authorization-code.e2e-spec.ts.snap index 69902e9..3ddf9d0 100644 --- a/e2e/tests/flows/__snapshots__/authorization-code.e2e-spec.ts.snap +++ b/e2e/tests/flows/__snapshots__/authorization-code.e2e-spec.ts.snap @@ -4,10 +4,10 @@ exports[`Authorization Code Flow - simple_user - Introspection Endpoint 1`] = ` { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-client-id", "sub": "simple_user", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -19,9 +19,6 @@ exports[`Authorization Code Flow - simple_user - Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-client-id", - "sub": "simple_user", - "idp": "local", "scope": [ "openid", "profile", @@ -31,7 +28,10 @@ exports[`Authorization Code Flow - simple_user - Token Endpoint 1`] = ` ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-client-id", + "sub": "simple_user", + "idp": "local" } `; @@ -45,12 +45,12 @@ exports[`Authorization Code Flow - user_with_all_claim_types - Introspection End { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-client-id", "sub": "user_with_all_claim_types", "idp": "local", "some-app-user-custom-claim": "Oliver's Custom User Claim", "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -62,11 +62,6 @@ exports[`Authorization Code Flow - user_with_all_claim_types - Token Endpoint 1` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-client-id", - "sub": "user_with_all_claim_types", - "idp": "local", - "some-app-user-custom-claim": "Oliver's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -76,7 +71,12 @@ exports[`Authorization Code Flow - user_with_all_claim_types - Token Endpoint 1` ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-client-id", + "sub": "user_with_all_claim_types", + "idp": "local", + "some-app-user-custom-claim": "Oliver's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim" } `; @@ -93,12 +93,12 @@ exports[`Authorization Code Flow - user_with_custom_api_resource_claims - Intros { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-client-id", "sub": "user_with_custom_api_resource_claims", "idp": "local", "some-app-user-custom-claim": "Sam's Custom User Claim", "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -110,11 +110,6 @@ exports[`Authorization Code Flow - user_with_custom_api_resource_claims - Token "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-client-id", - "sub": "user_with_custom_api_resource_claims", - "idp": "local", - "some-app-user-custom-claim": "Sam's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -124,7 +119,12 @@ exports[`Authorization Code Flow - user_with_custom_api_resource_claims - Token ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-client-id", + "sub": "user_with_custom_api_resource_claims", + "idp": "local", + "some-app-user-custom-claim": "Sam's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim" } `; @@ -140,10 +140,10 @@ exports[`Authorization Code Flow - user_with_custom_identity_claims - Introspect { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-client-id", "sub": "user_with_custom_identity_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -155,9 +155,6 @@ exports[`Authorization Code Flow - user_with_custom_identity_claims - Token Endp "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-client-id", - "sub": "user_with_custom_identity_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -167,7 +164,10 @@ exports[`Authorization Code Flow - user_with_custom_identity_claims - Token Endp ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-client-id", + "sub": "user_with_custom_identity_claims", + "idp": "local" } `; @@ -184,10 +184,10 @@ exports[`Authorization Code Flow - user_with_standard_claims - Introspection End { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "authorization-code-client-id", "sub": "user_with_standard_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -199,9 +199,6 @@ exports[`Authorization Code Flow - user_with_standard_claims - Token Endpoint 1` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "authorization-code-client-id", - "sub": "user_with_standard_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -211,7 +208,10 @@ exports[`Authorization Code Flow - user_with_standard_claims - Token Endpoint 1` ], "amr": [ "pwd" - ] + ], + "client_id": "authorization-code-client-id", + "sub": "user_with_standard_claims", + "idp": "local" } `; diff --git a/e2e/tests/flows/__snapshots__/client-credentials-flow.spec.ts.snap b/e2e/tests/flows/__snapshots__/client-credentials-flow.spec.ts.snap index 7f1fbe4..9a9de63 100644 --- a/e2e/tests/flows/__snapshots__/client-credentials-flow.spec.ts.snap +++ b/e2e/tests/flows/__snapshots__/client-credentials-flow.spec.ts.snap @@ -21,11 +21,11 @@ exports[`Client Credentials Flow Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "client-credentials-flow-client-id", - "string_claim": "string_claim_value", "scope": [ "some-app-scope-1" ], + "client_id": "client-credentials-flow-client-id", + "string_claim": "string_claim_value", "json_claim": [ "value1", "value2" diff --git a/e2e/tests/flows/__snapshots__/implicit-flow.e2e-spec.ts.snap b/e2e/tests/flows/__snapshots__/implicit-flow.e2e-spec.ts.snap index c37cbc7..090f421 100644 --- a/e2e/tests/flows/__snapshots__/implicit-flow.e2e-spec.ts.snap +++ b/e2e/tests/flows/__snapshots__/implicit-flow.e2e-spec.ts.snap @@ -6,13 +6,12 @@ exports[`Implicit Flow - simple_user - Authorization Endpoint (id_token only) 1` "typ": "JWT", "iss": "https://localhost:8443", "aud": "implicit-flow-client-id", - "nonce": "xyz", - "s_hash": "ungWv48Bz-pBQUDeXa4iIw", - "sub": "simple_user", - "idp": "local", "amr": [ "pwd" - ] + ], + "nonce": "xyz", + "sub": "simple_user", + "idp": "local" } `; @@ -22,9 +21,6 @@ exports[`Implicit Flow - simple_user - Authorization Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "implicit-flow-client-id", - "sub": "simple_user", - "idp": "local", "scope": [ "openid", "profile", @@ -34,7 +30,10 @@ exports[`Implicit Flow - simple_user - Authorization Endpoint 1`] = ` ], "amr": [ "pwd" - ] + ], + "client_id": "implicit-flow-client-id", + "sub": "simple_user", + "idp": "local" } `; @@ -42,10 +41,10 @@ exports[`Implicit Flow - simple_user - Introspection Endpoint 1`] = ` { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "implicit-flow-client-id", "sub": "simple_user", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -63,16 +62,15 @@ exports[`Implicit Flow - user_with_all_claim_types - Authorization Endpoint (id_ "typ": "JWT", "iss": "https://localhost:8443", "aud": "implicit-flow-client-id", + "amr": [ + "pwd" + ], "nonce": "xyz", - "s_hash": "ungWv48Bz-pBQUDeXa4iIw", "sub": "user_with_all_claim_types", "idp": "local", "name": "Oliver Hunter", "email": "oliver.hunter@gmail.com", - "some-custom-identity-user-claim": "Oliver's Custom User Claim", - "amr": [ - "pwd" - ] + "some-custom-identity-user-claim": "Oliver's Custom User Claim" } `; @@ -82,11 +80,6 @@ exports[`Implicit Flow - user_with_all_claim_types - Authorization Endpoint 1`] "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "implicit-flow-client-id", - "sub": "user_with_all_claim_types", - "idp": "local", - "some-app-user-custom-claim": "Oliver's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -96,7 +89,12 @@ exports[`Implicit Flow - user_with_all_claim_types - Authorization Endpoint 1`] ], "amr": [ "pwd" - ] + ], + "client_id": "implicit-flow-client-id", + "sub": "user_with_all_claim_types", + "idp": "local", + "some-app-user-custom-claim": "Oliver's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim" } `; @@ -104,12 +102,12 @@ exports[`Implicit Flow - user_with_all_claim_types - Introspection Endpoint 1`] { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "implicit-flow-client-id", "sub": "user_with_all_claim_types", "idp": "local", "some-app-user-custom-claim": "Oliver's Custom User Claim", "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -130,15 +128,14 @@ exports[`Implicit Flow - user_with_custom_api_resource_claims - Authorization En "typ": "JWT", "iss": "https://localhost:8443", "aud": "implicit-flow-client-id", + "amr": [ + "pwd" + ], "nonce": "xyz", - "s_hash": "ungWv48Bz-pBQUDeXa4iIw", "sub": "user_with_custom_api_resource_claims", "idp": "local", "name": "Sam Tailor", - "email": "sam.tailor@gmail.com", - "amr": [ - "pwd" - ] + "email": "sam.tailor@gmail.com" } `; @@ -148,11 +145,6 @@ exports[`Implicit Flow - user_with_custom_api_resource_claims - Authorization En "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "implicit-flow-client-id", - "sub": "user_with_custom_api_resource_claims", - "idp": "local", - "some-app-user-custom-claim": "Sam's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", "scope": [ "openid", "profile", @@ -162,7 +154,12 @@ exports[`Implicit Flow - user_with_custom_api_resource_claims - Authorization En ], "amr": [ "pwd" - ] + ], + "client_id": "implicit-flow-client-id", + "sub": "user_with_custom_api_resource_claims", + "idp": "local", + "some-app-user-custom-claim": "Sam's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim" } `; @@ -170,12 +167,12 @@ exports[`Implicit Flow - user_with_custom_api_resource_claims - Introspection En { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "implicit-flow-client-id", "sub": "user_with_custom_api_resource_claims", "idp": "local", "some-app-user-custom-claim": "Sam's Custom User Claim", "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -195,16 +192,15 @@ exports[`Implicit Flow - user_with_custom_identity_claims - Authorization Endpoi "typ": "JWT", "iss": "https://localhost:8443", "aud": "implicit-flow-client-id", + "amr": [ + "pwd" + ], "nonce": "xyz", - "s_hash": "ungWv48Bz-pBQUDeXa4iIw", "sub": "user_with_custom_identity_claims", "idp": "local", "name": "Jack Sparrow", "email": "jack.sparrow@gmail.com", - "some-custom-identity-user-claim": "Jack's Custom User Claim", - "amr": [ - "pwd" - ] + "some-custom-identity-user-claim": "Jack's Custom User Claim" } `; @@ -214,9 +210,6 @@ exports[`Implicit Flow - user_with_custom_identity_claims - Authorization Endpoi "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "implicit-flow-client-id", - "sub": "user_with_custom_identity_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -226,7 +219,10 @@ exports[`Implicit Flow - user_with_custom_identity_claims - Authorization Endpoi ], "amr": [ "pwd" - ] + ], + "client_id": "implicit-flow-client-id", + "sub": "user_with_custom_identity_claims", + "idp": "local" } `; @@ -234,10 +230,10 @@ exports[`Implicit Flow - user_with_custom_identity_claims - Introspection Endpoi { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "implicit-flow-client-id", "sub": "user_with_custom_identity_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -258,16 +254,15 @@ exports[`Implicit Flow - user_with_standard_claims - Authorization Endpoint (id_ "typ": "JWT", "iss": "https://localhost:8443", "aud": "implicit-flow-client-id", + "amr": [ + "pwd" + ], "nonce": "xyz", - "s_hash": "ungWv48Bz-pBQUDeXa4iIw", "sub": "user_with_standard_claims", "idp": "local", "name": "John Smith", "email": "john.smith@gmail.com", - "email_verified": "true", - "amr": [ - "pwd" - ] + "email_verified": "true" } `; @@ -277,9 +272,6 @@ exports[`Implicit Flow - user_with_standard_claims - Authorization Endpoint 1`] "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "implicit-flow-client-id", - "sub": "user_with_standard_claims", - "idp": "local", "scope": [ "openid", "profile", @@ -289,7 +281,10 @@ exports[`Implicit Flow - user_with_standard_claims - Authorization Endpoint 1`] ], "amr": [ "pwd" - ] + ], + "client_id": "implicit-flow-client-id", + "sub": "user_with_standard_claims", + "idp": "local" } `; @@ -297,10 +292,10 @@ exports[`Implicit Flow - user_with_standard_claims - Introspection Endpoint 1`] { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "implicit-flow-client-id", "sub": "user_with_standard_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } diff --git a/e2e/tests/flows/__snapshots__/password-flow.spec.ts.snap b/e2e/tests/flows/__snapshots__/password-flow.spec.ts.snap index 97eddcb..3004aac 100644 --- a/e2e/tests/flows/__snapshots__/password-flow.spec.ts.snap +++ b/e2e/tests/flows/__snapshots__/password-flow.spec.ts.snap @@ -4,10 +4,10 @@ exports[`Password Flow - simple_user - Introspection Endpoint 1`] = ` { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": "simple_user", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -19,9 +19,6 @@ exports[`Password Flow - simple_user - Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "password-flow-client-id", - "sub": "simple_user", - "idp": "local", "scope": [ "email", "openid", @@ -31,7 +28,10 @@ exports[`Password Flow - simple_user - Token Endpoint 1`] = ` ], "amr": [ "pwd" - ] + ], + "client_id": "password-flow-client-id", + "sub": "simple_user", + "idp": "local" } `; @@ -45,12 +45,12 @@ exports[`Password Flow - user_with_all_claim_types - Introspection Endpoint 1`] { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": "user_with_all_claim_types", "idp": "local", "some-app-user-custom-claim": "Oliver's Custom User Claim", "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -62,11 +62,6 @@ exports[`Password Flow - user_with_all_claim_types - Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "password-flow-client-id", - "sub": "user_with_all_claim_types", - "idp": "local", - "some-app-user-custom-claim": "Oliver's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim", "scope": [ "email", "openid", @@ -76,7 +71,12 @@ exports[`Password Flow - user_with_all_claim_types - Token Endpoint 1`] = ` ], "amr": [ "pwd" - ] + ], + "client_id": "password-flow-client-id", + "sub": "user_with_all_claim_types", + "idp": "local", + "some-app-user-custom-claim": "Oliver's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Oliver's Scope Custom User Claim" } `; @@ -93,12 +93,12 @@ exports[`Password Flow - user_with_custom_api_resource_claims - Introspection En { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": "user_with_custom_api_resource_claims", "idp": "local", "some-app-user-custom-claim": "Sam's Custom User Claim", "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -110,11 +110,6 @@ exports[`Password Flow - user_with_custom_api_resource_claims - Token Endpoint 1 "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "password-flow-client-id", - "sub": "user_with_custom_api_resource_claims", - "idp": "local", - "some-app-user-custom-claim": "Sam's Custom User Claim", - "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim", "scope": [ "email", "openid", @@ -124,7 +119,12 @@ exports[`Password Flow - user_with_custom_api_resource_claims - Token Endpoint 1 ], "amr": [ "pwd" - ] + ], + "client_id": "password-flow-client-id", + "sub": "user_with_custom_api_resource_claims", + "idp": "local", + "some-app-user-custom-claim": "Sam's Custom User Claim", + "some-app-scope-1-custom-user-claim": "Sam's Scope Custom User Claim" } `; @@ -140,10 +140,10 @@ exports[`Password Flow - user_with_custom_identity_claims - Introspection Endpoi { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": "user_with_custom_identity_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -155,9 +155,6 @@ exports[`Password Flow - user_with_custom_identity_claims - Token Endpoint 1`] = "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "password-flow-client-id", - "sub": "user_with_custom_identity_claims", - "idp": "local", "scope": [ "email", "openid", @@ -167,7 +164,10 @@ exports[`Password Flow - user_with_custom_identity_claims - Token Endpoint 1`] = ], "amr": [ "pwd" - ] + ], + "client_id": "password-flow-client-id", + "sub": "user_with_custom_identity_claims", + "idp": "local" } `; @@ -184,10 +184,10 @@ exports[`Password Flow - user_with_standard_claims - Introspection Endpoint 1`] { "iss": "https://localhost:8443", "aud": "some-app", + "amr": "pwd", "client_id": "password-flow-client-id", "sub": "user_with_standard_claims", "idp": "local", - "amr": "pwd", "active": true, "scope": "some-app-scope-1" } @@ -199,9 +199,6 @@ exports[`Password Flow - user_with_standard_claims - Token Endpoint 1`] = ` "typ": "JWT", "iss": "https://localhost:8443", "aud": "some-app", - "client_id": "password-flow-client-id", - "sub": "user_with_standard_claims", - "idp": "local", "scope": [ "email", "openid", @@ -211,7 +208,10 @@ exports[`Password Flow - user_with_standard_claims - Token Endpoint 1`] = ` ], "amr": [ "pwd" - ] + ], + "client_id": "password-flow-client-id", + "sub": "user_with_standard_claims", + "idp": "local" } `; diff --git a/src/.dockerignore b/src/.dockerignore index d93c5bf..f36a6f2 100644 --- a/src/.dockerignore +++ b/src/.dockerignore @@ -1,8 +1,7 @@ bin/ obj/ -Quickstart -Views +Pages wwwroot Dockerfile diff --git a/src/Config.cs b/src/Config.cs index 0303195..9a83e4d 100644 --- a/src/Config.cs +++ b/src/Config.cs @@ -1,13 +1,9 @@ -using System; -using System.IO; -using System.Linq; -using System.Collections.Generic; -using IdentityServer4.Configuration; -using IdentityServer4.Models; -using IdentityServer4.Test; +using Duende.IdentityServer.Configuration; +using Duende.IdentityServer.Models; +using Duende.IdentityServer.Test; using OpenIdConnectServer.Helpers; -using YamlDotNet.Serialization; using OpenIdConnectServer.YamlConverters; +using YamlDotNet.Serialization; namespace OpenIdConnectServer { @@ -44,19 +40,19 @@ public static IdentityServerOptions GetServerOptions() return serverOptions; } - public static void ConfigureAccountOptions() + public static void ConfigureOptions(string optionsName) { - string accountOptionsStr = Environment.GetEnvironmentVariable("ACCOUNT_OPTIONS_INLINE"); - if (string.IsNullOrWhiteSpace(accountOptionsStr)) + string optionsStr = Environment.GetEnvironmentVariable($"{optionsName.ToUpper()}_OPTIONS_INLINE"); + if (string.IsNullOrWhiteSpace(optionsStr)) { - var accountOptionsFilePath = Environment.GetEnvironmentVariable("ACCOUNT_OPTIONS_PATH"); - if (string.IsNullOrWhiteSpace(accountOptionsFilePath)) + var optionsFilePath = Environment.GetEnvironmentVariable($"{optionsName.ToUpper()}_OPTIONS_PATH"); + if (string.IsNullOrWhiteSpace(optionsFilePath)) { return; } - accountOptionsStr = File.ReadAllText(accountOptionsFilePath); + optionsStr = File.ReadAllText(optionsFilePath); } - AccountOptionsHelper.ConfigureAccountOptions(accountOptionsStr); + OptionsHelper.ConfigureOptions(optionsStr); } public static IEnumerable GetServerCorsAllowedOrigins() diff --git a/src/Controllers/UserController.cs b/src/Controllers/UserController.cs index 7c506cc..f6f91b6 100644 --- a/src/Controllers/UserController.cs +++ b/src/Controllers/UserController.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Reflection; using System.Security.Claims; -using IdentityServer4.Test; +using Duende.IdentityServer.Test; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; diff --git a/src/Dockerfile b/src/Dockerfile index cb69625..b059d3e 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -6,8 +6,7 @@ RUN apt-get update && apt-get install unzip -y WORKDIR /src -COPY ./getmain.sh ./getmain.sh -RUN ./getmain.sh +RUN curl -L https://raw.githubusercontent.com/DuendeSoftware/IdentityServer.Quickstart.UI/main/getmain.sh | bash COPY ./OpenIdConnectServerMock.csproj ./OpenIdConnectServerMock.csproj RUN dotnet restore diff --git a/src/Helpers/AccountOptionsHelper.cs b/src/Helpers/AccountOptionsHelper.cs deleted file mode 100644 index 7114d9e..0000000 --- a/src/Helpers/AccountOptionsHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Serilog; - -namespace OpenIdConnectServer.Helpers -{ - public class AccountOptionsHelper - { - public static void ConfigureAccountOptions(string accountOptionsStr) - { - var accountOptions = JsonConvert.DeserializeObject(accountOptionsStr); - var targetFields = typeof(IdentityServerHost.Quickstart.UI.AccountOptions).GetFields(); - var jValueValueProp = typeof(JValue).GetProperty(nameof(JValue.Value)); - Array.ForEach(targetFields, k => { - if (accountOptions.ContainsKey(k.Name)) { - var fieldJValue = accountOptions[k.Name] as JValue; - var fieldValue = jValueValueProp.GetValue(fieldJValue); - k.SetValue(null, fieldValue); - } - }); - } - } -} \ No newline at end of file diff --git a/src/Helpers/AspNetServicesHelper.cs b/src/Helpers/AspNetServicesHelper.cs index 27ca8e2..aea5b8c 100644 --- a/src/Helpers/AspNetServicesHelper.cs +++ b/src/Helpers/AspNetServicesHelper.cs @@ -1,13 +1,10 @@ -using System.Collections.Generic; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; using AspNetCorsOptions = Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions; namespace OpenIdConnectServer.Helpers { - public class AspNetServicesOptions + public class AspNetServicesOptions { public AspNetCorsOptions Cors { get; set; } diff --git a/src/Helpers/MergeHelper.cs b/src/Helpers/MergeHelper.cs index bf8ba4d..923480e 100644 --- a/src/Helpers/MergeHelper.cs +++ b/src/Helpers/MergeHelper.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace OpenIdConnectServer.Helpers { public static class MergeHelper @@ -21,4 +18,4 @@ public static void Merge(T source, T target) } } } -} \ No newline at end of file +} diff --git a/src/Helpers/OptionsHelper.cs b/src/Helpers/OptionsHelper.cs new file mode 100644 index 0000000..3c59eb2 --- /dev/null +++ b/src/Helpers/OptionsHelper.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace OpenIdConnectServer.Helpers +{ + public class OptionsHelper + { + public static void ConfigureOptions(string optionsStr) + { + var options = JsonConvert.DeserializeObject(optionsStr); + var targetFields = typeof(T).GetFields(); + var jValueValueProp = typeof(JValue).GetProperty(nameof(JValue.Value)); + Array.ForEach(targetFields, k => { + if (options.ContainsKey(k.Name)) { + var fieldJValue = options[k.Name] as JValue; + var fieldValue = jValueValueProp.GetValue(fieldJValue); + k.SetValue(null, fieldValue); + } + }); + } + } +} diff --git a/src/JsonConverters/ClaimJsonConverter.cs b/src/JsonConverters/ClaimJsonConverter.cs index 4ee95ed..1df1aa4 100644 --- a/src/JsonConverters/ClaimJsonConverter.cs +++ b/src/JsonConverters/ClaimJsonConverter.cs @@ -1,4 +1,3 @@ -using System; using System.Security.Claims; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -25,4 +24,4 @@ public override Claim ReadJson(JsonReader reader, Type objectType, Claim existin public override bool CanRead => true; public override bool CanWrite => false; } -} \ No newline at end of file +} diff --git a/src/Middlewares/BasePathMiddleware.cs b/src/Middlewares/BasePathMiddleware.cs index 9ac9522..79eb352 100644 --- a/src/Middlewares/BasePathMiddleware.cs +++ b/src/Middlewares/BasePathMiddleware.cs @@ -1,7 +1,5 @@ -using IdentityServer4.Extensions; -using Microsoft.AspNetCore.Http; -using System.Threading.Tasks; -using IdentityServer4.Configuration; +using Duende.IdentityServer.Extensions; +using Duende.IdentityServer.Configuration; #pragma warning disable 1591 diff --git a/src/OpenIdConnectServerMock.csproj b/src/OpenIdConnectServerMock.csproj index 95f52e1..ca8678c 100644 --- a/src/OpenIdConnectServerMock.csproj +++ b/src/OpenIdConnectServerMock.csproj @@ -2,6 +2,8 @@ net6.0 + enable + enable @@ -9,10 +11,10 @@ - + - + diff --git a/src/Program.cs b/src/Program.cs index aed1565..7ba74be 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,32 +1,89 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Duende.IdentityServer.Hosting; +using OpenIdConnectServer; +using OpenIdConnectServer.Helpers; +using OpenIdConnectServer.JsonConverters; +using OpenIdConnectServer.Middlewares; +using OpenIdConnectServer.Services; +using OpenIdConnectServer.Validation; using Serilog; using Serilog.Events; using Serilog.Sinks.SystemConsole.Themes; -namespace OpenIdConnectServer -{ - public class Program - { - public static void Main(string[] args) +Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information) + .MinimumLevel.Override("System", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Code) + .CreateLogger(); + +var builder = WebApplication.CreateBuilder(args); + +// Configure Serilog +builder.Host.UseSerilog(); + +// Add services to the container. +builder.Services.AddRazorPages(); + +builder.Services + .AddControllersWithViews() + .AddNewtonsoftJson(options => { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information) - .MinimumLevel.Override("System", LogEventLevel.Warning) - .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information) - .Enrich.FromLogContext() - .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Code) - .CreateLogger(); - - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .UseSerilog() - .Build(); - } + options.SerializerSettings.Converters.Add(new ClaimJsonConverter()); + }); + +builder.Services + .AddIdentityServer(options => + { + var configuredOptions = Config.GetServerOptions(); + MergeHelper.Merge(configuredOptions, options); + }) + .AddDeveloperSigningCredential() + .AddInMemoryIdentityResources(Config.GetIdentityResources()) + .AddInMemoryApiResources(Config.GetApiResources()) + .AddInMemoryApiScopes(Config.GetApiScopes()) + .AddInMemoryClients(Config.GetClients()) + .AddTestUsers(Config.GetUsers()) + .AddRedirectUriValidator() + .AddProfileService() + .AddCorsPolicyService(); + +var app = builder.Build(); + + +var aspNetServicesOptions = Config.GetAspNetServicesOptions(); +AspNetServicesHelper.ConfigureAspNetServices(builder.Services, aspNetServicesOptions); +AspNetServicesHelper.UseAspNetServices(app, aspNetServicesOptions); + +Config.ConfigureOptions("LOGIN"); +Config.ConfigureOptions("LOGOUT"); + +app.UseDeveloperExceptionPage(); + +app.UseIdentityServer(); + +var basePath = Config.GetAspNetServicesOptions().BasePath; +if (!string.IsNullOrEmpty(basePath)) +{ + app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments(basePath), appBuilder => { + appBuilder.UseMiddleware(); + appBuilder.UseMiddleware(); + }); } + +app.UseHttpsRedirection(); +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseAuthorization(); +app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + }); + +app.MapRazorPages(); + +app.Run(); diff --git a/src/Services/CorsPolicyService.cs b/src/Services/CorsPolicyService.cs index 243ba39..db5a3c4 100644 --- a/src/Services/CorsPolicyService.cs +++ b/src/Services/CorsPolicyService.cs @@ -1,7 +1,5 @@ -using System.Linq; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using IdentityServer4.Services; +using Duende.IdentityServer.Services; namespace OpenIdConnectServer.Services { @@ -18,4 +16,4 @@ public Task IsOriginAllowedAsync(string origin) return Task.FromResult(true); } } -} \ No newline at end of file +} diff --git a/src/Services/ProfileService.cs b/src/Services/ProfileService.cs index 3dd5c86..374cb7c 100644 --- a/src/Services/ProfileService.cs +++ b/src/Services/ProfileService.cs @@ -1,15 +1,11 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using IdentityServer4.Extensions; -using IdentityServer4.Models; -using IdentityServer4.Services; -using IdentityServer4.Test; -using Microsoft.Extensions.Logging; +using Duende.IdentityServer.Extensions; +using Duende.IdentityServer.Models; +using Duende.IdentityServer.Services; +using Duende.IdentityServer.Test; namespace OpenIdConnectServer.Services { - internal class ProfileService : IProfileService + internal class ProfileService : IProfileService { private readonly TestUserStore _userStore; private readonly ILogger Logger; @@ -44,4 +40,4 @@ public Task IsActiveAsync(IsActiveContext context) return Task.CompletedTask; } } -} \ No newline at end of file +} diff --git a/src/Startup.cs b/src/Startup.cs deleted file mode 100644 index 11aa7fb..0000000 --- a/src/Startup.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using OpenIdConnectServer.Helpers; -using OpenIdConnectServer.Services; -using OpenIdConnectServer.Validation; -using OpenIdConnectServer.JsonConverters; -using Newtonsoft.Json.Serialization; -using OpenIdConnectServer.Middlewares; -using IdentityServer4.Hosting; - -namespace OpenIdConnectServer -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - services.AddControllersWithViews().AddNewtonsoftJson(options => { - options.SerializerSettings.Converters.Add(new ClaimJsonConverter()); - }); - - services.AddIdentityServer(options => - { - var configuredOptions = Config.GetServerOptions(); - MergeHelper.Merge(configuredOptions, options); - }) - .AddDeveloperSigningCredential() - .AddInMemoryIdentityResources(Config.GetIdentityResources()) - .AddInMemoryApiResources(Config.GetApiResources()) - .AddInMemoryApiScopes(Config.GetApiScopes()) - .AddInMemoryClients(Config.GetClients()) - .AddTestUsers(Config.GetUsers()) - .AddRedirectUriValidator() - .AddProfileService() - .AddCorsPolicyService(); - - var aspNetServicesOptions = Config.GetAspNetServicesOptions(); - AspNetServicesHelper.ConfigureAspNetServices(services, aspNetServicesOptions); - - Config.ConfigureAccountOptions(); - - services.AddRouting(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseDeveloperExceptionPage(); - - var aspNetServicesOptions = Config.GetAspNetServicesOptions(); - AspNetServicesHelper.UseAspNetServices(app, aspNetServicesOptions); - - app.UseIdentityServer(); - - var basePath = Config.GetAspNetServicesOptions().BasePath; - if (!string.IsNullOrEmpty(basePath)) - { - app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments(basePath), appBuilder => { - appBuilder.UseMiddleware(); - appBuilder.UseMiddleware(); - }); - } - - app.UseStaticFiles(); - app.UseRouting(); - app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute(); - }); - } - } -} diff --git a/src/Validation/RedirectUriValidator.cs b/src/Validation/RedirectUriValidator.cs index 72efb1b..effa7f4 100644 --- a/src/Validation/RedirectUriValidator.cs +++ b/src/Validation/RedirectUriValidator.cs @@ -1,9 +1,6 @@ -using System.Threading.Tasks; -using IdentityServer4.Models; -using IdentityServer4.Validation; -using System.Linq; +using Duende.IdentityServer.Models; +using Duende.IdentityServer.Validation; using System.Text.RegularExpressions; -using System.Collections.Generic; namespace OpenIdConnectServer.Validation { @@ -22,4 +19,4 @@ public Task IsRedirectUriValidAsync(string requestedUri, Client client) return Task.FromResult(Validate(requestedUri, client.RedirectUris)); } } -} \ No newline at end of file +} diff --git a/src/YamlConverters/ClaimYamlConverter.cs b/src/YamlConverters/ClaimYamlConverter.cs index 657d70d..f646764 100644 --- a/src/YamlConverters/ClaimYamlConverter.cs +++ b/src/YamlConverters/ClaimYamlConverter.cs @@ -1,7 +1,4 @@ -using System; -using System.IO; using System.Security.Claims; -using Newtonsoft.Json.Linq; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; diff --git a/src/YamlConverters/SecretYamlConverter.cs b/src/YamlConverters/SecretYamlConverter.cs index f536e25..b46c5ab 100644 --- a/src/YamlConverters/SecretYamlConverter.cs +++ b/src/YamlConverters/SecretYamlConverter.cs @@ -1,5 +1,4 @@ -using System; -using IdentityServer4.Models; +using Duende.IdentityServer.Models; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; diff --git a/src/getmain.sh b/src/getmain.sh deleted file mode 100755 index 186ffd4..0000000 --- a/src/getmain.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -e - -SOURCE="https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/archive/main.zip" -curl -L -o ui.zip "$SOURCE" - -unzip -d ui ui.zip - -[[ -d Quickstart ]] || mkdir Quickstart -[[ -d Views ]] || mkdir Views -[[ -d wwwroot ]] || mkdir wwwroot - -cp -r ./ui/IdentityServer4.Quickstart.UI-main/Quickstart/* Quickstart -cp -r ./ui/IdentityServer4.Quickstart.UI-main/Views/* Views -cp -r ./ui/IdentityServer4.Quickstart.UI-main/wwwroot/* wwwroot - -rm -rf ui ui.zip \ No newline at end of file