cdn-experiments/boot/d4s-boot.js

368 lines
11 KiB
JavaScript
Raw Normal View History

2022-03-22 11:27:28 +01:00
window.customElements.define('d4s-boot-2', class extends HTMLElement {
#keycloak = null
#authorization = null
#url = null
#realm = "d4science"
#clientId = null
#redirectUrl = null
#audience = null
#authenticated = false
#locked = true
#queue = []
#interval = null
2022-03-22 11:27:28 +01:00
constructor() {
super()
}
unlock(){
this.#locked = false
}
2022-03-22 11:27:28 +01:00
fire(etype){
const evt = new CustomEvent(etype, { detail : ''})
document.dispatchEvent(evt)
}
connectedCallback(){
this.startStateChecker()
this.loadKeycloak().then(()=>{
console.log("Keycloak loaded")
return this.initKeycloak()
}).then((authenticated)=>{
if(!authenticated) throw "Failed to authenticate";
console.log("Keycloak initialized and user authenticated")
//if an audience is provided then perform also authorization
if(this.#audience){
return this.loadKeycloakAuthorization().then(
()=>{
this.#authorization = new KeycloakAuthorization(this.#keycloak)
console.log("Keycloak authorization loaded and initialized", this.#authorization)
}
)
}else{
return Promise.resolve()
}
}).then(()=>{
this.#authenticated = true
this.unlock()
this.fire("authenticated")
}).catch(err=>{
console.error("Unable to initialize Keycloak",err)
})
}
loadKeycloak(){
return new Promise((resolve, reject)=>{
2022-03-22 11:27:28 +01:00
if (typeof Keycloak === 'undefined') {
const script = document.createElement('script')
script.src = this.#url + '/js/keycloak.js'
script.type = 'text/javascript'
script.addEventListener('load', resolve)
2022-03-22 11:27:28 +01:00
document.head.appendChild(script)
} else {
resolve()
2022-03-22 11:27:28 +01:00
}
})
}
initKeycloak(){
this.#keycloak = new Keycloak({
url: this.#url,
realm: this.#realm,
clientId: this.#clientId
})
return this.#keycloak.init({onLoad: 'login-required', checkLoginIframe: false })
}
loadKeycloakAuthorization(){
return new Promise((resolve, reject)=>{
if (typeof KeycloakAuthorization === 'undefined') {
const authz = document.createElement('script')
authz.src = this.#url + '/js/keycloak-authz.js'
authz.type = 'text/javascript'
authz.addEventListener('load', resolve)
document.head.appendChild(authz)
} else {
resolve()
}
})
2022-03-22 11:27:28 +01:00
}
startStateChecker(){
this.#interval = window.setInterval(()=>{
if(this.#locked){
console.log("Still locked. Currently has " + this.#queue.length + " pending requests.")
}else if (!this.authenticated){
window.alert("Not authorized!")
}else{
if(this.#queue.length > 0){
this.#keycloak.updateToken(30).then(()=>{
if(this.#audience){
console.log("Checking entitlement for audience", this.#audience)
const audience = encodeURIComponent(this.#audience)
return this.#authorization.entitlement(audience)
} else {
return Promise.resolve(this.#keycloak.token)
}
}).then(
token => {
console.log("Authorized")
//transform all queued requests to fetches
console.log("All pending requests to promises")
let promises = this.#queue.map(r => {
r.request.headers["Authorization"] = "Bearer " + token
return r.resolve( fetch(r.url, r.request) )
2022-03-22 11:27:28 +01:00
})
//clear queue
this.#queue = []
console.log("Resolving all fetches")
return Promise.all(promises)
}
).catch(err => alert("Unable to make calls: " + err))
}
}
}, 300)
2022-03-22 11:27:28 +01:00
}
parseJwt(token) {
var base64Url = token.split('.')[1]
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
return JSON.parse(jsonPayload);
}
expirationDate(utc) {
let d = new Date(0)
d.setUTCSeconds(utc)
return d
}
checkContext() {
const parseJwt = this.parseJwt
const expDt = this.expirationDate
const audience = encodeURIComponent(this.#audience)
this.#authorization.entitlement(audience).then(function (rpt) {
// onGrant callback function.
// If authorization was successful you'll receive an RPT
// with the necessary permissions to access the resource server
console.log(rpt)
//console.log("rpt expires: " + expDt(parseJwt(rpt).exp))
2022-03-22 11:27:28 +01:00
})
}
secureFetch(url, request){
const p = new Promise((resolve, reject)=>{
let req = request ? request : {}
if("headers" in req){
req.headers["Authorization"] = null
} else {
req.headers = { "Authorization" : null}
2022-03-22 11:27:28 +01:00
}
console.log("Queued request to url ", url)
this.#queue.push({ url : url, request : req, resolve : resolve, reject : reject})
})
return p
2022-03-30 11:40:05 +02:00
}
download(url, name) {
this.secureFetch(url).then(reply=>{
if(reply.status !== 200) throw "Unable to download";
return reply.blob()
}).then(blob=>{
const objectURL = URL.createObjectURL(blob)
var tmplnk = document.createElement("a")
tmplnk.download = name
tmplnk.href = objectURL
document.body.appendChild(tmplnk)
tmplnk.click()
document.body.removeChild(tmplnk)
2022-04-12 19:11:54 +02:00
}).catch(err=>alert(err))
2022-03-22 11:27:28 +01:00
}
logout() {
if (this.#keycloak) {
if (!this.#redirectUrl) {
console.error("Missing required @redirectUrl attribute in d4s-boot")
} else {
this.#keycloak.logout({
redirectUri: this.#redirectUrl
})
}
}
}
static get observedAttributes() {
return ["url", "realm", "gateway", "redirect-url", "context"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
switch (name) {
case "url":
this.#url = newValue
break
case "realm":
this.#realm = newValue
break
case "gateway":
this.#clientId = newValue
break
case "redirect-url":
this.#redirectUrl = newValue
break
case "context":
this.#audience = newValue
break
}
}
}
get authenticated(){
return this.#authenticated
}
2022-03-22 11:27:28 +01:00
get url() {
return this.#url
}
set url(url) {
this.#url = url
this.setAttribute("url", url)
}
get realm() {
return this.#realm
}
set realm(realm) {
this.#realm = realm
this.setAttribute("realm", realm)
}
get clientId() {
return this.#clientId
}
set clientId(clientId) {
this.#clientId = clientId
this.setAttribute("gateway", clientId)
}
get redirectUrl() {
return this.#redirectUrl
}
set redirectUrl(redirectUrl) {
this.#redirectUrl = redirectUrl
this.setAttribute("redirect-url", redirectUrl)
}
get context() {
return this.#audience
}
set context(context) {
this.#audience = context
this.setAttribute("context", context)
}
})
/*connectedCallback() {
if (typeof Keycloak === 'undefined') {
const script = document.createElement('script')
script.src = this.#url + '/js/keycloak.js'
script.type = 'text/javascript'
script.addEventListener('load', () => {
this.initKeycloak()
})
document.head.appendChild(script)
} else {
this.initKeycloak()
}
}*/
/*initKeycloak() {
this.#keycloak = new Keycloak({
url: this.#url,
realm: this.#realm,
clientId: this.#clientId
})
const keycloak = this.#keycloak
const url = this.#url
keycloak.init({
onLoad: 'login-required'
, checkLoginIframe: false
}).then((authenticated) => {
console.log(authenticated ? 'Authenticated in ' + this.#realm : 'Not authenticated')
if (typeof KeycloakAuthorization === 'undefined') {
const authz = document.createElement('script')
authz.src = url + '/js/keycloak-authz.js'
authz.type = 'text/javascript'
authz.addEventListener('load', () => {
this.#authorization = new KeycloakAuthorization(keycloak)
})
document.head.appendChild(authz)
} else {
this.#authorization = new KeycloakAuthorization(keycloak)
}
//console.log("expires: " + this.expirationDate(keycloak.tokenParsed.exp))
}).catch(function(err) {
console.error("Failed to initialize d4science boot component")
})
}*/
/*service(endpoint, method, params, onSuccess, onForbidden) {
if (this.#authorization == null) {
if (this.#attempts-- > 0) {
setTimeout(() => this.service(endpoint, method, params, onSuccess, onForbidden), this.#timer)
return
} else {
console.error("Impossible to initialize D4Science authorization component")
throw "Fatal error"
}
}
this.#keycloak.updateToken(30).then(() => {
const audience = encodeURIComponent(this.#audience)
this.#authorization.entitlement(audience).then(function (rpt) {
var req = new XMLHttpRequest()
req.open(method, endpoint, true)
req.setRequestHeader('Accept', 'application/json')
req.setRequestHeader('Authorization', 'Bearer ' + rpt)
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200) {
onSuccess(req.response)
} else if (req.status == 403) {
onForbidden(req.statusText)
}
}
}
req.send(params)
})
}).catch(function() {
onForbidden('Failed to refresh token')
})
}*/