Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ REACT_APP_CERN_MODE=TRUE
REACT_APP_KEYCLOAK_URL=https://auth.cern.ch/auth
REACT_APP_KEYCLOAK_CLIENTID=eam-light
REACT_APP_KEYCLOAK_REALM=cern

REACT_APP_EAM_SERVICES_URL=/apis/cern-eam-services/rest
REACT_APP_KEYCLOAK_EAM_SERVICES_CLIENTID=cern-eam-services
58 changes: 53 additions & 5 deletions src/AuthWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ import React from "react";
import { ReactKeycloakProvider } from "@react-keycloak/web";
import { LinearProgress } from '@mui/material';
import Keycloak from "keycloak-js";
import axios from "axios";

const keycloak = new Keycloak({
url: process.env.REACT_APP_KEYCLOAK_URL,
realm: process.env.REACT_APP_KEYCLOAK_REALM,
clientId: process.env.REACT_APP_KEYCLOAK_CLIENTID,
});

let tokens;
let tokens = {};

const handleTokens = (freshTokens) => {
tokens = freshTokens;
const keycloakAxios = axios.create({
baseURL: `${process.env.REACT_APP_KEYCLOAK_URL}/realms/${process.env.REACT_APP_KEYCLOAK_REALM}`,
});

const handleTokens = (key, freshTokens) => {
tokens[key] = freshTokens;
};

export default (props) => {
Expand All @@ -22,7 +27,7 @@ export default (props) => {
return (
<ReactKeycloakProvider
authClient={keycloak}
onTokens={handleTokens}
onTokens={token => handleTokens(process.env.REACT_APP_KEYCLOAK_CLIENTID, token)}
initOptions={{ onLoad: "login-required" }}
LoadingComponent={<LinearProgress/>}
>
Expand Down Expand Up @@ -55,4 +60,47 @@ const logout = () => {
}
};

export { tokens, keycloak, logout };
const injectBearerToken = ({ config, clientID }) => {
const newConfig = config;
const clientTokens = tokens[clientID];
if (!clientTokens) return newConfig;
const token = clientTokens.token || clientTokens.access_token;
if (!token) return newConfig;
newConfig.headers.Authorization = `Bearer ${token}`;
return newConfig;
};

const exchangeToken = async ({ sourceClient, targetClient }) => {
if(!tokens[sourceClient]) return null;
if(tokens[targetClient]) return tokens[targetClient];

const formData = {
client_id: sourceClient,
subject_token: tokens[sourceClient].token,
audience: targetClient,
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
request_type: 'urn:ietf:params:oauth:token-type:access_token',
};

try {
const response = await keycloakAxios.post(
`/protocol/openid-connect/token`,
Object.keys(formData)
.map(key => `${key}=${encodeURIComponent(formData[key])}`)
.join('&'),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);

handleTokens(targetClient, response.data);
setTimeout(() => exchangeToken({ sourceClient, targetClient }), (response.data.expires_in - 20) * 1000);
return response.data;
} catch (error) {
console.error('Unable to exchange token: ' + error)
}
}

export { tokens, keycloak, logout, injectBearerToken, exchangeToken };
26 changes: 20 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'
// EAM-480, en-GB locale used in order to have monday as first day of the week
import { enGB } from "date-fns/locale";
import { UPDATE_SCANNED_USER } from "./actions/scannedUserActions";
import AuthWrapper, { tokens, keycloak } from "./AuthWrapper";
import AuthWrapper, { keycloak, exchangeToken, injectBearerToken } from "./AuthWrapper";

const jss = create(jssPreset());

let tokenExchange = {};

unregister();
polyfill();

Expand All @@ -35,12 +37,24 @@ Ajax.getAxiosInstance().interceptors.request.use(
return config;
}
// updateToken if it will last less than 5 minutes
return keycloak.updateToken(300).then(() => {
const newConfig = config;
if (tokens && tokens.token) {
newConfig.headers.Authorization = `Bearer ${tokens.token}`;
return keycloak.updateToken(300).then(async () => {
const clientID = config.clientIdExchange || process.env.REACT_APP_KEYCLOAK_CLIENTID;
if (clientID !== process.env.REACT_APP_KEYCLOAK_CLIENTID) {
if (!tokenExchange[clientID]) {
tokenExchange[clientID] = exchangeToken({
sourceClient: process.env.REACT_APP_KEYCLOAK_CLIENTID,
targetClient: clientID,
});
}
await tokenExchange[clientID];
}
return newConfig;
return injectBearerToken({
config: {
...config,
timeout: 300000,
},
clientID,
});
});
},
(error) => {
Expand Down
1 change: 1 addition & 0 deletions src/ui/pages/work/Workorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ const Workorder = () => {
workorder={workorder.number}
eqpToOtherId={otherIdMapping}
printingChecklistLinkToAIS={applicationData.EL_PRTCL}
edmsLoginServletLink={applicationData.EL_EDMSS}
maxExpandedChecklistItems={Math.abs(parseInt(applicationData.EL_MCHLS)) || 50}
getWoLink={wo => '/workorder/' + wo}
ref={checklists}
Expand Down