From d8df043dc12c76233807101985989db9356764aa Mon Sep 17 00:00:00 2001 From: Imre Farkas <ifarkas@gitlab.com> Date: Tue, 3 Mar 2020 21:16:33 +0100 Subject: [PATCH] Make hostname configurable for smartcard authentication Hostname is configurable for the endpoint requiring client side certificate. --- ...6-smartcard_support_different_hostname.yml | 5 + config/gitlab.yml.example | 4 +- config/initializers/1_settings.rb | 1 + ee/app/controllers/smartcard_controller.rb | 97 +++- .../devise/sessions/_new_smartcard.html.haml | 2 +- .../sessions/_new_smartcard_ldap.html.haml | 3 +- ee/config/routes/smartcard.rb | 9 +- ee/spec/requests/smartcard_controller_spec.rb | 434 ++++++++++++------ 8 files changed, 380 insertions(+), 175 deletions(-) create mode 100644 changelogs/unreleased/10526-smartcard_support_different_hostname.yml diff --git a/changelogs/unreleased/10526-smartcard_support_different_hostname.yml b/changelogs/unreleased/10526-smartcard_support_different_hostname.yml new file mode 100644 index 0000000000000..6990449d171e2 --- /dev/null +++ b/changelogs/unreleased/10526-smartcard_support_different_hostname.yml @@ -0,0 +1,5 @@ +--- +title: Make hostname configurable for smartcard authentication +merge_request: 26411 +author: +type: added diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 760688d808805..81085d4641e5b 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -752,7 +752,9 @@ production: &base # Path to a file containing a CA certificate ca_file: '/etc/ssl/certs/CA.pem' - # Port where the client side certificate is requested by the webserver (NGINX/Apache) + # Host and port where the client side certificate is requested by the + # webserver (NGINX/Apache) + # client_certificate_required_host: smartcard.gitlab.example.com # client_certificate_required_port: 3444 # Browser session with smartcard sign-in is required for Git access diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index f22ddc7f08179..1b368346cfaf5 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -77,6 +77,7 @@ Gitlab.ee do Settings['smartcard'] ||= Settingslogic.new({}) Settings.smartcard['enabled'] = false if Settings.smartcard['enabled'].nil? + Settings.smartcard['client_certificate_required_host'] = Settings.gitlab['host'] if Settings.smartcard['client_certificate_required_host'].nil? Settings.smartcard['client_certificate_required_port'] = 3444 if Settings.smartcard['client_certificate_required_port'].nil? Settings.smartcard['required_for_git_access'] = false if Settings.smartcard['required_for_git_access'].nil? Settings.smartcard['san_extensions'] = false if Settings.smartcard['san_extensions'].nil? diff --git a/ee/app/controllers/smartcard_controller.rb b/ee/app/controllers/smartcard_controller.rb index 8a7818795b307..ab0d086c95a4a 100644 --- a/ee/app/controllers/smartcard_controller.rb +++ b/ee/app/controllers/smartcard_controller.rb @@ -5,25 +5,58 @@ class SmartcardController < ApplicationController skip_before_action :verify_authenticity_token before_action :check_feature_availability - before_action :check_certificate_headers + before_action :check_certificate_required_host_and_port, only: :extract_certificate + before_action :check_ngingx_certificate_header, only: :extract_certificate + before_action :check_certificate_param, only: :verify_certificate def auth - certificate = Gitlab::Auth::Smartcard::Certificate.new(certificate_header) - sign_in_with(certificate) + redirect_to extract_certificate_smartcard_url(extract_certificate_url_options) end - def ldap_auth - certificate = Gitlab::Auth::Smartcard::LdapCertificate.new(params[:provider], certificate_header) - sign_in_with(certificate) + def extract_certificate + redirect_to verify_certificate_smartcard_url(verify_certificate_url_options) + end + + def verify_certificate + sign_in_with(client_certificate) end private + def extract_certificate_url_options + { + host: ::Gitlab.config.smartcard.client_certificate_required_host, + port: ::Gitlab.config.smartcard.client_certificate_required_port, + provider: params[:provider] + }.compact + end + + def verify_certificate_url_options + { + host: ::Gitlab.config.gitlab.host, + port: ::Gitlab.config.gitlab.port, + provider: params[:provider], + client_certificate: request.headers['HTTP_X_SSL_CLIENT_CERTIFICATE'] + }.compact + end + + def client_certificate + if ldap_provider? + Gitlab::Auth::Smartcard::LdapCertificate.new(params[:provider], certificate_param) + else + Gitlab::Auth::Smartcard::Certificate.new(certificate_param) + end + end + + def ldap_provider? + params[:provider].present? + end + def sign_in_with(certificate) user = certificate.find_or_create_user unless user&.persisted? flash[:alert] = _('Failed to signing using smartcard authentication') - redirect_to new_user_session_path(port: Gitlab.config.gitlab.port) + redirect_to new_user_session_path return end @@ -33,13 +66,43 @@ def sign_in_with(certificate) sign_in_and_redirect(user) end + def nginx_certificate_header + request.headers['HTTP_X_SSL_CLIENT_CERTIFICATE'] + end + + def certificate_param + param = params[:client_certificate] + return unless param + + unescaped_param = CGI.unescape(param) + if unescaped_param.include?("\n") + # NGINX forwarding the $ssl_client_escaped_cert variable + unescaped_param + else + # older version of NGINX forwarding the now deprecated $ssl_client_cert variable + param.gsub(/ (?!CERTIFICATE)/, "\n") + end + end + def check_feature_availability render_404 unless ::Gitlab::Auth::Smartcard.enabled? end - def check_certificate_headers - # Failing on requests coming from the port not requiring client side certificate - unless certificate_header.present? + def check_certificate_required_host_and_port + unless request.host == ::Gitlab.config.smartcard.client_certificate_required_host && + request.port == ::Gitlab.config.smartcard.client_certificate_required_port + render_404 + end + end + + def check_ngingx_certificate_header + unless nginx_certificate_header.present? + access_denied!(_('Smartcard authentication failed: client certificate header is missing.'), 401) + end + end + + def check_certificate_param + unless certificate_param.present? access_denied!(_('Smartcard authentication failed: client certificate header is missing.'), 401) end end @@ -52,20 +115,6 @@ def log_audit_event(user, options = {}) AuditEventService.new(user, user, options).for_authentication.security_event end - def certificate_header - header = request.headers['HTTP_X_SSL_CLIENT_CERTIFICATE'] - return unless header - - unescaped_header = CGI.unescape(header) - if unescaped_header.include?("\n") - # NGINX forwarding the $ssl_client_escaped_cert variable - unescaped_header - else - # older version of NGINX forwarding the now deprecated $ssl_client_cert variable - header.gsub(/ (?!CERTIFICATE)/, "\n") - end - end - def after_sign_in_path_for(resource) stored_location_for(:redirect) || stored_location_for(resource) || root_url(port: Gitlab.config.gitlab.port) end diff --git a/ee/app/views/devise/sessions/_new_smartcard.html.haml b/ee/app/views/devise/sessions/_new_smartcard.html.haml index ae19cd257940c..a836dc82305ba 100644 --- a/ee/app/views/devise/sessions/_new_smartcard.html.haml +++ b/ee/app/views/devise/sessions/_new_smartcard.html.haml @@ -1,6 +1,6 @@ - if smartcard_enabled? .login-box.tab-pane{ id: 'smartcard', role: 'tabpanel', class: active_when(form_based_auth_provider_has_active_class?(:smartcard)) } .login-body - = form_tag(smartcard_auth_url(port: smartcard_config_port), html: { 'aria-live' => 'assertive'}) do + = form_tag(auth_smartcard_url, html: { 'aria-live' => 'assertive'}) do .submit-container = submit_tag _('Login with smartcard'), class: 'btn btn-success' diff --git a/ee/app/views/devise/sessions/_new_smartcard_ldap.html.haml b/ee/app/views/devise/sessions/_new_smartcard_ldap.html.haml index 46125b1ebe139..294d9e077b7cb 100644 --- a/ee/app/views/devise/sessions/_new_smartcard_ldap.html.haml +++ b/ee/app/views/devise/sessions/_new_smartcard_ldap.html.haml @@ -9,8 +9,7 @@ = _('Use your smart card to authenticate with the LDAP server.') .login-body - = form_tag(smartcard_ldap_auth_url(provider: server['provider_name'], - port: smartcard_config_port), + = form_tag(auth_smartcard_url(provider: server['provider_name']), html: { 'aria-live' => 'assertive'}) do .submit-container = submit_tag(_('Sign in with smart card'), diff --git a/ee/config/routes/smartcard.rb b/ee/config/routes/smartcard.rb index 4fdaeaabc2536..569afb57a7e53 100644 --- a/ee/config/routes/smartcard.rb +++ b/ee/config/routes/smartcard.rb @@ -1,4 +1,9 @@ # frozen_string_literal: true -post 'smartcard/auth' => 'smartcard#auth' -post 'smartcard/ldap_auth' => 'smartcard#ldap_auth' +resource :smartcard, only: [], controller: :smartcard do + collection do + post :auth + get :extract_certificate + get :verify_certificate + end +end diff --git a/ee/spec/requests/smartcard_controller_spec.rb b/ee/spec/requests/smartcard_controller_spec.rb index 99f842cd780fc..d5cdad69dcbe9 100644 --- a/ee/spec/requests/smartcard_controller_spec.rb +++ b/ee/spec/requests/smartcard_controller_spec.rb @@ -5,61 +5,47 @@ describe SmartcardController, type: :request do include LdapHelpers - let(:certificate_headers) { { 'X-SSL-CLIENT-CERTIFICATE': 'certificate' } } - let(:openssl_certificate_store) { instance_double(OpenSSL::X509::Store) } - let(:audit_event_service) { instance_double(AuditEventService) } - let(:session_enforcer) { instance_double(Gitlab::Auth::Smartcard::SessionEnforcer) } + let(:smartcard_host) { 'smartcard.example.com' } + let(:smartcard_port) { 3443 } - shared_examples 'a client certificate authentication' do |auth_method| - context 'with smartcard_auth enabled' do - it 'allows sign in' do - subject + describe '#auth' do + let(:params) { {} } - expect(request.env['warden']).to be_authenticated - end + subject { post auth_smartcard_path, params: params } - it 'redirects to root' do - subject + before do + stub_smartcard_config( + client_certificate_required_host: smartcard_host, + client_certificate_required_port: smartcard_port + ) + end - expect(response).to redirect_to(root_url) + context 'with smartcard_auth enabled' do + before do + enable_smartcard_authentication end - it 'logs audit event' do - expect(AuditEventService).to( - receive(:new) - .with(instance_of(User), instance_of(User), with: auth_method) - .and_return(audit_event_service)) - expect(audit_event_service).to receive_message_chain(:for_authentication, :security_event) - + it 'redirects to extract certificate' do subject - end - - it 'stores active session' do - expect(::Gitlab::Auth::Smartcard::SessionEnforcer).to( - receive(:new).and_return(session_enforcer)) - expect(session_enforcer).to receive(:update_session) - subject + expect(response).to have_gitlab_http_status(:redirect) + expect(response.location).to( + eq(extract_certificate_smartcard_url(host: smartcard_host, + port: smartcard_port))) end - context 'user does not exist' do - context 'signup allowed' do - it 'creates user' do - expect { subject }.to change { User.count }.from(0).to(1) - end - end - - context 'signup disabled' do - it 'renders 401' do - allow(Gitlab::CurrentSettings.current_application_settings).to( - receive(:allow_signup?).and_return(false)) + context 'with provider param' do + let(:provider) { 'ldap-provider' } + let(:params) { { provider: provider } } - subject + it 'forwards the provider param' do + subject - expect(flash[:alert]).to eql('Failed to signing using smartcard authentication') - expect(response).to redirect_to(new_user_session_path) - expect(request.env['warden']).not_to be_authenticated - end + expect(response).to have_gitlab_http_status(:redirect) + expect(response.location).to( + eq(extract_certificate_smartcard_url(host: smartcard_host, + port: smartcard_port, + provider: provider))) end end end @@ -77,166 +63,324 @@ end end - describe '#auth' do - let(:subject_dn) { '/O=Random Corp Ltd/CN=gitlab-user/emailAddress=gitlab-user@random-corp.org' } - let(:issuer_dn) { '/O=Random Corp Ltd/CN=Random Corp' } - let(:certificate_headers) { { 'X-SSL-CLIENT-CERTIFICATE': 'certificate' } } - let(:openssl_certificate_store) { instance_double(OpenSSL::X509::Store) } - let(:openssl_certificate) { instance_double(OpenSSL::X509::Certificate, subject: subject_dn, issuer: issuer_dn) } - let(:audit_event_service) { instance_double(AuditEventService) } + describe '#extract_certificate' do + let(:certificate) { 'certificate' } + let(:certificate_headers) { { 'X-SSL-CLIENT-CERTIFICATE': certificate } } + let(:params) { {} } - before do - allow(Gitlab::Auth::Smartcard).to receive(:enabled?).and_return(true) - allow(Gitlab::Auth::Smartcard::Certificate).to receive(:store).and_return(openssl_certificate_store) - allow(openssl_certificate_store).to receive(:verify).and_return(true) - allow(OpenSSL::X509::Certificate).to receive(:new).and_return(openssl_certificate) + subject do + get(extract_certificate_smartcard_path, headers: certificate_headers, + params: params) end - subject { post '/-/smartcard/auth', params: {}, headers: certificate_headers } - - it_behaves_like 'a client certificate authentication', 'smartcard' + before do + stub_config_setting(host: 'example.com', + port: 443) + stub_smartcard_config( + client_certificate_required_host: smartcard_host, + client_certificate_required_port: smartcard_port + ) + host! "#{smartcard_host}:#{smartcard_port}" + end - context 'user already exists' do + context 'with smartcard_auth enabled' do before do - user = create(:user) - create(:smartcard_identity, subject: subject_dn, issuer: issuer_dn, user: user) + enable_smartcard_authentication end - it 'finds existing user' do - expect { subject }.not_to change { User.count } - expect(request.env['warden']).to be_authenticated + it 'redirects to verify certificate' do + subject + + expect(response).to have_gitlab_http_status(:redirect) + expect(response.location).to( + eq(verify_certificate_smartcard_url(host: ::Gitlab.config.gitlab.host, + port: ::Gitlab.config.gitlab.port, + client_certificate: certificate))) end - end - context 'certificate header formats from NGINX' do - shared_examples 'valid certificate header' do - it 'authenticates user' do - expect(Gitlab::Auth::Smartcard::Certificate).to receive(:new).with(expected_certificate).and_call_original + context 'with provider param' do + let(:provider) { 'ldap-provider' } + let(:params) { { provider: provider } } + it 'forwards the provider param' do subject - expect(request.env['warden']).to be_authenticated + expect(response).to have_gitlab_http_status(:redirect) + expect(response.location).to( + eq(verify_certificate_smartcard_url(host: ::Gitlab.config.gitlab.host, + port: ::Gitlab.config.gitlab.port, + client_certificate: certificate, + provider: provider))) end end - let(:expected_certificate) { "-----BEGIN CERTIFICATE-----\nrow\nrow\n-----END CERTIFICATE-----" } + context 'missing NGINX client certificate header' do + let(:certificate_headers) { {} } - context 'escaped format' do - let(:certificate_headers) { { 'X-SSL-CLIENT-CERTIFICATE': '-----BEGIN%20CERTIFICATE-----%0Arow%0Arow%0A-----END%20CERTIFICATE-----' } } + it 'renders unauthorized' do + subject - it_behaves_like 'valid certificate header' + expect(response).to have_gitlab_http_status(:unauthorized) + end end - context 'deprecated format' do - let(:certificate_headers) { { 'X-SSL-CLIENT-CERTIFICATE': '-----BEGIN CERTIFICATE----- row row -----END CERTIFICATE-----' } } + context 'request from different host / port' do + it 'renders 404' do + host! 'another.host:42' + + subject - it_behaves_like 'valid certificate header' + expect(response).to have_gitlab_http_status(:not_found) + end end end - context 'missing certificate headers' do - let(:certificate_headers) { nil } + context 'with smartcard_auth disabled' do + before do + allow(Gitlab::Auth::Smartcard).to receive(:enabled?).and_return(false) + end - it 'renders 401' do + it 'renders 404' do subject - expect(response).to have_gitlab_http_status(:unauthorized) - expect(request.env['warden']).not_to be_authenticated + expect(response).to have_gitlab_http_status(:not_found) end end end - describe '#ldap_auth ' do - let(:subject_ldap_dn) { 'uid=john doe,ou=people,dc=example,dc=com' } - let(:issuer_dn) { 'CN=Random Corp,O=Random Corp Ltd,C=US' } - let(:issuer) { instance_double(OpenSSL::X509::Name, to_s: issuer_dn) } - let(:serial) { '42' } - let(:openssl_certificate) do - instance_double(OpenSSL::X509::Certificate, - issuer: issuer, serial: serial) - end + describe '#verify_certificate' do + shared_examples 'a client certificate authentication' do |auth_method| + context 'with smartcard_auth enabled' do + it 'allows sign in' do + subject + + expect(request.env['warden']).to be_authenticated + end + + it 'redirects to root' do + subject + + expect(response).to redirect_to(root_url) + end + + it 'logs audit event' do + audit_event_service = instance_double(AuditEventService) + + expect(AuditEventService).to( + receive(:new) + .with(instance_of(User), instance_of(User), with: auth_method) + .and_return(audit_event_service)) + expect(audit_event_service).to receive_message_chain(:for_authentication, :security_event) + + subject + end + + it 'stores active session' do + session_enforcer = instance_double(Gitlab::Auth::Smartcard::SessionEnforcer) + + expect(::Gitlab::Auth::Smartcard::SessionEnforcer).to( + receive(:new).and_return(session_enforcer)) + expect(session_enforcer).to receive(:update_session) + + subject + end + + context 'user does not exist' do + context 'signup allowed' do + it 'creates user' do + expect { subject }.to change { User.count }.from(0).to(1) + end + end + + context 'signup disabled' do + it 'renders 401' do + allow(Gitlab::CurrentSettings.current_application_settings).to( + receive(:allow_signup?).and_return(false)) + + subject + + expect(flash[:alert]).to eql('Failed to signing using smartcard authentication') + expect(response).to redirect_to(new_user_session_path) + expect(request.env['warden']).not_to be_authenticated + end + end + end + + context 'missing client certificate param' do + let(:params) { {} } - let(:ldap_connection) { instance_double(::Net::LDAP) } - let(:ldap_email) { 'john.doe@example.com' } - let(:ldap_entry) do - Net::LDAP::Entry.new.tap do |entry| - entry['dn'] = subject_ldap_dn - entry['uid'] = 'john doe' - entry['cn'] = 'John Doe' - entry['mail'] = ldap_email + it 'renders unauthorized' do + subject + + expect(response).to have_gitlab_http_status(:unauthorized) + expect(request.env['warden']).not_to be_authenticated + end + end end - end - let(:ldap_user_search_scope) { 'dc=example,dc=com' } - let(:ldap_search_params) do - { attributes: array_including('dn', 'cn', 'mail', 'uid', 'userid'), - base: ldap_user_search_scope, - filter: Net::LDAP::Filter.ex( - 'userCertificate:certificateExactMatch', - "{ serialNumber #{serial}, issuer \"#{issuer_dn}\" }") } - end - subject do - post('/-/smartcard/ldap_auth', - { params: { provider: 'ldapmain' }, - headers: certificate_headers } ) + context 'with smartcard_auth disabled' do + before do + allow(Gitlab::Auth::Smartcard).to receive(:enabled?).and_return(false) + end + + it 'renders 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end end + let(:client_certificate) { 'certificate' } + let(:params) { { client_certificate: client_certificate } } + let(:serial) { '42' } + let(:subject_dn) { '/O=Random Corp Ltd/CN=gitlab-user/emailAddress=gitlab-user@random-corp.org' } + let(:issuer_dn) { 'CN=Random Corp,O=Random Corp Ltd,C=US' } + before do - allow(Gitlab::Auth::Smartcard).to receive(:enabled?).and_return(true) + enable_smartcard_authentication + stub_certificate_store + stub_certificate + end - allow(Gitlab::Auth::Smartcard::LdapCertificate).to( - receive(:store).and_return(openssl_certificate_store)) - allow(openssl_certificate_store).to receive(:verify).and_return(true) + context 'Smartcard::Certificate' do + subject { get verify_certificate_smartcard_path, params: params } - allow(OpenSSL::X509::Certificate).to( - receive(:new).and_return(openssl_certificate)) + it_behaves_like 'a client certificate authentication', 'smartcard' - allow(Net::LDAP).to receive(:new).and_return(ldap_connection) - allow(ldap_connection).to( - receive(:search).with(ldap_search_params).and_return([ldap_entry])) - end + context 'user already exists' do + before do + user = create(:user) + create(:smartcard_identity, subject: subject_dn, issuer: issuer_dn, user: user) + end + + it 'finds existing user' do + expect { subject }.not_to change { User.count } + expect(request.env['warden']).to be_authenticated + end + end + + context 'certificate header formats from NGINX' do + shared_examples 'valid certificate header' do + it 'authenticates user' do + expect(Gitlab::Auth::Smartcard::Certificate).to receive(:new).with(expected_certificate).and_call_original - it_behaves_like 'a client certificate authentication', 'smartcard_ldap' + subject - it 'sets correct parameters for LDAP search' do - expect(ldap_connection).to( - receive(:search).with(ldap_search_params).and_return([ldap_entry])) + expect(request.env['warden']).to be_authenticated + end + end + + let(:expected_certificate) { "-----BEGIN CERTIFICATE-----\nrow\nrow\n-----END CERTIFICATE-----" } + + context 'escaped format' do + let(:client_certificate) { '-----BEGIN%20CERTIFICATE-----%0Arow%0Arow%0A-----END%20CERTIFICATE-----' } + + it_behaves_like 'valid certificate header' + end - subject + context 'deprecated format' do + let(:client_certificate) { '-----BEGIN CERTIFICATE----- row row -----END CERTIFICATE-----' } + + it_behaves_like 'valid certificate header' + end + end end - context 'user already exists' do - let_it_be(:user) { create(:user) } + context 'Smartcard::LdapCertificate' do + let(:ldap_connection) { instance_double(::Net::LDAP) } + let(:subject_ldap_dn) { 'uid=john doe,ou=people,dc=example,dc=com' } + let(:ldap_email) { 'john.doe@example.com' } + let(:ldap_entry) do + Net::LDAP::Entry.new.tap do |entry| + entry['dn'] = subject_ldap_dn + entry['uid'] = 'john doe' + entry['cn'] = 'John Doe' + entry['mail'] = ldap_email + end + end + let(:ldap_user_search_scope) { 'dc=example,dc=com' } + let(:ldap_search_params) do + { attributes: array_including('dn', 'cn', 'mail', 'uid', 'userid'), + base: ldap_user_search_scope, + filter: Net::LDAP::Filter.ex( + 'userCertificate:certificateExactMatch', + "{ serialNumber #{serial}, issuer \"#{issuer_dn}\" }") } + end + + subject do + get(verify_certificate_smartcard_path, + { params: params.merge({ provider: 'ldapmain' }) }) + end + + before do + allow(Net::LDAP).to receive(:new).and_return(ldap_connection) + allow(ldap_connection).to( + receive(:search).with(ldap_search_params).and_return([ldap_entry])) + end - it 'finds existing user' do - create(:identity, { provider: 'ldapmain', - extern_uid: subject_ldap_dn, - user: user }) + it_behaves_like 'a client certificate authentication', 'smartcard_ldap' - expect { subject }.not_to change { User.count } + it 'sets correct parameters for LDAP search' do + expect(ldap_connection).to( + receive(:search).with(ldap_search_params).and_return([ldap_entry])) - expect(request.env['warden']).to be_authenticated + subject end - context "user has a different identity" do - let(:ldap_email) { user.email } + context 'user already exists' do + let_it_be(:user) { create(:user) } - before do + it 'finds existing user' do create(:identity, { provider: 'ldapmain', - extern_uid: 'different_identity_dn', + extern_uid: subject_ldap_dn, user: user }) - end - it "doesn't login a user" do - subject + expect { subject }.not_to change { User.count } - expect(request.env['warden']).not_to be_authenticated + expect(request.env['warden']).to be_authenticated end - it "doesn't create a new user entry either" do - expect { subject }.not_to change { User.count } + context 'user has a different identity' do + let(:ldap_email) { user.email } + + before do + create(:identity, { provider: 'ldapmain', + extern_uid: 'different_identity_dn', + user: user }) + end + + it "doesn't login a user" do + subject + + expect(request.env['warden']).not_to be_authenticated + end + + it "doesn't create a new user entry either" do + expect { subject }.not_to change { User.count } + end end end end end + + def enable_smartcard_authentication + allow(Gitlab::Auth::Smartcard).to receive(:enabled?).and_return(true) + end + + def stub_smartcard_config(smartcard_settings) + allow(::Gitlab.config.smartcard).to(receive_messages(smartcard_settings)) + end + + def stub_certificate_store + openssl_certificate_store = instance_double(OpenSSL::X509::Store) + allow(Gitlab::Auth::Smartcard::Base).to receive(:store).and_return(openssl_certificate_store) + allow(openssl_certificate_store).to receive(:verify).and_return(true) + end + + def stub_certificate + issuer = instance_double(OpenSSL::X509::Name, to_s: issuer_dn) + openssl_certificate = instance_double(OpenSSL::X509::Certificate, subject: subject_dn, issuer: issuer, serial: serial) + allow(OpenSSL::X509::Certificate).to receive(:new).and_return(openssl_certificate) + end end -- GitLab