diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 6df2ecf57a298d823000ccd3cc0013a79af962b0..1cd2302111ed9a10750c80a7ef12e64a40c6f551 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -16,9 +16,6 @@ .replace(':id', group_id); return $.ajax({ url: url, - data: { - private_token: gon.api_token - }, dataType: "json" }).done(function(group) { return callback(group); @@ -31,7 +28,6 @@ return $.ajax({ url: url, data: { - private_token: gon.api_token, search: query, per_page: 20 }, @@ -46,7 +42,6 @@ return $.ajax({ url: url, data: { - private_token: gon.api_token, search: query, per_page: 20 }, @@ -61,7 +56,6 @@ return $.ajax({ url: url, data: { - private_token: gon.api_token, search: query, order_by: order, per_page: 20 @@ -74,7 +68,6 @@ newLabel: function(project_id, data, callback) { var url = Api.buildUrl(Api.labelsPath) .replace(':id', project_id); - data.private_token = gon.api_token; return $.ajax({ url: url, type: "POST", @@ -93,7 +86,6 @@ return $.ajax({ url: url, data: { - private_token: gon.api_token, search: query, per_page: 20 }, diff --git a/doc/api/README.md b/doc/api/README.md index 7661e1eea028b0db1591d410647caeb1637ba0ce..6e3295e0e0c413e2118299e6907a30e24101955f 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -55,11 +55,12 @@ The following documentation is for the [internal CI API](ci/README.md): ## Authentication -All API requests require authentication via a token. There are three types of tokens -available: private tokens, OAuth 2 tokens, and personal access tokens. +All API requests require authentication via a session cookie or token. There are +three types of tokens available: private tokens, OAuth 2 tokens, and personal +access tokens. -If a token is invalid or omitted, an error message will be returned with -status code `401`: +If authentication information is invalid or omitted, an error message will be +returned with status code `401`: ```json { @@ -98,6 +99,13 @@ that needs access to the GitLab API. Once you have your token, pass it to the API using either the `private_token` parameter or the `PRIVATE-TOKEN` header. + +###Â Session cookie + +When signing in to GitLab as an ordinary user, a `_gitlab_session` cookie is +set. The API will use this cookie for authentication if it is present, but using +the API to generate a new session cookie is currently not supported. + ## Basic Usage API requests should be prefixed with `api` and the API version. The API version diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb index 7e67edb203ac73243a45a4f3e0eed0d583a10e6c..8cc7a26f1fa71249e79d28f71308a5fdc097a251 100644 --- a/lib/api/api_guard.rb +++ b/lib/api/api_guard.rb @@ -33,46 +33,29 @@ module API # # If the token is revoked, then it raises RevokedError. # - # If the token is not found (nil), then it raises TokenNotFoundError. + # If the token is not found (nil), then it returns nil # # Arguments: # # scopes: (optional) scopes required for this guard. # Defaults to empty array. # - def doorkeeper_guard!(scopes: []) - if (access_token = find_access_token).nil? - raise TokenNotFoundError - - else - case validate_access_token(access_token, scopes) - when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE - raise InsufficientScopeError.new(scopes) - when Oauth2::AccessTokenValidationService::EXPIRED - raise ExpiredError - when Oauth2::AccessTokenValidationService::REVOKED - raise RevokedError - when Oauth2::AccessTokenValidationService::VALID - @current_user = User.find(access_token.resource_owner_id) - end - end - end - def doorkeeper_guard(scopes: []) - if access_token = find_access_token - case validate_access_token(access_token, scopes) - when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE - raise InsufficientScopeError.new(scopes) + access_token = find_access_token + return nil unless access_token + + case validate_access_token(access_token, scopes) + when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE + raise InsufficientScopeError.new(scopes) - when Oauth2::AccessTokenValidationService::EXPIRED - raise ExpiredError + when Oauth2::AccessTokenValidationService::EXPIRED + raise ExpiredError - when Oauth2::AccessTokenValidationService::REVOKED - raise RevokedError + when Oauth2::AccessTokenValidationService::REVOKED + raise RevokedError - when Oauth2::AccessTokenValidationService::VALID - @current_user = User.find(access_token.resource_owner_id) - end + when Oauth2::AccessTokenValidationService::VALID + @current_user = User.find(access_token.resource_owner_id) end end @@ -96,19 +79,6 @@ module API end module ClassMethods - # Installs the doorkeeper guard on the whole Grape API endpoint. - # - # Arguments: - # - # scopes: (optional) scopes required for this guard. - # Defaults to empty array. - # - def guard_all!(scopes: []) - before do - guard! scopes: scopes - end - end - private def install_error_responders(base) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 150875ed4f083a790de485eebbccb46a59e3479e..714d4ea3dc642f5a64ff7062e11f3d01fd792b42 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -12,13 +12,30 @@ module API nil end + def private_token + params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER] + end + + def warden + env['warden'] + end + + # Check the Rails session for valid authentication details + def find_user_from_warden + warden ? warden.authenticate : nil + end + def find_user_by_private_token - token_string = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s - User.find_by_authentication_token(token_string) || User.find_by_personal_access_token(token_string) + token = private_token + return nil unless token.present? + + User.find_by_authentication_token(token) || User.find_by_personal_access_token(token) end def current_user - @current_user ||= (find_user_by_private_token || doorkeeper_guard) + @current_user ||= find_user_by_private_token + @current_user ||= doorkeeper_guard + @current_user ||= find_user_from_warden unless @current_user && Gitlab::UserAccess.new(@current_user).allowed? return nil diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index c5a11148d33f7c5dae8fa1c8b5811b91a177b9b7..2c21804fe7a6328b2f1d027b0dcacc918119d753 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -11,7 +11,6 @@ module Gitlab if current_user gon.current_user_id = current_user.id - gon.api_token = current_user.private_token end end end diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index bbdf8f03c2bc3578aec1c547d57853677ca2ed55..e66faeed705dbdfba330b74729e783cdf436785d 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -36,11 +36,36 @@ describe API::Helpers, api: true do params.delete(API::Helpers::SUDO_PARAM) end + def warden_authenticate_returns(value) + warden = double("warden", authenticate: value) + env['warden'] = warden + end + + def doorkeeper_guard_returns(value) + allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ value } + end + def error!(message, status) raise Exception end describe ".current_user" do + subject { current_user } + + describe "when authenticating via Warden" do + before { doorkeeper_guard_returns false } + + context "fails" do + it { is_expected.to be_nil } + end + + context "succeeds" do + before { warden_authenticate_returns user } + + it { is_expected.to eq(user) } + end + end + describe "when authenticating using a user's private token" do it "returns nil for an invalid token" do env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'