include KindAndEtag
include CommonApiTemplate
extend CurrentApiClient
+ extend DbCurrentTime
belongs_to :api_client
belongs_to :user
after_initialize :assign_random_api_token
serialize :scopes, Array
+ before_validation :clamp_token_expiration
+
api_accessible :user, extend: :common do |t|
t.add :owner_uuid
t.add :user_id
token_uuid = ''
secret = token
+ stored_secret = nil # ...if different from secret
optional = nil
case token[0..2]
# 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 = generate_uuid
- secret = hmac
+ stored_secret = hmac
else
return nil
end
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}"
auth.user = user
auth.api_client_id = 0
end
+ # If stored_secret is set, we save stored_secret in the database
+ # but return the real secret to the caller. This way, if we end
+ # up returning the auth record to the client, they see the same
+ # secret they supplied, instead of the HMAC we saved in the
+ # database.
+ 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"
+ expires_at: db_current_time + Rails.configuration.Login.RemoteTokenRefresh)
+ Rails.logger.debug "cached remote token #{token_uuid} with secret #{stored_secret} in local db"
+ auth.api_token = secret
return auth
end
protected
+ def clamp_token_expiration
+ if !current_user.andand.is_admin && Rails.configuration.API.MaxTokenLifetime > 0
+ max_token_expiration = db_current_time + Rails.configuration.API.MaxTokenLifetime
+ if (self.new_record? || self.expires_at_changed?) && (self.expires_at.nil? || self.expires_at > max_token_expiration)
+ self.expires_at = max_token_expiration
+ end
+ end
+ end
+
def permission_to_create
current_user.andand.is_admin or (current_user.andand.id == self.user_id)
end
end
def log_update
-
super unless (saved_changes.keys - UNLOGGED_CHANGES).empty?
end
end