omniauth_callbacks_controller_spec.rb 6.7 KB
Newer Older
1 2
require 'spec_helper'

3
describe OmniauthCallbacksController, type: :controller do
4 5
  include LoginHelpers

6 7
  describe 'omniauth' do
    let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) }
8

T
Tiago Botelho 已提交
9
    before do
10 11
      mock_auth_hash(provider.to_s, extern_uid, user.email)
      stub_omniauth_provider(provider, context: request)
12
    end
13

14 15
    context 'when the user is on the last sign in attempt' do
      let(:extern_uid) { 'my-uid' }
16

17 18 19
      before do
        user.update(failed_attempts: User.maximum_attempts.pred)
        subject.response = ActionDispatch::Response.new
20
      end
21

22 23
      context 'when using a form based provider' do
        let(:provider) { :ldap }
24

25 26 27
        it 'locks the user when sign in fails' do
          allow(subject).to receive(:params).and_return(ActionController::Parameters.new(username: user.username))
          request.env['omniauth.error.strategy'] = OmniAuth::Strategies::LDAP.new(nil)
28

29
          subject.send(:failure)
T
Tiago Botelho 已提交
30

31 32
          expect(user.reload).to be_access_locked
        end
33
      end
34

35 36
      context 'when using a button based provider' do
        let(:provider) { :github }
37

38 39
        it 'does not lock the user when sign in fails' do
          request.env['omniauth.error.strategy'] = OmniAuth::Strategies::GitHub.new(nil)
40

41
          subject.send(:failure)
42

43
          expect(user.reload).not_to be_access_locked
T
Tiago Botelho 已提交
44
        end
45
      end
46
    end
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    context 'when sign in fails' do
      include RoutesHelpers

      let(:extern_uid) { 'my-uid' }
      let(:provider) { :saml }

      def stub_route_as(path)
        allow(@routes).to receive(:generate_extras) { [path, []] }
      end

      it 'it calls through to the failure handler' do
        request.env['omniauth.error'] = OneLogin::RubySaml::ValidationError.new("Fingerprint mismatch")
        request.env['omniauth.error.strategy'] = OmniAuth::Strategies::SAML.new(nil)
        stub_route_as('/users/auth/saml/callback')

        ForgeryProtection.with_forgery_protection do
          post :failure
        end

        expect(flash[:alert]).to match(/Fingerprint mismatch/)
      end
    end

71 72 73 74 75 76 77 78 79 80
    context 'when a redirect fragment is provided' do
      let(:provider) { :jwt }
      let(:extern_uid) { 'my-uid' }

      before do
        request.env['omniauth.params'] = { 'redirect_fragment' => 'L101' }
      end

      context 'when a redirect url is stored' do
        it 'redirects with fragment' do
J
Jasper Maes 已提交
81
          post provider, session: { user_return_to: '/fake/url' }
82 83 84 85 86 87 88

          expect(response).to redirect_to('/fake/url#L101')
        end
      end

      context 'when a redirect url with a fragment is stored' do
        it 'redirects with the new fragment' do
J
Jasper Maes 已提交
89
          post provider, session: { user_return_to: '/fake/url#replaceme' }
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

          expect(response).to redirect_to('/fake/url#L101')
        end
      end

      context 'when no redirect url is stored' do
        it 'does not redirect with the fragment' do
          post provider

          expect(response.redirect?).to be true
          expect(response.location).not_to include('#L101')
        end
      end
    end

105 106 107 108
    context 'strategies' do
      context 'github' do
        let(:extern_uid) { 'my-uid' }
        let(:provider) { :github }
T
Tiago Botelho 已提交
109

110
        it 'allows sign in' do
T
Tiago Botelho 已提交
111
          post provider
112

T
Tiago Botelho 已提交
113 114
          expect(request.env['warden']).to be_authenticated
        end
115

116 117
        shared_context 'sign_up' do
          let(:user) { double(email: 'new@example.com') }
118

119 120 121
          before do
            stub_omniauth_setting(block_auto_created_users: false)
          end
122
        end
T
Tiago Botelho 已提交
123

124 125
        context 'sign up' do
          include_context 'sign_up'
T
Tiago Botelho 已提交
126

127 128
          it 'is allowed' do
            post provider
T
Tiago Botelho 已提交
129

130 131
            expect(request.env['warden']).to be_authenticated
          end
T
Tiago Botelho 已提交
132 133
        end

134 135 136 137 138 139
        context 'when OAuth is disabled' do
          before do
            stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
            settings = Gitlab::CurrentSettings.current_application_settings
            settings.update(disabled_oauth_sign_in_sources: [provider.to_s])
          end
T
Tiago Botelho 已提交
140

141
          it 'prevents login via POST' do
T
Tiago Botelho 已提交
142 143 144 145
            post provider

            expect(request.env['warden']).not_to be_authenticated
          end
146 147 148 149 150 151 152 153 154

          it 'shows warning when attempting login' do
            post provider

            expect(response).to redirect_to new_user_session_path
            expect(flash[:alert]).to eq('Signing in using GitHub has been disabled')
          end

          it 'allows linking the disabled provider' do
155
            user.identities.destroy_all # rubocop: disable DestroyAll
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
            sign_in(user)

            expect { post provider }.to change { user.reload.identities.count }.by(1)
          end

          context 'sign up' do
            include_context 'sign_up'

            it 'is prevented' do
              post provider

              expect(request.env['warden']).not_to be_authenticated
            end
          end
        end
      end

      context 'auth0' do
        let(:extern_uid) { '' }
        let(:provider) { :auth0 }

        it 'does not allow sign in without extern_uid' do
          post 'auth0'

          expect(request.env['warden']).not_to be_authenticated
          expect(response.status).to eq(302)
          expect(controller).to set_flash[:alert].to('Wrong extern UID provided. Make sure Auth0 is configured correctly.')
T
Tiago Botelho 已提交
183
        end
184 185
      end
    end
186 187 188 189 190 191 192 193 194 195
  end

  describe '#saml' do
    let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') }
    let(:mock_saml_response) { File.read('spec/fixtures/authentication/saml_response.xml') }
    let(:saml_config) { mock_saml_config_with_upstream_two_factor_authn_contexts }

    before do
      stub_omniauth_saml_config({ enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'],
                                  providers: [saml_config] })
196
      mock_auth_hash_with_saml_xml('saml', 'my-uid', user.email, mock_saml_response)
197 198 199 200
      request.env["devise.mapping"] = Devise.mappings[:user]
      request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth']
      post :saml, params: { SAMLResponse: mock_saml_response }
    end
201

202 203 204 205 206
    context 'when worth two factors' do
      let(:mock_saml_response) do
        File.read('spec/fixtures/authentication/saml_response.xml')
            .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN')
      end
207

208 209 210 211
      it 'expects user to be signed_in' do
        expect(request.env['warden']).to be_authenticated
      end
    end
212

213 214 215
    context 'when not worth two factors' do
      it 'expects user to provide second factor' do
        expect(response).to render_template('devise/sessions/two_factor')
T
Tiago Botelho 已提交
216 217
        expect(request.env['warden']).not_to be_authenticated
      end
218 219
    end
  end
220
end