Commit c5735309 authored by Evan Read's avatar Evan Read Committed by Kati Paizee

Update OIDC topic for current conventions

parent 0599a0c1
...@@ -290,6 +290,7 @@ kanbans ...@@ -290,6 +290,7 @@ kanbans
kaniko kaniko
Karma Karma
Kerberos Kerberos
Keycloak
keyset keyset
keyspace keyspace
keytab keytab
......
...@@ -159,14 +159,14 @@ gitlab_rails['omniauth_providers'] = [ ...@@ -159,14 +159,14 @@ gitlab_rails['omniauth_providers'] = [
### Microsoft Azure ### Microsoft Azure
The OpenID Connect (OIDC) protocol for Microsoft Azure uses the [Microsoft identity platform (v2) endpoints](https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/azure-ad-endpoint-comparison). The OpenID Connect (OIDC) protocol for Microsoft Azure uses the [Microsoft identity platform (v2) endpoints](https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/azure-ad-endpoint-comparison).
To get started, sign in to the [Azure Portal](https://portal.azure.com). For your app, you'll need the To get started, sign in to the [Azure Portal](https://portal.azure.com). For your app, you need the
following information: following information:
- A tenant ID. You may already have one. For more information, review the - A tenant ID. You may already have one. For more information, review the
[Microsoft Azure Tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant) documentation. [Microsoft Azure Tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant) documentation.
- A client ID and a client secret. Follow the instructions in the - A client ID and a client secret. Follow the instructions in the
[Microsoft Quickstart Register an Application](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) documentation. [Microsoft Quickstart Register an Application](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) documentation
to obtain the tenant ID, client ID, and client secret for your app. to obtain the tenant ID, client ID, and client secret for your app.
Example Omnibus configuration block: Example Omnibus configuration block:
...@@ -199,7 +199,7 @@ Microsoft has documented how its platform works with [the OIDC protocol](https:/ ...@@ -199,7 +199,7 @@ Microsoft has documented how its platform works with [the OIDC protocol](https:/
While GitLab works with [Azure Active Directory B2C](https://docs.microsoft.com/en-us/azure/active-directory-b2c/overview), it requires special While GitLab works with [Azure Active Directory B2C](https://docs.microsoft.com/en-us/azure/active-directory-b2c/overview), it requires special
configuration to work. To get started, sign in to the [Azure Portal](https://portal.azure.com). configuration to work. To get started, sign in to the [Azure Portal](https://portal.azure.com).
For your app, you'll need the following information from Azure: For your app, you need the following information from Azure:
- A tenant ID. You may already have one. For more information, review the - A tenant ID. You may already have one. For more information, review the
[Microsoft Azure Tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant) documentation. [Microsoft Azure Tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant) documentation.
...@@ -216,8 +216,8 @@ In addition, ensure that [ID tokens are enabled](https://docs.microsoft.com/en-u ...@@ -216,8 +216,8 @@ In addition, ensure that [ID tokens are enabled](https://docs.microsoft.com/en-u
Add the following API permissions to the app: Add the following API permissions to the app:
1. `openid` - `openid`
1. `offline_access` - `offline_access`
#### Configure custom policies #### Configure custom policies
...@@ -240,42 +240,42 @@ but `LocalAccounts` works for authenticating against local, Active Directory acc ...@@ -240,42 +240,42 @@ but `LocalAccounts` works for authenticating against local, Active Directory acc
1. To export the `email` claim, modify the `SignUpOrSignin.xml`. Replace the following line: 1. To export the `email` claim, modify the `SignUpOrSignin.xml`. Replace the following line:
```xml ```xml
<OutputClaim ClaimTypeReferenceId="email" /> <OutputClaim ClaimTypeReferenceId="email" />
``` ```
with: with:
```xml ```xml
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" /> <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
``` ```
1. For OIDC discovery to work with B2C, the policy must be configured with an issuer compatible with the [OIDC 1. For OIDC discovery to work with B2C, the policy must be configured with an issuer compatible with the [OIDC
specification](https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.4.3). specification](https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.4.3).
See the [token compatibility settings](https://docs.microsoft.com/en-us/azure/active-directory-b2c/configure-tokens?pivots=b2c-custom-policy#token-compatibility-settings). See the [token compatibility settings](https://docs.microsoft.com/en-us/azure/active-directory-b2c/configure-tokens?pivots=b2c-custom-policy#token-compatibility-settings).
In `TrustFrameworkBase.xml` under `JwtIssuer`, set `IssuanceClaimPattern` to `AuthorityWithTfp`: In `TrustFrameworkBase.xml` under `JwtIssuer`, set `IssuanceClaimPattern` to `AuthorityWithTfp`:
```xml ```xml
<ClaimsProvider> <ClaimsProvider>
<DisplayName>Token Issuer</DisplayName> <DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles> <TechnicalProfiles>
<TechnicalProfile Id="JwtIssuer"> <TechnicalProfile Id="JwtIssuer">
<DisplayName>JWT Issuer</DisplayName> <DisplayName>JWT Issuer</DisplayName>
<Protocol Name="None" /> <Protocol Name="None" />
<OutputTokenFormat>JWT</OutputTokenFormat> <OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata> <Metadata>
<Item Key="IssuanceClaimPattern">AuthorityWithTfp</Item> <Item Key="IssuanceClaimPattern">AuthorityWithTfp</Item>
... ...
``` ```
1. Now [upload the policy](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy#upload-the-policies). Overwrite 1. Now [upload the policy](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy#upload-the-policies). Overwrite
the existing files if you are updating an existing policy. the existing files if you are updating an existing policy.
1. Determine the issuer URL using the sign-in policy. The issuer URL will be in the form: 1. Determine the issuer URL using the sign-in policy. The issuer URL is in the form:
```markdown ```markdown
https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/<YOUR-SIGN-IN-POLICY-NAME>/v2.0/ https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/<YOUR-SIGN-IN-POLICY-NAME>/v2.0/
``` ```
The policy name is lowercased in the URL. For example, `B2C_1A_signup_signin` The policy name is lowercased in the URL. For example, `B2C_1A_signup_signin`
policy appears as `b2c_1a_signup_sigin`. policy appears as `b2c_1a_signup_sigin`.
...@@ -283,63 +283,61 @@ the existing files if you are updating an existing policy. ...@@ -283,63 +283,61 @@ the existing files if you are updating an existing policy.
Note that the trailing forward slash is required. Note that the trailing forward slash is required.
1. Verify the operation of the OIDC discovery URL and issuer URL, append `.well-known/openid-configuration` 1. Verify the operation of the OIDC discovery URL and issuer URL, append `.well-known/openid-configuration`
to the issuer URL: to the issuer URL:
```markdown ```markdown
https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/<YOUR-SIGN-IN-POLICY-NAME>/v2.0/.well-known/openid-configuration https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/<YOUR-SIGN-IN-POLICY-NAME>/v2.0/.well-known/openid-configuration
``` ```
For example, if `domain` is `example.b2clogin.com` and tenant ID is `fc40c736-476c-4da1-b489-ee48cee84386`, you can use `curl` and `jq` to For example, if `domain` is `example.b2clogin.com` and tenant ID is
extract the issuer: `fc40c736-476c-4da1-b489-ee48cee84386`, you can use `curl` and `jq` to extract the issuer:
```shell ```shell
$ curl --silent "https://example.b2clogin.com/tfp/fc40c736-476c-4da1-b489-ee48cee84386/b2c_1a_signup_signin/v2.0/.well-known/openid-configuration" | jq .issuer $ curl --silent "https://example.b2clogin.com/tfp/fc40c736-476c-4da1-b489-ee48cee84386/b2c_1a_signup_signin/v2.0/.well-known/openid-configuration" | jq .issuer
"https://example.b2clogin.com/tfp/fc40c736-476c-4da1-b489-ee48cee84386/b2c_1a_signup_signin/v2.0/" "https://example.b2clogin.com/tfp/fc40c736-476c-4da1-b489-ee48cee84386/b2c_1a_signup_signin/v2.0/"
``` ```
1. Configure the issuer URL with the custom policy used for 1. Configure the issuer URL with the custom policy used for `signup_signin`. For example, this is
`signup_signin`. For example, this is the Omnibus configuration with a the Omnibus configuration with a custom policy for `b2c_1a_signup_signin`:
custom policy for `b2c_1a_signup_signin`:
```ruby ```ruby
gitlab_rails['omniauth_providers'] = [ gitlab_rails['omniauth_providers'] = [
{ {
'name' => 'openid_connect', 'name' => 'openid_connect',
'label' => 'Azure B2C OIDC', 'label' => 'Azure B2C OIDC',
'args' => { 'args' => {
'name' => 'openid_connect', 'name' => 'openid_connect',
'scope' => ['openid'], 'scope' => ['openid'],
'response_mode' => 'query', 'response_mode' => 'query',
'response_type' => 'id_token', 'response_type' => 'id_token',
'issuer' => 'https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/b2c_1a_signup_signin/v2.0/', 'issuer' => 'https://<YOUR-DOMAIN>/tfp/<YOUR-TENANT-ID>/b2c_1a_signup_signin/v2.0/',
'client_auth_method' => 'query', 'client_auth_method' => 'query',
'discovery' => true, 'discovery' => true,
'send_scope_to_token_endpoint' => true, 'send_scope_to_token_endpoint' => true,
'client_options' => { 'client_options' => {
'identifier' => '<YOUR APP CLIENT ID>', 'identifier' => '<YOUR APP CLIENT ID>',
'secret' => '<YOUR APP CLIENT SECRET>', 'secret' => '<YOUR APP CLIENT SECRET>',
'redirect_uri' => 'https://gitlab.example.com/users/auth/openid_connect/callback' 'redirect_uri' => 'https://gitlab.example.com/users/auth/openid_connect/callback'
} }
} }
}] }]
``` ```
#### Troubleshooting Azure B2C #### Troubleshooting Azure B2C
- Ensure all occurrences of `yourtenant.onmicrosoft.com`, `ProxyIdentityExperienceFrameworkAppId`, and `IdentityExperienceFrameworkAppId` match your B2C tenant hostname and - Ensure all occurrences of `yourtenant.onmicrosoft.com`, `ProxyIdentityExperienceFrameworkAppId`, and `IdentityExperienceFrameworkAppId` match your B2C tenant hostname and
the respective client IDs in the XML policy files. the respective client IDs in the XML policy files.
- Add `https://jwt.ms` as a redirect URI to the app, and use the [custom policy tester](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy#test-the-custom-policy). - Add `https://jwt.ms` as a redirect URI to the app, and use the [custom policy tester](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy#test-the-custom-policy).
Make sure the payload includes `email` that matches the user's email access. Make sure the payload includes `email` that matches the user's email access.
- After you enable the custom policy, users might see "Invalid username or password" after they try to sign in. This might be a configuration - After you enable the custom policy, users might see "Invalid username or password" after they try to sign in. This might be a configuration
issue with the `IdentityExperienceFramework` app. See [this Microsoft comment](https://docs.microsoft.com/en-us/answers/questions/50355/unable-to-sign-on-using-custom-policy.html?childToView=122370#comment-122370) issue with the `IdentityExperienceFramework` app. See [this Microsoft comment](https://docs.microsoft.com/en-us/answers/questions/50355/unable-to-sign-on-using-custom-policy.html?childToView=122370#comment-122370)
that suggests checking that the app manifest contains these settings: that suggests checking that the app manifest contains these settings:
- `"accessTokenAcceptedVersion": null` - `"accessTokenAcceptedVersion": null`
- `"signInAudience": "AzureADMyOrg"` - `"signInAudience": "AzureADMyOrg"`
Note that this configuration corresponds with the `Supported account types` setting used when creating the `IdentityExperienceFramework` app. Note that this configuration corresponds with the `Supported account types` setting used when
creating the `IdentityExperienceFramework` app.
#### Keycloak #### Keycloak
...@@ -347,10 +345,9 @@ GitLab works with OpenID providers that use HTTPS. Although a Keycloak ...@@ -347,10 +345,9 @@ GitLab works with OpenID providers that use HTTPS. Although a Keycloak
server can be set up using HTTP, GitLab can only communicate server can be set up using HTTP, GitLab can only communicate
with a Keycloak server that uses HTTPS. with a Keycloak server that uses HTTPS.
We highly recommend configuring Keycloak to use public key encryption We highly recommend configuring Keycloak to use public key encryption algorithms (for example,
algorithms (for example, RSA256, RSA512, and so on) instead of symmetric key RSA256, RSA512, and so on) instead of symmetric key encryption algorithms (for example, HS256 or HS358) to
encryption algorithms (for example, HS256 or HS358) to sign tokens. Public key sign tokens. Public key encryption algorithms are:
encryption algorithms are:
- Easier to configure. - Easier to configure.
- More secure because leaking the private key has severe security consequences. - More secure because leaking the private key has severe security consequences.
...@@ -393,78 +390,73 @@ encryption should only be used when absolutely necessary. ...@@ -393,78 +390,73 @@ encryption should only be used when absolutely necessary.
To use symmetric key encryption: To use symmetric key encryption:
1. Extract the secret key from the Keycloak database. Keycloak doesn't 1. Extract the secret key from the Keycloak database. Keycloak doesn't expose this value in the Web
expose this value in the Web interface. The client secret seen in the interface. The client secret seen in the Web interface is the OAuth2 client secret, which is
Web interface is the OAuth2 client secret, which is different from the different from the secret used to sign JSON Web Tokens.
secret used to sign JSON Web Tokens.
For example, if you're using PostgreSQL as the backend database for Keycloak, log in to the
For example, if you're using PostgreSQL as the backend database for database console and extract the key via this SQL query:
Keycloak, login to the database console and extract the key via this SQL
query: ```sql
$ psql -U keycloak
```sql psql (13.3 (Debian 13.3-1.pgdg100+1))
$ psql -U keycloak Type "help" for help.
psql (13.3 (Debian 13.3-1.pgdg100+1))
Type "help" for help. keycloak=# SELECT c.name, value FROM component_config CC INNER JOIN component C ON(CC.component_id = C.id) WHERE C.realm_id = 'master' and provider_id = 'hmac-generated' AND CC.name = 'secret';
-[ RECORD 1 ]---------------------------------------------------------------------------------
keycloak=# SELECT c.name, value FROM component_config CC INNER JOIN component C ON(CC.component_id = C.id) WHERE C.realm_id = 'master' and provider_id = 'hmac-generated' AND CC.name = 'secret'; name | hmac-generated
-[ RECORD 1 ]--------------------------------------------------------------------------------- value | lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62-sqGc8drp3XW-wr93zru8PFsQokHZZuJJbaUXvmiOftCZM3C4KW3-g
name | hmac-generated -[ RECORD 2 ]---------------------------------------------------------------------------------
value | lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62-sqGc8drp3XW-wr93zru8PFsQokHZZuJJbaUXvmiOftCZM3C4KW3-g name | fallback-HS384
-[ RECORD 2 ]--------------------------------------------------------------------------------- value | UfVqmIs--U61UYsRH-NYBH3_mlluLONpg_zN7CXEwkJcO9xdRNlzZfmfDLPtf2xSTMvqu08R2VhLr-8G-oZ47A
name | fallback-HS384 ```
value | UfVqmIs--U61UYsRH-NYBH3_mlluLONpg_zN7CXEwkJcO9xdRNlzZfmfDLPtf2xSTMvqu08R2VhLr-8G-oZ47A
``` In this example, there are two private keys: one for HS256 (`hmac-generated`), and another for
HS384 (`fallback-HS384`). We use the first `value` to configure GitLab.
In this example, there are two private keys: one for HS256
(`hmac-generated`), and another for HS384 (`fallback-HS384`). We'll use 1. Convert `value` to standard base64. As [discussed in the post](https://keycloak.discourse.group/t/invalid-signature-with-hs256-token/3228/9),
the first `value` to configure GitLab. `value` is encoded in ["Base 64 Encoding with URL and Filename Safe Alphabet" in RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
This needs to be converted to [standard base64 as defined in RFC 2045](https://datatracker.ietf.org/doc/html/rfc2045).
1. Convert `value` to standard base64. As [discussed in the The following Ruby script does this:
post](https://keycloak.discourse.group/t/invalid-signature-with-hs256-token/3228/9),
`value` is encoded in ["Base 64 Encoding with URL and Filename Safe ```ruby
Alphabet" in RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5). This require 'base64'
needs to be converted to [standard base64 as defined in RFC 2045](https://datatracker.ietf.org/doc/html/rfc2045). The following Ruby
script does this: value = "lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62-sqGc8drp3XW-wr93zru8PFsQokHZZuJJbaUXvmiOftCZM3C4KW3-g"
Base64.encode64(Base64.urlsafe_decode64(value))
```ruby ```
require 'base64'
This results in the following value:
value = "lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62-sqGc8drp3XW-wr93zru8PFsQokHZZuJJbaUXvmiOftCZM3C4KW3-g"
Base64.encode64(Base64.urlsafe_decode64(value)) ```markdown
``` lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62+sqGc8drp3XW+wr93zru8PFsQokH\nZZuJJbaUXvmiOftCZM3C4KW3+g==\n
```
This results in the following value:
```markdown
lo6cqjD6Ika8pk7qc3fpFx9ysrhf7E62+sqGc8drp3XW+wr93zru8PFsQokH\nZZuJJbaUXvmiOftCZM3C4KW3+g==\n
```
1. Specify this base64-encoded secret in `jwt_secret_base64`. For example: 1. Specify this base64-encoded secret in `jwt_secret_base64`. For example:
```ruby ```ruby
gitlab_rails['omniauth_providers'] = [ gitlab_rails['omniauth_providers'] = [
{ {
'name' => 'openid_connect', 'name' => 'openid_connect',
'label' => 'Keycloak', 'label' => 'Keycloak',
'args' => { 'args' => {
'name' => 'openid_connect', 'name' => 'openid_connect',
'scope' => ['openid', 'profile', 'email'], 'scope' => ['openid', 'profile', 'email'],
'response_type' => 'code', 'response_type' => 'code',
'issuer' => 'https://keycloak.example.com/auth/realms/myrealm', 'issuer' => 'https://keycloak.example.com/auth/realms/myrealm',
'client_auth_method' => 'query', 'client_auth_method' => 'query',
'discovery' => true, 'discovery' => true,
'uid_field' => 'preferred_username', 'uid_field' => 'preferred_username',
'jwt_secret_base64' => '<YOUR BASE64-ENCODED SECRET>', 'jwt_secret_base64' => '<YOUR BASE64-ENCODED SECRET>',
'client_options' => { 'client_options' => {
'identifier' => '<YOUR CLIENT ID>', 'identifier' => '<YOUR CLIENT ID>',
'secret' => '<YOUR CLIENT SECRET>', 'secret' => '<YOUR CLIENT SECRET>',
'redirect_uri' => 'https://gitlab.example.com/users/auth/openid_connect/callback' 'redirect_uri' => 'https://gitlab.example.com/users/auth/openid_connect/callback'
} }
} }
} }
] ]
``` ```
If after reconfiguring, you see the error `JSON::JWS::VerificationFailed` error message, this means If after reconfiguring, you see the error `JSON::JWS::VerificationFailed` error message, this means
the incorrect secret was specified. the incorrect secret was specified.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment