Merge branch '16914-inactive-user' closes #16914
[arvados.git] / services / api / app / models / api_client_authorization.rb
index 55db16a4b5e3e81fe407263d0dda69cb1dce9c35..76b722694aa763baeb79a2ce621c620383c139a2 100644 (file)
@@ -92,9 +92,11 @@ class ApiClientAuthorization < ArvadosModel
        uuid_prefix+".arvadosapi.com")
   end
 
-  def self.make_http_client
+  def self.make_http_client(uuid_prefix:)
     clnt = HTTPClient.new
-    if Rails.configuration.TLS.Insecure
+
+    if uuid_prefix && (Rails.configuration.RemoteClusters[uuid_prefix].andand.Insecure ||
+                       Rails.configuration.RemoteClusters['*'].andand.Insecure)
       clnt.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
     else
       # Use system CA certificates
@@ -106,10 +108,26 @@ class ApiClientAuthorization < ArvadosModel
     clnt
   end
 
+  def self.check_system_root_token token
+    if token == Rails.configuration.SystemRootToken
+      return ApiClientAuthorization.new(user: User.find_by_uuid(system_user_uuid),
+                                        uuid: Rails.configuration.ClusterID+"-gj3su-000000000000000",
+                                        api_token: token,
+                                        api_client: system_root_token_api_client)
+    else
+      return nil
+    end
+  end
+
   def self.validate(token:, remote: nil)
-    return nil if !token
+    return nil if token.nil? or token.empty?
     remote ||= Rails.configuration.ClusterID
 
+    auth = self.check_system_root_token(token)
+    if !auth.nil?
+      return auth
+    end
+
     case token[0..2]
     when 'v2/'
       _, token_uuid, secret, optional = token.split('/')
@@ -146,6 +164,9 @@ class ApiClientAuthorization < ArvadosModel
          (secret == auth.api_token ||
           secret == OpenSSL::HMAC.hexdigest('sha1', auth.api_token, remote))
         # found it
+        if token_uuid[0..4] != Rails.configuration.ClusterID
+          Rails.logger.debug "found cached remote token #{token_uuid} with secret #{secret} in local db"
+        end
         return auth
       end
 
@@ -167,7 +188,7 @@ class ApiClientAuthorization < ArvadosModel
       # by a remote cluster when the token absent or expired in our
       # database.  To begin, we need to ask the cluster that issued
       # the token to [re]validate it.
-      clnt = ApiClientAuthorization.make_http_client
+      clnt = ApiClientAuthorization.make_http_client(uuid_prefix: token_uuid_prefix)
 
       host = remote_host(uuid_prefix: token_uuid_prefix)
       if !host
@@ -205,6 +226,11 @@ class ApiClientAuthorization < ArvadosModel
       # Add or update user and token in local database so we can
       # validate subsequent requests faster.
 
+      if remote_user['uuid'][-22..-1] == '-tpzed-anonymouspublic'
+        # Special case: map the remote anonymous user to local anonymous user
+        remote_user['uuid'] = anonymous_user_uuid
+      end
+
       user = User.find_by_uuid(remote_user['uuid'])
 
       if !user
@@ -219,20 +245,16 @@ class ApiClientAuthorization < ArvadosModel
 
       # Sync user record.
       if remote_user_prefix == Rails.configuration.Login.LoginCluster
-        # Remote cluster controls our user database, copy both
-        # 'is_active' and 'is_admin'
-        user.is_active = remote_user['is_active']
+        # Remote cluster controls our user database, set is_active if
+        # remote is active.  If remote is not active, user will be
+        # unsetup (see below).
+        user.is_active = true if remote_user['is_active']
         user.is_admin = remote_user['is_admin']
       else
         if Rails.configuration.Users.NewUsersAreActive ||
            Rails.configuration.RemoteClusters[remote_user_prefix].andand["ActivateUsers"]
-          # Default policy is to activate users, so match activate
-          # with the remote record.
-          user.is_active = remote_user['is_active']
-        elsif !remote_user['is_active']
-          # Deactivate user if the remote is inactive, otherwise don't
-          # change 'is_active'.
-          user.is_active = false
+          # Default policy is to activate users
+          user.is_active = true if remote_user['is_active']
         end
       end
 
@@ -240,9 +262,22 @@ class ApiClientAuthorization < ArvadosModel
         user.send(attr+'=', remote_user[attr])
       end
 
+      if remote_user['uuid'][-22..-1] == '-tpzed-000000000000000'
+        user.first_name = "root"
+        user.last_name = "from cluster #{remote_user_prefix}"
+      end
+
       act_as_system_user do
         user.save!
 
+        if (user.is_active && !remote_user['is_active']) or (user.is_invited && !remote_user['is_invited'])
+          # If the user is newly created and AutoSetupNewUsers is
+          # true, they will auto-setup in an after_create hook.
+          # Synchronize the user's "active/invited" state state after the record
+          # has been saved.
+          user.unsetup
+        end
+
         # We will accept this token (and avoid reloading the user
         # record) for 'RemoteTokenRefresh' (default 5 minutes).
         # Possible todo:
@@ -256,6 +291,7 @@ class ApiClientAuthorization < ArvadosModel
                                 api_token: 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"
       end
       return auth
     else
@@ -303,6 +339,7 @@ class ApiClientAuthorization < ArvadosModel
   end
 
   def log_update
-    super unless (changed - UNLOGGED_CHANGES).empty?
+
+    super unless (saved_changes.keys - UNLOGGED_CHANGES).empty?
   end
 end