Skip to content

Commit

Permalink
Apply web application that can make authentication requests with user…
Browse files Browse the repository at this point in the history
… token (#16488)

Currently oAuth requests are not allowed to use machine token, so this web app loads a keycloak token on start and opens the oauth authenticate popup with the help of the keycloak token. If we need to get the oauth provider's token the web app send a user token to the window which opened the app. Then the client that opened the app will receive a user token which can be used for other oAuth requests like getToken().
  • Loading branch information
vinokurig authored Apr 8, 2020
1 parent 7580ee9 commit 5c20e0e
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 119 deletions.
125 changes: 125 additions & 0 deletions assembly/assembly-root-war/src/main/webapp/_app/keycloackLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
export class KeycloakLoader {
/**
* Load keycloak settings
*/
loadKeycloakSettings() {
const msg = "Cannot load keycloak settings. This is normal for single-user mode.";

return new Promise((resolve, reject) => {
try {
if (window.parent && window.parent['_keycloak']) {
window['_keycloak'] = window.parent['_keycloak'];
resolve(window['_keycloak']);
return;
}
} catch (e) {
// parent frame has different origin, so access to parent frame is forbidden
console.error(msg, e);
}

try {
const request = new XMLHttpRequest();

request.onerror = request.onabort = function() {
reject(new Error(msg));
};

request.onload = () => {
if (request.status == 200) {
resolve(this.injectKeycloakScript(JSON.parse(request.responseText)));
} else {
reject(new Error(msg));
}
};

const url = "/api/keycloak/settings";
request.open("GET", url, true);
request.send();
} catch (e) {
reject(new Error(msg + e.message));
}
});
}

/**
* Injects keycloak javascript
*/
injectKeycloakScript(keycloakSettings) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.language = 'javascript';
script.async = true;
script.src = keycloakSettings['che.keycloak.js_adapter_url'];

script.onload = () => {
resolve(this.initKeycloak(keycloakSettings));
};

script.onerror = script.onabort = () => {
reject(new Error('cannot load ' + script.src));
};

document.head.appendChild(script);
});
}

/**
* Initialize keycloak
*/
initKeycloak(keycloakSettings) {
return new Promise((resolve, reject) => {

function keycloakConfig() {
const theOidcProvider = keycloakSettings['che.keycloak.oidc_provider'];
if (!theOidcProvider) {
return {
url: keycloakSettings['che.keycloak.auth_server_url'],
realm: keycloakSettings['che.keycloak.realm'],
clientId: keycloakSettings['che.keycloak.client_id']
};
} else {
return {
oidcProvider: theOidcProvider,
clientId: keycloakSettings['che.keycloak.client_id']
};
}
}
const keycloak = Keycloak(keycloakConfig());

window['_keycloak'] = keycloak;

var useNonce;
if (typeof keycloakSettings['che.keycloak.use_nonce'] === 'string') {
useNonce = keycloakSettings['che.keycloak.use_nonce'].toLowerCase() === 'true';
}
window.sessionStorage.setItem('oidcIdeRedirectUrl', location.href);
keycloak
.init({
onLoad: 'login-required',
checkLoginIframe: false,
useNonce: useNonce,
scope: 'email profile',
redirectUri: keycloakSettings['che.keycloak.redirect_url.ide']
})
.success(() => {
resolve(keycloak);
})
.error(() => {
reject(new Error('[Keycloak] Failed to initialize Keycloak'));
});
});
}

}
4 changes: 2 additions & 2 deletions assembly/assembly-root-war/src/main/webapp/_app/loader.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
<meta charset="UTF-8">
<title>Workspace token loader</title>

<link rel="stylesheet" href="./loader.css"></link>
<script src="./loader.js" defer></script>
<link rel="stylesheet" href="./loader.css"/>
<script type="module" src="loader.js" defer></script>
</head>

<body style="background-color: #21252b; transition: background-color 0.5s ease;">
Expand Down
114 changes: 1 addition & 113 deletions assembly/assembly-root-war/src/main/webapp/_app/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,120 +9,8 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
class KeycloakLoader {
/**
* Load keycloak settings
*/
loadKeycloakSettings() {
const msg = "Cannot load keycloak settings. This is normal for single-user mode.";

return new Promise((resolve, reject) => {
try {
if (window.parent && window.parent['_keycloak']) {
window['_keycloak'] = window.parent['_keycloak'];
resolve(window['_keycloak']);
return;
}
} catch (e) {
// parent frame has different origin, so access to parent frame is forbidden
console.error(msg, e);
}

try {
const request = new XMLHttpRequest();

request.onerror = request.onabort = function() {
reject(new Error(msg));
};

request.onload = () => {
if (request.status == 200) {
resolve(this.injectKeycloakScript(JSON.parse(request.responseText)));
} else {
reject(new Error(msg));
}
};

const url = "/api/keycloak/settings";
request.open("GET", url, true);
request.send();
} catch (e) {
reject(new Error(msg + e.message));
}
});
}

/**
* Injects keycloak javascript
*/
injectKeycloakScript(keycloakSettings) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.language = 'javascript';
script.async = true;
script.src = keycloakSettings['che.keycloak.js_adapter_url'];

script.onload = () => {
resolve(this.initKeycloak(keycloakSettings));
};

script.onerror = script.onabort = () => {
reject(new Error('cannot load ' + script.src));
};

document.head.appendChild(script);
});
}

/**
* Initialize keycloak
*/
initKeycloak(keycloakSettings) {
return new Promise((resolve, reject) => {

function keycloakConfig() {
const theOidcProvider = keycloakSettings['che.keycloak.oidc_provider'];
if (!theOidcProvider) {
return {
url: keycloakSettings['che.keycloak.auth_server_url'],
realm: keycloakSettings['che.keycloak.realm'],
clientId: keycloakSettings['che.keycloak.client_id']
};
} else {
return {
oidcProvider: theOidcProvider,
clientId: keycloakSettings['che.keycloak.client_id']
};
}
}
const keycloak = Keycloak(keycloakConfig());

window['_keycloak'] = keycloak;

var useNonce;
if (typeof keycloakSettings['che.keycloak.use_nonce'] === 'string') {
useNonce = keycloakSettings['che.keycloak.use_nonce'].toLowerCase() === 'true';
}
window.sessionStorage.setItem('oidcIdeRedirectUrl', location.href);
keycloak
.init({
onLoad: 'login-required',
checkLoginIframe: false,
useNonce: useNonce,
scope: 'email profile',
redirectUri: keycloakSettings['che.keycloak.redirect_url.ide']
})
.success(() => {
resolve(keycloak);
})
.error(() => {
reject(new Error('[Keycloak] Failed to initialize Keycloak'));
});
});
}

}
import { KeycloakLoader } from './keycloackLoader.js';

class Loader {

Expand Down
29 changes: 29 additions & 0 deletions assembly/assembly-root-war/src/main/webapp/_app/oauth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!--
Copyright (c) 2012-2018 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Authentication</title>
<script type="module" src="./oauthLoader.js" defer></script>
</head>

<body style="background-color: #21252b; transition: background-color 0.5s ease;">

<div id="error-console"></div>

</body>

</html>
Loading

0 comments on commit 5c20e0e

Please sign in to comment.