1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Oauth::TokensController, feature_category: :system_access do
describe 'POST /oauth/token' do
context 'for resource owner password credential flow', :aggregate_failures do
let_it_be(:password) { User.random_password }
def authenticate(with_password)
post '/oauth/token', params: { grant_type: 'password', username: user.username, password: with_password }
end
context 'when user does not have two factor enabled', :with_default_organization do
let_it_be(:user) { create(:user, password: password) }
it 'authenticates successfully' do
expect(::Gitlab::Auth).to receive(:find_with_user_password).and_call_original
authenticate(password)
expect(response).to have_gitlab_http_status(:ok)
expect(user.reload.failed_attempts).to eq(0)
end
it 'fails to authenticate and increments failed attempts when using the incorrect password' do
authenticate('incorrect_password')
expect(response).to have_gitlab_http_status(:bad_request)
expect(user.reload.failed_attempts).to eq(1)
end
end
context 'when the user has two factor enabled' do
let_it_be(:user) { create(:user, :two_factor, password: password) }
it 'fails to authenticate and does not call GitLab::Auth even when using the correct password' do
expect(::Gitlab::Auth).not_to receive(:find_with_user_password)
authenticate(password)
expect(response).to have_gitlab_http_status(:bad_request)
expect(user.reload.failed_attempts).to eq(0)
end
end
context "when the user's password is automatically set" do
let_it_be(:user) { create(:user, password_automatically_set: true) }
it 'fails to authenticate and does not call GitLab::Auth even when using the correct password' do
expect(::Gitlab::Auth).not_to receive(:find_with_user_password)
authenticate(password)
expect(response).to have_gitlab_http_status(:bad_request)
expect(user.reload.failed_attempts).to eq(0)
end
context 'when the user has an identity matching a provider that is not password-based' do
before do
create(:identity, provider: 'google_oauth2', user: user)
end
it 'fails to authenticate and does not call GitLab::Auth' do
expect(::Gitlab::Auth).not_to receive(:find_with_user_password)
authenticate(password)
expect(response).to have_gitlab_http_status(:bad_request)
expect(user.reload.failed_attempts).to eq(0)
end
end
context 'when the user is a password-based omniauth user' do
before do
create(:identity, provider: 'ldapmain', user: user)
end
it 'forwards the request to Gitlab::Auth' do
expect(::Gitlab::Auth).to receive(:find_with_user_password)
authenticate(password)
end
end
end
end
end
context 'for CORS requests' do
let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
let(:other_headers) { {} }
let(:headers) { cors_request_headers.merge(other_headers) }
let(:allowed_methods) { 'POST, OPTIONS' }
let(:authorization_methods) { %w[Authorization X-CSRF-Token X-Requested-With] }
shared_examples 'cross-origin POST request' do
it 'allows cross-origin requests' do
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
expect(response.headers['Access-Control-Allow-Headers']).to be_nil
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
end
shared_examples 'CORS preflight OPTIONS request' do
it 'returns 200' do
expect(response).to have_gitlab_http_status(:ok)
end
it 'allows cross-origin requests' do
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
expect(
Array.wrap(response.headers['Access-Control-Allow-Headers']).join("\n")
).to eq authorization_methods.join("\n")
end
end
describe 'POST /oauth/token' do
before do
post '/oauth/token', headers: headers
end
it_behaves_like 'cross-origin POST request'
end
describe 'OPTIONS /oauth/token' do
let(:other_headers) { { 'Access-Control-Request-Headers' => authorization_methods, 'Access-Control-Request-Method' => 'POST' } }
before do
options '/oauth/token', headers: headers
end
it_behaves_like 'CORS preflight OPTIONS request'
end
describe 'POST /oauth/revoke' do
let(:other_headers) { { 'Content-Type' => 'application/x-www-form-urlencoded' } }
before do
post '/oauth/revoke', headers: headers, params: { token: '12345' }
end
it 'returns 200' do
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'cross-origin POST request'
end
describe 'OPTIONS /oauth/revoke' do
let(:other_headers) { { 'Access-Control-Request-Headers' => authorization_methods, 'Access-Control-Request-Method' => 'POST' } }
before do
options '/oauth/revoke', headers: headers
end
it_behaves_like 'CORS preflight OPTIONS request'
end
end
end
|