diff --git a/README.md b/README.md index ccd869e..44ccd50 100644 --- a/README.md +++ b/README.md @@ -171,10 +171,10 @@ ch.sbb.polarion.extension.pdf-exporter.internalizeExternalCss=true ## Extension Configuration 1. On the top of the project's navigation pane click ⚙ (Actions) ➙ 🔧 Administration. Project's administration page will be opened. -2. On the administration's navigation pane select `PDF Export`. There are 5 sub-menus with different configuration options for PDF Exporter. -3. For 5 of these options (Cover page, Header and Footer, Localization, Webhooks and Filename template) `Quick Help` section available with option short description. For the rest 2 +2. On the administration's navigation pane select `PDF Export`. There are expandable sub-menus with different configuration options for PDF Exporter. +3. For some of these options (Cover page, Header and Footer, Localization, Webhooks and Filename template) `Quick Help` section available with option short description. For the rest (Style package, Stylesheets) there's no `Quick Help` section as their content is self-evident. -4. To change configuration of PDF exporter extension just edit corresponding section and press `Save` button. +4. To change configuration of PDF Exporter extension just edit corresponding section and press `Save` button. ## Usage diff --git a/src/main/java/ch/sbb/polarion/extension/pdf/exporter/converter/PdfConverter.java b/src/main/java/ch/sbb/polarion/extension/pdf/exporter/converter/PdfConverter.java index b97f9b8..d67333f 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf/exporter/converter/PdfConverter.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf/exporter/converter/PdfConverter.java @@ -1,6 +1,5 @@ package ch.sbb.polarion.extension.pdf.exporter.converter; -import ch.sbb.polarion.extension.generic.rest.filter.AuthenticationFilter; import ch.sbb.polarion.extension.generic.settings.NamedSettings; import ch.sbb.polarion.extension.generic.settings.SettingId; import ch.sbb.polarion.extension.generic.util.ScopeUtils; @@ -10,6 +9,7 @@ import ch.sbb.polarion.extension.pdf.exporter.rest.model.conversion.DocumentType; import ch.sbb.polarion.extension.pdf.exporter.rest.model.conversion.ExportParams; import ch.sbb.polarion.extension.pdf.exporter.rest.model.settings.headerfooter.HeaderFooterModel; +import ch.sbb.polarion.extension.pdf.exporter.rest.model.settings.webhooks.AuthType; import ch.sbb.polarion.extension.pdf.exporter.rest.model.settings.webhooks.WebhookConfig; import ch.sbb.polarion.extension.pdf.exporter.rest.model.settings.webhooks.WebhooksModel; import ch.sbb.polarion.extension.pdf.exporter.service.PdfExporterPolarionService; @@ -54,6 +54,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -205,24 +206,24 @@ private static void addAuthHeader(@NotNull WebhookConfig webhookConfig, @NotNull return; } - String authInfoFromUserAccountVault = getAuthInfoFromUserAccountVault(webhookConfig.getAuthTokenName()); - switch (webhookConfig.getAuthType()) { - case BEARER_TOKEN -> requestBuilder.header(HttpHeaders.AUTHORIZATION, AuthenticationFilter.BEARER + " " + authInfoFromUserAccountVault); - case XSRF_TOKEN -> requestBuilder.header(AuthenticationFilter.X_POLARION_REST_TOKEN_HEADER, webhookConfig.getAuthTokenName()); + String authInfoFromUserAccountVault = getAuthInfoFromUserAccountVault(webhookConfig.getAuthType(), webhookConfig.getAuthTokenName()); + if (authInfoFromUserAccountVault == null) { + return; } - if (webhookConfig.getAuthType() != null && webhookConfig.getAuthTokenName() != null) { - requestBuilder.header(HttpHeaders.AUTHORIZATION, webhookConfig.getAuthType() + " " + webhookConfig.getAuthTokenName()); - } + requestBuilder.header(HttpHeaders.AUTHORIZATION, webhookConfig.getAuthType().getAuthHeaderPrefix() + " " + authInfoFromUserAccountVault); } - private static String getAuthInfoFromUserAccountVault(String authTokenName) { - if (authTokenName != null && authTokenName.isEmpty()) { - return UserAccountVault.getInstance() - .getCredentialsForKey(authTokenName) - .getPassword(); - } - return null; + private static @Nullable String getAuthInfoFromUserAccountVault(@NotNull AuthType authType, @NotNull String authTokenName) { + @NotNull UserAccountVault.Credentials credentials = UserAccountVault.getInstance().getCredentialsForKey(authTokenName); + + return switch (authType) { + case BASIC_AUTH -> { + String authInfo = credentials.getUser() + ":" + credentials.getPassword(); + yield Base64.getEncoder().encodeToString(authInfo.getBytes()); + } + case BEARER_TOKEN -> credentials.getPassword(); + }; } @VisibleForTesting diff --git a/src/main/java/ch/sbb/polarion/extension/pdf/exporter/rest/model/settings/webhooks/AuthType.java b/src/main/java/ch/sbb/polarion/extension/pdf/exporter/rest/model/settings/webhooks/AuthType.java index 11aed5e..1af7c7e 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf/exporter/rest/model/settings/webhooks/AuthType.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf/exporter/rest/model/settings/webhooks/AuthType.java @@ -1,10 +1,18 @@ package ch.sbb.polarion.extension.pdf.exporter.rest.model.settings.webhooks; import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.Getter; +@Getter public enum AuthType { - BEARER_TOKEN, - XSRF_TOKEN; + BEARER_TOKEN("Bearer"), + BASIC_AUTH("Basic"); + + private final String authHeaderPrefix; + + AuthType(String authHeaderPrefix) { + this.authHeaderPrefix = authHeaderPrefix; + } @JsonCreator public static AuthType forName(String name) { diff --git a/src/main/resources/webapp/pdf-exporter-admin/js/webhooks.js b/src/main/resources/webapp/pdf-exporter-admin/js/webhooks.js index 7e44fd9..60c1782 100644 --- a/src/main/resources/webapp/pdf-exporter-admin/js/webhooks.js +++ b/src/main/resources/webapp/pdf-exporter-admin/js/webhooks.js @@ -40,11 +40,11 @@ const Webhooks = { if (webhooksModel.bundleTimestamp !== SbbCommon.getValueById('bundle-timestamp')) { Webhooks.loadDefaultContent() .then((responseText) => { - const defaultHooksModel = JSON.parse(responseText); - SbbCommon.setNewerVersionNotificationVisible(webhooksModel.webhooks && defaultHooksModel.webhooks - && (webhooksModel.webhooks.length !== defaultHooksModel.webhooks.length + const defaultWebhooksModel = JSON.parse(responseText); + SbbCommon.setNewerVersionNotificationVisible(webhooksModel.webhooks && defaultWebhooksModel.webhooks + && (webhooksModel.webhooks.length !== defaultWebhooksModel.webhooks.length || webhooksModel.webhooks.every(function (value, index) { - return value === defaultHooksModel.hooks[index] + return value === defaultWebhooksModel.hooks[index] }))); }) } @@ -172,11 +172,11 @@ const Webhooks = { const authTypeCombobox = document.createElement('select'); authTypeCombobox.setAttribute('name', 'auth_type'); - authTypeCombobox.innerHTML = ''; + authTypeCombobox.innerHTML = ''; if (webhookConfig?.authType) { switch (webhookConfig.authType) { case 'BEARER_TOKEN': authTypeCombobox.selectedIndex = 0; break; - case 'XSRF_TOKEN': authTypeCombobox.selectedIndex = 1; break; + case 'BASIC_AUTH': authTypeCombobox.selectedIndex = 1; break; } } else { authTypeCombobox.style.display = 'none'; @@ -191,6 +191,7 @@ const Webhooks = { const authTokenNameField = document.createElement('input'); authTokenNameField.setAttribute('name', 'auth_token_name'); + authTokenNameField.setAttribute('placeholder', 'Polarion Vault entry name'); if (webhookConfig?.authType) { authTokenNameField.setAttribute('value', webhookConfig.authTokenName ? webhookConfig.authTokenName : ''); } else { diff --git a/src/main/resources/webapp/pdf-exporter-admin/pages/webhooks.jsp b/src/main/resources/webapp/pdf-exporter-admin/pages/webhooks.jsp index 9f4bd42..b9ad4a3 100644 --- a/src/main/resources/webapp/pdf-exporter-admin/pages/webhooks.jsp +++ b/src/main/resources/webapp/pdf-exporter-admin/pages/webhooks.jsp @@ -31,6 +31,7 @@ #webhooks-table { width: 1100px; + table-layout: fixed; } .webhook-row td { @@ -38,7 +39,7 @@ } .webhook-row td:first-child { - width: 20px; + width: 30px; } .webhook-row td:nth-child(2) { @@ -119,6 +120,12 @@ A webhook is a REST endpoint accepting initial HTML as a string (POST request), making some modification to this HTML and returning resulting HTML as a string back in body of response. A webhook endpoint can locate anywhere, either within Polarion itself or outside of it.

+

Webhook configuration

+

+ Each webhook has an URL and optional auth info. The URL is the endpoint to invoke. The auth info is a authentication for this endpoint. + The auth info can be either a basic auth with username and password or a Bearer token. The auth info should be stored in Polarion Vault. + Here should be provided a name of the vault entry with auth info. +

Webhooks processing

Webhooks to run they should be selected in appropriate style package, or during PDF exporting. They are invoked in an order they entered on this page.