From cf92792db7ede5f35c3e2883f4353376e73ff7e3 Mon Sep 17 00:00:00 2001 From: Guillaume Chervet Date: Fri, 23 Feb 2024 12:45:57 +0100 Subject: [PATCH] doc(oidc-client-demo): repair demo --- examples/oidc-client-demo/index.html | 2 +- examples/oidc-client-demo/src/index.tsx | 246 ++++++++++++----------- examples/oidc-client-demo/vite.config.js | 2 +- 3 files changed, 136 insertions(+), 114 deletions(-) diff --git a/examples/oidc-client-demo/index.html b/examples/oidc-client-demo/index.html index d0912cccb..91a7df9b9 100644 --- a/examples/oidc-client-demo/index.html +++ b/examples/oidc-client-demo/index.html @@ -10,6 +10,6 @@
- + diff --git a/examples/oidc-client-demo/src/index.tsx b/examples/oidc-client-demo/src/index.tsx index bb6546119..16a397972 100644 --- a/examples/oidc-client-demo/src/index.tsx +++ b/examples/oidc-client-demo/src/index.tsx @@ -1,128 +1,137 @@ -import { OidcClient } from '@axa-fr/oidc-client'; +import {OidcClient} from "@axa-fr/oidc-client"; class Router { getCustomHistory(){ - const generateKey = () => - Math.random() - .toString(36) - .substr(2, 6); - - // Exported only for test - type WindowInternal = Window & { - CustomEvent?: new (typeArg: string, eventInitDict?: CustomEventInit) => CustomEvent; - Event: typeof Event; - }; - - type IPrototype = { - prototype: any; - }; - - type InitCustomEventParams = { - bubbles: boolean; - cancelable: boolean; - detail: T; - }; - - // IE Polyfill for CustomEvent - const CreateEvent = (windowInternal: Window, documentInternal: Document) => ( - event: string, - params: InitCustomEventParams, - ): CustomEvent => { - // @ts-ignore - if (typeof windowInternal.CustomEvent === 'function') { - // @ts-ignore - return new windowInternal.CustomEvent(event, params); - } - const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; - const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); - evt.initCustomEvent(event, paramsToFunction.bubbles, paramsToFunction.cancelable, paramsToFunction.detail); + const generateKey = () => + Math.random() + .toString(36) + .substr(2, 6); + + // Exported only for test + type WindowInternal = Window & { + CustomEvent?: new (typeArg: string, eventInitDict?: CustomEventInit) => CustomEvent; + Event: typeof Event; + }; + + type IPrototype = { + prototype: any; + }; + + type InitCustomEventParams = { + bubbles: boolean; + cancelable: boolean; + detail: T; + }; + + // IE Polyfill for CustomEvent + const CreateEvent = (windowInternal: Window, documentInternal: Document) => ( + event: string, + params: InitCustomEventParams, + ): CustomEvent => { + // @ts-ignore + if (typeof windowInternal.CustomEvent === 'function') { // @ts-ignore - (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; - return evt; - }; + return new windowInternal.CustomEvent(event, params); + } + const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; + const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); + evt.initCustomEvent(event, paramsToFunction.bubbles, paramsToFunction.cancelable, paramsToFunction.detail); + // @ts-ignore + (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; + return evt; + }; - type WindowHistoryState = typeof window.history.state; + type WindowHistoryState = typeof window.history.state; - type CustomHistory = { - replaceState(url?: string | null, stateHistory?: WindowHistoryState): void; - } + type CustomHistory = { + replaceState(url?: string | null, stateHistory?: WindowHistoryState): void; + } - const getHistory = ( - windowInternal: WindowInternal, - CreateEventInternal: (event: string, params?: InitCustomEventParams) => CustomEvent, - generateKeyInternal: typeof generateKey, - ): CustomHistory => { - return { - replaceState: (url?: string | null, stateHistory?: WindowHistoryState): void => { - const key = generateKeyInternal(); - const state = stateHistory || windowInternal.history.state; - // @ts-ignore - windowInternal.history.replaceState({ key, state }, null, url); - windowInternal.dispatchEvent(CreateEventInternal('popstate')); - }, - }; + const getHistory = ( + windowInternal: WindowInternal, + CreateEventInternal: (event: string, params?: InitCustomEventParams) => CustomEvent, + generateKeyInternal: typeof generateKey, + ): CustomHistory => { + return { + replaceState: (url?: string | null, stateHistory?: WindowHistoryState): void => { + const key = generateKeyInternal(); + const state = stateHistory || windowInternal.history.state; + // @ts-ignore + windowInternal.history.replaceState({ key, state }, null, url); + windowInternal.dispatchEvent(CreateEventInternal('popstate')); + }, }; + }; - // @ts-ignore + // @ts-ignore const getCustomHistory = () => getHistory(window, CreateEvent(window, document), generateKey); - return getCustomHistory(); - } + return getCustomHistory(); +} } -const router = new Router(); +// @ts-ignore +export const execute = () => { -document.body.innerHTML = `
`; -const element = document.getElementById("my-vanilla-app"); + const router = new Router(); -export const configuration = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/#/authentication/callback', - silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - refresh_time_before_tokens_expiration_in_second: 40, - service_worker_relative_url:'/OidcServiceWorker.js', - service_worker_only: true, -}; + const element = document.getElementById("root"); -const href = window.location.href; + const configuration = { + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/#/authentication/callback', + silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + refresh_time_before_tokens_expiration_in_second: 40, + service_worker_relative_url:'/OidcServiceWorker.js', + service_worker_only: true, + }; -const vanillaOidc = OidcClient.getOrCreate(() => fetch)(configuration); + const href = window.location.href; -console.log(href); + const vanillaOidc = OidcClient.getOrCreate(() => fetch)(configuration); -if(href.includes(configuration.redirect_uri)){ - // @ts-ignore - element.innerHTML = `
+ console.log(href); + + if(href.includes(configuration.redirect_uri)){ + // @ts-ignore + element.innerHTML = `

@axa-fr/oidc-client demo

Loading callback

`; - vanillaOidc.loginCallbackAsync().then(()=>{ - router.getCustomHistory().replaceState("/"); - // @ts-ignore - window.logout = () => vanillaOidc.logoutAsync(); - const tokens = vanillaOidc.tokens; - // @ts-ignore - element.innerHTML = `
+ vanillaOidc.loginCallbackAsync().then(()=>{ + router.getCustomHistory().replaceState("/"); + // @ts-ignore + function logout() { + vanillaOidc.logoutAsync(); + } + const tokens = vanillaOidc.tokens; + // @ts-ignore + element.innerHTML = `

@axa-fr/oidc-client demo

- +

Authenticated

${JSON.stringify(tokens,null,'\t')}
`; - }); -} -vanillaOidc.tryKeepExistingSessionAsync().then(() => { - const tokens = vanillaOidc.tokens; - if(tokens){ - - // @ts-ignore - window.logout = () => vanillaOidc.logoutAsync(); - // @ts-ignore - element.innerHTML = `
+ // @ts-ignore + window.document.getElementById('logout').addEventListener('click',logout); + }); + } + + vanillaOidc.tryKeepExistingSessionAsync().then(() => { + const tokens = vanillaOidc.tokens; + if(tokens){ + + // @ts-ignore + function logout () { + vanillaOidc.logoutAsync(); + } + // @ts-ignore + element.innerHTML = `

@axa-fr/oidc-client demo

- +

Game, let's try to make an XSS attacks to retrieve original tokens !

You may think servcie worker mode is not secure like said here https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#payload-new-flow So let try to hack it ! @@ -131,31 +140,44 @@ vanillaOidc.tryKeepExistingSessionAsync().then(() => { Content-Security-Policy: script-src 'self' and setting up the redirect_uri and redirect_silent_uri at the top level of your javascript application before any XSS attack could accur. - Security is always good a cursor level to adjsute and a set of good practices. + Security is always good a cursor level to adjsut and a set of good practices.

- +

Authenticated

${JSON.stringify(tokens,null,'\t')}
`; - } - else { - // @ts-ignore - window.login= () => { // @ts-ignore - element.innerHTML = `
+ window.document.getElementById('logout').addEventListener('click',logout); + // @ts-ignore + window.document.getElementById('buttonxsshack').addEventListener('click',()=> { + // @ts-ignore + eval(document.getElementById('xsshack').value) + }); + + } + else { + // @ts-ignore + function login() { + // @ts-ignore + element.innerHTML = `

@axa-fr/oidc-client demo

Loading

`; - vanillaOidc.loginAsync("/"); - }; - - // @ts-ignore - element.innerHTML = `
+ vanillaOidc.loginAsync("/"); + } + + // @ts-ignore + element.innerHTML = `

@axa-fr/oidc-client demo

- +
`; - } -}); + // @ts-ignore + document.getElementById('login').addEventListener('click',login); + } + }); + +}; +execute(); \ No newline at end of file diff --git a/examples/oidc-client-demo/vite.config.js b/examples/oidc-client-demo/vite.config.js index e95902064..3b8014a1d 100644 --- a/examples/oidc-client-demo/vite.config.js +++ b/examples/oidc-client-demo/vite.config.js @@ -7,7 +7,7 @@ export default defineConfig({ }, server: { headers: { - //"Content-Security-Policy": "script-src 'self';", + "Content-Security-Policy": "script-src 'self' 'unsafe-eval';", }, }, });