Skip to content
Snippets Groups Projects
Commit e752c1da authored by Sandro Weber's avatar Sandro Weber
Browse files

updated with newest changes form old frontend

parent 54019621
No related branches found
No related tags found
No related merge requests found
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
<title>Neurorobotics Platform</title> <title>Neurorobotics Platform</title>
</head> </head>
<body> <body>
<script src="https://iam.ebrains.eu/auth/js/keycloak.js"></script>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!-- <!--
......
import config from '../config.json'; import config from '../config.json';
/* global Keycloak */
let keycloakClient = undefined;
const INIT_CHECK_INTERVAL_MS = 100;
const INIT_CHECK_MAX_RETRIES = 10;
let _instance = null; let _instance = null;
const SINGLETON_ENFORCER = Symbol(); const SINGLETON_ENFORCER = Symbol();
...@@ -12,13 +19,13 @@ class AuthenticationService { ...@@ -12,13 +19,13 @@ class AuthenticationService {
throw new Error('Use ' + this.constructor.name + '.instance'); throw new Error('Use ' + this.constructor.name + '.instance');
} }
this.CLIENT_ID = config.authV2.clientId; this.proxyURL = config.api.proxy.url;
this.CLIENT_SECRET = config.authV2.secret; this.oidcEnabled = config.auth.enableOIDC;
this.STORAGE_KEY = `tokens-${this.CLIENT_ID}@https://iam.ebrains.eu/auth/realms/hbp/protocol/openid-connect/auth`; this.clientId = config.auth.clientId;
this.authURL = config.auth.url;
this.STORAGE_KEY = `tokens-${this.clientId}@https://iam.ebrains.eu/auth/realms/hbp`;
this.redirectToAuthPage = true; this.init();
this.checkForSessionStateAndAuthCode();
//this.checkForNewTokenToStore();
} }
static get instance() { static get instance() {
...@@ -29,120 +36,126 @@ class AuthenticationService { ...@@ -29,120 +36,126 @@ class AuthenticationService {
return _instance; return _instance;
} }
/** init() {
* Checks if the current page URL contains access tokens. this.initialized = false;
* This happens when the successfully logging in at the proxy login page and if (this.oidcEnabled) {
* being redirected back with the token info. this.authCollab().then(() => {
* Will automatically remove additional access info and present a clean URL after being redirected. this.initialized = true;
*/ });
checkForNewTokenToStore() { }
const path = window.location.href; else {
const accessTokenMatch = /&access_token=([^&]*)/.exec(path); this.checkForNewLocalTokenToStore();
this.initialized = true;
}
if (!accessTokenMatch || !accessTokenMatch[1]) { this.promiseInitialized = new Promise((resolve, reject) => {
return; let numChecks = 0;
let checkInterval = setInterval(() => {
numChecks++;
if (numChecks > INIT_CHECK_MAX_RETRIES) {
clearInterval(checkInterval);
reject();
}
if (this.initialized) {
clearInterval(checkInterval);
resolve();
}
}, INIT_CHECK_INTERVAL_MS);
});
}
authenticate(config) {
if (this.oidcEnabled) {
this.authCollab(config);
} }
else {
this.authLocal(config);
}
}
let accessToken = accessTokenMatch[1]; getToken() {
if (this.oidcEnabled) {
if (keycloakClient && keycloakClient.authenticated) {
keycloakClient
.updateToken(30)
.then(function() {})
.catch(function() {
console.error('Failed to refresh token');
});
return keycloakClient.token;
}
else {
console.error('getToken() - Client is not authenticated');
}
}
else {
return this.getStoredLocalToken();
}
}
localStorage.setItem( logout() {
this.STORAGE_KEY, if (this.oidcEnabled) {
//eslint-disable-next-line camelcase if (keycloakClient && keycloakClient.authenticated) {
JSON.stringify([{ access_token: accessToken }]) keycloakClient.logout();
); keycloakClient.clearStoredLocalToken();
const pathMinusAccessToken = path.substr(0, path.indexOf('&access_token=')); }
window.location.href = pathMinusAccessToken; else {
console.error('Client is not authenticated');
}
}
else {
return this.clearStoredLocalToken();
}
} }
/** authLocal(config) {
* Checks if the current page URL contains access tokens. if (this.authenticating) {
* This happens when the successfully logging in at the proxy login page and
* being redirected back with the token info.
* Will automatically remove additional access info and present a clean URL after being redirected.
*/
checkForSessionStateAndAuthCode() {
const path = window.location.href;
const sessionStateMatch = /session_state=([^&]*)/.exec(path);
const authCodeMatch = /code=([^&]*)/.exec(path);
if (!sessionStateMatch || !authCodeMatch) {
return; return;
} }
this.authenticating = true;
this.redirectToAuthPage = false; this.authURL = this.authURL || config.url;
this.clientId = this.clientId || config.clientId;
let sessionState = sessionStateMatch[1]; let absoluteUrl = /^https?:\/\//i;
let authCode = authCodeMatch[1]; if (!absoluteUrl.test(this.authURL)) {
console.info('authCode = ' + authCode); this.authURL = `${this.proxyURL}${this.authURL}`;
}
this.getAccessToken(authCode); this.clearStoredLocalToken();
window.location.href = `${this.authURL}&client_id=${this
.clientId}&redirect_uri=${encodeURIComponent(window.location.href)}`;
} }
async getAccessToken(authorizationCode) { checkForNewLocalTokenToStore() {
console.info('getAccessToken - origin = ' + window.location.origin); const path = window.location.pathname;
console.info('getAccessToken - authenticationCode = ' + authorizationCode);
let urlRequestAccessToken = 'https://iam.ebrains.eu/auth/realms/hbp/protocol/openid-connect/token'; const accessTokenMatch = /&access_token=([^&]*)/.exec(path);
if (!accessTokenMatch || !accessTokenMatch[1]) {
let options = { return;
method: 'POST', }
mode: 'cors', // no-cors, *cors, same-origin
//cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached let accessToken = accessTokenMatch[1];
//credentials: 'same-origin', // include, *same-origin, omit localStorage.setItem(
headers: {
'Content-Type': 'application/x-www-form-urlencoded'//,
//'Access-Control-Allow-Origin': '*',
//Referer: window.location.origin
},
// redirect: manual, *follow, error
//redirect: 'follow',
// referrerPolicy: no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin,
// strict-origin, strict-origin-when-cross-origin, unsafe-url
referrerPolicy: 'no-referrer'
};
let formDetails = {
grant_type: 'authorization_code',
client_id: this.CLIENT_ID,
redirect_uri: window.location.origin,
client_secret: this.CLIENT_SECRET,
code: authorizationCode
};
const formBody = Object.entries(formDetails)
.map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
.join('&');
options.body = formBody;
const responseAccessTokenRequest = await fetch(urlRequestAccessToken, options);
const responseAccessTokenRequestJSON = await responseAccessTokenRequest.json();
console.info(responseAccessTokenRequest);
console.info(responseAccessTokenRequestJSON);
/*localStorage.setItem(
this.STORAGE_KEY, this.STORAGE_KEY,
//eslint-disable-next-line camelcase //eslint-disable-next-line camelcase
JSON.stringify([{ access_token: accessToken }]) JSON.stringify([{ access_token: accessToken }])
);*/ );
//const pathMinusAccessToken = path.substr(0, path.indexOf('?'));
//window.location.href = pathMinusAccessToken; // navigate to clean url
let cleanedPath = path.substr(0, path.indexOf('&'));
window.location = cleanedPath;
} }
/** clearStoredLocalToken() {
* Clear currently stored access token.
*/
clearStoredToken() {
localStorage.removeItem(this.STORAGE_KEY); localStorage.removeItem(this.STORAGE_KEY);
} }
/** getStoredLocalToken() {
* Get the stored access token.
*
* @return token The stored access token. Or strings identifying 'no-token' / 'malformed-token'.
*/
getStoredToken() {
let storedItem = localStorage.getItem(this.STORAGE_KEY); let storedItem = localStorage.getItem(this.STORAGE_KEY);
if (!storedItem) { if (!storedItem) {
// this token will be rejected by the server and the client will get a proper auth error // this token will be rejected by the server and the client will get a proper auth error
return AuthenticationService.CONSTANTS.NO_TOKEN; return 'no-token';
} }
try { try {
...@@ -151,38 +164,57 @@ class AuthenticationService { ...@@ -151,38 +164,57 @@ class AuthenticationService {
} }
catch (e) { catch (e) {
// this token will be rejected by the server and the client will get a proper auth error // this token will be rejected by the server and the client will get a proper auth error
return AuthenticationService.CONSTANTS.MALFORMED_TOKEN; return 'malformed-token';
} }
} }
/** authCollab(config) {
* Opens the proxy's authentication page. if (this.authenticating) {
*
* @param {*} url The URL of the authentication page.
* If not an absolute URL it is assumed to be a subpage of the proxy.
*/
openAuthenticationPage(url = config.authV2.url) {
if (!this.redirectToAuthPage) {
return; return;
} }
console.info('openAuthenticationPage - origin=' + window.location.origin); this.authenticating = true;
this.clearStoredToken(); return new Promise(resolve => {
this.authURL = this.authURL || config.url;
this.initKeycloakClient().then(() => {
if (!keycloakClient.authenticated) {
// User is not authenticated, run login
keycloakClient
.login({ scope: 'openid profile email group' })
.then(() => {
resolve(true);
});
}
else {
keycloakClient.loadUserInfo().then(userInfo => {
this.userInfo = userInfo;
resolve(true);
});
}
});
});
}
let absoluteUrl = /^https?:\/\//i; initKeycloakClient() {
if (!absoluteUrl.test(url)) { return new Promise(resolve => {
url = `https://${url}`; keycloakClient = Keycloak({
} realm: 'hbp',
/*window.location.href = `${url} clientId: this.clientId,
&client_id=${this.CLIENT_ID} //'public-client': true,
&redirect_uri=${encodeURIComponent(window.location.href)}`;*/ 'confidential-port': 0,
url: this.authURL,
let testClientID = 'community-apps-tutorial'; redirectUri: window.location.href // 'http://localhost:9001/#/esv-private' //
console.info('redirect_uri=' + window.location.origin); });
let testRedirectURI = window.location.origin; //'http://localhost:3000';
window.location.href = url + keycloakClient
'&client_id=' + testClientID + .init({
'&redirect_uri=' + testRedirectURI; flow: 'hybrid' /*, responseMode: 'fragment'*/
})
.then(() => {
resolve(keycloakClient);
});
});
} }
} }
......
...@@ -253,13 +253,11 @@ class ExperimentStorageService extends HttpService { ...@@ -253,13 +253,11 @@ class ExperimentStorageService extends HttpService {
async setFile(directoryPath, filename, data, byname = true, contentType = 'text/plain') { async setFile(directoryPath, filename, data, byname = true, contentType = 'text/plain') {
let directory = directoryPath.replaceAll('/', '%2F'); let directory = directoryPath.replaceAll('/', '%2F');
const url = new URL(`${config.api.proxy.url}${endpoints.proxy.storage.url}/${directory}/${filename}`); const url = new URL(`${config.api.proxy.url}${endpoints.proxy.storage.url}/${directory}/${filename}`);
//console.info(url);
url.searchParams.append('byname', byname); url.searchParams.append('byname', byname);
let requestOptions = { let requestOptions = {
...this.POSTOptions, ...{ headers: { 'Content-Type': contentType } } ...this.POSTOptions, ...{ headers: { 'Content-Type': contentType } }
}; };
//console.info(requestOptions);
if (contentType === 'text/plain') { if (contentType === 'text/plain') {
return this.httpRequestPOST(url, data, requestOptions); return this.httpRequestPOST(url, data, requestOptions);
......
...@@ -44,7 +44,9 @@ export class HttpService extends EventEmitter { ...@@ -44,7 +44,9 @@ export class HttpService extends EventEmitter {
*/ */
performRequest = async (url, options, data) => { performRequest = async (url, options, data) => {
// Add authorization header // Add authorization header
options.headers.Authorization = `Bearer ${AuthenticationService.instance.getStoredToken()}`; await AuthenticationService.instance.promiseInitialized;
let token = AuthenticationService.instance.getToken();
options.headers.Authorization = 'Bearer ' + token;
if (data) { if (data) {
options.body = data; options.body = data;
} }
...@@ -54,10 +56,7 @@ export class HttpService extends EventEmitter { ...@@ -54,10 +56,7 @@ export class HttpService extends EventEmitter {
// error handling // error handling
if (!response.ok) { if (!response.ok) {
if (response.status === 477) { if (response.status === 477) {
const responseText = await response.text(); AuthenticationService.instance.authenticate();
console.info('auth error');
console.info(responseText);
AuthenticationService.instance.openAuthenticationPage(/*responseText*/);
} }
else if (response.status === 478) { else if (response.status === 478) {
//TODO: redirect to maintenance page //TODO: redirect to maintenance page
......
...@@ -62,7 +62,6 @@ class NrpUserService extends HttpService { ...@@ -62,7 +62,6 @@ class NrpUserService extends HttpService {
async getCurrentUser() { async getCurrentUser() {
if (!this.currentUser) { if (!this.currentUser) {
let responseIdentity = await this.httpRequestGET(IDENTITY_ME_URL); let responseIdentity = await this.httpRequestGET(IDENTITY_ME_URL);
console.info(responseIdentity);
if (responseIdentity.ok) { if (responseIdentity.ok) {
this.currentUser = await responseIdentity.json(); this.currentUser = await responseIdentity.json();
} }
......
import * as ROSLIB from 'roslib'; import * as ROSLIB from 'roslib';
import _ from 'lodash'; import _ from 'lodash';
import AuthenticationService from './authentication-service.js'; import AuthenticationService from './authentication-service-v2';
let _instance = null; let _instance = null;
const SINGLETON_ENFORCER = Symbol(); const SINGLETON_ENFORCER = Symbol();
...@@ -32,7 +32,7 @@ class RoslibService { ...@@ -32,7 +32,7 @@ class RoslibService {
*/ */
getConnection(url) { getConnection(url) {
if (!this.connections.has(url)) { if (!this.connections.has(url)) {
let urlWithAuth = url + '?token=' + AuthenticationService.instance.getStoredToken(); let urlWithAuth = url + '?token=' + AuthenticationService.instance.getToken();
this.connections.set(url, new ROSLIB.Ros({ url: urlWithAuth })); this.connections.set(url, new ROSLIB.Ros({ url: urlWithAuth }));
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment