BigW Consortium Gitlab

sessions_controller_spec.rb 7.08 KB
Newer Older
1 2 3 4 5 6 7 8
require 'spec_helper'

describe SessionsController do
  describe '#create' do
    before do
      @request.env['devise.mapping'] = Devise.mappings[:user]
    end

9
    context 'when using standard authentications' do
10 11 12 13 14
      context 'invalid password' do
        it 'does not authenticate user' do
          post(:create, user: { login: 'invalid', password: 'invalid' })

          expect(response)
Connor Shea committed
15
            .to set_flash.now[:alert].to /Invalid Login or password/
16 17 18
        end
      end

19
      context 'when using valid password' do
20 21 22 23 24 25 26 27
        let(:user) { create(:user) }

        it 'authenticates user correctly' do
          post(:create, user: { login: user.username, password: user.password })

          expect(response).to set_flash.to /Signed in successfully/
          expect(subject.current_user). to eq user
        end
28 29 30 31 32

        it "creates an audit log record" do
          expect { post(:create, user: { login: user.username, password: user.password }) }.to change { SecurityEvent.count }.by(1)
          expect(SecurityEvent.last.details[:with]).to eq("standard")
        end
33 34 35
      end
    end

36
    context 'when using two-factor authentication via OTP' do
37 38 39 40 41 42
      let(:user) { create(:user, :two_factor) }

      def authenticate_2fa(user_params)
        post(:create, { user: user_params }, { otp_user_id: user.id })
      end

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
      context 'remember_me field' do
        it 'sets a remember_user_token cookie when enabled' do
          allow(controller).to receive(:find_user).and_return(user)
          expect(controller).
            to receive(:remember_me).with(user).and_call_original

          authenticate_2fa(remember_me: '1', otp_attempt: user.current_otp)

          expect(response.cookies['remember_user_token']).to be_present
        end

        it 'does nothing when disabled' do
          allow(controller).to receive(:find_user).and_return(user)
          expect(controller).not_to receive(:remember_me)

          authenticate_2fa(remember_me: '0', otp_attempt: user.current_otp)

          expect(response.cookies['remember_user_token']).to be_nil
        end
      end

64 65 66
      ##
      # See #14900 issue
      #
67 68 69
      context 'when authenticating with login and OTP of another user' do
        context 'when another user has 2FA enabled' do
          let(:another_user) { create(:user, :two_factor) }
70

71 72 73 74
          context 'when OTP is valid for another user' do
            it 'does not authenticate' do
              authenticate_2fa(login: another_user.username,
                               otp_attempt: another_user.current_otp)
75

76
              expect(subject.current_user).not_to eq another_user
77
            end
78 79
          end

80 81 82 83
          context 'when OTP is invalid for another user' do
            it 'does not authenticate' do
              authenticate_2fa(login: another_user.username,
                               otp_attempt: 'invalid')
84

85
              expect(subject.current_user).not_to eq another_user
86
            end
87 88
          end

89 90 91 92 93 94 95 96
          context 'when authenticating with OTP' do
            context 'when OTP is valid' do
              it 'authenticates correctly' do
                authenticate_2fa(otp_attempt: user.current_otp)

                expect(subject.current_user).to eq user
              end
            end
97

98
            context 'when OTP is invalid' do
99
              before { authenticate_2fa(otp_attempt: 'invalid') }
100

101
              it 'does not authenticate' do
102
                expect(subject.current_user).not_to eq user
103 104 105
              end

              it 'warns about invalid OTP code' do
106 107
                expect(response).to set_flash.now[:alert]
                  .to /Invalid two-factor code/
108
              end
109 110 111
            end
          end

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
          context 'when the user is on their last attempt' do
            before do
              user.update(failed_attempts: User.maximum_attempts.pred)
            end

            context 'when OTP is valid' do
              it 'authenticates correctly' do
                authenticate_2fa(otp_attempt: user.current_otp)

                expect(subject.current_user).to eq user
              end
            end

            context 'when OTP is invalid' do
              before { authenticate_2fa(otp_attempt: 'invalid') }

              it 'does not authenticate' do
                expect(subject.current_user).not_to eq user
              end

              it 'warns about invalid login' do
                expect(response).to set_flash.now[:alert]
                  .to /Invalid Login or password/
              end

              it 'locks the user' do
                expect(user.reload).to be_access_locked
              end

              it 'keeps the user locked on future login attempts' do
                post(:create, user: { login: user.username, password: user.password })

                expect(response)
                  .to set_flash.now[:alert].to /Invalid Login or password/
              end
            end
          end

150 151
          context 'when another user does not have 2FA enabled' do
            let(:another_user) { create(:user) }
152

153 154 155
            it 'does not leak that 2FA is disabled for another user' do
              authenticate_2fa(login: another_user.username,
                               otp_attempt: 'invalid')
156

157 158
              expect(response).to set_flash.now[:alert]
                .to /Invalid two-factor code/
159 160 161 162
            end
          end
        end
      end
163 164 165 166 167 168 169 170 171 172 173 174 175 176

      it "creates an audit log record" do
        expect { authenticate_2fa(login: user.username, otp_attempt: user.current_otp) }.to change { SecurityEvent.count }.by(1)
        expect(SecurityEvent.last.details[:with]).to eq("two-factor")
      end
    end

    context 'when using two-factor authentication via U2F device' do
      let(:user) { create(:user, :two_factor) }

      def authenticate_2fa_u2f(user_params)
        post(:create, { user: user_params }, { otp_user_id: user.id })
      end

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
      context 'remember_me field' do
        it 'sets a remember_user_token cookie when enabled' do
          allow(U2fRegistration).to receive(:authenticate).and_return(true)
          allow(controller).to receive(:find_user).and_return(user)
          expect(controller).
            to receive(:remember_me).with(user).and_call_original

          authenticate_2fa_u2f(remember_me: '1', login: user.username, device_response: "{}")

          expect(response.cookies['remember_user_token']).to be_present
        end

        it 'does nothing when disabled' do
          allow(U2fRegistration).to receive(:authenticate).and_return(true)
          allow(controller).to receive(:find_user).and_return(user)
          expect(controller).not_to receive(:remember_me)

          authenticate_2fa_u2f(remember_me: '0', login: user.username, device_response: "{}")

          expect(response.cookies['remember_user_token']).to be_nil
        end
      end

200 201 202 203 204
      it "creates an audit log record" do
        allow(U2fRegistration).to receive(:authenticate).and_return(true)
        expect { authenticate_2fa_u2f(login: user.username, device_response: "{}") }.to change { SecurityEvent.count }.by(1)
        expect(SecurityEvent.last.details[:with]).to eq("two-factor-via-u2f-device")
      end
205 206 207
    end
  end
end