Commit 16913601 authored by Alex Kalderimis's avatar Alex Kalderimis

Support GraphQL authentication with project tokens

This enables the use of project and group access tokens for sessionless
API authentication. The primary effect of this is to allow the use of
project and group tokens in the GraphQL API.

The documentation is updated to explain a little how project tokens are
implemented, which is useful for future maintenance.

Changelog: changed
parent 55bc8d11
......@@ -26,6 +26,9 @@ module SessionlessAuthentication
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in(user, store: false, message: :sessionless_sign_in)
elsif request_authenticator.can_sign_in_bot?(user)
# we suppress callbacks to avoid redirecting the bot
sign_in(user, store: false, message: :sessionless_sign_in, run_callbacks: false)
end
end
......
......@@ -42,3 +42,5 @@ Other examples of internal users:
- [Ghost User](../user/profile/account/delete_account.md#associated-records)
- [Support Bot](../user/project/service_desk.md#support-bot-user)
- Visual Review Bot
- Resource access tokens (including [project access tokens](../user/project/settings/project_access_tokens.md)).
These are implemented as `project_bot` users with a `PersonalAccessToken`.
......@@ -42,6 +42,10 @@ module Gitlab
nil
end
def can_sign_in_bot?(user)
user&.project_bot? && api_request?
end
# To prevent Rack Attack from incorrectly rate limiting
# authenticated Git activity, we need to authenticate the user
# from other means (e.g. HTTP Basic Authentication) only if the
......
......@@ -139,8 +139,45 @@ RSpec.describe GraphqlController do
context 'when user uses an API token' do
let(:user) { create(:user, last_activity_on: Date.yesterday) }
let(:token) { create(:personal_access_token, user: user, scopes: [:api]) }
let(:query) { '{ __typename }' }
subject { post :execute, params: { access_token: token.token } }
subject { post :execute, params: { query: query, access_token: token.token } }
context 'when the user is a project bot' do
let(:user) { create(:user, :project_bot, last_activity_on: Date.yesterday) }
it 'updates the users last_activity_on field' do
expect { subject }.to change { user.reload.last_activity_on }
end
it "sets context's sessionless value as true" do
subject
expect(assigns(:context)[:is_sessionless_user]).to be true
end
it 'executes a simple query with no errors' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({ 'data' => { '__typename' => 'Query' } })
end
it 'can access resources the project_bot has access to' do
project_a, project_b = create_list(:project, 2, :private)
project_a.add_developer(user)
post :execute, params: { query: <<~GQL, access_token: token.token }
query {
a: project(fullPath: "#{project_a.full_path}") { name }
b: project(fullPath: "#{project_b.full_path}") { name }
}
GQL
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({ 'data' => { 'a' => { 'name' => project_a.name }, 'b' => nil } })
end
end
it 'updates the users last_activity_on field' do
expect { subject }.to change { user.reload.last_activity_on }
......
......@@ -44,6 +44,38 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do
end
end
describe '#can_sign_in_bot?' do
context 'the user is nil' do
it { is_expected.not_to be_can_sign_in_bot(nil) }
end
context 'the user is a bot, but for a web request' do
let(:user) { build(:user, :project_bot) }
it { is_expected.not_to be_can_sign_in_bot(user) }
end
context 'the user is a regular user, for an API request' do
let(:user) { build(:user) }
before do
env['SCRIPT_NAME'] = '/api/some_resource'
end
it { is_expected.not_to be_can_sign_in_bot(user) }
end
context 'the user is a project bot, for an API request' do
let(:user) { build(:user, :project_bot) }
before do
env['SCRIPT_NAME'] = '/api/some_resource'
end
it { is_expected.to be_can_sign_in_bot(user) }
end
end
describe '#find_sessionless_user' do
let_it_be(:dependency_proxy_user) { build(:user) }
let_it_be(:access_token_user) { build(:user) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment