diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 16d4a81ee9f4532149bfbca2a7ebf3605c366f9a..954d4ba9c98e3e387509289e53a301e4022fdf1c 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -63,7 +63,7 @@ def member? def member strong_memoize(:member) do - @token = params[:id] + @token = params[:id].to_s Member.find_by_invite_token(@token) end end diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index a541e7e703fee5cb6d1e7eb18ad762b95c51c581..2d408a4635f852200d664d864dc5acf6867f22eb 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -82,7 +82,7 @@ def add_read_user_scope! end def doorkeeper_application - strong_memoize(:doorkeeper_application) { ::Doorkeeper::OAuth::Client.find(params['client_id'])&.application } + strong_memoize(:doorkeeper_application) { ::Doorkeeper::OAuth::Client.find(params['client_id'].to_s)&.application } end def application_has_read_user_scope? diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb index 42c65a845c6387cba6762e305f43b2921cb53069..314d1e8db8bab2c486c3653cb53c76aeb54b6a87 100644 --- a/app/controllers/oauth/authorized_applications_controller.rb +++ b/app/controllers/oauth/authorized_applications_controller.rb @@ -14,9 +14,9 @@ def index def destroy if params[:token_id].present? - current_resource_owner.oauth_authorized_tokens.find(params[:token_id]).revoke + current_resource_owner.oauth_authorized_tokens.find(params[:token_id].to_s).revoke else - Doorkeeper::Application.revoke_tokens_and_grants_for(params[:id], current_resource_owner) + Doorkeeper::Application.revoke_tokens_and_grants_for(params[:id].to_s, current_resource_owner) end redirect_to user_settings_applications_url, diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index c352ea456def17cf186a9b951a9644e0d78c4175..60316e7d76037505f677c78c7c7ec8bfad947165 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -42,11 +42,12 @@ def failure update_login_counter_metric(failed_strategy.name, 'failed') log_saml_response if params['SAMLResponse'] - if params[:username].present? && AuthHelper.form_based_provider?(failed_strategy.name) - user = User.find_by_login(params[:username]) + username = params[:username].to_s + if username.present? && AuthHelper.form_based_provider?(failed_strategy.name) + user = User.find_by_login(username) user&.increment_failed_attempts! - log_failed_login(params[:username], failed_strategy.name) + log_failed_login(username, failed_strategy.name) end super diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index 48ce6479f07643a5a2484280903f6cad4b1e2f0a..d66d0c2b874aee7b252f77db59c76999ba37c459 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -55,8 +55,7 @@ def update def log_audit_reset_failure(_user); end def resource_from_email - email = resource_params[:email] - self.resource = resource_class.find_by_email(email) + self.resource = resource_class.find_by_email(resource_params[:email].to_s) end def check_password_authentication_available diff --git a/app/services/auth/dependency_proxy_authentication_service.rb b/app/services/auth/dependency_proxy_authentication_service.rb index 29f5a50d809ffb5f53a6c5a55dc0fb8f7714dd0d..84cbbc59cc2141d1d3ed010fb7240b80b43a8a40 100644 --- a/app/services/auth/dependency_proxy_authentication_service.rb +++ b/app/services/auth/dependency_proxy_authentication_service.rb @@ -54,7 +54,7 @@ def has_required_abilities?(authentication_abilities) end def group_access_token - PersonalAccessTokensFinder.new(state: 'active').find_by_token(raw_token) + PersonalAccessTokensFinder.new(state: 'active').find_by_token(raw_token.to_s) end def valid_deploy_token? diff --git a/ee/app/controllers/concerns/arkose/token_verifiable.rb b/ee/app/controllers/concerns/arkose/token_verifiable.rb index 3fb3ec7cb668b818a9d6bed32d172787361cf09a..bed6e376b531bccde166b21783dbc3c46079a180 100644 --- a/ee/app/controllers/concerns/arkose/token_verifiable.rb +++ b/ee/app/controllers/concerns/arkose/token_verifiable.rb @@ -45,7 +45,7 @@ def log_token_missing end def token - @token ||= params[:arkose_labs_token] + @token ||= params[:arkose_labs_token].to_s end def arkose_down? diff --git a/ee/app/controllers/ee/passwords_controller.rb b/ee/app/controllers/ee/passwords_controller.rb index c6197a879b3ffa23edcd2c5050de230239fb131e..fbf4c5214d98fef5542ea400b74fc8c7164f2839 100644 --- a/ee/app/controllers/ee/passwords_controller.rb +++ b/ee/app/controllers/ee/passwords_controller.rb @@ -25,7 +25,7 @@ def log_audit_event author: current_user || unauth_author, scope: requester, target: requester, - target_details: resource_params[:email], + target_details: resource_params[:email].to_s, message: "Ask for password reset", ip_address: request.remote_ip }) diff --git a/ee/app/controllers/ee/sessions_controller.rb b/ee/app/controllers/ee/sessions_controller.rb index 86ee4eac9a58957680330f3941d72742618f2056..e8b093b95800d6c3dc79f57e893d8597ade2e649 100644 --- a/ee/app/controllers/ee/sessions_controller.rb +++ b/ee/app/controllers/ee/sessions_controller.rb @@ -74,7 +74,7 @@ def log_failed_login end def complete_identity_verification - user = ::User.find_by_login(user_params[:login]) + user = ::User.find_by_login(user_params[:login].to_s) return if !user || !user.valid_password?(user_params[:password]) || user.access_locked? return if ::Gitlab::Qa.request?(request.user_agent) diff --git a/ee/spec/requests/users/registrations_identity_verification_controller_spec.rb b/ee/spec/requests/users/registrations_identity_verification_controller_spec.rb index 5a3dc9f78eb633d1e2a69b997a7756c6b668fd3c..f54ec42fbe2751a9c713ac069054427a40c2efae 100644 --- a/ee/spec/requests/users/registrations_identity_verification_controller_spec.rb +++ b/ee/spec/requests/users/registrations_identity_verification_controller_spec.rb @@ -784,6 +784,17 @@ expect(response.body).to eq({ message: service_response.message, reason: service_response.reason }.to_json) end end + + context 'when multiple codes are attempted' do + let_it_be(:params) do + { registrations_identity_verification: { verification_code: %w[998 999] } } + end + + it 'passes no params to VerifyCodeService' do + do_request + expect(::PhoneVerification::Users::VerifyCodeService).to have_received(:new).with(user, {}) + end + end end shared_examples 'it requires a user without an arkose risk_band' do diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb index b4ba2a8e50ea98fff521612d68bf599374c3ef5d..319d1121ec8f04a3e82bcd64680f71f20525f46d 100644 --- a/lib/gitlab/auth/auth_finders.rb +++ b/lib/gitlab/auth/auth_finders.rb @@ -54,7 +54,7 @@ def find_user_from_static_object_token(request_format) token = current_request.params[:token].presence || current_request.headers['X-Gitlab-Static-Object-Token'].presence return unless token - User.find_by_static_object_token(token) || raise(UnauthorizedError) + User.find_by_static_object_token(token.to_s) || raise(UnauthorizedError) end def find_user_from_feed_token(request_format) @@ -83,7 +83,7 @@ def find_user_from_job_token current_request.env[JOB_TOKEN_HEADER].presence return unless token - job = find_valid_running_job_by_token!(token) + job = find_valid_running_job_by_token!(token.to_s) @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables job.user @@ -96,7 +96,7 @@ def find_user_from_basic_auth_job return unless login.present? && password.present? return unless ::Gitlab::Auth::CI_JOB_USER == login - job = find_valid_running_job_by_token!(password) + job = find_valid_running_job_by_token!(password.to_s) @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables job.user @@ -108,16 +108,16 @@ def find_user_from_basic_auth_password login, password = user_name_and_password(current_request) return if ::Gitlab::Auth::CI_JOB_USER == login - Gitlab::Auth.find_with_user_password(login, password) + Gitlab::Auth.find_with_user_password(login.to_s, password.to_s) end def find_user_from_lfs_token return unless has_basic_credentials?(current_request) login, token = user_name_and_password(current_request) - user = User.find_by_login(login) + user = User.find_by_login(login.to_s) - user if user && Gitlab::LfsToken.new(user).token_valid?(token) + user if user && Gitlab::LfsToken.new(user).token_valid?(token.to_s) end def find_user_from_personal_access_token @@ -168,7 +168,7 @@ def deploy_token_from_request _, token = user_name_and_password(current_request) end - deploy_token = DeployToken.active.find_by_token(token) + deploy_token = DeployToken.active.find_by_token(token.to_s) @current_authenticated_deploy_token = deploy_token # rubocop:disable Gitlab/ModuleWithInstanceVariables deploy_token @@ -180,7 +180,7 @@ def cluster_agent_token_from_authorization_token authorization_token, _options = token_and_options(current_request) - ::Clusters::AgentToken.active.find_by_token(authorization_token) + ::Clusters::AgentToken.active.find_by_token(authorization_token.to_s) end def find_runner_from_token @@ -189,7 +189,7 @@ def find_runner_from_token token = current_request.params[RUNNER_TOKEN_PARAM].presence return unless token - ::Ci::Runner.find_by_token(token) || raise(UnauthorizedError) + ::Ci::Runner.find_by_token(token.to_s) || raise(UnauthorizedError) end def validate_access_token!(scopes: []) @@ -271,7 +271,7 @@ def find_personal_access_token return unless token # Expiration, revocation and scopes are verified in `validate_access_token!` - PersonalAccessToken.find_by_token(token) || raise(UnauthorizedError) + PersonalAccessToken.find_by_token(token.to_s) || raise(UnauthorizedError) end def find_oauth_access_token @@ -294,10 +294,11 @@ def find_personal_access_token_from_http_basic_auth return unless has_basic_credentials?(current_request) _username, password = user_name_and_password(current_request) - PersonalAccessToken.find_by_token(password) + PersonalAccessToken.find_by_token(password.to_s) end def find_feed_token_user(token) + token = token.to_s find_user_from_path_feed_token(token) || User.find_by_feed_token(token) end diff --git a/spec/controllers/oauth/authorized_applications_controller_spec.rb b/spec/controllers/oauth/authorized_applications_controller_spec.rb index cb047e55752f1f1f307f146d02e3a94329161659..f672552559bddabe96631b6832fbcfd3c9a041de 100644 --- a/spec/controllers/oauth/authorized_applications_controller_spec.rb +++ b/spec/controllers/oauth/authorized_applications_controller_spec.rb @@ -24,7 +24,7 @@ let!(:grant) { create(:oauth_access_grant, resource_owner_id: user.id, application: application) } let!(:access_token) { create(:oauth_access_token, resource_owner: user, application: application) } - it 'revokes both access grants and tokens' do + it 'revokes both access grants and tokens when id is passed' do expect(grant).not_to be_revoked expect(access_token).not_to be_revoked @@ -33,6 +33,18 @@ expect(grant.reload).to be_revoked expect(access_token.reload).to be_revoked end + + it 'revokes a specific token when token_id is passed' do + expect(grant).not_to be_revoked + expect(access_token).not_to be_revoked + + # id is required for this path, but is not used by the + # controller + delete :destroy, params: { id: 9999999, token_id: access_token.id } + + expect(grant.reload).not_to be_revoked + expect(access_token.reload).to be_revoked + end end it 'includes Two-factor enforcement concern' do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index a4acdc706996e0972ec6f068dad497fcd3b95b74..9058c5a33d08334fd4a1a384be8dbf7f2d932dce 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -93,6 +93,22 @@ end end + context 'mass assignment' do + it 'does not authenticate with multiple usernames' do + expect do + post(:create, params: { user: { login: ['invalid', user.username], password: user.password } }) + end.to raise_error(NoMethodError) + expect(@request.env['warden']).not_to be_authenticated + end + + it 'does not authenticate with multiple passwords' do + expect do + post(:create, params: { user: { login: user.username, password: ['aaaaaa', user.password] } }) + end.to raise_error(NoMethodError) + expect(@request.env['warden']).not_to be_authenticated + end + end + context 'when user with LDAP identity' do before do create(:identity, provider: 'ldapmain', user: user) @@ -436,6 +452,16 @@ def authenticate_2fa(otp_user_id: user.id, **user_params) authenticate_2fa(otp_attempt: code) end end + + context 'when OTP is an array' do + let(:code) { %w[000000 000001] } + + it 'does not authenticate' do + authenticate_2fa(otp_attempt: code) + + expect(subject.current_user).not_to eq user + end + end end context 'when the user is on their last attempt' do @@ -569,6 +595,26 @@ def authenticate_2fa(user_params) expect(subject.current_user).to eq user end + + context 'when the verification token is invalid' do + let(:user_params) { { verification_token: 'not-the-token' } } + + it 'does not log the user in' do + post_action + + expect(subject.current_user).to eq nil + end + end + + context 'when the verification token is an array' do + let(:user_params) { { verification_token: %w[not-the-token still-not-the-token] } } + + it 'does not log the user in' do + post_action + + expect(subject.current_user).to eq nil + end + end end end diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb index efce440b5281ce9dbb260deb283663e7989dd1c2..26e6cd3661585b9b708d1427f905b874ae0f3618 100644 --- a/spec/lib/gitlab/auth/auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/auth_finders_spec.rb @@ -76,6 +76,15 @@ def set_bearer_token(token) expect(@current_authenticated_job).to be_nil end end + + context 'for an array of tokens' do + let(:token) { [job.token, 'invalid token'] } + + it "returns an Unauthorized exception" do + expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError) + expect(@current_authenticated_job).to be_nil + end + end end context 'when route is not allowed to be authenticated', :request_store do @@ -236,6 +245,12 @@ def set_bearer_token(token) expect { find_user_from_feed_token(:rss) }.to raise_error(Gitlab::Auth::UnauthorizedError) end + + it 'returns exception if an array is passed' do + set_param(:feed_token, [feed_token, 'fake']) + + expect { find_user_from_feed_token(:rss) }.to raise_error(Gitlab::Auth::UnauthorizedError) + end end context 'when old format rss_token param is provided' do @@ -296,12 +311,20 @@ def set_bearer_token(token) end context 'when token is incorrect' do - it 'returns the user' do + it 'returns an error' do request.headers['X-Gitlab-Static-Object-Token'] = 'foobar' expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError) end end + + context 'when token is an array' do + it 'returns an error' do + request.headers['X-Gitlab-Static-Object-Token'] = [user.static_object_token, 'foobar'] + + expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError) + end + end end context 'when token query param is present' do @@ -314,12 +337,20 @@ def set_bearer_token(token) end context 'when token is incorrect' do - it 'returns the user' do + it 'raises an error' do set_param(:token, 'foobar') expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError) end end + + context 'when token is an array' do + it 'raises an error' do + set_param(:token, [user.static_object_token, 'foobar']) + + expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError) + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 25d33bbd7a362026ce4168a9027a9412be51fbd0..51b4d72b13913aac62576a2a4417394893ae5b3f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -7185,6 +7185,17 @@ def access_levels(groups) it { is_expected.to eq(false) } end + + context 'using an array' do + let(:user) { create(:user) } + let(:password) { [user.password, 'WRONG PASSWORD'] } + + it 'raises an error' do + expect do + validate_password + end.to raise_error(NoMethodError) + end + end end describe '#generate_otp_backup_codes!' do