123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe 'Sessions endpoints', type: :request do
- describe 'GET /' do
- let(:headers) { {} }
- let(:session_key) { Zammad::Application::Initializer::SessionStore::SESSION_KEY }
- before do
- Setting.set('http_type', http_type)
- get '/', headers: headers
- end
- context "when Setting 'http_type' is set to 'https'" do
- let(:http_type) { 'https' }
- context "when it's not an HTTPS request" do
- it 'sets no Cookie' do
- expect(response.header['Set-Cookie']).to be_nil
- end
- end
- context "when it's an HTTPS request" do
- let(:headers) do
- {
- 'X-Forwarded-Proto' => 'https'
- }
- end
- it "sets Cookie with 'secure' flag" do
- expect(response.header['Set-Cookie']).to include(session_key).and include('; secure;')
- end
- end
- end
- context "when Setting 'http_type' is set to 'http'" do
- let(:http_type) { 'http' }
- context "when it's not an HTTPS request" do
- it 'sets Cookie' do
- expect(response.header['Set-Cookie']).to include(session_key).and not_include('; secure;')
- end
- end
- context "when it's an HTTPS request" do
- let(:headers) do
- {
- 'X-Forwarded-Proto' => 'https'
- }
- end
- it "sets Cookie without 'secure' flag" do
- expect(response.header['Set-Cookie']).to include(session_key).and not_include('; secure;')
- end
- end
- end
- end
- describe 'GET /signshow' do
- context 'user logged in' do
- subject(:user) { create(:agent, password: password) }
- let(:password) { SecureRandom.urlsafe_base64(20) }
- let(:fingerprint) { SecureRandom.urlsafe_base64(40) }
- before do
- setting if defined?(setting)
- params = {
- fingerprint: fingerprint,
- username: user.login,
- password: password
- }
- post '/api/v1/signin', params: params, as: :json
- end
- it 'leaks no sensitive data' do
- params = { fingerprint: fingerprint }
- get '/api/v1/signshow', params: params, as: :json
- expect(json_response['session']).not_to include('password')
- end
- context 'when after auth modules are triggered' do
- subject(:user) { create(:customer, roles: [role], password: password) }
- let(:role) { create(:role, name: '2FA') }
- context 'with no enforcing roles' do
- it 'returns nil' do
- expect(json_response['after_auth']).to be_nil
- end
- end
- context 'with enforcing roles' do
- let(:setting) do
- Setting.set('two_factor_authentication_enforce_role_ids', [role.id])
- Setting.set('two_factor_authentication_method_authenticator_app', true)
- end
- it 'returns the after auth information' do
- expect(json_response['after_auth']).to eq({ 'data' => {}, 'type' => 'TwoFactorConfiguration' })
- end
- end
- end
- end
- context 'user not logged in' do
- subject(:user) { nil }
- it 'contains only user related object manager attributes' do
- get '/api/v1/signshow', params: {}, as: :json
- expect(json_response['models'].keys).to match_array(%w[User])
- end
- it 'does not contain fields with permission admin.*' do
- get '/api/v1/signshow', params: {}, as: :json
- expect(json_response['models']['User']).not_to include(hash_including('name' => 'role_ids'))
- end
- end
- end
- describe 'GET /auth/sso (single sign-on)' do
- before do
- Setting.set('auth_sso', true)
- end
- context 'when SSO is disabled' do
- before do
- Setting.set('auth_sso', false)
- end
- let(:headers) { { 'X-Forwarded-User' => login } }
- let(:login) { User.last.login }
- it 'returns a new user-session response' do
- get '/auth/sso', as: :json, headers: headers
- expect(response).to have_http_status(:forbidden)
- end
- end
- context 'with invalid user login' do
- let(:login) { User.pluck(:login).max.next }
- context 'in "REMOTE_USER" request env var' do
- let(:env) { { 'REMOTE_USER' => login } }
- it 'returns unauthorized response' do
- get '/auth/sso', as: :json, env: env
- expect(response).to have_http_status(:unauthorized)
- end
- end
- context 'in "HTTP_REMOTE_USER" request env var' do
- let(:env) { { 'HTTP_REMOTE_USER' => login } }
- it 'returns unauthorized response' do
- get '/auth/sso', as: :json, env: env
- expect(response).to have_http_status(:unauthorized)
- end
- end
- context 'in "X-Forwarded-User" request header' do
- let(:headers) { { 'X-Forwarded-User' => login } }
- it 'returns unauthorized response' do
- get '/auth/sso', as: :json, headers: headers
- expect(response).to have_http_status(:unauthorized)
- end
- end
- end
- context 'with valid user login' do
- let(:user) { create(:agent) }
- let(:login) { user.login }
- context 'in Maintenance Mode' do
- before { Setting.set('maintenance_mode', true) }
- context 'in "REMOTE_USER" request env var' do
- let(:env) { { 'REMOTE_USER' => login } }
- it 'returns 403 Forbidden' do
- get '/auth/sso', as: :json, env: env
- expect(response).to have_http_status(:forbidden)
- expect(json_response).to include('error' => 'Maintenance mode enabled!')
- end
- end
- context 'in "HTTP_REMOTE_USER" request env var' do
- let(:env) { { 'HTTP_REMOTE_USER' => login } }
- it 'returns 403 Forbidden' do
- get '/auth/sso', as: :json, env: env
- expect(response).to have_http_status(:forbidden)
- expect(json_response).to include('error' => 'Maintenance mode enabled!')
- end
- end
- context 'in "X-Forwarded-User" request header' do
- let(:headers) { { 'X-Forwarded-User' => login } }
- it 'returns 403 Forbidden' do
- get '/auth/sso', as: :json, headers: headers
- expect(response).to have_http_status(:forbidden)
- expect(json_response).to include('error' => 'Maintenance mode enabled!')
- end
- end
- end
- context 'in "REMOTE_USER" request env var' do
- let(:env) { { 'REMOTE_USER' => login } }
- it 'returns a new user-session response' do
- get '/auth/sso', as: :json, env: env
- expect(response).to redirect_to('/#')
- end
- it 'sets the :user_id session parameter' do
- expect { get '/auth/sso', as: :json, env: env }
- .to change { request&.session&.fetch(:user_id) }.to(user.id)
- end
- end
- context 'in "HTTP_REMOTE_USER" request env var' do
- let(:env) { { 'HTTP_REMOTE_USER' => login } }
- it 'returns a new user-session response' do
- get '/auth/sso', as: :json, env: env
- expect(response).to redirect_to('/#')
- end
- it 'sets the :user_id session parameter' do
- expect { get '/auth/sso', as: :json, env: env }
- .to change { request&.session&.fetch(:user_id) }.to(user.id)
- end
- end
- context 'in "X-Forwarded-User" request header' do
- let(:headers) { { 'X-Forwarded-User' => login } }
- it 'returns a new user-session response' do
- get '/auth/sso', as: :json, headers: headers
- expect(response).to redirect_to('/#')
- end
- it 'sets the :user_id session parameter on the client' do
- expect { get '/auth/sso', as: :json, headers: headers }
- .to change { request&.session&.fetch(:user_id) }.to(user.id)
- end
- end
- end
- end
- describe 'POST /auth/two_factor_initiate_authentication/:method' do
- let(:user) { create(:user, password: 'dummy') }
- let(:params) { {} }
- let(:method) { 'security_keys' }
- let(:user_two_factor_preference) { nil }
- before do
- if defined?(user_two_factor_preference)
- user_two_factor_preference
- user.reload
- end
- post "/api/v1/auth/two_factor_initiate_authentication/#{method}", params: params, as: :json
- end
- context 'with missing params' do
- it 'returns an error' do
- expect(response).to have_http_status(:unprocessable_entity)
- end
- end
- context 'with valid params' do
- let(:user_two_factor_preference) { create(:user_two_factor_preference, :security_keys, user: user) }
- let(:params) { { username: user.login, password: password, method: method } }
- context 'with invalid user/password' do
- let(:password) { 'invalid' }
- it 'returns an error' do
- expect(response).to have_http_status(:unprocessable_entity)
- end
- end
- context 'with valid user/password' do
- let(:password) { 'dummy' }
- it 'returns options for initiation phase', :aggregate_failures do
- expect(response).to have_http_status(:ok)
- expect(json_response).to include('challenge')
- end
- end
- end
- end
- end
|