debian-mirror-gitlab/spec/requests/openid_connect_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

384 lines
12 KiB
Ruby
Raw Normal View History

2019-12-26 22:10:19 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
require 'spec_helper'
2023-05-27 22:25:52 +05:30
RSpec.describe 'OpenID Connect requests', feature_category: :system_access do
2018-11-08 19:23:39 +05:30
let(:user) do
create(
:user,
name: 'Alice',
username: 'alice',
email: 'private@example.com',
website_url: 'https://example.com',
avatar: fixture_file_upload('spec/fixtures/dk.png')
)
end
2017-08-17 22:00:37 +05:30
let(:access_grant) { create :oauth_access_grant, application: application, resource_owner_id: user.id }
let(:access_token) { create :oauth_access_token, application: application, resource_owner_id: user.id }
2018-11-08 19:23:39 +05:30
let(:hashed_subject) do
Digest::SHA256.hexdigest("#{user.id}-#{Rails.application.secrets.secret_key_base}")
end
let(:id_token_claims) do
{
2022-10-11 01:57:18 +05:30
'sub' => user.id.to_s,
2018-11-08 19:23:39 +05:30
'sub_legacy' => hashed_subject
}
end
let(:user_info_claims) do
{
2022-10-11 01:57:18 +05:30
'name' => 'Alice',
'nickname' => 'alice',
2023-03-17 16:20:25 +05:30
'preferred_username' => 'alice',
2022-10-11 01:57:18 +05:30
'email' => 'public@example.com',
2020-05-30 21:06:31 +05:30
'email_verified' => true,
2022-10-11 01:57:18 +05:30
'website' => 'https://example.com',
'profile' => 'http://localhost/alice',
'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png",
'groups' => kind_of(Array),
'https://gitlab.org/claims/groups/owner' => kind_of(Array),
2022-01-26 12:08:38 +05:30
'https://gitlab.org/claims/groups/maintainer' => kind_of(Array),
2022-10-11 01:57:18 +05:30
'https://gitlab.org/claims/groups/developer' => kind_of(Array)
2018-11-08 19:23:39 +05:30
}
end
2021-09-04 01:27:46 +05:30
let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
2018-11-08 19:23:39 +05:30
def request_access_token!
2017-08-17 22:00:37 +05:30
login_as user
post '/oauth/token',
2019-02-15 15:39:39 +05:30
params: {
grant_type: 'authorization_code',
code: access_grant.token,
redirect_uri: application.redirect_uri,
client_id: application.uid,
client_secret: application.secret
}
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
def request_user_info!
2019-02-15 15:39:39 +05:30
get '/oauth/userinfo', params: {}, headers: { 'Authorization' => "Bearer #{access_token.token}" }
2017-08-17 22:00:37 +05:30
end
2020-05-30 21:06:31 +05:30
before do
email = create(:email, :confirmed, email: 'public@example.com', user: user)
user.update!(public_email: email.email)
end
2017-08-17 22:00:37 +05:30
context 'Application without OpenID scope' do
let(:application) { create :oauth_application, scopes: 'api' }
it 'token response does not include an ID token' do
2018-11-08 19:23:39 +05:30
request_access_token!
2017-08-17 22:00:37 +05:30
expect(json_response).to include 'access_token'
expect(json_response).not_to include 'id_token'
end
it 'userinfo response is unauthorized' do
2018-11-08 19:23:39 +05:30
request_user_info!
2017-08-17 22:00:37 +05:30
2020-03-13 15:44:24 +05:30
expect(response).to have_gitlab_http_status(:forbidden)
2017-08-17 22:00:37 +05:30
expect(response.body).to be_blank
end
end
2021-09-04 01:27:46 +05:30
shared_examples 'cross-origin GET request' do
it 'allows cross-origin request' do
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, HEAD'
expect(response.headers['Access-Control-Allow-Headers']).to be_nil
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
end
shared_examples 'cross-origin GET and POST request' do
it 'allows cross-origin request' do
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
2022-07-23 23:45:48 +05:30
expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, HEAD, POST, OPTIONS'
2021-09-04 01:27:46 +05:30
expect(response.headers['Access-Control-Allow-Headers']).to be_nil
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
end
2017-08-17 22:00:37 +05:30
context 'Application with OpenID scope' do
let(:application) { create :oauth_application, scopes: 'openid' }
it 'token response includes an ID token' do
2018-11-08 19:23:39 +05:30
request_access_token!
2017-08-17 22:00:37 +05:30
expect(json_response).to include 'id_token'
end
context 'UserInfo payload' do
2018-03-27 19:54:05 +05:30
let!(:group1) { create :group }
let!(:group2) { create :group }
let!(:group3) { create :group, parent: group2 }
let!(:group4) { create :group, parent: group3 }
before do
2022-08-13 15:12:31 +05:30
group1.add_member(user, GroupMember::OWNER)
group3.add_member(user, Gitlab::Access::DEVELOPER)
group4.add_member(user, Gitlab::Access::MAINTAINER)
2018-11-08 19:23:39 +05:30
request_user_info!
2018-03-27 19:54:05 +05:30
end
it 'includes all user information and group memberships' do
2018-11-08 19:23:39 +05:30
expect(json_response).to match(id_token_claims.merge(user_info_claims))
2018-03-27 19:54:05 +05:30
expected_groups = [group1.full_path, group3.full_path]
2019-10-12 21:52:04 +05:30
expected_groups << group4.full_path
2018-03-27 19:54:05 +05:30
expect(json_response['groups']).to match_array(expected_groups)
2022-01-26 12:08:38 +05:30
expect(json_response['https://gitlab.org/claims/groups/owner']).to match_array([group1.full_path])
expect(json_response['https://gitlab.org/claims/groups/maintainer']).to match_array([group4.full_path])
expect(json_response['https://gitlab.org/claims/groups/developer']).to match_array([group3.full_path])
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
it 'does not include any unknown claims' do
expect(json_response.keys).to eq %w[sub sub_legacy] + user_info_claims.keys
end
2019-03-02 22:35:43 +05:30
it 'includes email and email_verified claims' do
expect(json_response.keys).to include('email', 'email_verified')
end
it 'has public email in email claim' do
expect(json_response['email']).to eq(user.public_email)
end
it 'has false in email_verified claim' do
2020-05-30 21:06:31 +05:30
expect(json_response['email_verified']).to eq(true)
2019-03-02 22:35:43 +05:30
end
2017-08-17 22:00:37 +05:30
end
context 'ID token payload' do
2021-11-11 11:23:49 +05:30
let!(:group1) { create :group }
let!(:group2) { create :group }
let!(:group3) { create :group, parent: group2 }
let!(:group4) { create :group, parent: group3 }
2017-08-17 22:00:37 +05:30
before do
2022-08-13 15:12:31 +05:30
group1.add_member(user, Gitlab::Access::OWNER)
group3.add_member(user, Gitlab::Access::DEVELOPER)
2021-11-11 11:23:49 +05:30
2018-11-08 19:23:39 +05:30
request_access_token!
2017-08-17 22:00:37 +05:30
@payload = JSON::JWT.decode(json_response['id_token'], :skip_verification)
end
2018-11-08 19:23:39 +05:30
it 'includes the subject claims' do
expect(@payload).to match(a_hash_including(id_token_claims))
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
it 'includes the GitLab root URL' do
2018-11-08 19:23:39 +05:30
expect(@payload['iss']).to eq Gitlab.config.gitlab.url
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
it 'includes the time of the last authentication', :clean_gitlab_redis_shared_state do
2017-08-17 22:00:37 +05:30
expect(@payload['auth_time']).to eq user.current_sign_in_at.to_i
end
2020-07-28 23:09:34 +05:30
it 'has public email in email claim' do
expect(@payload['email']).to eq(user.public_email)
end
it 'has true in email_verified claim' do
expect(@payload['email_verified']).to eq(true)
end
2017-08-17 22:00:37 +05:30
it 'does not include any unknown properties' do
2023-04-23 21:23:45 +05:30
expect(@payload.keys).to eq %w[iss sub aud exp iat auth_time sub_legacy name nickname preferred_username email email_verified website profile picture groups_direct]
2021-11-11 11:23:49 +05:30
end
it 'does include groups' do
expected_groups = [group1.full_path, group3.full_path]
expect(@payload['groups_direct']).to match_array(expected_groups)
2017-08-17 22:00:37 +05:30
end
end
context 'when user is blocked' do
2019-12-21 20:55:43 +05:30
it 'redirects to login page' do
2017-08-17 22:00:37 +05:30
access_grant
2018-11-08 19:23:39 +05:30
user.block!
2017-08-17 22:00:37 +05:30
2019-12-21 20:55:43 +05:30
request_access_token!
expect(response).to redirect_to('/users/sign_in')
2017-08-17 22:00:37 +05:30
end
end
context 'when user is ldap_blocked' do
2019-12-21 20:55:43 +05:30
it 'redirects to login page' do
2017-08-17 22:00:37 +05:30
access_grant
2018-11-08 19:23:39 +05:30
user.ldap_block!
2017-08-17 22:00:37 +05:30
2019-12-21 20:55:43 +05:30
request_access_token!
expect(response).to redirect_to('/users/sign_in')
2017-08-17 22:00:37 +05:30
end
end
2021-09-04 01:27:46 +05:30
context 'OpenID Discovery keys' do
context 'with a cross-origin request' do
before do
get '/oauth/discovery/keys', headers: cors_request_headers
end
it 'returns data' do
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'cross-origin GET request'
end
context 'with a cross-origin preflight OPTIONS request' do
before do
options '/oauth/discovery/keys', headers: cors_request_headers
end
it_behaves_like 'cross-origin GET request'
end
end
context 'OpenID WebFinger endpoint' do
context 'with a cross-origin request' do
before do
get '/.well-known/webfinger', headers: cors_request_headers, params: { resource: 'user@example.com' }
end
it 'returns data' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['subject']).to eq('user@example.com')
end
it_behaves_like 'cross-origin GET request'
end
end
context 'with a cross-origin preflight OPTIONS request' do
before do
options '/.well-known/webfinger', headers: cors_request_headers, params: { resource: 'user@example.com' }
end
it_behaves_like 'cross-origin GET request'
end
2017-08-17 22:00:37 +05:30
end
2018-05-09 12:01:36 +05:30
context 'OpenID configuration information' do
it 'correctly returns the configuration' do
get '/.well-known/openid-configuration'
2020-03-13 15:44:24 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(json_response['issuer']).to eq('http://localhost')
expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
2023-06-20 00:43:36 +05:30
expect(json_response['scopes_supported']).to match_array %w[admin_mode api read_user read_api read_repository write_repository sudo openid profile email read_observability write_observability]
2019-03-02 22:35:43 +05:30
end
2021-09-04 01:27:46 +05:30
context 'with a cross-origin request' do
before do
get '/.well-known/openid-configuration', headers: cors_request_headers
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['issuer']).to eq('http://localhost')
expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
2023-06-20 00:43:36 +05:30
expect(json_response['scopes_supported']).to match_array %w[admin_mode api read_user read_api read_repository write_repository sudo openid profile email read_observability write_observability]
2021-09-04 01:27:46 +05:30
end
it_behaves_like 'cross-origin GET request'
end
context 'with a cross-origin preflight OPTIONS request' do
before do
options '/.well-known/openid-configuration', headers: cors_request_headers
end
it_behaves_like 'cross-origin GET request'
end
2019-03-02 22:35:43 +05:30
end
context 'Application with OpenID and email scopes' do
let(:application) { create :oauth_application, scopes: 'openid email' }
it 'token response includes an ID token' do
request_access_token!
expect(json_response).to include 'id_token'
end
context 'UserInfo payload' do
before do
request_user_info!
end
it 'includes the email and email_verified claims' do
expect(json_response.keys).to include('email', 'email_verified')
end
it 'has private email in email claim' do
expect(json_response['email']).to eq(user.email)
end
it 'has true in email_verified claim' do
expect(json_response['email_verified']).to eq(true)
end
2021-09-04 01:27:46 +05:30
context 'with a cross-origin request' do
before do
get '/oauth/userinfo', headers: cors_request_headers
end
it_behaves_like 'cross-origin GET and POST request'
end
context 'with a cross-origin POST request' do
before do
post '/oauth/userinfo', headers: cors_request_headers
end
it_behaves_like 'cross-origin GET and POST request'
end
context 'with a cross-origin preflight OPTIONS request' do
before do
options '/oauth/userinfo', headers: cors_request_headers
end
it_behaves_like 'cross-origin GET and POST request'
end
2018-05-09 12:01:36 +05:30
end
2020-07-28 23:09:34 +05:30
context 'ID token payload' do
2021-11-11 11:23:49 +05:30
let!(:group1) { create :group }
let!(:group2) { create :group }
let!(:group3) { create :group, parent: group2 }
let!(:group4) { create :group, parent: group3 }
2020-07-28 23:09:34 +05:30
before do
2022-08-13 15:12:31 +05:30
group1.add_member(user, Gitlab::Access::OWNER)
group3.add_member(user, Gitlab::Access::DEVELOPER)
2021-11-11 11:23:49 +05:30
2020-07-28 23:09:34 +05:30
request_access_token!
@payload = JSON::JWT.decode(json_response['id_token'], :skip_verification)
end
it 'has private email in email claim' do
expect(@payload['email']).to eq(user.email)
end
it 'has true in email_verified claim' do
expect(@payload['email_verified']).to eq(true)
end
2021-11-11 11:23:49 +05:30
it 'does include groups' do
expected_groups = [group1.full_path, group3.full_path]
expect(@payload['groups_direct']).to match_array(expected_groups)
end
2020-07-28 23:09:34 +05:30
end
2018-05-09 12:01:36 +05:30
end
2017-08-17 22:00:37 +05:30
end