diff --git a/app/contracts/oauth_clients/create_contract.rb b/app/contracts/oauth_clients/create_contract.rb index 83df00f53977..398a9a21f634 100644 --- a/app/contracts/oauth_clients/create_contract.rb +++ b/app/contracts/oauth_clients/create_contract.rb @@ -36,11 +36,9 @@ class CreateContract < ::ModelContract validates :client_id, presence: true, length: { maximum: 255 } attribute :client_secret, writable: true - validates :client_secret, presence: true, if: :client_secret_required? + validates :client_secret, presence: true validates :client_secret, length: { maximum: 255 } - def client_secret_required? = true - attribute :integration_type, writable: true validates :integration_type, presence: true diff --git a/modules/wikis/app/components/wikis/admin/forms/general_info_form_component.html.erb b/modules/wikis/app/components/wikis/admin/forms/general_info_form_component.html.erb index 7f74304d01a1..3bb7990e3274 100644 --- a/modules/wikis/app/components/wikis/admin/forms/general_info_form_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/forms/general_info_form_component.html.erb @@ -2,12 +2,12 @@ component_wrapper do flex_layout(mb: 3) do |general_info_row| general_info_row.with_row do - render(Primer::Beta::Text.new(font_weight: :bold)) { t("wikis.admin.wiki_providers.xwiki_instance") } + render(Primer::Beta::Text.new(font_weight: :bold)) { t("wikis.provider_types.#{wiki_provider}.name") } end general_info_row.with_row do render(Primer::Beta::Text.new(color: :subtle, test_selector: "wiki-provider-configuration-instructions")) do - t(".xwiki_instance_description") + t(".provider_description") end end diff --git a/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.html.erb b/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.html.erb index be3f3e4d80d6..400cd63dd16a 100644 --- a/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.html.erb @@ -1,12 +1,14 @@ <%= component_wrapper do flex_layout(flex_items: :center) do |credentials_row| - credentials_row.with_row do - render(Primer::Beta::Text.new(font_weight: :bold)) { t("wikis.admin.wiki_providers.oauth.openproject_oauth") } - end - credentials_row.with_row(mb: 3) do - render(Primer::Beta::Text.new(color: :subtle)) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.openproject_oauth_description") } + render(Primer::Alpha::Banner.new(icon: :alert, scheme: :warning)) do + helpers.link_translate( + "wikis.instructions.xwiki.oauth_application_details_html", + links: { xwiki_admin_link: xwiki_admin_url }, + external: true + ) + end end credentials_row.with_row(mb: 3) do diff --git a/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.rb b/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.rb index 55ab8108c73a..b0b3c39b101c 100644 --- a/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.rb +++ b/modules/wikis/app/components/wikis/admin/forms/oauth_application_form_component.rb @@ -30,6 +30,8 @@ module Wikis::Admin::Forms class OAuthApplicationFormComponent < Wikis::Admin::WikiProviderComponent + OPENPROJECT_PLUGIN_ADMIN_PATH = "/bin/admin/XWiki/XWikiPreferences?editor=globaladmin§ion=OpenProject" + def self.wrapper_key = :wiki_provider_oauth_application_section delegate :oauth_application, to: :wiki_provider @@ -43,5 +45,9 @@ def done_button_path url_helpers.edit_admin_settings_wiki_provider_path(wiki_provider) end end + + def xwiki_admin_url + "#{wiki_provider.url.to_s.chomp('/')}#{OPENPROJECT_PLUGIN_ADMIN_PATH}" + end end end diff --git a/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.html.erb b/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.html.erb index 1c71a51c859b..2f06f1418985 100644 --- a/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.html.erb @@ -14,19 +14,43 @@ render(Primer::Beta::Text.new(color: :subtle)) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.provider_oauth_description") } end + oauth_client_row.with_row(mb: 3) do + render(Primer::Alpha::TextField.new( + name: "oauth_client[client_id]", + label: t(".client_id"), + visually_hide_label: false, + value: resolved_oauth_client.client_id, + input_width: :large, + required: true, + validation_message: validation_message_for(:client_id) + )) + end + + oauth_client_row.with_row(mb: 3) do + render(Primer::Alpha::TextField.new( + name: "oauth_client[client_secret]", + label: t(".client_secret"), + visually_hide_label: false, + value: resolved_oauth_client.client_secret, + input_width: :large, + required: true, + validation_message: validation_message_for(:client_secret) + )) + end + oauth_client_row.with_row(mb: 3) do render(Primer::OpenProject::InputGroup.new(input_width: :large)) do |input_group| input_group.with_text_input( - name: "oauth_client[client_id]", - label: t(".client_id"), + name: "oauth_client[redirect_uri]", + label: t(".redirect_uri"), visually_hide_label: false, - value: resolved_oauth_client.client_id, - readonly: true + value: resolved_oauth_client.redirect_uri ) input_group.with_trailing_action_clipboard_copy_button( - value: resolved_oauth_client.client_id, + value: resolved_oauth_client.redirect_uri, aria: { label: t("button_copy_to_clipboard") } ) + input_group.with_caption { t(".redirect_uri_caption") } end end diff --git a/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.rb b/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.rb index 37c7b8bbb721..54137492bc47 100644 --- a/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.rb +++ b/modules/wikis/app/components/wikis/admin/forms/oauth_client_form_component.rb @@ -51,7 +51,14 @@ def cancel_button_path def resolved_oauth_client oauth_client || wiki_provider.oauth_client || - wiki_provider.build_oauth_client(client_id: Wikis::XWikiProvider.generate_client_id) + wiki_provider.build_oauth_client( + client_id: Wikis::XWikiProvider.generate_client_id, + client_secret: Wikis::XWikiProvider.generate_client_secret + ) + end + + def validation_message_for(attribute) + resolved_oauth_client.errors.messages_for(attribute).to_sentence.presence end end end diff --git a/modules/wikis/app/components/wikis/admin/general_info_component.html.erb b/modules/wikis/app/components/wikis/admin/general_info_component.html.erb index ef908a10b825..fb6ff7086ba5 100644 --- a/modules/wikis/app/components/wikis/admin/general_info_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/general_info_component.html.erb @@ -2,13 +2,16 @@ component_wrapper do grid_layout("op-storage-view--row", tag: :div, align_items: :center) do |grid| grid.with_area(:item, tag: :div, mr: 3) do - concat(render(Primer::Beta::Text.new(font_weight: :bold, mr: 1)) { t("wikis.admin.wiki_providers.xwiki_instance") }) + concat(render(Primer::Beta::Text.new(font_weight: :bold, mr: 1)) { t("wikis.provider_types.#{wiki_provider}.name") }) concat(render(Primer::Beta::Label.new(scheme: :success, test_selector: "wiki-provider-general-info-status")) { t(:label_completed) }) end grid.with_area(:description, tag: :div, color: :subtle, test_selector: "wiki-provider-description") do - concat(render(Primer::Beta::Text.new) { "#{wiki_provider.name} - " }) - concat(render(Primer::Beta::Link.new(href: wiki_provider.url, target: "_blank", underline: true)) { wiki_provider.url }) + concat(render(Primer::Beta::Text.new) { "#{t("wikis.provider_types.#{wiki_provider}.name")} - #{wiki_provider.name} - #{wiki_provider.url}" }) + if wiki_provider.url.present? + concat(render(Primer::Beta::Text.new) { " - " }) + concat(helpers.static_link_to(href: wiki_provider.url, label: t("wikis.buttons.open_wiki"), underline: true)) + end end grid.with_area(:"icon-button", tag: :div, color: :muted) do diff --git a/modules/wikis/app/components/wikis/admin/oauth_application_info_component.html.erb b/modules/wikis/app/components/wikis/admin/oauth_application_info_component.html.erb index 9ef7e1cd6d40..b8209c20a807 100644 --- a/modules/wikis/app/components/wikis/admin/oauth_application_info_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/oauth_application_info_component.html.erb @@ -11,7 +11,11 @@ end grid.with_area(:description, tag: :div, color: :subtle) do - render(Primer::Beta::Text.new) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.openproject_oauth_description") } + if oauth_application.present? + render(Primer::Beta::Text.new) { "#{t(".label_oauth_client_id")}: #{oauth_application.uid}" } + else + render(Primer::Beta::Text.new) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.openproject_oauth_description") } + end end if wiki_provider.persisted? diff --git a/modules/wikis/app/components/wikis/admin/oauth_client_info_component.html.erb b/modules/wikis/app/components/wikis/admin/oauth_client_info_component.html.erb index 801914d20694..ad152a7620a0 100644 --- a/modules/wikis/app/components/wikis/admin/oauth_client_info_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/oauth_client_info_component.html.erb @@ -10,8 +10,12 @@ end end - grid.with_area(:description, tag: :div, color: :subtle) do - render(Primer::Beta::Text.new) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.provider_oauth_description") } + grid.with_area(:description, classes: "wb-break-word", tag: :div, color: :subtle) do + if oauth_client.present? + render(Primer::Beta::Text.new) { "#{t('.label_oauth_client_id')}: #{oauth_client.client_id}" } + else + render(Primer::Beta::Text.new) { t("wikis.admin.wiki_providers.#{wiki_provider}.oauth.provider_oauth_description") } + end end if wiki_provider.persisted? diff --git a/modules/wikis/app/components/wikis/admin/wiki_provider_list_component.html.erb b/modules/wikis/app/components/wikis/admin/wiki_provider_list_component.html.erb index 1c52774b0259..fa23c31dca97 100644 --- a/modules/wikis/app/components/wikis/admin/wiki_provider_list_component.html.erb +++ b/modules/wikis/app/components/wikis/admin/wiki_provider_list_component.html.erb @@ -29,7 +29,7 @@ end grid.with_area(:provider, tag: :div, color: :subtle, mr: 3, hide: :sm) do - render(Primer::Beta::Text.new(color: :subtle)) { wiki_provider.model_name.human } + render(Primer::Beta::Text.new(color: :subtle)) { t("wikis.provider_types.#{wiki_provider}.name") } end grid.with_area(:time, tag: :div, color: :subtle, hide: :sm) do diff --git a/modules/wikis/app/contracts/wikis/oauth_clients/xwiki_create_contract.rb b/modules/wikis/app/contracts/wikis/oauth_clients/xwiki_create_contract.rb deleted file mode 100644 index df7d5fdc57dc..000000000000 --- a/modules/wikis/app/contracts/wikis/oauth_clients/xwiki_create_contract.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 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 Wikis - module OAuthClients - # XWiki uses a public OAuth client (RFC 6749 §2.1) — no client_secret is issued. - class XWikiCreateContract < ::OAuthClients::CreateContract - def client_secret_required? = false - end - end -end diff --git a/modules/wikis/app/controllers/wikis/admin/oauth_clients_controller.rb b/modules/wikis/app/controllers/wikis/admin/oauth_clients_controller.rb index 96c4ff9efa64..40613992e4e2 100644 --- a/modules/wikis/app/controllers/wikis/admin/oauth_clients_controller.rb +++ b/modules/wikis/app/controllers/wikis/admin/oauth_clients_controller.rb @@ -42,7 +42,10 @@ class OAuthClientsController < ApplicationController menu_item :wiki_providers def new - oauth_client = OAuthClient.new(client_id: Wikis::XWikiProvider.generate_client_id) + oauth_client = OAuthClient.new( + client_id: Wikis::XWikiProvider.generate_client_id, + client_secret: Wikis::XWikiProvider.generate_client_secret + ) update_via_turbo_stream( component: Wikis::Admin::Forms::OAuthClientFormComponent.new(@wiki_provider, @@ -92,7 +95,7 @@ def save_oauth_client end def oauth_client_params - params.expect(oauth_client: [:client_id]) + params.expect(oauth_client: %i[client_id client_secret]) end def find_wiki_provider diff --git a/modules/wikis/app/models/wikis/xwiki_provider.rb b/modules/wikis/app/models/wikis/xwiki_provider.rb index 47f535987edd..5937021f5076 100644 --- a/modules/wikis/app/models/wikis/xwiki_provider.rb +++ b/modules/wikis/app/models/wikis/xwiki_provider.rb @@ -45,7 +45,8 @@ class XWikiProvider < Provider class << self def registry_prefix = "xwiki" - def generate_client_id = SecureRandom.uuid + def generate_client_id = "openproject-#{SecureRandom.hex(8)}" + def generate_client_secret = SecureRandom.hex(32) end def configured? diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/oauth_configuration.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/oauth_configuration.rb index 32228586974f..01b14a753a64 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/oauth_configuration.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/oauth_configuration.rb @@ -35,8 +35,6 @@ module XWiki # OAuth2 configuration for XWiki's OIDC Provider extension. # # Deviations from a standard OAuth2 confidential client: - # - Public client: no client_secret; token_endpoint_auth_method is :none. - # - No pre-registration: XWiki accepts any client_id/redirect_uri; consent is stored on first auth. # - No refresh tokens: tokens are long-lived; re-auth via ensure_connection if revoked. # - No expires_in: tokens do not expire; expires_in is stored as nil. # @@ -69,9 +67,9 @@ def authorization_uri(state: nil) def basic_rack_oauth_client uri = provider_uri - # XWiki is a public client — no secret is used. Rack::OAuth2::Client.new( identifier: @oauth_client.client_id, + secret: @oauth_client.client_secret, redirect_uri: @oauth_client.redirect_uri, scheme: uri.scheme, host: uri.host, diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/user.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/user.rb index 4c7a28b9a02f..a49fbb3296f9 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/user.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/user.rb @@ -35,7 +35,7 @@ module XWiki module Queries class User < BaseQuery def call(auth_strategy:) - url = "#{provider.url.chomp('/')}/rest/" + url = "#{provider.url.chomp('/')}/rest/wikis/xwiki/user" Adapters::Authentication[auth_strategy].call do |http| handle_response(http.get(url)) end diff --git a/modules/wikis/app/services/wikis/oauth_clients/create_service.rb b/modules/wikis/app/services/wikis/oauth_clients/create_service.rb index 65c3dfaaade8..41b062391764 100644 --- a/modules/wikis/app/services/wikis/oauth_clients/create_service.rb +++ b/modules/wikis/app/services/wikis/oauth_clients/create_service.rb @@ -32,7 +32,7 @@ module Wikis module OAuthClients class CreateService < ::OAuthClients::CreateService def initialize(**) - super(contract_class: Wikis::OAuthClients::XWikiCreateContract, **) + super(contract_class: ::OAuthClients::CreateContract, **) end def attributes_service_class diff --git a/modules/wikis/app/views/wikis/admin/wiki_providers/edit.html.erb b/modules/wikis/app/views/wikis/admin/wiki_providers/edit.html.erb index 8c9a161588be..b8afd7cbb115 100644 --- a/modules/wikis/app/views/wikis/admin/wiki_providers/edit.html.erb +++ b/modules/wikis/app/views/wikis/admin/wiki_providers/edit.html.erb @@ -32,7 +32,12 @@ See COPYRIGHT and LICENSE files for more details. <% html_title t(:label_administration), t(:project_module_wiki_platforms), page_title %> <%= render(Primer::OpenProject::PageHeader.new) do |header| %> - <% header.with_title { page_title } %> + <% header.with_title do %> + <%= page_title %> + <%= render(Primer::Beta::Text.new(tag: :span, font_weight: :light, color: :muted)) do %> + (<%= t("wikis.provider_types.#{@wiki_provider}.name") %>) + <% end %> + <% end %> <% header.with_breadcrumbs( @@ -90,7 +95,7 @@ See COPYRIGHT and LICENSE files for more details. render(Wikis::Admin::WikiProviderViewComponent.new(@wiki_provider, wizard: @wizard)) end - page.with_sidebar(col_placement: :end, row_placement: :start) do + page.with_sidebar(col_placement: :end, row_placement: :end) do render(Wikis::Admin::SidePanelComponent.new(@wiki_provider)) end end diff --git a/modules/wikis/app/views/wikis/admin/wiki_providers/index.html.erb b/modules/wikis/app/views/wikis/admin/wiki_providers/index.html.erb index bfec99652b7b..fb08ec6d2e51 100644 --- a/modules/wikis/app/views/wikis/admin/wiki_providers/index.html.erb +++ b/modules/wikis/app/views/wikis/admin/wiki_providers/index.html.erb @@ -50,7 +50,7 @@ See COPYRIGHT and LICENSE files for more details. test_selector: "wiki-providers-create-new-button" } ) do |menu| menu.with_item( - label: I18n.t("activerecord.models.wikis/xwiki_provider"), + label: I18n.t("wikis.provider_types.xwiki.name"), href: new_admin_settings_wiki_provider_path ) end diff --git a/modules/wikis/app/views/wikis/admin/wiki_providers/new.html.erb b/modules/wikis/app/views/wikis/admin/wiki_providers/new.html.erb index 10ae6e7a8d29..9128d2f50de7 100644 --- a/modules/wikis/app/views/wikis/admin/wiki_providers/new.html.erb +++ b/modules/wikis/app/views/wikis/admin/wiki_providers/new.html.erb @@ -27,17 +27,17 @@ See COPYRIGHT and LICENSE files for more details. ++#%> -<% html_title t(:label_administration), t(:project_module_wiki_platforms), t("wikis.admin.wiki_providers.label_new_xwiki_instance") %> +<% html_title t(:label_administration), t(:project_module_wiki_platforms), t("wikis.admin.wiki_providers.label_new_provider") %> <%= render(Primer::OpenProject::PageHeader.new) do |header| %> <% header.with_title(test_selector: "wiki-provider-new-page-header--title") do %> - <%= t("wikis.admin.wiki_providers.label_new_xwiki_instance") %> + <%= t("wikis.admin.wiki_providers.label_new_provider") %> <% end %> <% header.with_breadcrumbs([ { href: admin_index_path, text: t(:label_administration) }, { href: admin_settings_wiki_providers_path, text: t(:project_module_wiki_platforms) }, - t("wikis.admin.wiki_providers.label_new_xwiki_instance") + t("wikis.admin.wiki_providers.label_new_provider") ]) %> <% header.with_description(test_selector: "wiki-provider-new-page-header--description") do %> diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml index 9e8ca1b996a9..ecdd28f9b102 100644 --- a/modules/wikis/config/locales/en.yml +++ b/modules/wikis/config/locales/en.yml @@ -35,8 +35,16 @@ en: buttons: connect_account: Connect %{provider} account done_continue: Done, continue + open_wiki: Open wiki save_and_continue: Save and continue wiki_page: Wiki page + instructions: + xwiki: + integration: XWiki Administration + oauth_application_details_html: The client secret value will not be accessible again after you close this window. Please copy these values into the [XWiki OpenProject Integration settings](xwiki_admin_link). + provider_types: + xwiki: + name: XWiki delete_relation_page_link_confirmation_dialog: title: Delete related wiki page link heading: Delete related wiki page link? @@ -80,12 +88,15 @@ en: inline wiki page link will no longer be accessible. This action is irreversible. forms: general_info_form_component: - xwiki_instance_description: Please make sure you have administration privileges in your XWiki instance before doing the setup. + provider_description: Please make sure you have administration privileges in your XWiki instance before doing the setup. oauth_application_form_component: - application_id: Application ID - application_secret: Application secret + application_id: OpenProject OAuth Application ID + application_secret: OpenProject OAuth Application secret oauth_client_form_component: - client_id: Client ID + client_id: Wiki OAuth Client ID + client_secret: Wiki OAuth Client secret + redirect_uri: Redirect URI + redirect_uri_caption: Copy this value into the Redirect URI field of your XWiki OIDC client registration. health_status: show: actions: @@ -98,10 +109,12 @@ en: title: Health Report oauth_application_info_component: confirm_replace_oauth_application: This action will reset the current OAuth credentials. After confirming you will have to reenter the credentials in your XWiki instance and all users will have to reauthorize. Are you sure you want to proceed? + label_oauth_client_id: OAuth Client ID label_pending: Pending replace_oauth_application: Replace OpenProject OAuth application oauth_client_info_component: confirm_replace_oauth_client: This action will reset the current XWiki OAuth credentials. All users will need to reauthorize against XWiki. Are you sure you want to proceed? + label_oauth_client_id: OAuth Client ID label_pending: Pending replace_oauth_client: Replace XWiki OAuth application side_panel: @@ -120,7 +133,7 @@ en: index_description: Add an external wiki service to link work packages to existing wiki pages or create new ones directly from OpenProject. label_add_new: Add new wiki provider label_edit: Edit XWiki provider - label_new_xwiki_instance: New XWiki provider + label_new_provider: New XWiki provider label_wiki_platform: Wiki provider name_caption: Give your storage a name so that users can differentiate between multiple wiki platforms. name_placeholder: XWiki knowledge base @@ -128,15 +141,14 @@ en: oauth: openproject_oauth: OpenProject OAuth sections: - general_information: Basic details + general_information: General information oauth_configuration: OAuth configuration url_caption: Please add the host address of your wiki platform including the https://. It should not be longer than 255 characters. - xwiki_instance: XWiki Instance xwiki: oauth: openproject_oauth_description: Allow XWiki to access OpenProject data using an OAuth application. Copy the credentials below into your XWiki instance. - provider_oauth: XWiki OAuth - provider_oauth_description: Allow OpenProject to access XWiki data using OAuth. A client ID is automatically generated to identify OpenProject to XWiki — no manual configuration is needed on the XWiki side. + provider_oauth: Wiki OAuth + provider_oauth_description: Allow OpenProject to access XWiki data using OAuth. A client ID and client secret have been pre-generated for you — copy them along with the redirect URI into your XWiki OIDC client registration. You can change the client ID and secret if needed. openproject_oauth_description: Allow XWiki to access OpenProject data using an OAuth. xwiki_oauth: XWiki OAuth xwiki_oauth_description: Allow OpenProject to access XWiki data using an OAuth. diff --git a/modules/wikis/spec/components/wikis/admin/oauth_application_info_component_spec.rb b/modules/wikis/spec/components/wikis/admin/oauth_application_info_component_spec.rb index f10b22afbe7d..4c9413d8ab1b 100644 --- a/modules/wikis/spec/components/wikis/admin/oauth_application_info_component_spec.rb +++ b/modules/wikis/spec/components/wikis/admin/oauth_application_info_component_spec.rb @@ -65,9 +65,11 @@ expect(page).to have_text(I18n.t(:label_completed)) end - it "renders the description" do + it "renders the oauth application id" do render_inline(described_class.new(wiki_provider)) - expect(page).to have_text(I18n.t("wikis.admin.wiki_providers.xwiki.oauth.openproject_oauth_description")) + expect(page).to have_text( + "#{I18n.t('wikis.admin.oauth_application_info_component.label_oauth_client_id')}: #{oauth_application.uid}" + ) end it "renders a sync button with a confirm dialog" do diff --git a/modules/wikis/spec/components/wikis/admin/oauth_client_info_component_spec.rb b/modules/wikis/spec/components/wikis/admin/oauth_client_info_component_spec.rb index ce923d80de79..05831fddd7c9 100644 --- a/modules/wikis/spec/components/wikis/admin/oauth_client_info_component_spec.rb +++ b/modules/wikis/spec/components/wikis/admin/oauth_client_info_component_spec.rb @@ -63,9 +63,11 @@ expect(page).to have_text(I18n.t(:label_completed)) end - it "renders the description" do + it "renders the oauth client id" do render_inline(described_class.new(wiki_provider)) - expect(page).to have_text(I18n.t("wikis.admin.wiki_providers.xwiki.oauth.provider_oauth_description")) + expect(page).to have_text( + "#{I18n.t('wikis.admin.oauth_client_info_component.label_oauth_client_id')}: #{oauth_client.client_id}" + ) end it "renders a sync icon button with a confirm dialog" do diff --git a/modules/wikis/spec/contracts/wikis/oauth_clients/x_wiki_create_contract_spec.rb b/modules/wikis/spec/contracts/wikis/oauth_clients/x_wiki_create_contract_spec.rb deleted file mode 100644 index 8b9f8065e2b7..000000000000 --- a/modules/wikis/spec/contracts/wikis/oauth_clients/x_wiki_create_contract_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 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. -#++ - -require "spec_helper" -require_module_spec_helper -require "contracts/shared/model_contract_shared_context" - -RSpec.describe Wikis::OAuthClients::XWikiCreateContract do - include_context "ModelContract shared context" - - let(:current_user) { create(:admin) } - let(:client_id) { SecureRandom.uuid } - let(:client_secret) { nil } - let(:integration) { create(:xwiki_provider) } - let(:oauth_client) { build(:oauth_client, client_id:, client_secret:, integration:) } - - let(:contract) { described_class.new(oauth_client, current_user) } - - describe "client_secret" do - context "when absent (nil)" do - include_examples "contract is valid" - end - - context "when empty string" do - let(:client_secret) { "" } - - include_examples "contract is valid" - end - - context "when too long" do - let(:client_secret) { "X" * 257 } - - include_examples "contract is invalid", client_secret: :too_long - end - end -end diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/oauth_configuration_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/oauth_configuration_spec.rb index 0676df3b9997..1fa212d3fcdb 100644 --- a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/oauth_configuration_spec.rb +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/oauth_configuration_spec.rb @@ -32,7 +32,9 @@ RSpec.describe Wikis::Adapters::Providers::XWiki::OAuthConfiguration do let(:wiki_provider) { build_stubbed(:xwiki_provider, url: "https://xwiki.example.com/xwiki") } - let(:oauth_client) { build_stubbed(:oauth_client, client_id: "xwiki-uuid", integration: wiki_provider) } + let(:oauth_client) do + build_stubbed(:oauth_client, client_id: "xwiki-uuid", client_secret: "xwiki-secret", integration: wiki_provider) + end before do allow(wiki_provider).to receive(:oauth_client).and_return(oauth_client) @@ -90,7 +92,7 @@ it "configures the rack client with correct attributes" do expect(rack_client).to have_attributes( identifier: "xwiki-uuid", - secret: nil, + secret: "xwiki-secret", token_endpoint: "/xwiki/oidc/token", authorization_endpoint: "/xwiki/oidc/authorization" ) diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/user_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/user_spec.rb index d02794d64e40..b36acd3ec67b 100644 --- a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/user_spec.rb +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/user_spec.rb @@ -35,7 +35,7 @@ let(:user) { build_stubbed(:user) } let(:oauth_client) { build_stubbed(:oauth_client) } let(:wiki_provider) { build_stubbed(:xwiki_provider, url: "https://xwiki.local/") } - let(:rest_url) { "https://xwiki.local/rest/" } + let(:user_url) { "https://xwiki.local/rest/wikis/xwiki/user" } let(:auth_strategy) { Wikis::Adapters::Input::AuthStrategy.build(key: :bearer_token, user:, provider: wiki_provider).value! } subject(:query) { described_class.new(model: wiki_provider) } @@ -51,9 +51,9 @@ end describe "#call" do - context "when the request succeeds with xwiki-user header" do + context "when the request succeeds with an xwiki-user header" do before do - stub_request(:get, rest_url) + stub_request(:get, user_url) .with(headers: { "Authorization" => "Bearer some-token" }) .to_return(status: 200, body: "", headers: { "xwiki-user" => "XWiki.admin" }) end @@ -65,10 +65,10 @@ end end - context "when the token is absent or invalid (XWiki returns 200 without xwiki-user header)" do + context "when the response is missing the xwiki-user header" do before do - stub_request(:get, rest_url) - .to_return(status: 200, body: "", headers: {}) + stub_request(:get, user_url) + .to_return(status: 200, body: "") end it "returns Failure with :unauthorized code" do @@ -80,7 +80,7 @@ context "when XWiki returns a non-2xx status" do before do - stub_request(:get, rest_url).to_return(status: 500, body: "Internal Server Error") + stub_request(:get, user_url).to_return(status: 401, body: "Unauthorized") end it "returns Failure with :request_failed code" do @@ -91,7 +91,7 @@ end context "when a network error occurs" do - before { stub_request(:get, rest_url).to_timeout } + before { stub_request(:get, user_url).to_timeout } it "returns Failure with :connection_error code" do result = query.call(auth_strategy:)