From 3a5d039daa174a58ff7f19f6b42290167ee14052 Mon Sep 17 00:00:00 2001 From: Gabriel Pelouze Date: Thu, 30 Nov 2023 14:07:08 +0100 Subject: [PATCH 1/7] fix https://reactjs.org/link/warning-keys in Nav --- vre-panel/templates/Nav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vre-panel/templates/Nav.tsx b/vre-panel/templates/Nav.tsx index 55ae4e4..35ae826 100644 --- a/vre-panel/templates/Nav.tsx +++ b/vre-panel/templates/Nav.tsx @@ -103,7 +103,7 @@ const Nav = () => {
{menuPages.map((page) => { return ( - + {({active}) => ( Date: Thu, 30 Nov 2023 11:47:52 +0100 Subject: [PATCH 2/7] fix jwt refresh to avoid intempestive disconnections --- vre-panel/environment.d.ts | 3 -- vre-panel/pages/api/auth/[...nextauth].ts | 49 ++++++++++------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/vre-panel/environment.d.ts b/vre-panel/environment.d.ts index 6a8da89..fff184f 100644 --- a/vre-panel/environment.d.ts +++ b/vre-panel/environment.d.ts @@ -1,9 +1,6 @@ declare namespace NodeJS { interface ProcessEnv { NEXT_PUBLIC_SECRET: string, - KEYCLOAK_CLIENT_ID: string, - KEYCLOAK_CLIENT_SECRET: string, - KEYCLOAK_ISSUER: string, AUTH0_ID: string, AUTH0_SECRET: string, AUTH0_ISSUER: string, diff --git a/vre-panel/pages/api/auth/[...nextauth].ts b/vre-panel/pages/api/auth/[...nextauth].ts index 2982992..1ec541b 100644 --- a/vre-panel/pages/api/auth/[...nextauth].ts +++ b/vre-panel/pages/api/auth/[...nextauth].ts @@ -11,13 +11,14 @@ const { publicRuntimeConfig } = getConfig() const refreshAccessToken = async (token: JWT) => { try { // Get a new set of tokens with a refreshToken - console.log("KEYCLOAK_ISSUER", process.env.KEYCLOAK_ISSUER) + // console.log("AUTH0_ISSUER", process.env.AUTH0_ISSUER) const tokenResponse = await axios.post( - process.env.KEYCLOAK_ISSUER + '/protocol/openid-connect/token', + process.env.AUTH0_ISSUER + '/protocol/openid-connect/token', { - grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', - subject_token: token.accessToken, - client_id: process.env.KEYCLOAK_CLIENT_ID, + grant_type: 'refresh_token', + refresh_token: token.refreshToken, + client_id: process.env.AUTH0_ID, + client_secret: process.env.AUTH0_SECRET, requested_token_type: 'urn:ietf:params:oauth:token-type:refresh_token' }, { @@ -31,11 +32,13 @@ const refreshAccessToken = async (token: JWT) => { return { ...token, - accessToken: tokenResponse.data.accessToken, - accessTokenExpiry: tokenResponse.data.accessTokenExpiry, - refreshToken: tokenResponse.data.refreshToken + accessToken: tokenResponse.data.access_token, + accessTokenExpiry: Date.now() / 1e3 + tokenResponse.data.expires_in, + refreshToken: tokenResponse.data.refresh_token, } } catch (error) { + console.log('Caught exception in refreshAccessToken') + console.log(error) return { ...token, error: "RefreshAccessTokenError", @@ -44,8 +47,6 @@ const refreshAccessToken = async (token: JWT) => { }; export default (req : NextApiRequest, res: NextApiResponse) => { - console.log("AUTH0_ID", process.env.AUTH0_ID); - console.log("AUTH0_ISSUER", process.env.AUTH0_ISSUER); return NextAuth(req, res, { providers: [ KeycloakProvider({ @@ -54,36 +55,28 @@ export default (req : NextApiRequest, res: NextApiResponse) => { issuer: process.env.AUTH0_ISSUER, }) ], - // The secret should be set to a reasonably long random string. - // It is used to sign cookies and to sign and encrypt JSON Web Tokens, unless - // a separate secret is defined explicitly for encrypting the JWT. secret: process.env.SECRET, callbacks: { async jwt({ token, user, account }) { if (account && user) { - token.accessToken = account.access_token; token.refreshToken = account.refresh_token; token.accessTokenExpiry = account.expires_at; - token.user = user; } - // console.log(token); - - const unixTimeZero = Date.parse('01 Jan 1970 00:00:00 GMT'); - const expiryDate = new Date(); - expiryDate.setTime(unixTimeZero) - expiryDate.setSeconds(expiryDate.getSeconds() + token.accessTokenExpiry); - const refreshElapse = Math.round(expiryDate.getTime() - Date.now()); - - if (refreshElapse > 0) return token; - - return refreshAccessToken(token); - + const expDate = new Date(token.accessTokenExpiry * 1e3) + const nowDate = new Date() + const tokenExpired = (expDate < nowDate) + + if (tokenExpired) { + token = await refreshAccessToken(token); + } + + return token; + }, async session({ session, token }) { if (token) { - session.user = token.user; session.error = token.error; session.accessToken = token.accessToken; session.accessTokenExpiry = token.accessTokenExpiry; From e6858f9b5797739cbcb42a79ba8490532dfa129c Mon Sep 17 00:00:00 2001 From: Gabriel Pelouze Date: Thu, 30 Nov 2023 15:20:59 +0100 Subject: [PATCH 3/7] cleanup unused RefreshTokenHandler --- vre-panel/pages/_app.tsx | 1 - vre-panel/pages/auth/refreshTokenHandler.ts | 18 ------------------ 2 files changed, 19 deletions(-) delete mode 100644 vre-panel/pages/auth/refreshTokenHandler.ts diff --git a/vre-panel/pages/_app.tsx b/vre-panel/pages/_app.tsx index a531187..871953e 100644 --- a/vre-panel/pages/_app.tsx +++ b/vre-panel/pages/_app.tsx @@ -2,7 +2,6 @@ import { AppProps } from 'next/app'; import '../styles/globals.css'; import { SessionProvider } from "next-auth/react" import { useState } from 'react'; -// import RefreshTokenHandler from './auth/refreshTokenHandler'; import getConfig from 'next/config' import {PaasConfigProvider} from '../context/PaasConfig'; diff --git a/vre-panel/pages/auth/refreshTokenHandler.ts b/vre-panel/pages/auth/refreshTokenHandler.ts deleted file mode 100644 index 9166012..0000000 --- a/vre-panel/pages/auth/refreshTokenHandler.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useSession } from "next-auth/react"; -import { useEffect } from "react"; - -const RefreshTokenHandler = (props:any) => { - const { data: session } = useSession(); - - useEffect(() => { - if(!!session) { - const timeRemaining = Math.round((((session.accessTokenExpiry - 30 * 60 * 100) - Date.now()) / 1000)); - console.log(timeRemaining); - props.setInterval(timeRemaining > 0 ? timeRemaining : 0); - } - }, [session]); - - return null; -} - -export default RefreshTokenHandler; \ No newline at end of file From 105e6fe255490d4a13e730e49265384ebdcef4fb Mon Sep 17 00:00:00 2001 From: Gabriel Pelouze Date: Thu, 30 Nov 2023 15:56:51 +0100 Subject: [PATCH 4/7] fix invalid DOM nesting --- vre-panel/pages/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vre-panel/pages/index.tsx b/vre-panel/pages/index.tsx index 7d08e77..7ba8674 100644 --- a/vre-panel/pages/index.tsx +++ b/vre-panel/pages/index.tsx @@ -54,7 +54,7 @@ const VLabs = ({}) => { paasConfig.title )} -

+

{paasConfigLoading ? ( { {paasConfig.description}
)} -

+
{paasConfigLoading || ( paasConfig.documentation_url && (

From 7a1339bd2409768c6eec1a6ef2d65805b5089842 Mon Sep 17 00:00:00 2001 From: Gabriel Pelouze Date: Thu, 30 Nov 2023 17:01:00 +0100 Subject: [PATCH 5/7] update authentication flow - skip login screen with single 'login with keycloak' button by using keycloak as default provider - redirect to VLab details page after login instead of VL list --- vre-panel/pages/api/auth/[...nextauth].ts | 7 --- vre-panel/pages/auth/signin.tsx | 53 ---------------------- vre-panel/pages/auth/useAuth.ts | 24 ++++------ vre-panel/public/LW_VLICVRE_logo.png | Bin 27642 -> 0 bytes vre-panel/templates/Nav.tsx | 9 ++-- 5 files changed, 16 insertions(+), 77 deletions(-) delete mode 100644 vre-panel/pages/auth/signin.tsx delete mode 100644 vre-panel/public/LW_VLICVRE_logo.png diff --git a/vre-panel/pages/api/auth/[...nextauth].ts b/vre-panel/pages/api/auth/[...nextauth].ts index 1ec541b..3a2886d 100644 --- a/vre-panel/pages/api/auth/[...nextauth].ts +++ b/vre-panel/pages/api/auth/[...nextauth].ts @@ -4,10 +4,6 @@ import { JWT } from "next-auth/jwt"; import KeycloakProvider from "next-auth/providers/keycloak" import type { NextApiRequest, NextApiResponse } from 'next' -import getConfig from 'next/config' - -const { publicRuntimeConfig } = getConfig() - const refreshAccessToken = async (token: JWT) => { try { // Get a new set of tokens with a refreshToken @@ -84,8 +80,5 @@ export default (req : NextApiRequest, res: NextApiResponse) => { return session; }, }, - pages: { - signIn: `${publicRuntimeConfig.basePath}/auth/signin` - } }) } \ No newline at end of file diff --git a/vre-panel/pages/auth/signin.tsx b/vre-panel/pages/auth/signin.tsx deleted file mode 100644 index b6982dc..0000000 --- a/vre-panel/pages/auth/signin.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { getProviders, getSession, signIn } from "next-auth/react" -import getConfig from 'next/config' -import {useContext} from "react"; -import {PaasConfigContext} from "../../context/PaasConfig"; - -const { publicRuntimeConfig } = getConfig() - -export default function SignIn({ providers }: { providers: any }) { - - const {paasConfig, paasConfigLoading} = useContext(PaasConfigContext) - - return ( -

- -
- {paasConfigLoading || ( - Site icon - )} - <> - {Object.values(providers).map((provider: any) => ( -
- -
- ))} - -
-
- ) -} - -export async function getServerSideProps(context: { req: any; }) { - - const { req } = context; - console.log("getProviders") - const providers = await getProviders() - const session = await getSession({ req }) - if (session) { - console.log("Session exists, redirecting to", '/') - return { - redirect: { destination: '/' }, - }; - } - console.log("providers: ", providers) - return { - props: { providers }, - } -} \ No newline at end of file diff --git a/vre-panel/pages/auth/useAuth.ts b/vre-panel/pages/auth/useAuth.ts index 5f80607..c53e706 100644 --- a/vre-panel/pages/auth/useAuth.ts +++ b/vre-panel/pages/auth/useAuth.ts @@ -1,4 +1,4 @@ -import { signOut, useSession } from "next-auth/react"; +import { signIn, signOut, useSession } from "next-auth/react"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; @@ -11,29 +11,25 @@ export default function useAuth(shouldRedirect: boolean) { useEffect(() => { if (session?.error === "RefreshAccessTokenError") { - signOut({ redirect: shouldRedirect }); } if (session === null) { - - if (router.route !== `/auth/signin`) { - router.replace(`/auth/signin`); - } - setIsAuthenticated(false); - } - - else if (session !== undefined) { - - if (router.route === '/auth/signin') { - router.replace('/'); + console.log(router) + if (router.isReady && (router.route !== `/auth/signin`)) { + const callbackUrl = `${router.basePath}${router.asPath}` + Promise.all([ + signIn('keycloak', {callbackUrl: callbackUrl}), + ]) } + } + else if (session !== undefined) { setIsAuthenticated(true); } - }, [session]); + }, [session, router.isReady]); return isAuthenticated; } \ No newline at end of file diff --git a/vre-panel/public/LW_VLICVRE_logo.png b/vre-panel/public/LW_VLICVRE_logo.png deleted file mode 100644 index ca2f86f2f0f8f9479020b545d318c1b54453d6c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27642 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⩔tsf%Y)SwAEfUVWK+$Kz@T;!`5$Jf8RFsl| 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 i7ykE2$OpWeoR4 diff --git a/vre-panel/templates/Nav.tsx b/vre-panel/templates/Nav.tsx index 35ae826..c647e69 100644 --- a/vre-panel/templates/Nav.tsx +++ b/vre-panel/templates/Nav.tsx @@ -25,6 +25,9 @@ const Nav = () => { const {paasConfig, paasConfigLoading} = useContext(PaasConfigContext) + const signOutOptions = {callbackUrl: router.basePath, shouldRedirect: true} + const signInProvider = 'keycloak' + return (