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 e260f337731a..fe442ea23ae3 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 @@ -3,147 +3,7 @@ > [!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. -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. +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/). -However, for some deployment scenarios, it might be desirable to configure a provider through environment variables. - -> [!WARNING] -> Only do this if you know what you are doing. Otherwise this may break your existing OpenID Connect authentication or cause other issues. - -## Environment variables - -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: - -```shell -OPENPROJECT_OPENID__CONNECT_OKTA_DISPLAY__NAME="Okta" -OPENPROJECT_OPENID__CONNECT_OKTA_HOST="mypersonal.okta.com" -OPENPROJECT_OPENID__CONNECT_OKTA_IDENTIFIER="" -# etc. -``` - -> [!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 - - - -## Configuration - -Use the following configuration as a template for your configuration. - -> [!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. - - - -```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" - -# The Client ID of OpenProject, usually the client host in Keycloak -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER="https://" - -# The Client Secret used by OpenProject for your provider -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET="" - -# The Issuer configuration for your provider -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER="https://keycloak.example.com/realms/" - -# 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" - -# Optional: endpoint to redirect users for logout -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http://keycloak.example.com/realms//protocol/openid-connect/logout" - -# Host name of Keycloak, required if endpoint information are not absolute URLs -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST="" - -# Optional: Specify if non-standard port -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_PORT="443" - -# Optional: Specify if not using https (only for development/testing purposes) -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SCHEME="https" - -# Optional: Where to redirect the user after a completed logout flow -OPENPROJECT_OPENID__CONNECT_LOCALKEYCLOAK_POST__LOGOUT__REDIRECT__URI="http://example.com" - -# Optional: if you have created the client scope mapper as shown above -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ATTRIBUTE__MAP_LOGIN="preferred_username" - -# Optional: Claim mapping using acr_value syntax -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ACR__VALUES="phr phrh Multi_Factor" - -# Optional: Claim mapping using JSON -OPENPROJECT_OPENID__CONNECT_KEYCLOAK_CLAIMS="{\"id_token\":{\"acr\":{\"essential\":true,\"values\":[\"phr\",\"phrh\",\"Multi_Factor\"]}}}" -``` - - - -## Applying the configuration - -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: - -- **Packaged installation**: `sudo openproject run bundle exec rake db:seed` -- **Docker**: `docker exec -it bundle exec rake db:seed`. - -### Claims - -You can also request [claims](https://openid.net/specs/openid-connect-core-1_0-final.html#Claims) for both the id_token and userinfo endpoint. -Mind though that currently only claims requested for the id_token returned with the authorize response are validated. -That is authentication will fail if a requested essential claim is not returned. - -#### Requesting MFA authentication via the ACR claim - -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. - -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`. - -You have to check with your identity provider how these values must be called. - -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. - -```ruby -options = { ... } - -options["claims"] = { - "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: - -```ruby -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. +Please use this document 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. diff --git a/docs/system-admin-guide/authentication/openid-providers/README.md b/docs/system-admin-guide/authentication/openid-providers/README.md index 04d6211e96c5..0c226cb635e5 100644 --- a/docs/system-admin-guide/authentication/openid-providers/README.md +++ b/docs/system-admin-guide/authentication/openid-providers/README.md @@ -172,7 +172,7 @@ Next, you need to create the OpenID Connect provider in OpenProject: 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. +![Saved Google authentication provider](./oidc-index-page.png) Congratulations, your users can now authenticate using your Microsoft Entra ID provider using the button in the Login form. ## Custom OpenID Connect Provider @@ -208,7 +208,7 @@ To start creating a custom provider, please follow these steps: - **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. +- 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) @@ -233,7 +233,7 @@ For example: Keycloak allows you to map custom properties of the user. This allo 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. -If you do not need Claims or are unaware of their use-cases, simply skip this step and click **Finish setup** . +If you do not need Claims or are unaware of their use-cases, simply skip this step and click **Finish setup** . **Requesting MFA authentication via the ACR claim** @@ -276,41 +276,13 @@ 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. +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) -## 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 OpenID provider. In this case, if you want to allow existing users to be automatically remapped to the OpenID 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 -# or if using docker: -# docker-compose run --rm web bundle exec rails console -``` - -Once in the console you can then enter the following to enable the setting and leave the console. - -```shell -Setting.oauth_allow_remapping_of_existing_users = true -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 +### Additional custom configuration instructions for Okta If you use Okta with OpenID Connect, use these configuration properties in the custom provider form: @@ -323,7 +295,7 @@ If you use Okta with OpenID Connect, use these configuration properties in the c -### Configuration for Keycloak +### Additional custom configuration instructions for Keycloak In Keycloak, use the following steps to set up an OIDC integration for OpenProject: @@ -371,3 +343,122 @@ In OpenProject, create a custom provider as shown above using these parameters - **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) + + + + + +## Configuration using environment variables + +For some deployment scenarios, it might be desirable to configure a provider through environment variables. + +> [!WARNING] +> Only do this if you know what you are doing. Otherwise this may break your existing OpenID Connect authentication or cause other issues. + +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: + +```shell +OPENPROJECT_OPENID__CONNECT_OKTA_DISPLAY__NAME="Okta" +OPENPROJECT_OPENID__CONNECT_OKTA_HOST="mypersonal.okta.com" +OPENPROJECT_OPENID__CONNECT_OKTA_IDENTIFIER="" +# etc. +``` + +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 + +Use the following configuration as a template for your configuration. + +> [!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. + + + +```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" + +# The Client ID of OpenProject, usually the client host in Keycloak +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER="https://" + +# The Client Secret used by OpenProject for your provider +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET="" + +# The Issuer configuration for your provider +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER="https://keycloak.example.com/realms/" + +# 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" + +# Optional: endpoint to redirect users for logout +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http://keycloak.example.com/realms//protocol/openid-connect/logout" + +# Host name of Keycloak, required if endpoint information are not absolute URLs +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST="" + +# Optional: Specify if non-standard port +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_PORT="443" + +# Optional: Specify if not using https (only for development/testing purposes) +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SCHEME="https" + +# Optional: Where to redirect the user after a completed logout flow +OPENPROJECT_OPENID__CONNECT_LOCALKEYCLOAK_POST__LOGOUT__REDIRECT__URI="http://example.com" + +# Optional: if you have created the client scope mapper as shown above +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ATTRIBUTE__MAP_LOGIN="preferred_username" + +# Optional: Claim mapping using acr_value syntax +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ACR__VALUES="phr phrh Multi_Factor" + +# Optional: Claim mapping using JSON, see Step 7 above for more information on syntax +OPENPROJECT_OPENID__CONNECT_KEYCLOAK_CLAIMS="{\"id_token\":{\"acr\":{\"essential\":true,\"values\":[\"phr\",\"phrh\",\"Multi_Factor\"]}}}" +``` + + + +### Applying the configuration + +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: + +- **Packaged installation**: `sudo openproject run bundle exec rake db:seed` +- **Docker**: `docker exec -it bundle exec rake db:seed`. + + + +## 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 OpenID provider. In this case, if you want to allow existing users to be automatically remapped to the OpenID 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](https://github.com/opf/openproject/blob/dev/docs/installation-and-operations/operation/control) for information on other installation types. + +``` +sudo openproject run console +# or if using docker: +# docker-compose run --rm web bundle exec rails console +``` + + + +Once in the console you can then enter the following to enable the setting and leave the console. + +``` +Setting.oauth_allow_remapping_of_existing_users = true +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. diff --git a/docs/system-admin-guide/authentication/openid-providers/oidc-index-page.png b/docs/system-admin-guide/authentication/openid-providers/oidc-index-page.png new file mode 100644 index 000000000000..09c0e4432211 Binary files /dev/null and b/docs/system-admin-guide/authentication/openid-providers/oidc-index-page.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 297ebb19d2eb..c7e87dc5c26a 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 @@ -21,22 +21,13 @@ def name 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 + render( + Primer::Beta::Link.new( + href: url_for(action: :show, id: provider.id), + font_weight: :bold, + mr: 1 + ) + ) { provider.display_name } end def incomplete_label diff --git a/modules/openid_connect/app/components/openid_connect/providers/sections/form_component.html.erb b/modules/openid_connect/app/components/openid_connect/providers/sections/form_component.html.erb index 5339d40ecdc1..677ed8c0b0fa 100644 --- a/modules/openid_connect/app/components/openid_connect/providers/sections/form_component.html.erb +++ b/modules/openid_connect/app/components/openid_connect/providers/sections/form_component.html.erb @@ -3,8 +3,7 @@ id: "openid-connect-providers-edit-form", model: provider, url:, - method: form_method, - data: { turbo: true, turbo_stream: true } + method: form_method ) do |form| flex_layout do |flex| if @heading diff --git a/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.html.erb b/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.html.erb new file mode 100644 index 000000000000..cc4a09471cab --- /dev/null +++ b/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.html.erb @@ -0,0 +1,24 @@ +<%= + render(Primer::OpenProject::SidePanel::Section.new) do |section| + section.with_title { I18n.t("saml.providers.label_openproject_information") } + section.with_description { I18n.t("openid_connect.instructions.redirect_url") } + + component_collection do |collection| + collection.with_component(Primer::Beta::Heading.new(tag: :h5, mb: 1)) do + I18n.t("activemodel.attributes.openid_connect/provider.slug") + end + + collection.with_component( + OpPrimer::CopyToClipboardComponent.new(provider.slug, scheme: :input) + ) + + collection.with_component(Primer::Beta::Heading.new(tag: :h5, mt: 4, mb: 1)) do + I18n.t("activemodel.attributes.openid_connect/provider.redirect_url") + end + + collection.with_component( + OpPrimer::CopyToClipboardComponent.new(provider.callback_url, scheme: :input) + ) + end + end +%> diff --git a/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.rb b/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.rb new file mode 100644 index 000000000000..610e01b3e969 --- /dev/null +++ b/modules/openid_connect/app/components/openid_connect/providers/side_panel/information_component.rb @@ -0,0 +1,39 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module OpenIDConnect::Providers + module SidePanel + class InformationComponent < ApplicationComponent + include ApplicationHelper + include OpTurbo::Streamable + include OpPrimer::ComponentHelpers + + alias_method :provider, :model + end + end +end diff --git a/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.html.erb b/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.html.erb new file mode 100644 index 000000000000..b05772b94cb4 --- /dev/null +++ b/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.html.erb @@ -0,0 +1,11 @@ +<%= + component_wrapper do + render(Primer::OpenProject::SidePanel.new(spacious: true)) do |panel| + [ + OpenIDConnect::Providers::SidePanel::InformationComponent.new(@provider), + ].each do |component| + panel.with_section(component) + end + end + end +%> diff --git a/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.rb b/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.rb new file mode 100644 index 000000000000..5764ea920d5a --- /dev/null +++ b/modules/openid_connect/app/components/openid_connect/providers/side_panel_component.rb @@ -0,0 +1,43 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module OpenIDConnect + module Providers + class SidePanelComponent < ApplicationComponent + include ApplicationHelper + include OpTurbo::Streamable + include OpPrimer::ComponentHelpers + + def initialize(provider) + super() + + @provider = provider + end + end + end +end diff --git a/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb b/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb index e2477b25b1ef..5433718cd63d 100644 --- a/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb +++ b/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb @@ -7,13 +7,15 @@ class ProvidersController < ::ApplicationController before_action :require_admin before_action :check_ee - before_action :find_provider, only: %i[edit update confirm_destroy destroy] + before_action :find_provider, only: %i[edit show update confirm_destroy destroy] before_action :set_edit_state, only: %i[create edit update] def index @providers = ::OpenIDConnect::Provider.all end + def show; end + def new oidc_provider = case params[:oidc_provider] when "google" @@ -44,7 +46,20 @@ def create end end - def edit; end + def edit + respond_to do |format| + format.turbo_stream do + component = OpenIDConnect::Providers::ViewComponent.new(@provider, + view_mode: :edit, + edit_mode: @edit_mode, + edit_state: @edit_state) + update_via_turbo_stream(component:) + scroll_into_view_via_turbo_stream("openid-connect-providers-edit-form", behavior: :instant) + render turbo_stream: turbo_streams + end + format.html + end + end def update update_params = params @@ -59,7 +74,7 @@ def update successful_save_response else @provider = call.result - failed_save_response(edit) + failed_save_response(:edit) end end diff --git a/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb b/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb index 186c079beb80..bc753198ad44 100644 --- a/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb +++ b/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb @@ -26,7 +26,21 @@ end %> -<%= render(OpenIDConnect::Providers::ViewComponent.new(@provider, - view_mode: :edit, - edit_mode: @edit_mode, - edit_state: @edit_state)) %> +<%= + render(Primer::Alpha::Layout.new(stacking_breakpoint: :md)) do |content| + content.with_main do + render(OpenIDConnect::Providers::ViewComponent.new(@provider, + view_mode: :edit, + edit_mode: @edit_mode, + edit_state: @edit_state)) + end + + if @provider.persisted? + content.with_sidebar(row_placement: :start, col_placement: :end) do + render(OpenIDConnect::Providers::SidePanelComponent.new(@provider)) + end + end + end +%> + +<%= %> diff --git a/modules/openid_connect/app/views/openid_connect/providers/show.html.erb b/modules/openid_connect/app/views/openid_connect/providers/show.html.erb new file mode 100644 index 000000000000..846ccd519fe6 --- /dev/null +++ b/modules/openid_connect/app/views/openid_connect/providers/show.html.erb @@ -0,0 +1,38 @@ +<% html_title(t(:label_administration), t('openid_connect.providers.plural'), @provider.display_name) -%> + +<% html_title(t(:label_administration), page_title) -%> + +<%= + render Primer::OpenProject::PageHeader.new do |header| + header.with_title { @provider.display_name } + header.with_breadcrumbs([{ href: admin_index_path, text: t(:label_administration) }, + { href: admin_settings_authentication_path, text: t(:label_authentication) }, + { href: openid_connect_providers_path, text: t("openid_connect.providers.plural") }, + @provider.display_name]) + header.with_action_button( + tag: :a, + scheme: :danger, + mobile_icon: :trash, + mobile_label: t(:button_delete), + size: :medium, + href: confirm_destroy_openid_connect_provider_path(@provider), + aria: { label: I18n.t(:button_delete) }, + title: I18n.t(:button_delete) + ) do |button| + button.with_leading_visual_icon(icon: :trash) + t(:button_delete) + end + end +%> + +<%= + render(Primer::Alpha::Layout.new(stacking_breakpoint: :md)) do |content| + content.with_main do + render OpenIDConnect::Providers::ViewComponent.new(@provider, view_mode: :show) + end + + content.with_sidebar(row_placement: :start, col_placement: :end) do + render OpenIDConnect::Providers::SidePanelComponent.new(@provider) + end + end +%> diff --git a/modules/openid_connect/config/locales/en.yml b/modules/openid_connect/config/locales/en.yml index 76689750d8c5..d6bafddb14f1 100644 --- a/modules/openid_connect/config/locales/en.yml +++ b/modules/openid_connect/config/locales/en.yml @@ -9,6 +9,7 @@ en: attributes: openid_connect/provider: name: Name + slug: Unique identifier display_name: Display name client_id: Client ID client_secret: Client secret @@ -27,6 +28,7 @@ en: icon: Custom icon claims: Claims acr_values: ACR values + redirect_url: Redirect URL activerecord: errors: models: @@ -55,6 +57,7 @@ en: delete_title: "Delete OpenID Connect provider" instructions: + redirect_url: This is the redirect URL that the OpenID Connect provider should use to redirect back to OpenProject after a successful login. endpoint_url: The endpoint URL given to you by the OpenID Connect provider metadata_none: I don't have this information metadata_url: I have a discovery endpoint URL diff --git a/modules/openid_connect/config/routes.rb b/modules/openid_connect/config/routes.rb index aa31fbcf26f3..110a5b553d6a 100644 --- a/modules/openid_connect/config/routes.rb +++ b/modules/openid_connect/config/routes.rb @@ -3,7 +3,7 @@ scope :admin do namespace :openid_connect do - resources :providers, except: %i[show] do + resources :providers do get :confirm_destroy, on: :member end end