From 27a830f9b8084e09a870b5aeb7d0abb4eadcb332 Mon Sep 17 00:00:00 2001 From: Andrew Wylde Date: Fri, 22 Mar 2024 13:55:33 -0500 Subject: [PATCH] feat(swagger): handle redirects from OIDC IdP and initialize swagger (#467) Co-authored-by: Devon Langendoerfer --- package.json | 2 +- src/locales/ca_ES.ts | 8 +++ src/locales/de.ts | 8 +++ src/locales/en.ts | 8 +++ src/locales/es_ES.ts | 8 +++ src/locales/fr.ts | 8 +++ src/locales/i18n-type.d.ts | 8 +++ src/router/index.ts | 8 +++ src/views/OAuth2Redirect.vue | 118 +++++++++++++++++++++++++++++++++++ src/views/Spec.vue | 19 ++++++ yarn.lock | 67 +++++++++++++------- 11 files changed, 240 insertions(+), 22 deletions(-) create mode 100644 src/views/OAuth2Redirect.vue diff --git a/package.json b/package.json index 035bd510..2c32068b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@kong-ui-public/analytics-utilities": "0.10.1", "@kong-ui-public/copy-uuid": "1.1.5", "@kong-ui-public/document-viewer": "2.0.16", - "@kong-ui-public/spec-renderer": "2.1.0", + "@kong-ui-public/spec-renderer": "2.1.5", "@kong/kong-auth-elements": "2.11.1", "@kong/kongponents": "8.127.0", "@kong/sdk-portal-js": "2.10.0", diff --git a/src/locales/ca_ES.ts b/src/locales/ca_ES.ts index 423ad3bc..19dfbedb 100644 --- a/src/locales/ca_ES.ts +++ b/src/locales/ca_ES.ts @@ -329,6 +329,7 @@ export const ca_ES: I18nType = { resetPasswordTitle: 'Restablir la contrasenya', catalogTitleProduct: 'Catàleg de productes', specTitle: "Especificació de l'API", + oauth2RedirectTitle: translationNeeded(en.router.oauth2RedirectTitle), docsTitle: "Documentació de l'API", appsTitle: 'Les meves aplicacions', createAppTitle: 'Crear nova aplicació', @@ -338,5 +339,12 @@ export const ca_ES: I18nType = { notFoundTitle: 'No trobat', forbiddenTitle: 'Prohibit', errorTitle: 'Error' + }, + oauth2: { + dataNotFound: translationNeeded(en.oauth2.authMaybeUnsafe), + noDescription: translationNeeded(en.oauth2.noDescription), + moreInfo: translationNeeded(en.oauth2.moreInfo), + authMaybeUnsafe: translationNeeded(en.oauth2.authMaybeUnsafe), + defaultError: translationNeeded(en.oauth2.defaultError) } } diff --git a/src/locales/de.ts b/src/locales/de.ts index dc610d38..ee0a4ed4 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -329,6 +329,7 @@ export const de: I18nType = { resetPasswordTitle: 'Passwort zurücksetzen', catalogTitleProduct: 'Produktkatalog', specTitle: 'API Spezifikation', + oauth2RedirectTitle: translationNeeded(en.router.oauth2RedirectTitle), docsTitle: 'API Dokumentation', appsTitle: 'Meine Applikationen', createAppTitle: 'Neue Applikation anlegen', @@ -338,5 +339,12 @@ export const de: I18nType = { notFoundTitle: 'Nicht gefunden', forbiddenTitle: 'Zugriff verweigert', errorTitle: 'Fehler' + }, + oauth2: { + dataNotFound: translationNeeded(en.oauth2.dataNotFound), + moreInfo: translationNeeded(en.oauth2.moreInfo), + noDescription: translationNeeded(en.oauth2.noDescription), + authMaybeUnsafe: translationNeeded(en.oauth2.authMaybeUnsafe), + defaultError: translationNeeded(en.oauth2.defaultError) } } diff --git a/src/locales/en.ts b/src/locales/en.ts index bfc73864..be03e429 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -325,6 +325,7 @@ export const en = { resetPasswordTitle: 'Reset Password', catalogTitleProduct: 'Product Catalog', specTitle: 'API Spec', + oauth2RedirectTitle: 'OAuth2 Authorization', docsTitle: 'API Docs', appsTitle: 'My Apps', createAppTitle: 'Create New Application', @@ -334,5 +335,12 @@ export const en = { notFoundTitle: 'Not Found', forbiddenTitle: 'Forbidden', errorTitle: 'Error' + }, + oauth2: { + dataNotFound: 'OAuth data not found', + noDescription: 'No description', + moreInfo: 'More info: ', + authMaybeUnsafe: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server", + defaultError: '[Authorization failed]: no accessCode received from the server' } } diff --git a/src/locales/es_ES.ts b/src/locales/es_ES.ts index 003c12f7..b7c1ed16 100644 --- a/src/locales/es_ES.ts +++ b/src/locales/es_ES.ts @@ -329,6 +329,7 @@ export const es_ES: I18nType = { resetPasswordTitle: 'Restablecer contraseña', catalogTitleProduct: 'Catálogo de productos', specTitle: 'Especificación de la API', + oauth2RedirectTitle: translationNeeded(en.router.oauth2RedirectTitle), docsTitle: 'Documentación de la API', appsTitle: 'Mis aplicacione', createAppTitle: 'Crear nueva aplicación', @@ -338,5 +339,12 @@ export const es_ES: I18nType = { notFoundTitle: 'No encontrado', forbiddenTitle: 'Prohibido', errorTitle: 'Error' + }, + oauth2: { + authMaybeUnsafe: translationNeeded(en.oauth2.authMaybeUnsafe), + defaultError: translationNeeded(en.oauth2.defaultError), + dataNotFound: translationNeeded(en.oauth2.dataNotFound), + moreInfo: translationNeeded(en.oauth2.moreInfo), + noDescription: translationNeeded(en.oauth2.noDescription) } } diff --git a/src/locales/fr.ts b/src/locales/fr.ts index 0304ee84..d8846498 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -329,6 +329,7 @@ export const fr: I18nType = { resetPasswordTitle: 'Réinitialisation du mot de passe', catalogTitleProduct: 'Catalogue des produits', specTitle: 'Spécification de l\'API', + oauth2RedirectTitle: translationNeeded(en.router.oauth2RedirectTitle), docsTitle: 'Documentation de l\'API', appsTitle: 'Mes applications', createAppTitle: 'Créer une nouvelle application', @@ -338,5 +339,12 @@ export const fr: I18nType = { notFoundTitle: 'Page non trouvée', forbiddenTitle: 'Accès interdit', errorTitle: 'Erreur' + }, + oauth2: { + authMaybeUnsafe: translationNeeded(en.oauth2.authMaybeUnsafe), + defaultError: translationNeeded(en.oauth2.defaultError), + dataNotFound: translationNeeded(en.oauth2.dataNotFound), + moreInfo: translationNeeded(en.oauth2.moreInfo), + noDescription: translationNeeded(en.oauth2.noDescription) } } diff --git a/src/locales/i18n-type.d.ts b/src/locales/i18n-type.d.ts index e9f1a27b..7605c47c 100644 --- a/src/locales/i18n-type.d.ts +++ b/src/locales/i18n-type.d.ts @@ -325,6 +325,7 @@ export interface I18nType { resetPasswordTitle: string; catalogTitleProduct: string; specTitle: string; + oauth2RedirectTitle: string; docsTitle: string; appsTitle: string; createAppTitle: string; @@ -335,4 +336,11 @@ export interface I18nType { forbiddenTitle: string; errorTitle: string; }; + oauth2: { + dataNotFound: string; + noDescription: string; + moreInfo: string; + authMaybeUnsafe: string; + defaultError: string; + } } diff --git a/src/router/index.ts b/src/router/index.ts index 04823a22..3eb79479 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -94,6 +94,14 @@ export const portalRouter = () => { }, component: () => import('../views/Spec.vue') }, + { + path: '/spec/:product/oauth2-redirect.html', + name: 'oauth2-redirect', + component: () => import('../views/OAuth2Redirect.vue'), + meta: { + title: helpText.oauth2RedirectTitle + } + }, { path: '/docs/:product/:slug*', name: 'api-documentation-page', diff --git a/src/views/OAuth2Redirect.vue b/src/views/OAuth2Redirect.vue new file mode 100644 index 00000000..3f422e56 --- /dev/null +++ b/src/views/OAuth2Redirect.vue @@ -0,0 +1,118 @@ + + + diff --git a/src/views/Spec.vue b/src/views/Spec.vue index 39a4bca8..7e9c54d4 100644 --- a/src/views/Spec.vue +++ b/src/views/Spec.vue @@ -87,6 +87,7 @@ specDetailsRef.value, (newValue, oldValue) => { + if (newValue && newValue !== oldValue) { + newValue.swaggerInstance.instance.initOAuth({ + usePkceWithAuthorizationCodeGrant: true, + additionalQueryStringParams: { + nonce: Math.random().toString(36).substring(7) + } + }) + } + }) + // fallback in case the operations are loaded in after the spec. watch(() => sidebarOperations.value, async () => { if (sidebarOperations.value?.length) { @@ -541,6 +555,7 @@ export default defineComponent({ } return { + specDetailsRef, authMethodLabelObj, helpText, viewSpecModalIsVisible, @@ -643,5 +658,9 @@ export default defineComponent({ border: 1px solid transparent; color: var(--button_colors-primary-text, #fff); } + + .swagger-ui .auth-container .errors { + word-wrap: break-word; + } } diff --git a/yarn.lock b/yarn.lock index e89d2b22..ad572854 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1143,10 +1143,10 @@ flat "^6.0.1" intl-messageformat "^10.5.8" -"@kong-ui-public/i18n@^2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@kong-ui-public/i18n/-/i18n-2.1.3.tgz#69274abb275c612f999f6e0944da11c341fdc347" - integrity sha512-KPEzrVsfTjAGTZ2kcPK+b+hRwDlLjeY4Ys6VnTn+qYEYJjiPEjKansw5zJk33c8R4CTM4a7Zf5DPg1zaWjmNoQ== +"@kong-ui-public/i18n@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@kong-ui-public/i18n/-/i18n-2.1.4.tgz#14358c953511da14ca59c0475a7c6f8706abf1e7" + integrity sha512-fueflh8p98qLITjfqzRoIDXhqTWv5GEiFduSxs5p2f5J1bIeczRTwG3T3k86KI8HwbiU3jG2r5+rZ6d/WFPHYg== dependencies: "@formatjs/intl" "^2.10.0" flat "^6.0.1" @@ -1160,27 +1160,27 @@ "@kong/icons" "^1.8.0" approximate-number "^2.1.1" -"@kong-ui-public/spec-renderer@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@kong-ui-public/spec-renderer/-/spec-renderer-2.1.0.tgz#004d438c7cbfcf5b3904ad081703d32cf71ada87" - integrity sha512-b7LaYLVOoWRyirpm+52Da6IgrFE+MA2A5JgyssrZXBARGClJczCeR3t5G18ATMshKXdR4lAetMCKzk7Scy+LDQ== +"@kong-ui-public/spec-renderer@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@kong-ui-public/spec-renderer/-/spec-renderer-2.1.5.tgz#d91000e323b5f0a07f07e998583f71cc368f5b5c" + integrity sha512-RETh6TGgSOtRViZZOO+XYFO+Hu/eUohrsQmScYTuZvroW/sLqmQNkbZMN5LNUb62D2xgCQyaDiUgUgYN2jpLsg== dependencies: - "@kong-ui-public/i18n" "^2.1.3" - "@kong-ui-public/swagger-ui-web-component" "^0.11.0" + "@kong-ui-public/i18n" "^2.1.4" + "@kong-ui-public/swagger-ui-web-component" "^0.11.3" "@kong/icons" "^1.8.14" lodash.clonedeep "^4.5.0" uuid "^9.0.1" -"@kong-ui-public/swagger-ui-web-component@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@kong-ui-public/swagger-ui-web-component/-/swagger-ui-web-component-0.11.0.tgz#9b4b938e6e0ecd3adcc35f364eab569d02930ab4" - integrity sha512-KkbK+XFbFNhGNqufJlNnJ3TBsAb3Egf7HY9eDdV4f7/6VobfRSwgiHmsFTl2PmeIiLI2BulO7lfzi5MF3LJFAg== +"@kong-ui-public/swagger-ui-web-component@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@kong-ui-public/swagger-ui-web-component/-/swagger-ui-web-component-0.11.3.tgz#7631f0b7642529759157fd406150344c2ede367c" + integrity sha512-Ku7rH6Z897VR8TxWxDh9OBjfAf+nsk9tYgmS7obNp82vuS21/m/iVAls1MQxhjQNMFADYKurmgSKj3tgfMsj6g== dependencies: "@kong/swagger-ui-kong-theme-universal" "^4.3.3" react "17.0.2" react-dom "17.0.2" - swagger-client "^3.25.4" - swagger-ui "^5.1.0" + swagger-client "^3.26.0" + swagger-ui "^5.1.3" "@kong/icons@^1.8.0": version "1.8.0" @@ -10285,7 +10285,16 @@ stream@^0.0.2: dependencies: emitter-component "^1.1.1" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10353,7 +10362,7 @@ stringify-object@^3.2.1, stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -10367,6 +10376,13 @@ strip-ansi@^3.0.0: dependencies: ansi-regex "^2.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -10492,7 +10508,7 @@ svgo@^3.0.2: csso "^5.0.5" picocolors "^1.0.0" -swagger-client@^3.25.4, swagger-client@^3.26.0: +swagger-client@^3.26.0: version "3.26.0" resolved "https://registry.yarnpkg.com/swagger-client/-/swagger-client-3.26.0.tgz#95d28f0c61f39717b84e0e3914319d817c59a868" integrity sha512-1yFR/S2V3v5DwgmNePoHEjq2dZJxDx1leDQ53r5M4hZs+dozm9VnznlSl9a1V5iTYw4UsS4PQuBRQsmBH21ViA== @@ -10513,7 +10529,7 @@ swagger-client@^3.25.4, swagger-client@^3.26.0: qs "^6.10.2" traverse "~0.6.6" -swagger-ui@^5.1.0: +swagger-ui@^5.1.3: version "5.12.0" resolved "https://registry.yarnpkg.com/swagger-ui/-/swagger-ui-5.12.0.tgz#e10fc5d626670a75e596e23a65ec84c374cbe4ce" integrity sha512-Zf62HaUpUc0H1VMcB+HMp1ARaof+xv7ppU4XXbDHSsKxLxxOfQrRxsmoBdaJz2jfgHAes3h7FMsAy6vpCDWv9Q== @@ -11439,7 +11455,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11457,6 +11473,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"