raise "remote cluster #{upstream_cluster_id} returned invalid token uuid #{token_uuid.inspect}"
end
rescue HTTPClient::BadResponseError => e
+ if e.res.status_code >= 400 && e.res.status_code < 500
+ # Remote cluster does not accept this token.
+ return nil
+ end
# CurrentApiToken#call and ApplicationController#render_error will
# propagate the status code from the #http_status method, so define
# that here.
if user.nil? and remote_user.nil?
Rails.logger.warn "remote token #{token.inspect} rejected: cannot get owner #{remote_user_uuid} from database or remote cluster"
return nil
+ end
+
# Invariant: remote_user_prefix == upstream_cluster_id
# therefore: remote_user_prefix != Rails.configuration.ClusterID
# Add or update user and token in local database so we can
# validate subsequent requests faster.
- elsif user.nil?
- # Create a new record for this user.
- user = User.new(uuid: remote_user['uuid'],
- is_active: false,
- is_admin: false,
- email: remote_user['email'],
- owner_uuid: system_user_uuid)
- user.set_initial_username(requested: remote_user['username'])
- end
- # Sync user record if we loaded a remote user.
act_as_system_user do
- if remote_user
- %w[first_name last_name email prefs].each do |attr|
- user.send(attr+'=', remote_user[attr])
- end
-
- begin
- user.save!
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
- Rails.logger.debug("remote user #{remote_user['uuid']} already exists, retrying...")
- # Some other request won the race: retry fetching the user record.
- user = User.uncached do
- User.find_by_uuid(remote_user['uuid'])
- end
- if !user
- Rails.logger.warn("cannot find or create remote user #{remote_user['uuid']}")
- return nil
- end
- end
-
- if user.is_invited && !remote_user['is_invited']
- # Remote user is not "invited" state, they should be unsetup, which
- # also makes them inactive.
- user.unsetup
- else
- if !user.is_invited && remote_user['is_invited'] and
- (remote_user_prefix == Rails.configuration.Login.LoginCluster or
- Rails.configuration.Users.AutoSetupNewUsers or
- Rails.configuration.Users.NewUsersAreActive or
- Rails.configuration.RemoteClusters[remote_user_prefix].andand["ActivateUsers"])
- user.setup
- end
-
- if !user.is_active && remote_user['is_active'] && user.is_invited and
- (remote_user_prefix == Rails.configuration.Login.LoginCluster or
- Rails.configuration.Users.NewUsersAreActive or
- Rails.configuration.RemoteClusters[remote_user_prefix].andand["ActivateUsers"])
- user.update!(is_active: true)
- elsif user.is_active && !remote_user['is_active']
- user.update!(is_active: false)
- end
-
- if remote_user_prefix == Rails.configuration.Login.LoginCluster and
- user.is_active and
- user.is_admin != remote_user['is_admin']
- # Remote cluster controls our user database, including the
- # admin flag.
- user.update!(is_admin: remote_user['is_admin'])
- end
- end
+ if remote_user && remote_user_uuid != anonymous_user_uuid
+ # Sync user record if we loaded a remote user.
+ user = User.update_remote_user remote_user
end
# If stored_secret is set, we save stored_secret in the database
end
rescue ActiveRecord::RecordNotUnique
Rails.logger.debug("cached remote token #{token_uuid} already exists, retrying...")
- # Some other request won the race: retry just once before erroring out
- if (retries += 1) <= 1
+ # Another request won the race (trying to find_or_create the
+ # same token UUID) ...and/or... there is an expired entry with
+ # the same secret but a different UUID (e.g., the token is an
+ # OIDC access token and [a] our database has an expired cached
+ # row that was not used above, and [b] the remote cluster had
+ # deleted its expired cached row so it assigned a new UUID).
+ #
+ # Delete any conflicting row if any. Retry twice (in case we
+ # hit both of those situations at once), then give up.
+ if (retries += 1) <= 2
+ ApiClientAuthorization.where('api_token=? and uuid<>?', stored_secret, token_uuid).delete_all
retry
else
Rails.logger.warn("cannot find or create cached remote token #{token_uuid}")