diff --git a/docs/development/development-environment/docker/README.md b/docs/development/development-environment/docker/README.md index e9f54ab237dc..a16792714f2e 100644 --- a/docs/development/development-environment/docker/README.md +++ b/docs/development/development-environment/docker/README.md @@ -466,7 +466,7 @@ Once the keycloak service is started and running, you can access the keycloak in and login with initial username and password as `admin`. Keycloak being an OpenID connect provider, we need to setup an OIDC integration for OpenProject. -[Setup OIDC (keycloak) integration for OpenProject](../../../installation-and-operations/misc/custom-openid-connect-providers/#keycloak) +[Setup OIDC (keycloak) integration for OpenProject](../../../system-admin-guide/authentication/openid-providers/) Once the above setup is completed, In the root `docker-compose.override.yml` file, uncomment all the environment in `backend` service for keycloak and set the values according to configuration done in keycloak for OpenProject Integration. diff --git a/docs/installation-and-operations/misc/custom-openid-connect-providers/README.md b/docs/installation-and-operations/misc/custom-openid-connect-providers/README.md index ffda2ec0a781..e260f337731a 100644 --- a/docs/installation-and-operations/misc/custom-openid-connect-providers/README.md +++ b/docs/installation-and-operations/misc/custom-openid-connect-providers/README.md @@ -1,159 +1,98 @@ # Custom OpenID Connect providers -OpenProject's admin interface only allows you to configure providers from a pre-defined list. -This includes Google Workspace and Microsoft Azure Active Directory right now. Find out how to use those in the [OpenID Providers Authentication Guide](../../../system-admin-guide/authentication/openid-providers/). +> [!IMPORTANT] +> OpenID Connect providers is an Enterprise add-on. If you do not see the button you will have to activate the Enterprise edition first. -You can still use an arbitrary provider. But for the time being there is no user interface for this. -That means you will have to do it directly using the console on the server or via environment variables. +Starting in OpenProject 15.0., you can create custom OpenID Connect providers with the user interface [OpenID Providers Authentication Guide](../../../system-admin-guide/authentication/openid-providers/). Please consult this document first for references on all configuration options. Any providers you have created in earlier versions will have been migrated and should be available from the user interface. -> **Warning**: Only do this if you know what you are doing. This may break your existing OpenID Connect authentication or cause other issues otherwise. +However, for some deployment scenarios, it might be desirable to configure a provider through environment variables. -First start the console. +> [!WARNING] +> Only do this if you know what you are doing. Otherwise this may break your existing OpenID Connect authentication or cause other issues. -```shell -sudo openproject run console -# if user the docker all-in-one container: docker exec -it openproject bundle exec rails console -# if using docker-compose: docker-compose run --rm web bundle exec rails console -``` - -Once in the console you can change the `plugin_openproject_openid_connect` setting -directly to configure arbitrary providers. - -Next define the settings for your custom provider. In this example we are configuring Okta: - -```ruby -options = { - "display_name"=>"Okta", - "host"=>"mypersonal.okta.com", - "identifier"=>"", - "secret"=>"", - "authorization_endpoint" => "/oauth2/v1/authorize", - "token_endpoint" => "/oauth2/v1/token", - "userinfo_endpoint" => "/oauth2/v1/userinfo", - "end_session_endpoint" => "https://mypersonal.okta.com/oauth2/{authorizationServerId}/v1/logout" -} -``` - -For Keycloak, settings similar to the following would be used: - -```ruby -options = { - "display_name"=>"Keycloak", - "host"=>"keycloak.example.com", - "identifier"=>"", - "secret"=>"", - "authorization_endpoint" => "/auth/realms/REALM/protocol/openid-connect/auth", - "token_endpoint" => "/auth/realms/REALM/protocol/openid-connect/token", - "userinfo_endpoint" => "/auth/realms/REALM/protocol/openid-connect/userinfo" -} -``` - -Just type this into the console and confirm by pressing *Enter*. +## Environment variables -This assumes that you have configured your application in the respective provider correctly -including the **redirect URL** which will be the following: +The provider entries are defined dynamically based on the environment keys. All variables will start with the prefix +`OPENPROJECT_OPENID__CONNECT_` followed by the provider name. For instance an Okta example would +be defined via environment variables like this: -```ruby -"#{Setting.protocol}://#{Setting.host_name}/auth/okta/callback" +```shell +OPENPROJECT_OPENID__CONNECT_OKTA_DISPLAY__NAME="Okta" +OPENPROJECT_OPENID__CONNECT_OKTA_HOST="mypersonal.okta.com" +OPENPROJECT_OPENID__CONNECT_OKTA_IDENTIFIER="" +# etc. ``` -You can copy that into the console to get the URL you need. - -Finally you can the write the actual setting like this: +> [!NOTE] +> Underscores in option names must be escaped by doubling them. So make sure to really do use two consecutive underscores in `DISPLAY__NAME`, `TOKEN__ENDPOINT` and so forth -```ruby -Setting.plugin_openproject_openid_connect = Hash(Setting.plugin_openproject_openid_connect || {}).deep_merge({ - "providers" => { - "okta" => options - } -}) -``` -Replace "okta" with any other value such as "keycloak". It is used as the identifier in some URLs so keep it a plain lowercase string. -Just copy these lines into the console and again confirm using *Enter*. -After you are done you can leave the console by entering `exit`. +## Configuration -Once this is done you will see an "Okta" button in the bottom area of the login form. -Clicking on it will start the login process. +Use the following configuration as a template for your configuration. -_**Note**: This is an Enterprise add-on. If you do not see the button you will have to activate the Enterprise edition first._ +> [!NOTE] +> +> Replace `KEYCLOAK` in the environment name with an alphanumeric identifier. This will become the slug in the redirect URI like follows: +> +> `https://openproject.example.com/auth/keycloak/callback` +> +> You can also see the actual redirect URI in the user interface after the provider has been successfully created from these environment variables. -## Environment variables -Rather than setting these options via the rails console, you can also define them through the -[OpenProject configuration](../../configuration/) which can -also be defined through -[environment variables](../../configuration/environment/). -The variable names can be derived from the options seen above. All variables will start with the prefix -`OPENPROJECT_OPENID__CONNECT_` followed by the provider name. For instance the okta example from above would -be defined via environment variables like this: +```bash +# The name of the login button in OpenProject, you can freely set this to anything you like +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_DISPLAY__NAME="Keycloak" -```shell -OPENPROJECT_OPENID__CONNECT_OKTA_DISPLAY__NAME="Okta" -OPENPROJECT_OPENID__CONNECT_OKTA_HOST="mypersonal.okta.com" -OPENPROJECT_OPENID__CONNECT_OKTA_IDENTIFIER="" -# etc. -``` +# The Client ID of OpenProject, usually the client host in Keycloak +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER="https://" -**Note**: Underscores in option names must be escaped by doubling them. So make sure to really do use two consecutive -underscores in `DISPLAY__NAME`, `TOKEN__ENDPOINT` and so forth. +# The Client Secret used by OpenProject for your provider +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET="" -## More options +# The Issuer configuration for your provider +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER="https://keycloak.example.com/realms/" -You can see a list of possible options [here](https://github.com/m0n9oose/omniauth_openid_connect#options-overview). +# Endpoints for Authorization, Token, Userinfo +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT="/realms//protocol/openid-connect/auth" +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT="/realms//protocol/openid-connect/token" +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT="/realms//protocol/openid-connect/userinfo" -### Known providers and multiple connection per provider +# Optional: endpoint to redirect users for logout +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http://keycloak.example.com/realms//protocol/openid-connect/logout" -There are a number of known providers where the endpoints are configured automatically based on the provider name in the configuration. All that is required are the client ID (identifier) and secret in that case. +# Host name of Keycloak, required if endpoint information are not absolute URLs +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST="" -If you want to configure multiple connections using the same provider you can prefix an arbitrary name with the -provider name followed by a period. For instance, if you want to configure 2 AzureAD connections and 1 Google connection it would look like this: +# Optional: Specify if non-standard port +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_PORT="443" -```ruby -Setting.plugin_openproject_openid_connect = Hash(Setting.plugin_openproject_openid_connect || {}).deep_merge({ - "providers" => { - "azure.dept1" => { "display_name"=>"Department 1","identifier"=>"...","secret"=>"..." }, - "azure.dept2" => { "display_name"=>"Department 2","identifier"=>"...","secret"=>"..." }, - "google" => { "display_name"=>"Google","identifier"=>"...","secret"=>"..." } - } -}) -``` +# Optional: Specify if not using https (only for development/testing purposes) +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SCHEME="https" -At the time of writing the known providers are: `azure`, `google`, `okta` +# Optional: Where to redirect the user after a completed logout flow +OPENPROJECT_OPENID__CONNECT_LOCALKEYCLOAK_POST__LOGOUT__REDIRECT__URI="http://example.com" -### Attribute mapping +# Optional: if you have created the client scope mapper as shown above +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ATTRIBUTE__MAP_LOGIN="preferred_username" -You can override the default attribute mapping for values derived from the userinfo endpoint. For example, let's map the OpenProject login to the claim `preferred_username` that is sent by many OIDC providers. +# Optional: Claim mapping using acr_value syntax +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ACR__VALUES="phr phrh Multi_Factor" -```ruby -options = { - # ... other options - attribute_map: { - 'login' => 'preferred_username' - } -} +# Optional: Claim mapping using JSON +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_CLAIMS="{\"id_token\":{\"acr\":{\"essential\":true,\"values\":[\"phr\",\"phrh\",\"Multi_Factor\"]}}}" ``` -### Back-channel logout -OpenProject OIDC integration supports [back-channel logouts](https://openid.net/specs/openid-connect-backchannel-1_0.html) if OpenProject is configured for ActiveRecord based sessions (which is the default). -On the identity provider side, you need to set `https:///auth//backchannel-logout`. `` is the identifier of the OIDC configuration as provided above. +## Applying the configuration -#### Respecting self-registration +To apply the configuration after changes, you need to run the `db:seed` rake task. In all installations, this command is run automatically when you upgrade or install your application. Use the following commands based on your installation method: -You can configure OpenProject to restrict which users can register on the system with the [authentication self-registration setting](../../../system-admin-guide/authentication/authentication-settings) - - By default, users returning from a SAML idP will be automatically created. If you'd like for the SAML integration to respect the configured self-registration option, please use setting `limit_self_registration`: - -```ruby -options = { - # ... other options - limit_self_registration: true -} -``` +- **Packaged installation**: `sudo openproject run bundle exec rake db:seed` +- **Docker**: `docker exec -it bundle exec rake db:seed`. ### Claims @@ -208,107 +147,3 @@ more complicated `claims` option above but with `"essential": false`. For all other claims there is no such shorthand. -## Instructions for common OIDC providers - -The following section contains instructions for common OpenID Connect providers. Feel free to contribute your settings through the editing functionality at the bottom of this page. - -### Keycloak - -In Keycloak, use the following steps to set up a OIDC integration for OpenProject: - -- Select or create a realm you want to authenticate OpenProject with. Remember that realm identifier. For the remainder of this section, we're using REALM as the placeholder you'll need to replace. -- Under "Clients" menu, click on "Create" or "Create client" -- **Add client**: Enter the following details - - **Client type / protocol**: OpenID Connect - - **Client ID**: `https://` - - **Name**: Choose any name, used only within keycloak -- For the **Capability config**, keep Standard flow checked. In our tested version of Keycloak, this was the default. -- Click on Save - -You will be forwarded to the settings tab of the new client. Change these settings: - -- Set **Valid redirect URIs** to `https:///auth/keycloak/*` -- Enable **Sign Documents** -- If you want to enable [Backchannel logout](https://openid.net/specs/openid-connect-backchannel-1_0.html), set **Backchannel logout URL** to `https:///auth/keycloak/backchannel-logout` - -Next, you will need to create or note down the client secret for that client. - -- Go to the **Credentials** tab -- Click on the copy to clipboard button next to **Client secret** to copy that value - -**OPTIONAL:** By default, OpenProject will map the user's email to the login attribute in OpenProject. If you want to change that, you can do it by providing an alternate claim value in Keycloak: - -- Go to **Client scopes** -- Click on the `https://-dedicated` scope -- Click on **Add mapper** and **By configuration** -- Select **User property** -- Assuming you want to provide the username as `preferred_username` to OpenProject, set these values. This will depend on what attribute you want to map: - - Set name and to `username` - - Set Token claim name to `preferred_username` -- Click on **Save** - -#### Setting up OpenProject for Keycloak integration - -In OpenProject, these are the variables you will need to set. Please refer to the above documentation for the different ways you can configure these variables: - -```shell -# The name of the login button in OpenProject, you can freely set this to anything you like -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_DISPLAY__NAME="Keycloak" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST="" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER="https://" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET="" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER="https:///realms/" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT="/realms//protocol/openid-connect/auth" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT="/realms//protocol/openid-connect/token" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT="/realms//protocol/openid-connect/userinfo" -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http:///realms//protocol/openid-connect/logout" -# Optional, if you have created the client scope mapper as shown above -# OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ATTRIBUTE__MAP_LOGIN="preferred_username" -``` - -### Azure with Microsoft Graph API - -The Azure integration for OpenProject uses the previous userinfo endpoints, which for some tenants results in not being able to access the user's email attribute. [See this bug report for more information](https://community.openproject.org/projects/openproject/work_packages/45832). While our UI is still being extended to accept the new endpoints, you can manually configure Azure like follows. - -**What you need from Azure** - -Use our [Azure Active Directory guide](../../../system-admin-guide/authentication/openid-providers/#azure-active-directory) to create the OpenProject client and note down these values - -- The Client ID you set up for OpenProject (assumed to be `https://`) -- The client secret -- The tenant's UUID ([Please see this guide](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc) for more information on the tenant value) - -#### Setting up OpenProject for Keycloak integration - -In OpenProject, these are the variables you will need to set. Please refer to the above documentation for the different ways you can configure these variables: - -```shell -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_DISPLAY__NAME="Azure" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_HOST="login.microsoftonline.com" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_IDENTIFIER="https://" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_SECRET="" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_AUTHORIZATION__ENDPOINT="https://login.microsoftonline.com/%3CUUID%3E/oauth2/v2.0/authorize" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_TOKEN__ENDPOINT="https://login.microsoftonline.com/%3CUUID%3E/oauth2/v2.0/token" -openproject config:set OPENPROJECT_OPENID__CONNECT_AZURE_USERINFO__ENDPOINT="https://graph.microsoft.com/oidc/userinfo" -``` - -Restart your OpenProject server and test the login button to see if it works. - -## Troubleshooting - -**Q: After clicking on a provider badge, I am redirected to a signup form that says a user already exists with that login.** - -A: This can happen if you previously created user accounts in OpenProject with the same email than what is stored in the identity provider. In this case, if you want to allow existing users to be automatically remapped to the OIDC provider, you should do the following: - -Spawn an interactive console in OpenProject. The following example shows the command for the packaged installation. -See [our process control guide](../../../installation-and-operations/operation/control/) for information on other installation types. - -```shell -sudo openproject run console -> Setting.oauth_allow_remapping_of_existing_users = true -> exit -``` - -Then, existing users should be able to log in using their OIDC identity. Note that this works only if the user is using password-based authentication, and is not linked to any other authentication source (e.g. LDAP) or identity provider. - -Note that this setting is set to true by default for new installations already. diff --git a/docs/system-admin-guide/authentication/authentication-faq/README.md b/docs/system-admin-guide/authentication/authentication-faq/README.md index 451636ac081e..157cfa6ac209 100644 --- a/docs/system-admin-guide/authentication/authentication-faq/README.md +++ b/docs/system-admin-guide/authentication/authentication-faq/README.md @@ -46,8 +46,8 @@ We support all authentication providers that support the SAML and OpenID Connec ## Is it possible to use a custom SSO provider (e.g. Keycloak) with the Enterprise cloud edition? -It is possible to use Keycloak, but you can't configure it yourself at the moment as there's no user interface (UI) for custom SSO providers. We can set up the custom provider for you. Then you can access and edit it in the administration. You will be able to enter client ID and client secret via the OpenProject UI. -For context: The connection of custom SSO providers is also described [here](../../../installation-and-operations/misc/custom-openid-connect-providers/#custom-openid-connect-providers) (however, we would enter this configuration for your Enterprise cloud environment). +It is possible to use Keycloak, Okta, or other OpenID Connect providers with the user interface (UI) for custom SSO providers. +For context: The connection of custom SSO providers is also described [here](../openid-providers/). ## I want to connect AD and LDAP to OpenProject. Which attribute for authentication sources does OpenProject use? diff --git a/docs/system-admin-guide/authentication/openid-providers/README.md b/docs/system-admin-guide/authentication/openid-providers/README.md index e8120fe018a1..04d6211e96c5 100644 --- a/docs/system-admin-guide/authentication/openid-providers/README.md +++ b/docs/system-admin-guide/authentication/openid-providers/README.md @@ -9,48 +9,38 @@ keywords: OpenID providers | Topic | Content | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| [Google Workspace](#google-workspace) | How to use Google Workspace as an SSO provider for OpenProject? | -| [Azure Active Directory](#azure-active-directory) | How to use Microsoft Azure Active Directory as an SSO provider for OpenProject? | -| [Custom OpenID Connect Providers](#custom-openid-connect-providers) | Configuration of additional OpenID Connect providers. | +| Login with [Google Workspace](#google) | How to use Google Workspace as an SSO provider for OpenProject? | +| [Microsoft Entra ID](#microsoft-entra) (previously Azure) | How to use Microsoft Azure Active Directory as an SSO provider for OpenProject? | +| [Custom OpenID Connect Providers](#custom-openid-connect-provider) | Configuration of additional OpenID Connect providers. | | [Troubleshooting](#troubleshooting) | Common complications when using OpenID as SSO. | To activate and configure OpenID providers in OpenProject, navigate to *Administration* -> *Authentication* and choose -> *OpenID providers*. -## Add a new authentication application for oauth +## Add a new OpenID Connect provider To add a new OpenID provider, click the green **+ OpenID provider** button. -![OpenID providers in OpenProject administration](openproject_system-admin-guide_authentication_openid_provider.png) +![OpenIDprovider selection in OpenProject administration](openproject_system-admin-guide_authentication_openid_provider_empty.png) -You can configure the following options. -1. Choose **Google** or **Azure** to add as an OpenID provider to OpenProject. -2. Optionally enter a **display name**. +You can create different kinds of providers with a different set of properties. You can choose from: -3. Enter the **Identifier**. +- [Google](#google) +- [Microsoft Entra ID](#microsoft-entra) (previously Azure) +- [Custom OpenID Connect Providers](#custom-openid-connect-provider) -4. Enter the **Secret**. -5. Optionally, if you want to honor the system-wide self-registration setting, enable "Limit self registration". - When checked, users will be created according to the [self-registration setting](../authentication-settings). - -6. Set the **tenant** of your Azure endpoint. This will control who gets access to the OpenProject instance. For more information, please see [our user guide on Azure OpenID connect](#azure-active-directory) - -7. Press the **create** button. - - ![Add a new OpenID provider in OpenProject administration](openproject_system-admin-guide_authentication_openid_provider_new.png) - -## Google Workspace +## Google ### Step 1: Create the OAuth consent screen 1. Navigate to your GCP console. (https://console.cloud.google.com/) 2. Go to **APIs & Services** > OAuth consent screen. -![g1-apis-and-services-oauth-consent-screen](g1-apis-and-services-oauth-consent-screen.png) +![APIs and services OAuth consent screen](g1-apis-and-services-oauth-consent-screen.png) -3. Create a new project and a new app or edit an existing project and an existing app, setting the following fields (shall be Internal): +3. Create a new project and a new app or edit an existing project and an existing app, setting the following fields (should be internal): 1. **App name** (e.g. EXAMPLE.COM SSO) 2. **User support email** (e.g. user-support@example.com) 3. **App domains** (at minimum, you must provide the Application home page - e.g. `https://example.openproject.com`) @@ -58,7 +48,7 @@ You can configure the following options. 5. **Developer Contact information** (e.g. developer@example.com) 6. Click **SAVE AND CONTINUE** to proceed. -![g2-edit-app-registration](g2-edit-app-registration.png) +![Edit app registration](g2-edit-app-registration.png) 4. **Scopes** - Press **SAVE AND CONTINUE** 5. **Summary** - Press **SAVE AND CONTINUE** @@ -67,45 +57,45 @@ You can configure the following options. 1. Under **APIs & Services**, go to **Credentials**. -![g3-apis-and-services-credentials](g3-apis-and-services-credentials.png) +![APIs and services credentials](g3-apis-and-services-credentials.png) 2. Click **Create Credentials** and select **OAuth Client ID**. 1. When prompted for your **Application type**, choose **Web Application**. - 2. Provide a **Name** for your application. (e.g. example-openproject-com) + 2. Provide a **Name** for your application. (e.g. example-openproject.com) 3. Under Authorized redirect URIs, click **Add URI**, and provide your URI (e.g. [example.openproject.com]/auth/google/callback). 4. Click **CREATE** or **SAVE** . -![g4-create-credentials-oauth-client-id](g4-create-credentials-oauth-client-id.png) +![Create credentials for OAuth client id](g4-create-credentials-oauth-client-id.png) -After pressing **CREATE** you will get a pop-up window like the following +After pressing **CREATE** you will see a following pop-up window. -- Note **Client ID** -- Note **Client Secret** +> [!TIP] +> +> Make sure to note your **Client ID** and **Client Secret**. -![g5-oauth-client-created](g5-oauth-client-created.png) +![OAuth client created](g5-oauth-client-created.png) ### Step 3: Add Google as an OpenID Provider to OpenProject 1. Login as OpenProject Administrator -2. Navigate to *Administration* -> *Authentication* and choose -> *OpenID providers*. - 1. **Name** Choose Google - 2. **Display Name** (e.g. **EXAMPLE.COM SSO**) - 3. **Identifier** (**Client ID** from step 2) - 4. **Secret** (**Client Secret** from step 2) - 5. Enable **Limit self registration** option -3. Press **Create** +2. Navigate to *Administration* -> *Authentication* and choose -> *OpenID providers*. + - **Click** the green *+ OpenID Connect provider* button + - **Choose** Choose the Option Google + - Set a **Display Name**, this is the name of the login button shown to users. + - On the next section, set **Client ID** and **Client Secret** (from step 2) + - Enable **Limit self registration** option if you want users that create accounts with this provider to bypass the configured limit for self-registration. ![Add a new OpenID Gogole provider in OpenProject administration](openproject_system-admin-guide_authentication_openid_provider_new_google.png) -4. The following green notification **Successful creation** should appear +Press **Finish setup** to save the client and complete. If you go back to the index page of OpenID connect providers, the new provider should be visible. -![Successful OpenID creation message in OpenProject administration](openproject_system-admin-guide_authentication_openid_provider_new_google_successful_message.png) +![Saved Google authentication provider](openproject_system-admin-guide_authentication_openid_provider_saved_google.png) -## Azure Active Directory +## Microsoft Entra ### Step 1: Register an App in Azure Active Directory @@ -113,41 +103,51 @@ If your organization currently has an Azure Active Directory to manage users, an The steps are as follows: -Log into your Microsoft account, and go to the Azure Active Directory administration page. +1. Log into your Microsoft account, and go to the Azure Active Directory administration page. ![Azure Active Directory administration page](01-menu.png) -In the sidebar, click on "All services". +2. In the sidebar, click **All services**. ![Azure Active Directory All services](02-admin-dashboard.png) -Click on the link named "App registrations". +3. Click the link named **App registrations**. ![Azure Active Directory App registrations](03-app-registrations.png) -Click on "New registration". +4. Click **New registration**. ![Azure Active Directory New registration](04-register-app.png) -You are now asked for a few settings: +5. You will then be asked to specify the following settings: + +* For **Name**, enter *OpenProject*. +* For **Supported account types**, select *Accounts in this organization directory only*. +* For **Redirect URI**, select the *Web* type, and enter the URL to your OpenProject installation, followed by */auth/oidc-microsoft-entra/callback*. For instance: "https://myserver.com/auth/oidc-microsoft-entra/callback". -* For "Name", enter "OpenProject". -* For "Supported account types", select "Accounts in this organization directory only". -* For "Redirect URI", select the "Web" type, and enter the URL to your OpenProject installation, followed by "/auth/azure/callback". For instance: "https://myserver.com/auth/azure/callback". +> [!NOTE] +> +> The Redirect URI is dependent on the display name that you choose later on. You might need to change it to the correct value shown in the administration of OpenProject. -When you are done, click on the "Register" button at the end of the page. You are redirected to your new App registration, be sure to save the "Application (client) ID" that is now displayed. You will need it later. +6. When you are done, click the **Register** button at the end of the page. You will be redirected to your new App registration. + +> [!IMPORTANT] +> Make sure to save the **Application (client) ID** that is now displayed. You will need it later. ![Azure Active Directory Admin Dashboard](02-admin-dashboard-1580821056307.png) -You can now click on "Certificates & secret". +7. You can then click **Certificates & secret**. ![Azure Active Directory Certificates](06-certificates.png) -Then click on "New client secret", set the description to "client_secret", and the expiration to "730 days (24 months)". Then click on "Add". +8. Then click **New client secret**, set the description to *client_secret*, and the expiration to *730 days (24 months)*. Then click **Add**. ![Azure Active Directory New Client Secret](07-client-secret.png) -A secret should have been generated and is now displayed on the page. Be sure to save it somewhere because it will only be displayed once. +9. A secret should have been generated and will be displayed on the page. + +> [!IMPORTANT] +> Make sure to save it because it will only be displayed once. ![Azure Active Directory Add Secret](08-add-secret.png) @@ -155,30 +155,132 @@ At the end of this step, you should have a copy of the Application client ID as ### Step 2: Configure OpenProject -Now, head over to OpenProject > Administration > OpenID providers. Click on "New OpenID provider", select the Azure type, enter the client ID and client Secret. +Next, you need to create the OpenID Connect provider in OpenProject: + +1. Login as OpenProject Administrator +2. Navigate to *Administration* -> *Authentication* and choose -> *OpenID providers*. + - **Click** the green *+ OpenID Connect provider* button + - **Choose** Choose the option **Microsoft Entra** + - Set display name **Microsoft Entra**. Please note that if you change this value, the redirect URI in step 1) might change. The redirect URI is shown in the side panel on the right side once you saved the configuration. + - Set the **Tenant**: By default, OpenProject will use the Microsoft Graph API endpoint to perform user info requests. + For that, you will need to enter the correct tenant identifier for your Azure instance. + To find the correct value for your instance, [please see this guide](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri). + - In the next section, set **Client ID** and **Client Secret** (from step 1) + - Enable **Limit self registration** option if you want users that create accounts with this provider to bypass the configured limit for self-registration. + +![Add a new OpenID Google provider in OpenProject administration](azure-display-name-tenant.png) + +Press **Finish setup** to save the client and complete. If you go back to the index page of OpenID connect providers, the new provider should be visible. There you will see the redirect URI on the right side in case you set a custom display name. + +![Saved Google authentication provider](azure-provider-index.png) Congratulations, your users can now authenticate using your Microsoft Entra ID provider using the button in the Login form. + +## Custom OpenID Connect Provider + +Starting with OpenProject 15.0., you can also create custom OpenID Connect providers using the user interface. + +To start creating a custom provider, please follow these steps: + +1. Login as OpenProject Administrator +2. Navigate to *Administration* -> *Authentication* and choose -> *OpenID providers*. + - **Click** the green *+ OpenID Connect provider* button + - **Choose** Choose the *Option* **Custom** + +#### Step 1: Display name + +- Set a **Display Name**, this is the name of the login button shown to users. Let's assume we're trying to connect *Keycloak* with OpenProject for this example. We will type in Keycloak as that's the label of the button to be shown to users trying to authenticate. + + + +#### Step 2: Discovery endpoint + +- In the next section, you have the option to specify a discovery endpoint URL to pre-fill some public attributes + - For Keycloak, this URL is based on the configured realm name `http://keycloak.example.com:443/realms/{realm}/.well-known/openid-configuration` +- If you have a discovery endpoint URL, choose **I have a discovery endpoint URL** and fill it in +- Click **Continue**. With a discovery endpoint URL, OpenProject will try to fetch this information and take you to the next step. Observe the page for error responses in case it cannot connect to the endpoint or the returned information is invalid. + +![Discovery endpoint URL](./custom-provider-metadata-discovery.png) + +#### Step 3: Advanced configuration + +- Unless the metadata endpoint provided these values, you will have to fill out some required endpoint URLs, such as **Authorization endpoint**, **User information endpoint**, and **Token endpoint**. +- Fill out the **Issuer** field which depends on the provider. For Keycloak, this value would be the realm URL: `http://keycloak.example.com:443/realms/{realm}` +- Optionally fill out: + - **End session endpoint**, an URL where OpenProject should redirect to terminate a user's session. + - **JWKS URI**. This is the URL of the provider's JSON Web Key Set document containing e.g., signing keys and certificates. + - A custom icon by using a publicly available URL to fetch the logo from. +- Click **Continue** to validate this form and move to the next step. If there are any errors in this form, they will turn red and inform you about what you need to change. + +![Custom OpenID provider advanced configuration in OpenProject](custom-provider-advanced-config.png) + +#### Step 5: Client details + +In the next section, fill out the client credentials provided from your OpenID Connect provider: + +- Fill out **Client ID** and **Client secret** +- If you want users to be redirected to a separate endpoint _after logging out_ at the identity provider, set **Post Logout Redirect URI**. +- If you want this login mechanism to respect the global setting for self registration limits, check **Limit self registration**. +- Click **Continue**. + +#### Step 6: Optional attribute mapping + +You can optionally provide a custom mapping for attributes in the `userinfo` endpoint response. In most cases, you can leave this empty, unless you are providing custom attributes for user properties. + +If you need to set some of these values, enter the attribute key used/returned in the `userinfo` endpoint. + +For example: Keycloak allows you to map custom properties of the user. This allows you to specify a login with, e.g, `preferred_username` userinfo. In this case, you would fill out `Mapping for: Username` with that attribute returned in the userinfo JSON response. + +#### Step 7: Claims + +You can optionally request [claims](https://openid.net/specs/openid-connect-core-1_0-final.html#Claims) for both the id_token and userinfo endpoint. Keep in mind that currently only claims requested for the id_token returned with the authorize response are validated. That means that the authentication will fail if a requested essential claim is not returned. -By default, OpenProject will use the Microsoft Graph API endpoint to perform user info requests. -For that, you will need to enter the correct tenant identifier for your Azure instance. -To find the correct value for your instance, [please see this guide](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri). +If you do not need Claims or are unaware of their use-cases, simply skip this step and click **Finish setup** . -Once you filled out the form, hit save and the Azure provider has been created. +**Requesting MFA authentication via the ACR claim** -You can now log out, and see that the login form displays a badge for authenticating with Azure. If you click on that badge, you will be redirected to Azure to enter your credentials and allow the App to access your Azure profile, and you should then be automatically logged in. +Say for example that you want to request that the user authenticate using MFA (multi-factor authentication). You can do this by using the ACR (Authentication Context Class Reference) claim. -Congratulations, your users can now authenticate using your Azure Active Directory! +This may look different for each identity provider. But if they follow, for instance the [EAP (Extended Authentication Profile)](https://openid.net/specs/openid-connect-eap-acr-values-1_0.html) then the claims would be `phr` (phishing-resistant) and ‘phrh’ (phishing-resistant hardware-protected). Others may simply have an additional claim called `Multi_Factor`. -#### Tenant configuration +You have to check with your identity provider how these values must be called, as they vary from provider. -Sometimes you may need to configure the `tenant` option for the AzureAD connection. -Currently this is not possible through the user interface. +In the following example we request a list of ACR values. One of which must be satisfied (i.e. returned in the ID token by the identity provider, meaning that the requested authentication mechanism was used) for the login in OpenProject to succeed. If none of the requested claims are present, authentication will fail. -But you can do it via the console as described [here](../../../installation-and-operations/misc/custom-openid-connect-providers/#custom-openid-connect-providers) where you can add `tenant` next to the other options like `host`, `identifier` and `secret`. +To specify these, you can provide a JSON. Use the following template as a starting point: -## Custom OpenID Connect Providers +``` +{ + "id_token": { + "acr": { + "essential": true, + "values": ["phr", "phrh", "Multi_Factor"] + } + } +} +``` + + + +**Non-essential claims** + +You may also request non-essential claims. In the example above this indicates that users should preferably be authenticated using those mechanisms but it’s not strictly required. The login into OpenProject will then work even if none of the claims are returned by the identity provider. + +**The acr_values option** + +For non-essential ACR claims you can also use the shorthand form of the option like this: + +``` +options = { ... } + +options["acr_values"] = "phr phrh Multi_Factor" +``` + +The option takes a space-separated list of ACR values. This is functionally the same as using the more complicated `claims` option above but with `"essential": false`. For all other claims there is no such shorthand. + +After entering Claims information, click **Finish setup** to complete the provider creation form. + +![Bildschirmfoto 2024-11-06 um 18.34.28](./custom-provider-claims.png) -You can still use an arbitrary provider. But for the time being there is no user interface yet for this. That means you will have to do it directly using the console on the server or via environment variables. -Please continue reading in the [Miscellaneous section of the Installation and Operations Guide](../../../installation-and-operations/misc/custom-openid-connect-providers/). ## Troubleshooting @@ -205,3 +307,67 @@ exit Then, existing users should be able to log in using their Azure identity. Note that this works only if the user is using password-based authentication, and is not linked to any other authentication source (e.g. LDAP) or OpenID provider. Note that this setting is set to true by default for new installations already. + + + +### Configuration for Okta + +If you use Okta with OpenID Connect, use these configuration properties in the custom provider form: + +- **Display name:** Okta +- **Client ID / Secret**: Values provided from Okta +- **Authorization endpoint**: `/oauth2/v1/authorize` +- **User information endpoint**: `/oauth2/v1/userinfo` +- **Token endpoint**: `/oauth2/v1/token` +- **End session endpoint**: `https://mypersonal.okta.com/oauth2/{authorizationServerId}/v1/logout` + + + +### Configuration for Keycloak + +In Keycloak, use the following steps to set up an OIDC integration for OpenProject: + +- Select or create a realm you want to authenticate OpenProject with. Remember that realm identifier. For the remainder of this section, we're using REALM as the placeholder you'll need to replace. +- Under **Clients** menu, click *Create* or *Create client* +- **Add client**: Enter the following details + - **Client type / protocol**: OpenID Connect + - **Client ID**: `https://` + - **Name**: Choose any name, used only within Keycloak +- For the **Capability config**, keep Standard flow checked. In our tested version of Keycloak, this was the default. +- Click **Save** + +You will be forwarded to the settings tab of the new client. Change these settings: + +- Set **Valid redirect URIs** to `https:///auth/oidc-keycloak/*` +- Enable **Sign Documents** +- If you want to enable [Backchannel logout](https://openid.net/specs/openid-connect-backchannel-1_0.html), set **Backchannel logout URL** to `https:///auth/oidc-keycloak/backchannel-logout` + +Next, you will need to create or note down the client secret for that client. + +- Go to the **Credentials** tab +- Click the **copy to clipboard button** next to **Client secret** to copy that value + +**OPTIONAL:** By default, OpenProject will map the user's email to the login attribute in OpenProject. If you want to change that, you can do it by providing an alternate claim value in Keycloak: + +- Go to **Client scopes** +- Click the `https://-dedicated` scope +- Click **Add mapper** and **By configuration** +- Select **User property** +- Assuming you want to provide the username as `preferred_username` to OpenProject, set these values. This will depend on what attribute you want to map: + - Set name to `username` + - Set Token claim name to `preferred_username` +- Click **Save** + + + +#### Form values for OpenProject + +In OpenProject, create a custom provider as shown above using these parameters + +- **Display name:** Keycloak +- **Client ID / Secret**: Credentials shown above +- **Authorization endpoint**: `/oauth2/v1/authorize` +- **User information endpoint**: `/oauth2/v1/userinfo` +- **Token endpoint**: `/oauth2/v1/token` +- **End session endpoint**: `https://mypersonal.okta.com/oauth2/{authorizationServerId}/v1/logout` +- **OpenProject Redirect URI**: `https://openproject.example.com/auth/oidc-keycloak/callback` (Note that this URL depends on the display name above. See the UI for the actual Redirect URI) diff --git a/docs/system-admin-guide/authentication/openid-providers/azure-display-name-tenant.png b/docs/system-admin-guide/authentication/openid-providers/azure-display-name-tenant.png new file mode 100644 index 000000000000..9bbb7a5495db Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/azure-display-name-tenant.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/azure-provider-index.png b/docs/system-admin-guide/authentication/openid-providers/azure-provider-index.png new file mode 100644 index 000000000000..5908679a2964 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/azure-provider-index.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/custom-provider-advanced-config.png b/docs/system-admin-guide/authentication/openid-providers/custom-provider-advanced-config.png new file mode 100644 index 000000000000..e7d477a353c9 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/custom-provider-advanced-config.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/custom-provider-claims.png b/docs/system-admin-guide/authentication/openid-providers/custom-provider-claims.png new file mode 100644 index 000000000000..0178b49510b6 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/custom-provider-claims.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/custom-provider-metadata-discovery.png b/docs/system-admin-guide/authentication/openid-providers/custom-provider-metadata-discovery.png new file mode 100644 index 000000000000..134426d9f556 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/custom-provider-metadata-discovery.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_empty.png b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_empty.png new file mode 100644 index 000000000000..57a9adaf5b34 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_empty.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google.png b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google.png index 36301c3ff739..fece608b05a1 100644 Binary files a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google.png and b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google.png differ diff --git a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google_successful_message.png b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google_successful_message.png deleted file mode 100644 index 3ac418daf544..000000000000 Binary files a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_new_google_successful_message.png and /dev/null differ diff --git a/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_saved_google.png b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_saved_google.png new file mode 100644 index 000000000000..9f2bb67a2a36 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/openproject_system-admin-guide_authentication_openid_provider_saved_google.png differ diff --git a/modules/openid_connect/app/components/openid_connect/providers/row_component.rb b/modules/openid_connect/app/components/openid_connect/providers/row_component.rb index 0eae5bfaabcf..297ebb19d2eb 100644 --- a/modules/openid_connect/app/components/openid_connect/providers/row_component.rb +++ b/modules/openid_connect/app/components/openid_connect/providers/row_component.rb @@ -14,19 +14,33 @@ def column_args(column) end def name - link = render( - Primer::Beta::Link.new( - href: url_for(action: :edit, id: provider.id), - font_weight: :bold, - mr: 1 - ) - ) { provider.display_name } - if !provider.configured? - link.concat( - render(Primer::Beta::Label.new(scheme: :attention)) { I18n.t(:label_incomplete) } - ) + concat(provider_name) + unless provider.configured? + concat(incomplete_label) end - link + end + + def provider_name + render(Primer::OpenProject::FlexLayout.new) do |layout| + layout.with_row do + render( + Primer::Beta::Link.new( + href: url_for(action: :edit, id: provider.id), + font_weight: :bold, + mr: 1 + ) + ) { provider.display_name } + end + layout.with_row do + render(Primer::Beta::Text.new(font_size: :small, color: :subtle)) do + provider.callback_url + end + end + end + end + + def incomplete_label + render(Primer::Beta::Label.new(scheme: :attention)) { I18n.t(:label_incomplete) } end def type