diff --git a/docs/de/user/admin/assets/administration-myC-confirmation.png b/docs/de/user/admin/assets/administration-myC-confirmation.png new file mode 100644 index 0000000000..03026d75fb Binary files /dev/null and b/docs/de/user/admin/assets/administration-myC-confirmation.png differ diff --git a/docs/de/user/admin/assets/administration-plugin-center-connected.png b/docs/de/user/admin/assets/administration-plugin-center-connected.png new file mode 100644 index 0000000000..38f7536c24 Binary files /dev/null and b/docs/de/user/admin/assets/administration-plugin-center-connected.png differ diff --git a/docs/de/user/admin/assets/administration-plugin-center-not-connected.png b/docs/de/user/admin/assets/administration-plugin-center-not-connected.png new file mode 100644 index 0000000000..22d5d4413a Binary files /dev/null and b/docs/de/user/admin/assets/administration-plugin-center-not-connected.png differ diff --git a/docs/de/user/admin/assets/administration-settings-connected.png b/docs/de/user/admin/assets/administration-settings-connected.png new file mode 100644 index 0000000000..8559e299fd Binary files /dev/null and b/docs/de/user/admin/assets/administration-settings-connected.png differ diff --git a/docs/de/user/admin/assets/administration-settings-not-connected.png b/docs/de/user/admin/assets/administration-settings-not-connected.png new file mode 100644 index 0000000000..17f4502027 Binary files /dev/null and b/docs/de/user/admin/assets/administration-settings-not-connected.png differ diff --git a/docs/de/user/admin/assets/myCloudogu-login.png b/docs/de/user/admin/assets/myCloudogu-login.png new file mode 100644 index 0000000000..0d107626ab Binary files /dev/null and b/docs/de/user/admin/assets/myCloudogu-login.png differ diff --git a/docs/de/user/admin/plugins.md b/docs/de/user/admin/plugins.md index 10714fafb6..f0049cd38c 100644 --- a/docs/de/user/admin/plugins.md +++ b/docs/de/user/admin/plugins.md @@ -2,14 +2,32 @@ title: Administration subtitle: Plugins --- -Unter dem Eintrag "Plugins" können mithilfe des externen Plugin-Centers Plugins für den SCM Manager verwaltet werden. Die Plugins werden nach installierten und verfügbaren Plugins unterschieden und nach Funktionsschwerpunkt wie bspw. Workflow oder Authentifizierung gruppiert. +Unter dem Eintrag "Plugins" werden mithilfe des externen Plugin-Centers Plugins für den SCM Manager verwaltet. Die Plugins werden nach installierten und verfügbaren Plugins unterschieden und nach Funktionsschwerpunkt wie bspw. Workflow oder Authentifizierung gruppiert. -Die Plugins können über Funktions-Icons auf den Kacheln verwaltet werden. Systemrelevante Plugins, die der SCM-Manager selbst liefert, können weder deinstalliert noch aktualisiert werden. +Die Plugins können über Aktions-Icons auf den Kacheln verwaltet werden. Systemrelevante Plugins, die der SCM-Manager selbst liefert, können weder deinstalliert noch aktualisiert werden. -Damit Änderungen der Plugins wirksam werden, muss der SCM-Manager-Server neugestartet werden. Das kann nach jeder einzelnen Aktion erfolgen. Es ist aber auch möglich viele unterschiedliche Aktionen wie Installieren, Aktualisieren und Löschen in eine Warteschlange einzureihen und alle Aktionen mit einem einzigen Neustart auszuführen. Wird eine Aktion (Installieren, Deinstallieren, Aktualisieren) für ein Plugin ausgewählt, erscheinen die Schaltflächen "Änderungen ausführen" und "Änderungen abbrechen". Über "Änderungen ausführen" öffnet sich ein Pop-Up Fenster, indem die aktuelle Warteschlange (alle ausgeführten Aktionen ohne Neustart) angezeigt werden. Der Anwender hat nun die Möglichkeit zu entscheiden, ob die Änderungen durch einen Neustart ausgeführt werden sollen. Falls Aktionen, die sich bereits in der Warteschlange befinden nicht mehr erwünscht sind, kann die gesamte Warteschlange über den Button "Änderungen abbrechen" verworfen werden. +Damit Änderungen der Plugins wirksam werden, muss der SCM-Manager-Server neu gestartet werden. Das kann nach jeder einzelnen Aktion erfolgen. Es ist aber auch möglich viele unterschiedliche Aktionen wie Installieren, Aktualisieren und Löschen in eine Warteschlange einzureihen und alle Aktionen mit einem einzigen Neustart auszuführen. Wird eine Aktion (Installieren, Deinstallieren, Aktualisieren) für ein Plugin ausgewählt, erscheinen die Schaltflächen „Änderungen ausführen“ und „Änderungen abbrechen“. Über „Änderungen ausführen“ öffnet sich ein Pop-Up Fenster, in dem die aktuelle Warteschlange (alle ausgeführten Aktionen ohne Neustart) angezeigt werden. Der Anwender hat nun die Möglichkeit zu entscheiden, ob die Änderungen durch einen Neustart ausgeführt werden sollen. Falls Aktionen, die sich bereits in der Warteschlange befinden nicht mehr erwünscht sind, kann die gesamte Warteschlange über den Button „Änderungen abbrechen“ verworfen werden. + +### myCloudogu-Plugins +Einige besondere Plugins sind nur für Instanzen des SCM-Managers verfügbar, die mit myCloudogu verbunden sind. Der SCM-Manager kann über den Button „Mit myCloudogu verbinden“ mit myCloudogu verbunden werden. +![Plugin-Center nicht verbunden, Button zur Verbindung mit myCloudogu](assets/administration-plugin-center-not-connected.png) +Sie werden dann zur myCloudogu-Login-Maske weitergeleitet. +![myCloudogu-Login-Maske](assets/myCloudogu-login.png) +Wenn Sie über ein myCloudogu-Konto verfügen, können Sie sich einloggen. Ansonsten erstellen Sie über einen konföderierten Identitätsanbieter (Google oder github) oder Ihre Email-Adresse ein Konto. +Anschließend werden Sie zurück zum SCM-Manager geleitet und können Details zur verbundenen Instanz und Konto überprüfen. Mit „Verbinden“ bestätigen Sie die Verbindung, mit „Abbrechen“ brechen Sie den Vorgang ab. +![Bestätigung der Verbindung mit myCloudogu](assets/administration-myC-confirmation.png) +Jetzt können Sie im Plugin-Center myCloudogu-Plugins genau wie Basis-Plugins installieren. +![SCM-Manager mit myCloudogu verbunden](assets/administration-plugin-center-connected.png) +Eine Instanz des SCM-Managers muss nur mit einem Konto verbunden werden, damit die myCloudogu-Plugins für die gesamte Instanz zur Verfügung stehen. +Sie können die Verbindung zu myCloudogu jederzeit unter Plugin Center Einstellungen in den Settings lösen. + +#### Was ist myCloudogu und warum sollte ich ein Konto erstellen? +myCloudogu ist nicht nur die Heimat der SCM-Manager-Community. Sie können sich auch mit anderen Nutzenden austauschen, Bugs melden oder neue Funktionen im Forum zur Diskussion stellen. +myCloudogu bietet weiter besondere Plugins speziell für die Community an. In der Zukunft folgen weitere nützliche Plugins, die auch gemeinsam mit Partnern bereitgestellt werden. +Nutzen Sie erweiterte Plugin-Funktionen im SCM-Managers, treten Sie mit den Entwicklern in Kontakt und schließen Sie sich [myCloudogu](https://my.cloudogu.com) kostenfrei an! ### Installiert -Auf der Übersicht für installierte Plugins werden alle auf der SCM-Manager Instanz installierten Plugins angezeigt. Optionale Plugins können hier deinstalliert und aktualisiert werden. +Auf der Übersicht für installierte Plugins werden alle auf der SCM-Manager Instanz installierten Plugins angezeigt. Optionale Plugins können hier aktualisiert und deinstalliert werden. ![Administration-Plugins-Installed](assets/administration-plugins-installed.png) diff --git a/docs/de/user/admin/settings.md b/docs/de/user/admin/settings.md index 452780e96d..a093db4394 100644 --- a/docs/de/user/admin/settings.md +++ b/docs/de/user/admin/settings.md @@ -23,8 +23,13 @@ Auf der Login-Seite des SCM-Managers werden hilfreiche Plugins und Features vorg #### XSRF Protection aktivieren Um Angriffe auf den SCM-Manager mit Cross Site Scripting (XSS / XSRF) zu erschweren. Dieses Feature ist noch experimentell. -#### Plugin-Center-URL +#### Plugin-Settings Der SCM-Manager kann ein Plugin-Center anbinden, um schnell und bequem Plugins verwalten zu können. Um ein anderes SCM-Plugin-Center als das vorkonfigurierte zu verwenden, reicht es aus diese URL zu ändern. Läuft der SCM-Manager im Cloudogu EcoSystem kann die Plugin Center URL über einen Eintrag im etcd gesetzt werden. +Wenn das vorkonfigurierte Plugin-Center verwendet wird, kann der SCM-Manager mit myCloudogu verbunden werden. +![Einstellungen, Plugin-Center nicht mit myCloudogu verbunden](assets/administration-settings-not-connected.png) +So können über das Plugin-Center besondere myCloudogu-Plugins bezogen werden. Details sind in der Dokumentation des Plugin-Centers aufgeführt. +Eine bestehende Verbindung zwischen dem SCM-Manager und myCloudogu kann hier aufgehoben werden. +![Einstellungen, Plugin-Center mit myCloudogu verbunden, Button zum Lösen der Verbindung](assets/administration-settings-connected.png) #### Anonyme Zugriff Der SCM-Manager 2 hat das Konzept für anonyme Zugriffe über einen "_anonymous"-Benutzer realisiert. Beim Aktivieren des anonymen Zugriffs wird ein neuer Benutzer erstellt mit dem Namen "_anonymous". Dieser Nutzer kann wie ein gewöhnlicher Benutzer für unterschiedliche Aktionen berechtigt werden. Bei einem Zugriff auf den SCM-Manager ohne Zugangsdaten wird dieser anonyme Benutzer verwendet. diff --git a/docs/en/user/admin/assets/administration-myC-confirmation.png b/docs/en/user/admin/assets/administration-myC-confirmation.png new file mode 100644 index 0000000000..7982b07b4b Binary files /dev/null and b/docs/en/user/admin/assets/administration-myC-confirmation.png differ diff --git a/docs/en/user/admin/assets/administration-plugin-center-connected.png b/docs/en/user/admin/assets/administration-plugin-center-connected.png new file mode 100644 index 0000000000..d813b2ec69 Binary files /dev/null and b/docs/en/user/admin/assets/administration-plugin-center-connected.png differ diff --git a/docs/en/user/admin/assets/administration-plugin-center-not-connected.png b/docs/en/user/admin/assets/administration-plugin-center-not-connected.png new file mode 100644 index 0000000000..50bdee7f41 Binary files /dev/null and b/docs/en/user/admin/assets/administration-plugin-center-not-connected.png differ diff --git a/docs/en/user/admin/assets/administration-setings-not-connected.png b/docs/en/user/admin/assets/administration-setings-not-connected.png new file mode 100644 index 0000000000..09663483ed Binary files /dev/null and b/docs/en/user/admin/assets/administration-setings-not-connected.png differ diff --git a/docs/en/user/admin/assets/administration-settings-connected.png b/docs/en/user/admin/assets/administration-settings-connected.png new file mode 100644 index 0000000000..c3616ac9f3 Binary files /dev/null and b/docs/en/user/admin/assets/administration-settings-connected.png differ diff --git a/docs/en/user/admin/assets/myCloudogu-Login.png b/docs/en/user/admin/assets/myCloudogu-Login.png new file mode 100644 index 0000000000..9b4683d29e Binary files /dev/null and b/docs/en/user/admin/assets/myCloudogu-Login.png differ diff --git a/docs/en/user/admin/plugins.md b/docs/en/user/admin/plugins.md index 07cc6676eb..e7c374e537 100644 --- a/docs/en/user/admin/plugins.md +++ b/docs/en/user/admin/plugins.md @@ -2,18 +2,36 @@ title: Administration subtitle: Plugins --- -In the plugins section, plugins for SCM-Manager can be managed with the help of the external plugin center. Plugins are distinguished between installed and available plugins and are grouped based on their main functionality like for example workflow or authentication. +In the plugins section, plugins for SCM-Manager can be managed with the help of the external plugin center. Plugins are distinguished between installed and available plugins. They are grouped based on their main functionality like for example workflow or authentication. -Plugins can be managed by functionality icons on the tiles. System relevant plugins that come with SCM-Manager by default cannot be deinstalled or updated. +Plugins can be managed by action icons on the tiles. System relevant plugins that come with SCM-Manager by default cannot be uninstalled or updated. -In order for changes to plugins to become effective, the SCM-Manager server needs to be restarted. That can be done after every single action. It is also possible to queue several actions like the installation of a new plugin, updates or the deletion of a plugin and to perform all actions with one restart. If an action (installation, deinstallation, update) for a plugin was performed, the buttons "Execute changes" and "Abort changes" appear. If you choose to execute the changes, a popup window that shows the current queue (all actions without a restart) appears. Now the user can decide whether to execute the changes by restarting the server. If there are actions in the queue that are no longer desired, the queue can be emptied with the about changes button. +In order for changes to plugins to become effective, the SCM-Manager server needs to be restarted. That can be done after every single action. It is also possible to queue several actions like the installation of a new plugin, updates or the deletion of a plugin and to perform all actions with one restart. If an action (installation, uninstallation, update) for a plugin was performed, the buttons "Execute changes" and "Abort changes" appear. If you choose to execute the changes, a popup window that shows the current queue (all actions without a restart) appears. Now the user can decide whether to execute the changes by restarting the server. If there are actions in the queue that are no longer desired, the queue can be emptied with the abort changes button. + +### myCloudogu plugins +Some special plugins are only available to instances of SCM-Manager that are connected to myCloudogu. You may connect your instance by clicking the button “Connect to myCloudogu” ![Plugin-center not connected](assets/administration-plugin-center-not-connected.png). + +You will be redirected to a myCloudogu login form. ![myCloudogu-Login-Form](assets/myCloudogu-Login.png) If you already have an account you simply log in. Otherwise you can create an account either by using a confederate identity provider (Google or github) +or with your email. +After a successful login you will return to the SCM-Manager. Here you can review the instance and account to connect. By clicking the button “Connect” you approve the connection and return to the plugin center. ![Confirmation of connection](assets/administration-myC-confirmation.png) + +Now you can install myCloudogu plugins like basic plugins. +![Plugin-center connected with myCloudogu](assets/administration-plugin-center-connected.png) +Only one user with sufficient permissions needs to connect the instance with myCloudogu. The myCloudogu plugins can than be installed by every user with suitable permissions. +You can always sever the connection in the plugin center settings in global settings of your instance. + +#### What is myCloudogu and why should you create an account? +myCloudogu is not only the home of the SCM-Manager community. You can connect to other users, get help and express feature requests in the forum. +myCloudogu also serves special plugins to provide more value for our community. In the future myCloudogu will offer exiting plugins developed in cooperation with our partners. +To unlock the full power of SCM-Manager and to hang out with our developers, join [myCloudogu](https://my.cloudogu.com/) for free! ### Installed -The overview for installed plugins shows all plugins that are currently installed on the SCM-Manager instance. Plugins that are optional can be deinstalled or updated here. +The overview for installed plugins shows all plugins that are currently installed on the SCM-Manager instance. Optional plugins can be uninstalled or updated here. ![Administration-Plugins-Installed](assets/administration-plugins-installed.png) ### Available The overview of all available plugins shows all plugins that are compatible with the current version of the SCM-Manager instance that are available through the SCM-plugin-center. The plugins can be downloaded by clicking on the icon and will be installed after a restart of the SCM-Manager server. +Special myCloudogu-plugins can be installed the same way if your instance of SCM-Manager is connected to myCloudogu as described above. ![Administration-Plugins-Available](assets/administration-plugins-available.png) diff --git a/docs/en/user/admin/settings.md b/docs/en/user/admin/settings.md index d49e89b6b1..19147475f3 100644 --- a/docs/en/user/admin/settings.md +++ b/docs/en/user/admin/settings.md @@ -23,8 +23,12 @@ The login screen of SCM-Manager shows helpful plugins and features. If you want #### Enable XSRF Protection Activate this option to make attacks using cross site scripting (XSS / XSRF) on SCM-Manager more difficult. This feature is still in an experimental state. -#### Plugin Center URL +#### Plugin-Settings A plugin center can be used to conveniently manage plugins. If you want to use a plugin center that is not the default one, you only have to change this URL. If SCM-Manager is operated as part of a Cloudogu EcoSystem, the plugin center URL can be changed in the etcd. +If the default plugin center is used, the SCM-Manager may be connected to myCloudogu to receive special myCloudogu-Plugins. Details can be found in the plugin-center documentation. +![Plugin center settings, not connected to myCloudogu](assets/administration-setings-not-connected.png) +An existing connection between a SCM-Manager and myCloudogu may be severed here. +![Plugin center settings, button sever connection to myCloudogu](assets/administration-settings-connected.png) #### Anonymous Access In SCM-Manager 2 the access for anonymous access is realized by using an "_anonymous" user. When the feature is activated, a new user with the name "_anonymous" is created. This user can be authorized just like any other user. This user is used for access to SCM-Manager without login credentials. diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index dfc448032f..72d1a0e8b1 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -69,6 +69,13 @@ public class ScmConfiguration implements Configuration { public static final String DEFAULT_PLUGINURL = "https://plugin-center-api.scm-manager.org/api/v1/plugins/{version}?os={os}&arch={arch}&jre={jre}"; + /** + * Default url for plugin center authentication. + * @since 2.28.0 + */ + public static final String DEFAULT_PLUGIN_AUTH_URL = + "https://plugin-center-api.scm-manager.org/api/v1/auth/oidc"; + /** * SCM Manager release feed url */ @@ -154,6 +161,9 @@ public class ScmConfiguration implements Configuration { @XmlElement(name = "plugin-url") private String pluginUrl = DEFAULT_PLUGINURL; + @XmlElement(name = "plugin-auth-url") + private String pluginAuthUrl = DEFAULT_PLUGIN_AUTH_URL; + @XmlElement(name = "release-feed-url") private String releaseFeedUrl = DEFAULT_RELEASE_FEED_URL; @@ -163,7 +173,7 @@ public class ScmConfiguration implements Configuration { * @since 1.34 */ @XmlElement(name = "login-attempt-limit-timeout") - private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5l); + private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5L); private boolean enableProxy = false; @@ -243,6 +253,7 @@ public class ScmConfiguration implements Configuration { this.realmDescription = other.realmDescription; this.dateFormat = other.dateFormat; this.pluginUrl = other.pluginUrl; + this.pluginAuthUrl = other.pluginAuthUrl; this.anonymousMode = other.anonymousMode; this.enableProxy = other.enableProxy; this.proxyPort = other.proxyPort; @@ -319,6 +330,24 @@ public class ScmConfiguration implements Configuration { return pluginUrl; } + /** + * Returns the url which is used for plugin center authentication. + * @return authentication url + * @since 2.28.0 + */ + public String getPluginAuthUrl() { + return pluginAuthUrl; + } + + /** + * Returns {@code true} if the default plugin auth url is used. + * @return {@code true} if the default plugin auth url is used + * @since 2.28.0 + */ + public boolean isDefaultPluginAuthUrl() { + return DEFAULT_PLUGIN_AUTH_URL.equals(pluginAuthUrl); + } + /** * Returns the url of the rss release feed. * @@ -543,6 +572,15 @@ public class ScmConfiguration implements Configuration { this.pluginUrl = pluginUrl; } + /** + * Set the url for plugin center authentication. + * @param pluginAuthUrl authentication url + * @since 2.28.0 + */ + public void setPluginAuthUrl(String pluginAuthUrl) { + this.pluginAuthUrl = pluginAuthUrl; + } + public void setReleaseFeedUrl(String releaseFeedUrl) { this.releaseFeedUrl = releaseFeedUrl; } diff --git a/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java b/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java index 5b0ebc453c..55ef1f033b 100644 --- a/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java +++ b/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java @@ -106,6 +106,18 @@ public abstract class BaseHttpRequest return self(); } + /** + * Enable authentication with a bearer token. + * @param bearerToken bearer token + * @return http request instance + * @since 2.28.0 + */ + public T bearerAuth(String bearerToken) { + headers.put("Authorization", "Bearer ".concat(bearerToken)); + + return self(); + } + /** * Enable or disabled gzip decoding. The default value is false. * diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java index 4b90b258e5..75ff8957c4 100644 --- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java +++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java @@ -69,6 +69,7 @@ public class VndMediaType { public static final String REPOSITORY_TYPE = PREFIX + "repositoryType" + SUFFIX; public static final String PLUGIN = PREFIX + "plugin" + SUFFIX; public static final String PLUGIN_COLLECTION = PREFIX + "pluginCollection" + SUFFIX; + public static final String PLUGIN_CENTER_AUTH_INFO = PREFIX + "pluginCenterAuthInfo" + SUFFIX; public static final String UI_PLUGIN = PREFIX + "uiPlugin" + SUFFIX; public static final String UI_PLUGIN_COLLECTION = PREFIX + "uiPluginCollection" + SUFFIX; @SuppressWarnings("squid:S2068") diff --git a/scm-core/src/test/java/sonia/scm/config/ScmConfigurationTest.java b/scm-core/src/test/java/sonia/scm/config/ScmConfigurationTest.java new file mode 100644 index 0000000000..a1771b9c05 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/config/ScmConfigurationTest.java @@ -0,0 +1,46 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.config; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ScmConfigurationTest { + + private final ScmConfiguration scmConfiguration = new ScmConfiguration(); + + @Test + void shouldReturnTrueForInitialPluginAuthUrl() { + assertThat(scmConfiguration.isDefaultPluginAuthUrl()).isTrue(); + } + + @Test + void shouldReturnFalseIfPluginAuthUrlHasChanged() { + scmConfiguration.setPluginAuthUrl("https://plug.ins/oidc"); + assertThat(scmConfiguration.isDefaultPluginAuthUrl()).isFalse(); + } + +} diff --git a/scm-core/src/test/java/sonia/scm/net/ahc/BaseHttpRequestTest.java b/scm-core/src/test/java/sonia/scm/net/ahc/BaseHttpRequestTest.java index b06f6c098e..d4f98663f6 100644 --- a/scm-core/src/test/java/sonia/scm/net/ahc/BaseHttpRequestTest.java +++ b/scm-core/src/test/java/sonia/scm/net/ahc/BaseHttpRequestTest.java @@ -28,108 +28,116 @@ import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import java.io.IOException; import java.util.Collection; -import org.junit.Test; -import static org.junit.Assert.*; -import static org.hamcrest.Matchers.*; -import org.junit.Before; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; + +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; /** * * @author Sebastian Sdorra */ -@RunWith(MockitoJUnitRunner.class) -public class BaseHttpRequestTest { +@ExtendWith(MockitoExtension.class) +class BaseHttpRequestTest { @Mock private AdvancedHttpClient ahc; private BaseHttpRequest request; - @Before + @BeforeEach public void before(){ request = new AdvancedHttpRequest(ahc, HttpMethod.GET, "https://www.scm-manager.org"); } @Test - public void testBasicAuth() - { + void shouldAddAuthorizationHeaderWithBasicScheme() { request.basicAuth("tricia", "mcmillian123"); Multimap headers = request.getHeaders(); - assertEquals("Basic dHJpY2lhOm1jbWlsbGlhbjEyMw==", headers.get("Authorization").iterator().next()); + assertThat(headers.get("Authorization").iterator().next()).isEqualTo("Basic dHJpY2lhOm1jbWlsbGlhbjEyMw=="); + } + + @Test + void shouldAddAuthorizationHeaderWithBearerScheme() { + request.bearerAuth("awesome-access-token"); + Multimap headers = request.getHeaders(); + assertThat(headers.get("Authorization").iterator().next()).isEqualTo("Bearer awesome-access-token"); } @Test - public void testQueryString(){ + void shouldAppendQueryString(){ request.queryString("a", "b"); - assertEquals("https://www.scm-manager.org?a=b", request.getUrl()); + assertThat(request.getUrl()).isEqualTo("https://www.scm-manager.org?a=b"); } @Test - public void testQueryStringMultiple(){ + void shouldAppendMultipleQueryStrings(){ request.queryString("a", "b"); request.queryString("c", "d", "e"); - assertEquals("https://www.scm-manager.org?a=b&c=d&c=e", request.getUrl()); + assertThat(request.getUrl()).isEqualTo("https://www.scm-manager.org?a=b&c=d&c=e"); } @Test - public void testQueryStringEncoded(){ + void shouldEscapeQueryString(){ request.queryString("a", "äüö"); - assertEquals("https://www.scm-manager.org?a=%C3%A4%C3%BC%C3%B6", request.getUrl()); + assertThat(request.getUrl()).isEqualTo("https://www.scm-manager.org?a=%C3%A4%C3%BC%C3%B6"); } @Test - public void testQueryStrings(){ - Iterable i1 = Lists.newArrayList("b"); - Iterable i2 = Lists.newArrayList("d", "e"); + void shouldAppendQueryStringFromIterable(){ + Iterable i1 = Lists.newArrayList("b"); + Iterable i2 = Lists.newArrayList("d", "e"); request.queryStrings("a", i1); request.queryStrings("c", i2); - assertEquals("https://www.scm-manager.org?a=b&c=d&c=e", request.getUrl()); + + assertThat(request.getUrl()).isEqualTo("https://www.scm-manager.org?a=b&c=d&c=e"); } @Test - public void testQuerqStringNullValue(){ + void ShouldNotAppendQueryStringWithNullValue(){ request.queryString("a", null, "b"); - assertEquals("https://www.scm-manager.org?a=&a=b", request.getUrl()); + assertThat(request.getUrl()).isEqualTo("https://www.scm-manager.org?a=&a=b"); } @Test - public void testHeader(){ + void shouldAddHeader(){ request.header("a", "b"); - assertEquals("b", request.getHeaders().get("a").iterator().next()); + assertThat(request.getHeaders().get("a").iterator().next()).isEqualTo("b"); } @Test - public void testHeaderMultiple(){ + void shouldAddHeaderWithMultipleValues(){ request.header("a", "b", "c", "d"); - Collection values = request.getHeaders().get("a"); - assertThat(values, contains("b", "c", "d")); + assertThat( request.getHeaders().get("a")).contains("b", "c", "d"); } @Test - public void testRequest() throws IOException{ + void shouldExecuteWithClient() throws IOException{ request.request(); + verify(ahc).request(request); } @Test - public void testBuilderMethods(){ - Iterable i1 = Lists.newArrayList("b"); - assertThat(request.decodeGZip(true), instanceOf(AdvancedHttpRequest.class)); - assertTrue(request.isDecodeGZip()); - assertThat(request.disableCertificateValidation(true), instanceOf(AdvancedHttpRequest.class)); - assertTrue(request.isDisableCertificateValidation()); - assertThat(request.disableHostnameValidation(true), instanceOf(AdvancedHttpRequest.class)); - assertTrue(request.isDisableHostnameValidation()); - assertThat(request.ignoreProxySettings(true), instanceOf(AdvancedHttpRequest.class)); - assertTrue(request.isIgnoreProxySettings()); - assertThat(request.header("a", "b"), instanceOf(AdvancedHttpRequest.class)); - assertThat(request.headers("a", i1), instanceOf(AdvancedHttpRequest.class)); - assertThat(request.queryString("a", "b"), instanceOf(AdvancedHttpRequest.class)); - assertThat(request.queryStrings("a", i1), instanceOf(AdvancedHttpRequest.class)); + void shouldApplyValueFromBuilderMethods(){ + Iterable i1 = Lists.newArrayList("b"); + assertThat(request.decodeGZip(true)).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.isDecodeGZip()).isTrue(); + assertThat(request.disableCertificateValidation(true)).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.isDisableCertificateValidation()).isTrue(); + assertThat(request.disableHostnameValidation(true)).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.isDisableHostnameValidation()).isTrue(); + assertThat(request.ignoreProxySettings(true)).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.isIgnoreProxySettings()).isTrue(); + assertThat(request.header("a", "b")).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.headers("a", i1)).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.queryString("a", "b")).isInstanceOf(AdvancedHttpRequest.class); + assertThat(request.queryStrings("a", i1)).isInstanceOf(AdvancedHttpRequest.class); } } diff --git a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStore.java b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStore.java index 791a535521..560c0779f1 100644 --- a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStore.java +++ b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStore.java @@ -45,4 +45,8 @@ public class InMemoryConfigurationStore implements ConfigurationStore { this.object = obejct; } + @Override + public void delete() { + object = null; + } } diff --git a/scm-ui/ui-api/src/config.test.ts b/scm-ui/ui-api/src/config.test.ts index 900c297fc2..2b1f7311a0 100644 --- a/scm-ui/ui-api/src/config.test.ts +++ b/scm-ui/ui-api/src/config.test.ts @@ -50,6 +50,7 @@ describe("Test config hooks", () => { namespaceStrategy: "", emergencyContacts: [], pluginUrl: "", + pluginAuthUrl: "", proxyExcludes: [], proxyPassword: null, proxyPort: 0, diff --git a/scm-ui/ui-api/src/index.ts b/scm-ui/ui-api/src/index.ts index 1d25c4b1ca..e13c174c25 100644 --- a/scm-ui/ui-api/src/index.ts +++ b/scm-ui/ui-api/src/index.ts @@ -59,6 +59,7 @@ export * from "./contentType"; export * from "./annotations"; export * from "./search"; export * from "./loginInfo"; +export * from "./usePluginCenterAuthInfo"; export { default as ApiProvider } from "./ApiProvider"; export * from "./ApiProvider"; diff --git a/scm-ui/ui-api/src/usePluginCenterAuthInfo.ts b/scm-ui/ui-api/src/usePluginCenterAuthInfo.ts new file mode 100644 index 0000000000..a160625a20 --- /dev/null +++ b/scm-ui/ui-api/src/usePluginCenterAuthInfo.ts @@ -0,0 +1,78 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { ApiResult, useIndexLink } from "./base"; +import { Link, PluginCenterAuthenticationInfo } from "@scm-manager/ui-types"; +import { useMutation, useQuery, useQueryClient } from "react-query"; +import { apiClient } from "./apiclient"; +import { useLocation } from "react-router-dom"; + +export const usePluginCenterAuthInfo = (): ApiResult => { + const link = useIndexLink("pluginCenterAuth"); + const location = useLocation(); + return useQuery( + ["pluginCenterAuth"], + () => { + if (!link) { + throw new Error("no such plugin center auth link"); + } + return apiClient + .get(link) + .then(response => response.json()) + .then((result: PluginCenterAuthenticationInfo) => { + if (result._links?.login) { + (result._links.login as Link).href += `?source=${location.pathname}`; + } + return result; + }); + }, + { + enabled: !!link + } + ); +}; + +export const usePluginCenterLogout = (authenticationInfo: PluginCenterAuthenticationInfo) => { + const queryClient = useQueryClient(); + const { mutate, isLoading, error } = useMutation( + () => { + if (!authenticationInfo._links.logout) { + throw new Error("authenticationInfo has no logout link"); + } + const logout = authenticationInfo._links.logout as Link; + return apiClient.delete(logout.href); + }, + { + onSuccess: () => queryClient.invalidateQueries("pluginCenterAuth") + } + ); + + return { + logout: () => { + mutate(); + }, + isLoading, + error + }; +}; diff --git a/scm-ui/ui-components/src/buttons/Button.tsx b/scm-ui/ui-components/src/buttons/Button.tsx index 910c660690..d2bd3f0651 100644 --- a/scm-ui/ui-components/src/buttons/Button.tsx +++ b/scm-ui/ui-components/src/buttons/Button.tsx @@ -61,32 +61,43 @@ const Button: FC = ({ loading, disabled, action, - color = "default", + color = "default" }) => { const renderIcon = () => { return <>{icon ? : null}; }; + const classes = classNames( + "button", + "is-" + color, + { "is-loading": loading }, + { "is-fullwidth": fullWidth }, + { "is-reduced-mobile": reducedMobile }, + className + ); + + const content = ( + <> + {renderIcon()}{" "} + {(label || children) && ( + <> + {label} {children} + + )} + + ); + if (link && !disabled) { + if (link.includes("://")) { + return ( + + {content} + + ); + } return ( - - {renderIcon()}{" "} - {(label || children) && ( - <> - {label} {children} - - )} + + {content} ); } @@ -96,23 +107,11 @@ const Button: FC = ({ type={type} title={title} disabled={disabled} - onClick={(event) => action && action(event)} - className={classNames( - "button", - "is-" + color, - { "is-loading": loading }, - { "is-fullwidth": fullWidth }, - { "is-reduced-mobile": reducedMobile }, - className - )} + onClick={event => action && action(event)} + className={classes} {...createAttributesForTesting(testId)} > - {renderIcon()}{" "} - {(label || children) && ( - <> - {label} {children} - - )} + {content} ); }; diff --git a/scm-ui/ui-styles/src/components/_main.scss b/scm-ui/ui-styles/src/components/_main.scss index aa1ade6a3d..a9b85bc537 100644 --- a/scm-ui/ui-styles/src/components/_main.scss +++ b/scm-ui/ui-styles/src/components/_main.scss @@ -384,6 +384,15 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; .has-border-white { border-color: $white !important; } + +.has-border-success { + border-color: $success !important; +} + +.has-border-info { + border-color: $info !important; +} + ul.is-separated { > li:after { content: ",\2800"; @@ -396,12 +405,12 @@ ul.is-separated { // card columns for repo and plugins overview .card-columns { .column { - height: 120px; + height: 160px; margin-bottom: 1.5rem; .overlay-column { position: absolute; - height: calc(120px - 1.5rem); + height: calc(160px - 1.5rem); } } diff --git a/scm-ui/ui-types/src/Config.ts b/scm-ui/ui-types/src/Config.ts index 808c8e7a59..dce8616fd1 100644 --- a/scm-ui/ui-types/src/Config.ts +++ b/scm-ui/ui-types/src/Config.ts @@ -43,6 +43,7 @@ export type Config = HalRepresentation & { proxyExcludes: string[]; skipFailedAuthenticators: boolean; pluginUrl: string; + pluginAuthUrl: string; loginAttemptLimitTimeout: number; enabledXsrfProtection: boolean; enabledUserConverter: boolean; diff --git a/scm-ui/ui-types/src/Plugin.ts b/scm-ui/ui-types/src/Plugin.ts index a9955d27e0..c351aea7d8 100644 --- a/scm-ui/ui-types/src/Plugin.ts +++ b/scm-ui/ui-types/src/Plugin.ts @@ -59,3 +59,10 @@ export type PendingPlugins = HalRepresentationWithEmbedded<{ update: Plugin[]; uninstall: Plugin[]; }>; + +export type PluginCenterAuthenticationInfo = HalRepresentation & { + principal?: string; + pluginCenterSubject?: string; + date?: string; + default: boolean; +}; diff --git a/scm-ui/ui-webapp/public/locales/de/admin.json b/scm-ui/ui-webapp/public/locales/de/admin.json index c8e6d079b7..2459bc1075 100644 --- a/scm-ui/ui-webapp/public/locales/de/admin.json +++ b/scm-ui/ui-webapp/public/locales/de/admin.json @@ -49,7 +49,7 @@ "install": "{{name}} Plugin installieren", "update": "{{name}} Plugin aktualisieren", "uninstall": "{{name}} Plugin deinstallieren", - "cloudoguInstall": "Plugin über myCloudogu installieren" + "cloudoguInstall": "{{name}} Plugin installieren" }, "restart": "Neustarten, um Plugin-Änderungen wirksam zu machen", "install": "Installieren", @@ -69,8 +69,8 @@ "version": "Version", "currentVersion": "Installierte Version", "newVersion": "Neue Version", - "cloudoguInstallInfo": "Dieses Plugin ist exklusiv über myCloudogu erhältlich. Zum Installieren folgen Sie bitte der Anleitung.", - "cloudoguInstall": "Zur Installationsanleitung", + "cloudoguInstallInfo": "Verbinden Sie Ihre SCM-Manager-Instanz mit ihrem myCloudogu-Account um Zugriff auf myCloudogu-Plugins zu erhalten. Falls Sie noch über keinen Account verfügen, können Sie sich einfach kostenlos registrieren.", + "cloudoguInstall": "Mit myCloudogu verbinden und installieren", "dependencyNotification": "Mit diesem Plugin werden folgende Abhängigkeiten mit installiert bzw. aktualisiert, wenn sie noch nicht in der aktuellen Version vorhanden sind!", "optionalDependencyNotification": "Mit diesem Plugin werden folgende optionale Abhängigkeiten mit aktualisiert, falls sie installiert sind!", "dependencies": "Abhängigkeiten", @@ -85,6 +85,15 @@ "updateAllInfo": "Die folgenden Plugins werden aktualisiert. Die Änderungen werden nach dem nächsten Neustart wirksam.", "manualRestartRequired": "Nachdem die Plugin-Änderung durchgeführt wurde, muss SCM-Manager neu gestartet werden.", "showPending": "Um die folgenden Plugin-Änderungen auszuführen, muss SCM-Manager neu gestartet werden." + }, + "myCloudogu": { + "connectionInfo": "Instanz ist mit myCloudogu verbunden.\nAccount: {{pluginCenterSubject}}", + "login": { + "button": { + "label": "Mit <0>myCloudogu verbinden" + }, + "description": "Verbinden Sie Ihren SCM-Manager mit <0>myCloudogu um besondere Plugins zu installieren. myCloudogu ist die Heimat der SCM-Manager Community, getragen von Maintainern des SCM-Managers. Sie haben noch kein Konto? Erstellen Sie während der Verbindung der SCM-Manager-Instanz kostenfrei ein myCloudogu-Konto." + } } }, "repositoryRole": { diff --git a/scm-ui/ui-webapp/public/locales/de/config.json b/scm-ui/ui-webapp/public/locales/de/config.json index cf0799becc..f3056f2940 100644 --- a/scm-ui/ui-webapp/public/locales/de/config.json +++ b/scm-ui/ui-webapp/public/locales/de/config.json @@ -11,6 +11,19 @@ "no-write-permission-notification": "Hinweis: Es fehlen Berechtigungen zum Bearbeiten der Einstellungen!" } }, + "pluginSettings": { + "subtitle": "Plugin Einstellungen", + "pluginUrl": "Plugin Center URL", + "pluginAuthUrl": "Plugin Center Authentifizierungs URL", + "auth": { + "loading": "Lade Authentifizierungs Informationen ...", + "notAuthenticated": "Das Plugin Center ist nicht authentifiziert", + "authenticate": "Authentifizieren", + "authenticated": "Das Plugin Center ist als <0 /> authentifiziert", + "subjectTooltip": "Authentifiziert als {{ principal }} {{ ago }}", + "logout": "Abmelden" + } + }, "proxySettings": { "subtitle": "Proxy Einstellungen", "enable": "Proxy aktivieren", @@ -54,7 +67,6 @@ "off": "Deaktivieren" }, "skip-failed-authenticators": "Fehlgeschlagene Authentifizierer überspringen", - "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", "mail-domain-name": "Fallback E-Mail Domain Name", "enabled-xsrf-protection": "XSRF Protection aktivieren", @@ -79,6 +91,7 @@ "realmDescriptionHelpText": "Beschreibung des Authentication Realm.", "dateFormatHelpText": "Moments Datumsformat. Zulässige Formate sind in der MomentJS Dokumentation beschrieben.", "pluginUrlHelpText": "Die URL der Plugin Center API. Beschreibung der Platzhalter: version = SCM-Manager Version; os = Betriebssystem; arch = Architektur", + "pluginAuthUrlHelpText": "Die URL der Plugin Center Authentifizierungs API.", "releaseFeedUrlHelpText": "Die URL des RSS Release Feed des SCM-Manager. Darüber wird über die neue SCM-Manager Version informiert. Um diese Funktion zu deaktivieren lassen Sie dieses Feld leer.", "mailDomainNameHelpText": "Dieser Domain Name wird genutzt, wenn für einen User eine E-Mail-Adresse benötigt wird, für den keine hinterlegt ist. Diese Domain wird nicht zum Versenden von E-Mails genutzt und auch keine anderweitige Verbindung aufgebaut.", "enableForwardingHelpText": "mod_proxy Port Weiterleitung aktivieren.", diff --git a/scm-ui/ui-webapp/public/locales/en/admin.json b/scm-ui/ui-webapp/public/locales/en/admin.json index 69478a13df..18121a3c3f 100644 --- a/scm-ui/ui-webapp/public/locales/en/admin.json +++ b/scm-ui/ui-webapp/public/locales/en/admin.json @@ -49,7 +49,7 @@ "install": "Install {{name}} Plugin", "update": "Update {{name}} Plugin", "uninstall": "Uninstall {{name}} Plugin", - "cloudoguInstall": "Get plugin from myCloudogu" + "cloudoguInstall": "Install {{name}} Plugin" }, "restart": "Restart to make plugin changes effective", "install": "Install", @@ -69,8 +69,8 @@ "version": "Version", "currentVersion": "Installed version", "newVersion": "New version", - "cloudoguInstallInfo": "This plugin is exclusively available via myCloudogu. Follow the instructions to install it.", - "cloudoguInstall": "To Installation Instructions", + "cloudoguInstallInfo": "Connect your SCM-Manager instance with your myCloudogu account to access myCloudogu plugins. If you do not already have an account you can easily register for free.", + "cloudoguInstall": "Connect myCloudogu and install", "dependencyNotification": "With this plugin, the following dependencies will be installed/updated if their latest versions are not installed yet!", "optionalDependencyNotification": "With this plugin, the following optional dependencies will be updated if they are installed!", "dependencies": "Dependencies", @@ -85,6 +85,15 @@ "updateAllInfo": "The following plugin changes will be executed. You need to restart the SCM-Manager to make these changes effective.", "manualRestartRequired": "After the plugin change has been made, SCM-Manager must be restarted.", "showPending": "To execute the following plugin changes, SCM-Manager must be restarted." + }, + "myCloudogu": { + "connectionInfo": "Instance is connected to myCloudogu.\nAccount: {{pluginCenterSubject}}", + "login": { + "button": { + "label": "Connect to <0>myCloudogu" + }, + "description": "Connect your SCM-Manager with <0>myCloudogu to install special plugins. myCloudogu is the home of the SCM-Manager Community, sustained by the maintainers of the SCM-Manager. You don't have an account yet? Create a free myCloudogu account while connecting your SCM-Manager instance." + } } }, "repositoryRole": { diff --git a/scm-ui/ui-webapp/public/locales/en/config.json b/scm-ui/ui-webapp/public/locales/en/config.json index 47722eab64..7a18d41a71 100644 --- a/scm-ui/ui-webapp/public/locales/en/config.json +++ b/scm-ui/ui-webapp/public/locales/en/config.json @@ -11,6 +11,19 @@ "no-write-permission-notification": "Please note: You do not have the permission to edit the config!" } }, + "pluginSettings": { + "subtitle": "Plugin Settings", + "pluginUrl": "Plugin Center URL", + "pluginAuthUrl": "Plugin Center Authentication URL", + "auth": { + "loading": "Loading authentication info ...", + "notAuthenticated": "Plugin Center is not authenticated", + "authenticate": "Authenticate", + "authenticated": "Plugin Center is authenticated as <0 />", + "subjectTooltip": "Authenticated by {{ principal }} {{ ago }}", + "logout": "Logout" + } + }, "proxySettings": { "subtitle": "Proxy Settings", "enable": "Enable Proxy", @@ -54,7 +67,6 @@ "off": "Disabled" }, "skip-failed-authenticators": "Skip Failed Authenticators", - "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", "mail-domain-name": "Fallback Mail Domain Name", "enabled-xsrf-protection": "Enabled XSRF Protection", @@ -79,6 +91,7 @@ "realmDescriptionHelpText": "Enter authentication realm description.", "dateFormatHelpText": "Moments date format. Please have a look at the MomentJS documentation.", "pluginUrlHelpText": "The url of the Plugin Center API. Explanation of the placeholders: version = SCM-Manager Version; os = Operation System; arch = Architecture", + "pluginAuthUrlHelpText": "The url of the Plugin Center authentication API.", "releaseFeedUrlHelpText": "The url of the RSS Release Feed for SCM-Manager. This provides up-to-date version information. To disable this feature just leave the url blank.", "mailDomainNameHelpText": "This domain name will be used to create email addresses for users without one when needed. It will not be used to send mails nor will be accessed otherwise.", "enableForwardingHelpText": "Enable mod_proxy port forwarding.", diff --git a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx index 48e7ec5e38..6cef88cd61 100644 --- a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx +++ b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx @@ -29,6 +29,7 @@ import ProxySettings from "./ProxySettings"; import GeneralSettings from "./GeneralSettings"; import BaseUrlSettings from "./BaseUrlSettings"; import LoginAttempt from "./LoginAttempt"; +import PluginSettings from "./PluginSettings"; type Props = { submitForm: (p: Config) => void; @@ -65,6 +66,7 @@ const ConfigForm: FC = ({ proxyExcludes: [], skipFailedAuthenticators: false, pluginUrl: "", + pluginAuthUrl: "", loginAttemptLimitTimeout: 0, enabledXsrfProtection: true, enabledUserConverter: false, @@ -142,7 +144,6 @@ const ConfigForm: FC = ({ dateFormat={innerConfig.dateFormat} anonymousMode={innerConfig.anonymousMode} skipFailedAuthenticators={innerConfig.skipFailedAuthenticators} - pluginUrl={innerConfig.pluginUrl} releaseFeedUrl={innerConfig.releaseFeedUrl} mailDomainName={innerConfig.mailDomainName} enabledXsrfProtection={innerConfig.enabledXsrfProtection} @@ -168,6 +169,13 @@ const ConfigForm: FC = ({ hasUpdatePermission={configUpdatePermission} />
+ onChange(isValid, changedValue, name)} + hasUpdatePermission={configUpdatePermission} + /> +
= ({ realmDescription, loginInfoUrl, anonymousMode, - pluginUrl, releaseFeedUrl, mailDomainName, enabledXsrfProtection, @@ -91,9 +89,6 @@ const GeneralSettings: FC = ({ const handleNamespaceStrategyChange = (value: string) => { onChange(true, value, "namespaceStrategy"); }; - const handlePluginCenterUrlChange = (value: string) => { - onChange(true, value, "pluginUrl"); - }; const handleReleaseFeedUrlChange = (value: string) => { onChange(true, value, "releaseFeedUrl"); }; @@ -163,21 +158,13 @@ const GeneralSettings: FC = ({
-
- -