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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
commit8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch)
tree544930fb309b30317ae9797a9683768705d664c4 /lib/gitlab/auth
parent4b1de649d0168371549608993deac953eb692019 (diff)
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'lib/gitlab/auth')
-rw-r--r--lib/gitlab/auth/auth_finders.rb7
-rw-r--r--lib/gitlab/auth/crowd/authentication.rb35
-rw-r--r--lib/gitlab/auth/ldap/config.rb34
-rw-r--r--lib/gitlab/auth/ldap/user.rb14
-rw-r--r--lib/gitlab/auth/o_auth/provider.rb2
-rw-r--r--lib/gitlab/auth/o_auth/user.rb19
-rw-r--r--lib/gitlab/auth/otp/fortinet.rb20
-rw-r--r--lib/gitlab/auth/otp/session_enforcer.rb36
-rw-r--r--lib/gitlab/auth/otp/strategies/base.rb4
-rw-r--r--lib/gitlab/auth/otp/strategies/forti_authenticator.rb7
-rw-r--r--lib/gitlab/auth/otp/strategies/forti_token_cloud.rb72
-rw-r--r--lib/gitlab/auth/request_authenticator.rb9
12 files changed, 230 insertions, 29 deletions
diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb
index f3975fe219a..caa881eeeab 100644
--- a/lib/gitlab/auth/auth_finders.rb
+++ b/lib/gitlab/auth/auth_finders.rb
@@ -46,6 +46,7 @@ module Gitlab
def find_user_from_feed_token(request_format)
return unless valid_rss_format?(request_format)
+ return if Gitlab::CurrentSettings.disable_feed_token
# NOTE: feed_token was renamed from rss_token but both needs to be supported because
# users might have already added the feed to their RSS reader before the rename
@@ -193,6 +194,10 @@ module Gitlab
def access_token
strong_memoize(:access_token) do
+ # The token can be a PAT or an OAuth (doorkeeper) token
+ # It is also possible that a PAT is encapsulated in a `Bearer` OAuth token
+ # (e.g. NPM client registry auth), this case will be properly handled
+ # by find_personal_access_token
find_oauth_access_token || find_personal_access_token
end
end
@@ -236,7 +241,7 @@ module Gitlab
end
def matches_personal_access_token_length?(token)
- token.length == PersonalAccessToken::TOKEN_LENGTH
+ PersonalAccessToken::TOKEN_LENGTH_RANGE.include?(token.length)
end
# Check if the request is GET/HEAD, or if CSRF token is valid.
diff --git a/lib/gitlab/auth/crowd/authentication.rb b/lib/gitlab/auth/crowd/authentication.rb
new file mode 100644
index 00000000000..7f3e980034e
--- /dev/null
+++ b/lib/gitlab/auth/crowd/authentication.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Crowd
+ class Authentication < Gitlab::Auth::OAuth::Authentication
+ def login(login, password)
+ return unless Gitlab::Auth::OAuth::Provider.enabled?(@provider)
+ return unless login.present? && password.present?
+
+ user_info = user_info_from_authentication(login, password)
+ return unless user_info&.key?(:user)
+
+ Gitlab::Auth::OAuth::User.find_by_uid_and_provider(user_info[:user], provider)
+ end
+
+ private
+
+ def config
+ gitlab_crowd_config = Gitlab::Auth::OAuth::Provider.config_for(@provider)
+ raise "OmniAuth Crowd is not configured." unless gitlab_crowd_config && gitlab_crowd_config[:args]
+
+ OmniAuth::Strategies::Crowd::Configuration.new(
+ gitlab_crowd_config[:args].symbolize_keys)
+ end
+
+ def user_info_from_authentication(login, password)
+ validator = OmniAuth::Strategies::Crowd::CrowdValidator.new(
+ config, login, password, RequestContext.instance.client_ip, nil)
+ validator&.user_info&.symbolize_keys
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/ldap/config.rb b/lib/gitlab/auth/ldap/config.rb
index 88cc840c395..f5931a1d5eb 100644
--- a/lib/gitlab/auth/ldap/config.rb
+++ b/lib/gitlab/auth/ldap/config.rb
@@ -53,6 +53,10 @@ module Gitlab
raise InvalidProvider.new("Unknown provider (#{provider}). Available providers: #{providers}")
end
+ def self.encrypted_secrets
+ Settings.encrypted(Gitlab.config.ldap.secret_file)
+ end
+
def initialize(provider)
if self.class.valid_provider?(provider)
@provider = provider
@@ -89,8 +93,8 @@ module Gitlab
if has_auth?
opts.merge!(
- bind_dn: options['bind_dn'],
- password: options['password']
+ bind_dn: auth_username,
+ password: auth_password
)
end
@@ -155,7 +159,7 @@ module Gitlab
end
def has_auth?
- options['password'] || options['bind_dn']
+ auth_password || auth_username
end
def allow_username_or_email_login
@@ -267,12 +271,32 @@ module Gitlab
{
auth: {
method: :simple,
- username: options['bind_dn'],
- password: options['password']
+ username: auth_username,
+ password: auth_password
}
}
end
+ def secrets
+ @secrets ||= self.class.encrypted_secrets[@provider.delete_prefix('ldap').to_sym]
+ rescue => e
+ Gitlab::AppLogger.error "LDAP encrypted secrets are invalid: #{e.inspect}"
+
+ nil
+ end
+
+ def auth_password
+ return options['password'] if options['password']
+
+ secrets&.fetch(:password, nil)&.chomp
+ end
+
+ def auth_username
+ return options['bind_dn'] if options['bind_dn']
+
+ secrets&.fetch(:bind_dn, nil)&.chomp
+ end
+
def omniauth_user_filter
uid_filter = Net::LDAP::Filter.eq(uid, '%{username}')
diff --git a/lib/gitlab/auth/ldap/user.rb b/lib/gitlab/auth/ldap/user.rb
index 1405fb4ab95..814c17b7e44 100644
--- a/lib/gitlab/auth/ldap/user.rb
+++ b/lib/gitlab/auth/ldap/user.rb
@@ -11,16 +11,6 @@ module Gitlab
module Ldap
class User < Gitlab::Auth::OAuth::User
extend ::Gitlab::Utils::Override
- class << self
- # rubocop: disable CodeReuse/ActiveRecord
- def find_by_uid_and_provider(uid, provider)
- identity = ::Identity.with_extern_uid(provider, uid).take
-
- identity && identity.user
- end
- # rubocop: enable CodeReuse/ActiveRecord
- end
-
def save
super('LDAP')
end
@@ -30,10 +20,6 @@ module Gitlab
find_by_uid_and_provider || find_by_email || build_new_user
end
- def find_by_uid_and_provider
- self.class.find_by_uid_and_provider(auth_hash.uid, auth_hash.provider)
- end
-
override :should_save?
def should_save?
gl_user.changed? || gl_user.identities.any?(&:changed?)
diff --git a/lib/gitlab/auth/o_auth/provider.rb b/lib/gitlab/auth/o_auth/provider.rb
index 1eae7af442d..57ff3fcd1f0 100644
--- a/lib/gitlab/auth/o_auth/provider.rb
+++ b/lib/gitlab/auth/o_auth/provider.rb
@@ -18,6 +18,8 @@ module Gitlab
authenticator =
case provider
+ when /crowd/
+ Gitlab::Auth::Crowd::Authentication
when /^ldap/
Gitlab::Auth::Ldap::Authentication
when 'database'
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index 3211d2ffaea..f556a7f40e9 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -9,6 +9,16 @@ module Gitlab
module Auth
module OAuth
class User
+ class << self
+ # rubocop: disable CodeReuse/ActiveRecord
+ def find_by_uid_and_provider(uid, provider)
+ identity = ::Identity.with_extern_uid(provider, uid).take
+
+ identity && identity.user
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+
SignupDisabledError = Class.new(StandardError)
SigninDisabledForProviderError = Class.new(StandardError)
@@ -190,15 +200,12 @@ module Gitlab
@auth_hash = AuthHash.new(auth_hash)
end
- # rubocop: disable CodeReuse/ActiveRecord
def find_by_uid_and_provider
- identity = Identity.with_extern_uid(auth_hash.provider, auth_hash.uid).take
- identity&.user
+ self.class.find_by_uid_and_provider(auth_hash.uid, auth_hash.provider)
end
- # rubocop: enable CodeReuse/ActiveRecord
- def build_new_user
- user_params = user_attributes.merge(skip_confirmation: true)
+ def build_new_user(skip_confirmation: true)
+ user_params = user_attributes.merge(skip_confirmation: skip_confirmation)
Users::BuildService.new(nil, user_params).execute(skip_authorization: true)
end
diff --git a/lib/gitlab/auth/otp/fortinet.rb b/lib/gitlab/auth/otp/fortinet.rb
new file mode 100644
index 00000000000..a561e97dfcd
--- /dev/null
+++ b/lib/gitlab/auth/otp/fortinet.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+module Gitlab
+ module Auth
+ module Otp
+ module Fortinet
+ private
+
+ def forti_authenticator_enabled?(user)
+ ::Gitlab.config.forti_authenticator.enabled &&
+ Feature.enabled?(:forti_authenticator, user)
+ end
+
+ def forti_token_cloud_enabled?(user)
+ ::Gitlab.config.forti_token_cloud.enabled &&
+ Feature.enabled?(:forti_token_cloud, user)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/otp/session_enforcer.rb b/lib/gitlab/auth/otp/session_enforcer.rb
new file mode 100644
index 00000000000..8cc280756cc
--- /dev/null
+++ b/lib/gitlab/auth/otp/session_enforcer.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ class SessionEnforcer
+ OTP_SESSIONS_NAMESPACE = 'session:otp'
+ DEFAULT_EXPIRATION = 15.minutes.to_i
+
+ def initialize(key)
+ @key = key
+ end
+
+ def update_session
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.setex(key_name, DEFAULT_EXPIRATION, true)
+ end
+ end
+
+ def access_restricted?
+ Gitlab::Redis::SharedState.with do |redis|
+ !redis.get(key_name)
+ end
+ end
+
+ private
+
+ attr_reader :key
+
+ def key_name
+ @key_name ||= "#{OTP_SESSIONS_NAMESPACE}:#{key.id}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/otp/strategies/base.rb b/lib/gitlab/auth/otp/strategies/base.rb
index 718630e0e31..7d8513642c4 100644
--- a/lib/gitlab/auth/otp/strategies/base.rb
+++ b/lib/gitlab/auth/otp/strategies/base.rb
@@ -25,6 +25,10 @@ module Gitlab
result
end
+
+ def error_from_response(response)
+ error(response.message, response.code)
+ end
end
end
end
diff --git a/lib/gitlab/auth/otp/strategies/forti_authenticator.rb b/lib/gitlab/auth/otp/strategies/forti_authenticator.rb
index fbcb9fd8cdb..c1433f05db2 100644
--- a/lib/gitlab/auth/otp/strategies/forti_authenticator.rb
+++ b/lib/gitlab/auth/otp/strategies/forti_authenticator.rb
@@ -17,7 +17,10 @@ module Gitlab
# Successful authentication results in HTTP 200: OK
# https://docs.fortinet.com/document/fortiauthenticator/6.2.0/rest-api-solution-guide/704555/authentication-auth
- response.ok? ? success : error(message: response.message, http_status: response.code)
+ response.ok? ? success : error_from_response(response)
+ rescue StandardError => ex
+ Gitlab::AppLogger.error(ex)
+ error(ex.message)
end
private
@@ -32,7 +35,7 @@ module Gitlab
def api_credentials
{ username: ::Gitlab.config.forti_authenticator.username,
- password: ::Gitlab.config.forti_authenticator.token }
+ password: ::Gitlab.config.forti_authenticator.access_token }
end
end
end
diff --git a/lib/gitlab/auth/otp/strategies/forti_token_cloud.rb b/lib/gitlab/auth/otp/strategies/forti_token_cloud.rb
new file mode 100644
index 00000000000..d7506eca242
--- /dev/null
+++ b/lib/gitlab/auth/otp/strategies/forti_token_cloud.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module Strategies
+ class FortiTokenCloud < Base
+ include Gitlab::Utils::StrongMemoize
+ BASE_API_URL = 'https://ftc.fortinet.com:9696/api/v1'
+
+ def validate(otp_code)
+ if access_token_create_response.created?
+ otp_verification_response = verify_otp(otp_code)
+
+ otp_verification_response.ok? ? success : error_from_response(otp_verification_response)
+ else
+ error_from_response(access_token_create_response)
+ end
+ end
+
+ private
+
+ # TODO: Cache the access token: https://gitlab.com/gitlab-org/gitlab/-/issues/292437
+ def access_token_create_response
+ # Returns '201 CREATED' on successful creation of a new access token.
+ strong_memoize(:access_token_create_response) do
+ post(
+ url: url('/login'),
+ body: {
+ client_id: ::Gitlab.config.forti_token_cloud.client_id,
+ client_secret: ::Gitlab.config.forti_token_cloud.client_secret
+ }.to_json
+ )
+ end
+ end
+
+ def access_token
+ Gitlab::Json.parse(access_token_create_response)['access_token']
+ end
+
+ def verify_otp(otp_code)
+ # Returns '200 OK' on successful verification.
+ # Uses the access token created via `access_token_create_response` as the auth token.
+ post(
+ url: url('/auth'),
+ headers: { 'Authorization': "Bearer #{access_token}" },
+ body: {
+ username: user.username,
+ token: otp_code
+ }.to_json
+ )
+ end
+
+ def url(path)
+ BASE_API_URL + path
+ end
+
+ def post(url:, body:, headers: {})
+ Gitlab::HTTP.post(
+ url,
+ headers: {
+ 'Content-Type': 'application/json'
+ }.merge(headers),
+ body: body,
+ verify: false # FTC API Docs specifically mentions to turn off SSL Verification while making requests.
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/request_authenticator.rb b/lib/gitlab/auth/request_authenticator.rb
index c6216fa9cad..d28ee54cfbc 100644
--- a/lib/gitlab/auth/request_authenticator.rb
+++ b/lib/gitlab/auth/request_authenticator.rb
@@ -49,9 +49,16 @@ module Gitlab
private
+ def access_token
+ strong_memoize(:access_token) do
+ super || find_personal_access_token_from_http_basic_auth
+ end
+ end
+
def route_authentication_setting
@route_authentication_setting ||= {
- job_token_allowed: api_request?
+ job_token_allowed: api_request?,
+ basic_auth_personal_access_token: api_request?
}
end
end