11454: Conditional login to remote API servers.
[arvados.git] / apps / workbench / app / assets / javascripts / models / session_db.js
index a43cd79545b66ff47dda07f3097b3c8803a47262..79e98ca37e84a0b577e5c342e6a2e804cdf355eb 100644 (file)
@@ -2,9 +2,10 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-window.SessionDB = function() {
+window.SessionDB = function(rhosts) {
     var db = this
     Object.assign(db, {
+        remoteHosts: rhosts || [],
         discoveryCache: {},
         loadFromLocalStorage: function() {
             try {
@@ -81,7 +82,21 @@ window.SessionDB = function() {
             // also call checkForNewToken() on (at least) its first
             // render. Otherwise, the login procedure can't be
             // completed.
-            document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href.replace(/\?.*/, '')+'?baseURL='+encodeURIComponent(baseURL))
+            var session = db.loadLocal()
+            var uuidPrefix = session.user.owner_uuid.slice(0, 5)
+            var apiHostname = new URL(session.baseURL).hostname
+            m.request(baseURL+'discovery/v1/apis/arvados/v1/rest').then(function(dd) {
+                if (uuidPrefix in dd.remoteHosts ||
+                    (dd.remoteHostsViaDNS && apiHostname.indexOf('arvadosapi.com') >= 0)) {
+                    // Federated identity login via salted token
+                    db.saltedToken(dd.uuidPrefix).then(function(token) {
+                        document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href.replace(/\?.*/, '')+'?baseURL='+encodeURIComponent(baseURL)) + '&api_token='+encodeURIComponent(token)
+                    })
+                } else {
+                    // Classic login
+                    document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href.replace(/\?.*/, '')+'?baseURL='+encodeURIComponent(baseURL))
+                }
+            })
             return false
         },
         logout: function(k) {
@@ -92,6 +107,27 @@ window.SessionDB = function() {
             delete sessions[k].token
             db.save(k, sessions[k])
         },
+        saltedToken: function(uuid_prefix) {
+            // Takes a cluster UUID prefix and returns a salted token to allow
+            // log into said cluster using federated identity.
+            var session = db.loadLocal()
+            return db.request(session, '/arvados/v1/api_client_authorizations', {
+                data: {
+                    filters: JSON.stringify([['api_token', '=', session.token]]),
+                }
+            }).then(function(resp) {
+                if (resp.items.length == 1) {
+                    var token_uuid = resp.items[0].uuid
+                    if (token_uuid.length !== '') {
+                        var shaObj = new jsSHA("SHA-1", "TEXT")
+                        shaObj.setHMACKey(session.token, "TEXT")
+                        shaObj.update(uuid_prefix)
+                        var hmac = shaObj.getHMAC("HEX")
+                        return 'v2/' + token_uuid + '/' + hmac
+                    } else { return null }
+                }
+            }).catch(function(err) { return null })
+        },
         checkForNewToken: function() {
             // If there's a token and baseURL in the location bar (i.e.,
             // we just landed here after a successful login), save it and
@@ -127,7 +163,7 @@ window.SessionDB = function() {
                     },
                 }).then(function(user) {
                     session.user = user
-                    db.save(user.uuid.slice(0, 5), session)
+                    db.save(user.owner_uuid.slice(0, 5), session)
                     db.trash(key)
                 })
             })