diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb index c1c0d3449179ecf51319368800fa8be3093a05ed..0a93e71858e1dc9e42c671b28407355e09536e28 100644 --- a/lib/api/api_guard.rb +++ b/lib/api/api_guard.rb @@ -74,43 +74,27 @@ module API private - def find_user_from_access_token - return unless access_token - - validate_access_token! - - access_token.user || raise(UnauthorizedError) - end - - # Check the Rails session for valid authentication details - def find_user_from_warden - warden.try(:authenticate) if verified_request? - end - - def warden - env['warden'] - end - - # Check if the request is GET/HEAD, or if CSRF token is valid. - def verified_request? - Gitlab::RequestForgeryProtection.verified?(env) - end - - def find_oauth_access_token - token = Doorkeeper::OAuth::Token.from_request(doorkeeper_request, *Doorkeeper.configuration.access_token_methods) - return unless token - - # Expiration, revocation and scopes are verified in `find_user_by_access_token` - access_token = OauthAccessToken.by_token(token) - raise UnauthorizedError unless access_token - - access_token.revoke_previous_refresh_token! - access_token + def raise_unauthorized_error! + raise UnauthorizedError end - def find_personal_access_token - token = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s - return unless token.present? + # If token is presented and valid, then it sets @current_user. + # + # If the token does not have sufficient scopes to cover the requred scopes, + # then it raises InsufficientScopeError. + # + # If the token is expired, then it raises ExpiredError. + # + # If the token is revoked, then it raises RevokedError. + # + # If the token is not found (nil), then it returns nil + # + # Arguments: + # + # scopes: (optional) scopes required for this guard. + # Defaults to empty array. + def find_user_by_access_token(access_token) + scopes = scopes_registered_for_endpoint # Expiration, revocation and scopes are verified in `find_user_by_access_token` access_token = PersonalAccessToken.find_by(token: token) @@ -119,10 +103,6 @@ module API access_token end - def doorkeeper_request - @doorkeeper_request ||= ActionDispatch::Request.new(env) - end - # An array of scopes that were registered (using `allow_access_with_scope`) # for the current endpoint class. It also returns scopes registered on # `API::API`, since these are meant to apply to all API routes. diff --git a/lib/gitlab/auth/request_authenticator.rb b/lib/gitlab/auth/request_authenticator.rb index 999104f91f57bf5cf31041ca470f8df68243a0ed..123a39dea751a0fa253804dedd1780e20469f1c6 100644 --- a/lib/gitlab/auth/request_authenticator.rb +++ b/lib/gitlab/auth/request_authenticator.rb @@ -3,6 +3,10 @@ module Gitlab module Auth class RequestAuthenticator + include UserAuthFinders + + attr_reader :request + def initialize(request) @request = ensure_action_dispatch_request(request) end @@ -14,49 +18,6 @@ module Gitlab def find_sessionless_user find_user_by_private_token || find_user_by_rss_token || find_user_by_oauth_token end - - private - - def find_session_user - @request.env['warden']&.authenticate if verified_request? - end - - def find_user_by_private_token - token = @request.params[:private_token].presence || @request.headers['PRIVATE-TOKEN'].presence - return unless token.present? - - User.find_by_authentication_token(token) || User.find_by_personal_access_token(token) - end - - def find_user_by_rss_token - return unless @request.path.ends_with?('atom') || @request.format == 'atom' - - token = @request.params[:rss_token].presence - return unless token.present? - - User.find_by_rss_token(token) - end - - def find_user_by_oauth_token - access_token = find_oauth_access_token - access_token&.user - end - - def find_oauth_access_token - token = Doorkeeper::OAuth::Token.from_request(@request, *Doorkeeper.configuration.access_token_methods) - OauthAccessToken.by_token(token) if token - end - - # Check if the request is GET/HEAD, or if CSRF token is valid. - def verified_request? - Gitlab::RequestForgeryProtection.verified?(@request.env) - end - - def ensure_action_dispatch_request(request) - return request if request.is_a?(ActionDispatch::Request) - - ActionDispatch::Request.new(request.env) - end end end end diff --git a/lib/gitlab/auth/user_auth_finders.rb b/lib/gitlab/auth/user_auth_finders.rb new file mode 100644 index 0000000000000000000000000000000000000000..2f4aeff14ac83b2ee54408ec18287892672291d2 --- /dev/null +++ b/lib/gitlab/auth/user_auth_finders.rb @@ -0,0 +1,92 @@ +module Gitlab + module Auth + module UserAuthFinders + # Check the Rails session for valid authentication details + def find_session_user + request.env['warden']&.authenticate if verified_request? + end + + def find_user_by_private_token + token = private_token + return unless token.present? + + user = + find_user_by_authentication_token(token) || + find_user_by_personal_access_token(token) + + raise_unauthorized_error! unless user + + user + end + + def private_token + request.params[:private_token].presence || + request.headers['PRIVATE-TOKEN'].presence + end + + def find_user_by_authentication_token(token_string) + User.find_by_authentication_token(token_string) + end + + def find_user_by_personal_access_token(token_string) + access_token = PersonalAccessToken.find_by_token(token_string) + return unless access_token + + find_user_by_access_token(access_token) + end + + def find_user_by_rss_token + return unless request.path.ends_with?('atom') || request.format.atom? + + token = request.params[:rss_token].presence + return unless token.present? + + user = User.find_by_rss_token(token) + raise_unauthorized_error! unless user + + user + end + + def find_user_by_oauth_token + access_token = find_oauth_access_token + + return unless access_token + + find_user_by_access_token(access_token) + end + + def find_oauth_access_token + return @oauth_access_token if defined?(@oauth_access_token) + + current_request = ensure_action_dispatch_request(request) + token = Doorkeeper::OAuth::Token.from_request(current_request, *Doorkeeper.configuration.access_token_methods) + return @oauth_access_token = nil unless token + + @oauth_access_token = OauthAccessToken.by_token(token) + raise_unauthorized_error! unless @oauth_access_token + + @oauth_access_token.revoke_previous_refresh_token! + @oauth_access_token + end + + def find_user_by_access_token(access_token) + access_token&.user + end + + # Check if the request is GET/HEAD, or if CSRF token is valid. + def verified_request? + Gitlab::RequestForgeryProtection.verified?(request.env) + end + + def ensure_action_dispatch_request(request) + return request if request.is_a?(ActionDispatch::Request) + + ActionDispatch::Request.new(request.env) + end + + def raise_unauthorized_error! + return nil + end + end + end +end diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb index 6c0996c543d38ea287ea890768cf65fc961eee99..fc1444e40185b9990cda4e633f21d7495a0e9f51 100644 --- a/spec/requests/api/helpers_spec.rb +++ b/spec/requests/api/helpers_spec.rb @@ -23,6 +23,7 @@ describe API::Helpers do } end let(:header) { } + let(:request) { Grape::Request.new(env)} before do allow_any_instance_of(self.class).to receive(:options).and_return({})