17106: Improve handling of bare tokens issued by remote clusters.
authorTom Clegg <tom@tomclegg.ca>
Tue, 17 Nov 2020 20:42:28 +0000 (15:42 -0500)
committerTom Clegg <tom@tomclegg.ca>
Wed, 18 Nov 2020 14:56:08 +0000 (09:56 -0500)
When caching, use the remote cluster's original token UUID.

When returning the current api_client_authorization record, include
the secret supplied by the caller, even when only storing the HMAC in
the database.

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

services/api/app/models/api_client_authorization.rb

index 74a4c1efa571b5229825243c98034957e99d4e45..1c1c669deb27d55d24774b3392077a4710840eb6 100644 (file)
@@ -130,6 +130,7 @@ class ApiClientAuthorization < ArvadosModel
 
     token_uuid = ''
     secret = token
+    stored_secret = nil         # ...if different from secret
     optional = nil
 
     case token[0..2]
@@ -206,8 +207,7 @@ class ApiClientAuthorization < ArvadosModel
         # below. If so, we'll stuff the database with hmac instead of
         # the real OIDC token.
         upstream_cluster_id = Rails.configuration.Login.LoginCluster
-        token_uuid = upstream_cluster_id + generate_uuid[5..27]
-        secret = hmac
+        stored_secret = hmac
       else
         return nil
       end
@@ -246,6 +246,23 @@ class ApiClientAuthorization < ArvadosModel
 
     remote_user_prefix = remote_user['uuid'][0..4]
 
+    if token_uuid == ''
+      # Use the same UUID as the remote when caching the token.
+      begin
+        remote_token = SafeJSON.load(
+          clnt.get_content('https://' + host + '/arvados/v1/api_client_authorizations/current',
+                           {'remote' => Rails.configuration.ClusterID},
+                           {'Authorization' => 'Bearer ' + token}))
+        token_uuid = remote_token['uuid']
+        if !token_uuid.match(HasUuid::UUID_REGEX) || token_uuid[0..4] != upstream_cluster_id
+          raise "remote cluster #{upstream_cluster_id} returned invalid token uuid #{token_uuid.inspect}"
+        end
+      rescue => e
+        Rails.logger.warn "error getting remote token details for #{token.inspect}: #{e}"
+        return nil
+      end
+    end
+
     # Clusters can only authenticate for their own users.
     if remote_user_prefix != upstream_cluster_id
       Rails.logger.warn "remote authentication rejected: claimed remote user #{remote_user_prefix} but token was issued by #{upstream_cluster_id}"
@@ -328,11 +345,13 @@ class ApiClientAuthorization < ArvadosModel
         auth.user = user
         auth.api_client_id = 0
       end
+      stored_secret = stored_secret || secret
       auth.update_attributes!(user: user,
-                              api_token: secret,
+                              api_token: stored_secret,
                               api_client_id: 0,
                               expires_at: Time.now + Rails.configuration.Login.RemoteTokenRefresh)
-      Rails.logger.debug "cached remote token #{token_uuid} with secret #{secret} in local db"
+      Rails.logger.debug "cached remote token #{token_uuid} with secret #{stored_secret} in local db"
+      auth.api_token = secret
       return auth
     end