Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2018-12-17 15:29:20 +0300
committerGitLab Release Tools Bot <robert+release-tools@gitlab.com>2018-12-18 22:40:40 +0300
commitcc2211295ee7a45906878fac728ab2bc1b26d591 (patch)
treeee28c59c5f5a67fc43a5d88d4b7a4175659bd38c /lib
parent7da68ab3f22412272596b0a87c7f69bcb633f731 (diff)
Merge branch '55433-un-revert-https-gitlab-com-gitlab-org-gitlab-ce-commit-00acef434031b5dc0bf39576a9e83802c7806842-revert' into 'master'
Resolve "Un-revert https://gitlab.com/gitlab-org/gitlab-ce/commit/00acef434031b5dc0bf39576a9e83802c7806842 revert" Closes #55433 See merge request gitlab-org/gitlab-ce!23861 (cherry picked from commit e8374cb6f493880042bf21d70c275bfdeed65fbe) 8ce86bf9 Revert "Revert "LfsToken uses JSONWebToken::HMACToken by default""
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/auth.rb4
-rw-r--r--lib/gitlab/lfs_token.rb121
2 files changed, 104 insertions, 21 deletions
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 6eb5f9e2300..7aa02009aa0 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -199,7 +199,7 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
- def lfs_token_check(login, password, project)
+ def lfs_token_check(login, encoded_token, project)
deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/)
actor =
@@ -222,7 +222,7 @@ module Gitlab
read_authentication_abilities
end
- if Devise.secure_compare(token_handler.token, password)
+ if token_handler.token_valid?(encoded_token)
Gitlab::Auth::Result.new(actor, nil, token_handler.type, authentication_abilities)
end
end
diff --git a/lib/gitlab/lfs_token.rb b/lib/gitlab/lfs_token.rb
index 05d3096a208..c09d3ebc7be 100644
--- a/lib/gitlab/lfs_token.rb
+++ b/lib/gitlab/lfs_token.rb
@@ -2,10 +2,21 @@
module Gitlab
class LfsToken
- attr_accessor :actor
+ module LfsTokenHelper
+ def user?
+ actor.is_a?(User)
+ end
+
+ def actor_name
+ user? ? actor.username : "lfs+deploy-key-#{actor.id}"
+ end
+ end
+
+ include LfsTokenHelper
- TOKEN_LENGTH = 50
- EXPIRY_TIME = 1800
+ DEFAULT_EXPIRE_TIME = 1800
+
+ attr_accessor :actor
def initialize(actor)
@actor =
@@ -19,36 +30,108 @@ module Gitlab
end
end
- def token
- Gitlab::Redis::SharedState.with do |redis|
- token = redis.get(redis_shared_state_key)
- token ||= Devise.friendly_token(TOKEN_LENGTH)
- redis.set(redis_shared_state_key, token, ex: EXPIRY_TIME)
+ def token(expire_time: DEFAULT_EXPIRE_TIME)
+ HMACToken.new(actor).token(expire_time)
+ end
- token
- end
+ def token_valid?(token_to_check)
+ HMACToken.new(actor).token_valid?(token_to_check) ||
+ LegacyRedisDeviseToken.new(actor).token_valid?(token_to_check)
end
def deploy_key_pushable?(project)
actor.is_a?(DeployKey) && actor.can_push_to?(project)
end
- def user?
- actor.is_a?(User)
- end
-
def type
user? ? :lfs_token : :lfs_deploy_token
end
- def actor_name
- actor.is_a?(User) ? actor.username : "lfs+deploy-key-#{actor.id}"
+ private # rubocop:disable Lint/UselessAccessModifier
+
+ class HMACToken
+ include LfsTokenHelper
+
+ def initialize(actor)
+ @actor = actor
+ end
+
+ def token(expire_time)
+ hmac_token = JSONWebToken::HMACToken.new(secret)
+ hmac_token.expire_time = Time.now + expire_time
+ hmac_token[:data] = { actor: actor_name }
+ hmac_token.encoded
+ end
+
+ def token_valid?(token_to_check)
+ decoded_token = JSONWebToken::HMACToken.decode(token_to_check, secret).first
+ decoded_token.dig('data', 'actor') == actor_name
+ rescue JWT::DecodeError
+ false
+ end
+
+ private
+
+ attr_reader :actor
+
+ def secret
+ salt + key
+ end
+
+ def salt
+ case actor
+ when DeployKey, Key
+ actor.fingerprint.delete(':').first(16)
+ when User
+ # Take the last 16 characters as they're more unique than the first 16
+ actor.id.to_s + actor.encrypted_password.last(16)
+ end
+ end
+
+ def key
+ # Take 16 characters of attr_encrypted_db_key_base, as that's what the
+ # cipher needs exactly
+ Settings.attr_encrypted_db_key_base.first(16)
+ end
end
- private
+ # TODO: LegacyRedisDeviseToken and references need to be removed after
+ # next released milestone
+ #
+ class LegacyRedisDeviseToken
+ TOKEN_LENGTH = 50
+ DEFAULT_EXPIRY_TIME = 1800 * 1000 # 30 mins
+
+ def initialize(actor)
+ @actor = actor
+ end
+
+ def token_valid?(token_to_check)
+ Devise.secure_compare(stored_token, token_to_check)
+ end
+
+ def stored_token
+ Gitlab::Redis::SharedState.with { |redis| redis.get(state_key) }
+ end
+
+ # This method exists purely to facilitate legacy testing to ensure the
+ # same redis key is used.
+ #
+ def store_new_token(expiry_time_in_ms = DEFAULT_EXPIRY_TIME)
+ Gitlab::Redis::SharedState.with do |redis|
+ new_token = Devise.friendly_token(TOKEN_LENGTH)
+ redis.set(state_key, new_token, px: expiry_time_in_ms)
+ new_token
+ end
+ end
+
+ private
- def redis_shared_state_key
- "gitlab:lfs_token:#{actor.class.name.underscore}_#{actor.id}" if actor
+ attr_reader :actor
+
+ def state_key
+ "gitlab:lfs_token:#{actor.class.name.underscore}_#{actor.id}"
+ end
end
end
end