Initial commit
This commit is contained in:
307
spec/api/v2/auth/audit_spec.rb
Normal file
307
spec/api/v2/auth/audit_spec.rb
Normal file
@@ -0,0 +1,307 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe '/api/v2/auth functionality test' do
|
||||
include_context 'geoip mock'
|
||||
before do
|
||||
end
|
||||
before do
|
||||
create :permission, role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users'
|
||||
create :permission, role: 'member'
|
||||
create :permission, role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets'
|
||||
create :permission, role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets'
|
||||
@user = create(:user)
|
||||
@accountant_user = create(:user, role: 'accountant')
|
||||
@admin_user = create(:user, role: 'admin')
|
||||
@technical_user = create(:user, role: 'technical')
|
||||
|
||||
Permission.create(role: 'admin', action: 'ACCEPT', verb: 'get', path: 'api/v2/admin/users/list')
|
||||
Permission.create(role: 'accountant', action: 'ACCEPT', verb: 'post', path: 'api/v2/accountant/documents')
|
||||
end
|
||||
|
||||
let(:uri) { '/api/v2/identity/sessions' }
|
||||
|
||||
let(:do_create_session_request_acc) { post uri, params: { email: @accountant_user.email, password: @accountant_user.password }, headers: { 'HTTP_USER_AGENT' => 'random-browser' }}
|
||||
let(:do_create_session_request_adm) { post uri, params: { email: @admin_user.email, password: @admin_user.password, otp_code: '1357' }, headers: { 'HTTP_USER_AGENT' => 'random-browser' } }
|
||||
let(:do_create_session_request_tech) { post uri, params: { email: @technical_user.email, password: @technical_user.password }, headers: { 'HTTP_USER_AGENT' => 'random-browser' } }
|
||||
|
||||
let(:do_create_session_request) { post uri, params: { email: @user.email, password: @user.password }, headers: { 'HTTP_USER_AGENT' => 'random-browser' } }
|
||||
let(:auth_request) { '/api/v2/auth/not_in_the_rules_path' }
|
||||
let(:protected_request) { '/api/v2/resource/users/me' }
|
||||
|
||||
describe 'audit permissions testing' do
|
||||
let!(:turn_off_2fa) do
|
||||
User.all.each { |u| u.update(otp: false) }
|
||||
end
|
||||
let(:do_some_requests) do
|
||||
delete '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
post '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
put '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
end
|
||||
|
||||
context 'records activity if path doesnt match with AUDIT permission path but matches with DROP or BLANK' do
|
||||
context 'acts as expected with different roles with another permission type match' do
|
||||
before do
|
||||
Permission.delete_all
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
it 'for accountant' do
|
||||
expect(Permission.all.count).to eq(0)
|
||||
# accountant
|
||||
do_create_session_request_acc
|
||||
do_some_requests
|
||||
expect(Activity.where(category: 'admin', result: 'denied').count).to eq(3)
|
||||
|
||||
end
|
||||
|
||||
it 'for admin' do
|
||||
expect(Permission.all.count).to eq(0)
|
||||
# admin
|
||||
do_create_session_request_adm
|
||||
do_some_requests
|
||||
expect(Activity.where(category: 'admin', result: 'denied').count).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
context 'acts as expected with different roles without any permissions' do
|
||||
before do
|
||||
Permission.delete_all
|
||||
Rails.cache.delete('permissions')
|
||||
expect(Permission.all.count).to eq(0)
|
||||
end
|
||||
|
||||
it 'for accountant' do
|
||||
# accountant
|
||||
do_create_session_request_acc
|
||||
do_some_requests
|
||||
expect(response.status).to eq(401)
|
||||
expect(Activity.where(category: 'admin', result: 'denied').count).to eq(3)
|
||||
end
|
||||
|
||||
it 'for admin' do
|
||||
# admin
|
||||
do_create_session_request_adm
|
||||
do_some_requests
|
||||
expect(response.status).to eq(401)
|
||||
expect(Activity.where(category: 'admin', result: 'denied').count).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'records failed activity if path matches with AUDIT permission path' do
|
||||
context 'creates only one thread' do
|
||||
before do
|
||||
Permission.delete_all
|
||||
Permission.create(role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets')
|
||||
Permission.create(role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users')
|
||||
Permission.create(role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets')
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
end
|
||||
|
||||
context 'without topic specified and without user_uid in params' do
|
||||
let!(:create_audit_permissions) do
|
||||
Permission.create(role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets')
|
||||
Permission.create(role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users')
|
||||
Permission.create(role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets')
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
it 'works for general topic' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
get '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('general')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'works for patch request' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
patch '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('general')
|
||||
expect(Activity.last.action).to eq('update')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'works for non - put post patch get delete requests' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
head '/api/v2/auth/api/v2/admin', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('general')
|
||||
expect(Activity.last.action).to eq('system')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'for account role' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'for admin role' do
|
||||
do_create_session_request_adm
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
put '/api/v2/auth/api/v2/admin/users', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('users')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'for technical role' do
|
||||
do_create_session_request_tech
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
post '/api/v2/auth/api/v2/admin/wallets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('wallets')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with specified topic and without user_uid' do
|
||||
let!(:create_audit_permissions) do
|
||||
Permission.delete_all
|
||||
Permission.create(role: 'technical', action: 'ACCEPT', verb: 'post', path: 'api/v2/admin/wallets', topic: 'tech_support')
|
||||
Permission.create(role: 'admin', action: 'ACCEPT', verb: 'put', path: 'api/v2/admin/users', topic: 'administrating')
|
||||
Permission.create(role: 'accountant', action: 'ACCEPT', verb: 'delete', path: 'api/v2/admin/markets', topic: 'accounting')
|
||||
|
||||
Permission.create(role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets', topic: 'tech_support')
|
||||
Permission.create(role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users', topic: 'administrating')
|
||||
Permission.create(role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets', topic: 'accounting')
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
context 'for different roles' do
|
||||
it 'accountant' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('accounting')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
|
||||
it 'technical' do
|
||||
do_create_session_request_tech
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
post '/api/v2/auth/api/v2/admin/wallets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('tech_support')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
|
||||
it 'admin' do
|
||||
do_create_session_request_adm
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
put '/api/v2/auth/api/v2/admin/users', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('administrating')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with specified topic and user_uid' do
|
||||
let!(:create_audit_permissions) do
|
||||
Permission.create(role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets', topic: 'tech_support')
|
||||
Permission.create(role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users', topic: 'administrating')
|
||||
Permission.create(role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets', topic: 'accounting')
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
it 'for different roles' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', params: { uid: @user.uid } ,headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
end
|
||||
|
||||
it 'includes data in denied activity' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }, params: { user_uid: @user.uid }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('denied')
|
||||
expect(Activity.last.target_uid).to eq(@user.uid)
|
||||
expect(JSON.parse(Activity.last.data).keys).to include('user_uid', 'path', 'note')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'records succesfull activity if path matches with AUDIT permission path' do
|
||||
context 'with different params combination' do
|
||||
let!(:create_audit_permissions) do
|
||||
Permission.create(role: 'accountant', action: 'ACCEPT', verb: 'delete', path: 'api/v2/admin/markets')
|
||||
Permission.create(role: 'admin', action: 'ACCEPT', verb: 'put', path: 'api/v2/admin/users')
|
||||
Permission.create(role: 'technical', action: 'ACCEPT', verb: 'post', path: 'api/v2/admin/wallets')
|
||||
Permission.create(role: 'technical', action: 'AUDIT', verb: 'post', path: 'api/v2/admin/wallets')
|
||||
Permission.create(role: 'admin', action: 'AUDIT', verb: 'put', path: 'api/v2/admin/users')
|
||||
Permission.create(role: 'accountant', action: 'AUDIT', verb: 'delete', path: 'api/v2/admin/markets')
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
context 'for different roles without params' do
|
||||
it 'accountant' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
|
||||
it 'technical' do
|
||||
do_create_session_request_tech
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
post '/api/v2/auth/api/v2/admin/wallets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('wallets')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
|
||||
it 'admin' do
|
||||
do_create_session_request_adm
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
put '/api/v2/auth/api/v2/admin/users', headers: { 'HTTP_USER_AGENT' => 'random-browser' }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('users')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for different roles with user_uid in params' do
|
||||
it 'includes data in succesfull activity' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }, params: { user_uid: @user.uid }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
expect(Activity.last.target_uid).to eq(@user.uid)
|
||||
expect(JSON.parse(Activity.last.data).keys).to include('user_uid', 'path', 'note')
|
||||
end
|
||||
|
||||
it 'create activity and save target_uid for accountant if user with this uid exists' do
|
||||
do_create_session_request_acc
|
||||
expect(Activity.where(category: 'admin').count).to eq(0)
|
||||
delete '/api/v2/auth/api/v2/admin/markets', headers: { 'HTTP_USER_AGENT' => 'random-browser' }, params: { user_uid: @user.uid }
|
||||
expect(Activity.where(category: 'admin').count).to eq(1)
|
||||
expect(Activity.last.topic).to eq('markets')
|
||||
expect(Activity.last.result).to eq('succeed')
|
||||
expect(Activity.last.target_uid).to eq(@user.uid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
366
spec/api/v2/auth/auth_spec.rb
Normal file
366
spec/api/v2/auth/auth_spec.rb
Normal file
@@ -0,0 +1,366 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe '/api/v2/auth functionality test' do
|
||||
include_context 'geoip mock'
|
||||
|
||||
let(:uri) { '/api/v2/identity/sessions' }
|
||||
let!(:create_permissions) do
|
||||
create :permission, role: 'admin'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'all', path: 'not_in_the_rules_path'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'get', path: '/api/v2/resource/users/me'
|
||||
create :permission, role: 'accountant'
|
||||
end
|
||||
let!(:user) { create(:user) }
|
||||
let(:params) do
|
||||
{
|
||||
email: user.email,
|
||||
password: user.password
|
||||
}
|
||||
end
|
||||
|
||||
let(:do_create_session_request) { post uri, params: params }
|
||||
let(:auth_request) { '/api/v2/auth/not_in_the_rules_path' }
|
||||
let(:protected_request) { '/api/v2/resource/users/me' }
|
||||
|
||||
describe 'testing workability with session' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
context 'with valid session' do
|
||||
before do
|
||||
do_create_session_request
|
||||
end
|
||||
|
||||
it 'returns bearer token on valid session' do
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'allows any type of request' do
|
||||
available_types = %w[post get put head delete patch]
|
||||
available_types.each do |ping|
|
||||
method("#{ping}").call auth_request
|
||||
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ip related' do
|
||||
let(:create_session_uri) { uri }
|
||||
let(:auth_uri) { '/api/v2/auth/not_in_the_rules_path' }
|
||||
let(:ip_to_be_equal) { '168.238.57.64' }
|
||||
let(:ip_that_differs) { '168.27.3.225' }
|
||||
|
||||
context 'default ip behaviour from HTTP_X_FORWARDED_FOR via action_dispatch.remote_ip' do
|
||||
it 'works if ip from session matches request ip' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'denies access if ip from session doesnt match request ip' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_that_differs }
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'ip behaviour from TRUE_CLIENT_IP header' do
|
||||
before do
|
||||
allow(Barong::App.config).to receive_messages(gateway: 'akamai')
|
||||
end
|
||||
|
||||
it 'works if ip from session matches request ip' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal, 'HTTP_TRUE_CLIENT_IP' => ip_to_be_equal }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_that_differs, 'HTTP_TRUE_CLIENT_IP' => ip_to_be_equal }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'uses HTTP_X_FORWARDED_FOR if TRUE_CLIENT_IP missing and works' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'uses HTTP_X_FORWARDED_FOR if TRUE_CLIENT_IP empty and works' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal, 'HTTP_TRUE_CLIENT_IP' => '' }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal, 'HTTP_TRUE_CLIENT_IP' => '' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'denies access if ip from session doesnt match request ip in HTTP_TRUE_CLIENT_IP' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal, 'HTTP_TRUE_CLIENT_IP' => ip_to_be_equal }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_that_differs, 'HTTP_TRUE_CLIENT_IP' => ip_that_differs }
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'uses HTTP_X_FORWARDED_FOR if TRUE_CLIENT_IP empty or missing and denies access' do
|
||||
post create_session_uri, params: params, headers: { 'HTTP_X_FORWARDED_FOR' => ip_to_be_equal, 'HTTP_TRUE_CLIENT_IP' => '' }
|
||||
get auth_uri, headers: { 'HTTP_X_FORWARDED_FOR' => ip_that_differs }
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'testing session related errors' do
|
||||
it 'renders error if no session or api key headers provided' do
|
||||
get auth_request
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_session\"]}")
|
||||
end
|
||||
|
||||
it 'renders error if session belongs to non-active user' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
user.update(state: 'banned')
|
||||
|
||||
get auth_request
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.user_not_active\"]}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'testing restrictions' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
let(:do_restricted_request) { put '/api/v2/auth/api/v2/peatio/management/ping' }
|
||||
|
||||
it 'receives access error if path is blacklisted' do
|
||||
do_restricted_request
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.permission_denied\"]}")
|
||||
end
|
||||
|
||||
let(:do_whitelisted_request) { put '/api/v2/auth/api/v2/peatio/public/ping' }
|
||||
|
||||
it 'receives access error if path is blacklisted' do
|
||||
do_whitelisted_request
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to be_empty
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'testing workability with api keys' do
|
||||
include_context 'bearer authentication'
|
||||
let!(:test_user) { create(:user, otp: otp_enabled) }
|
||||
let(:otp_enabled) { true }
|
||||
let!(:api_key) { create :api_key, key_holder_account: test_user }
|
||||
let(:otp_code) { '1357' }
|
||||
let(:nonce) { (Time.now.to_f * 1000).to_i }
|
||||
let(:kid) { api_key.kid }
|
||||
let(:secret) { api_key.secret }
|
||||
let(:data) { nonce.to_s + kid }
|
||||
let(:algorithm) { 'SHA' + api_key.algorithm[2..4]}
|
||||
let(:signature) { OpenSSL::HMAC.hexdigest(algorithm, secret, data) }
|
||||
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
SecretStorage.store_secret(secret, api_key.kid)
|
||||
allow(TOTPService).to receive(:validate?)
|
||||
.with(test_user.uid, otp_code) { true }
|
||||
end
|
||||
|
||||
context 'testing api key related errors' do
|
||||
it 'catches api key headers and renders error on missing header' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
}
|
||||
expect(response.status).to eq(422)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_api_key_headers\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'catches api key headers and renders error if nonce is string' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => 'nonce',
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.nonce_not_valid_timestamp\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'catches api key headers and renders error if nonce is zero' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => 0,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.nonce_not_valid_timestamp\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'catches api key headers and renders error if nonce is older than default 5 seconds in milliseconds' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => ((Time.now - 10.seconds).to_f * 1000).to_i,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.nonce_expired\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'catches api key headers and renders error if nonce is from future with milisecond' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => ((Time.now + 10.seconds).to_f * 1000).to_i,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.nonce_expired\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'catches api key headers and renders error on blank header' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => ' '
|
||||
}
|
||||
expect(response.status).to eq(422)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_api_key_headers\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'renders error when signature is invalid' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => 'some-random-signature'
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_signature\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
let(:ban_api_key) { APIKey.last.update(state: 'banned') }
|
||||
|
||||
it 'renders error when api key state is not active' do
|
||||
ban_api_key
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.apikey_not_active\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
let(:ban_user) { test_user.update(state: 'banned') }
|
||||
|
||||
it 'renders error when api key state is not active' do
|
||||
ban_user
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.apikey_not_active\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
let(:disable_user_2fa) { test_user.update(otp: false) }
|
||||
|
||||
it 'renders error when api key is valid but user have disabled 2fa' do
|
||||
disable_user_2fa
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.apikey_not_active\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'testing api key with valid params' do
|
||||
it 'catches api key headers and works as expected with milisecond nonce' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to be_empty
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'testing restrictions' do
|
||||
let(:do_restricted_request) {
|
||||
put '/api/v2/auth/api/v2/peatio/management/ping', headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
}
|
||||
|
||||
it 'receives access error if path is blacklisted' do
|
||||
do_restricted_request
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.permission_denied\"]}")
|
||||
end
|
||||
|
||||
let(:do_whitelisted_request) {
|
||||
put '/api/v2/auth/api/v2/peatio/public/ping', headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
}
|
||||
|
||||
it 'receives access error if path is whitelisted' do
|
||||
do_whitelisted_request
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to be_empty
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
138
spec/api/v2/auth/csrf_spec.rb
Normal file
138
spec/api/v2/auth/csrf_spec.rb
Normal file
@@ -0,0 +1,138 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe '/api/v2/auth CSRF functionality test' do
|
||||
include_context 'geoip mock'
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Barong::Authorize).to receive(:validate_csrf!).and_call_original
|
||||
end
|
||||
let(:uri) { '/api/v2/identity/sessions' }
|
||||
let!(:create_permissions) do
|
||||
create :permission, role: 'admin'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'all', path: 'not_in_the_rules_path'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'get', path: '/api/v2/resource/users/me'
|
||||
create :permission, role: 'accountant'
|
||||
end
|
||||
let!(:user) { create(:user) }
|
||||
let(:params) do
|
||||
{
|
||||
email: user.email,
|
||||
password: user.password
|
||||
}
|
||||
end
|
||||
|
||||
let(:do_create_session_request) { post uri, params: params }
|
||||
let(:auth_request) { '/api/v2/auth/not_in_the_rules_path' }
|
||||
let(:protected_request) { '/api/v2/resource/users/me' }
|
||||
|
||||
describe 'testing workability with session' do
|
||||
context 'without CSRF token' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
do_create_session_request
|
||||
end
|
||||
|
||||
it 'doesnt return bearer token on valid session without CSRF' do
|
||||
post auth_request
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.missing_csrf_token\"]}")
|
||||
end
|
||||
|
||||
it 'works with any type of changing state verb request' do
|
||||
available_types = %w[post put delete patch]
|
||||
available_types.each do |ping|
|
||||
method("#{ping}").call auth_request
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.missing_csrf_token\"]}")
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
it 'works without CSRF token on any type of safe verb request' do
|
||||
available_types = %w[get head]
|
||||
available_types.each do |ping|
|
||||
method("#{ping}").call auth_request
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with CSRF token' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
do_create_session_request
|
||||
@csrf = json_body[:csrf_token]
|
||||
end
|
||||
|
||||
it 'doesnt return bearer token on valid session without CSRF' do
|
||||
get auth_request, headers: { 'X-CSRF-Token': @csrf }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
end
|
||||
|
||||
it 'doesnt work on any type of request without csrf' do
|
||||
available_types = %w[post get put delete patch]
|
||||
available_types.each do |ping|
|
||||
method("#{ping}").call auth_request, headers: { 'X-CSRF-Token': @csrf }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'testing workability with api keys' do
|
||||
let!(:test_user) { create(:user, otp: otp_enabled) }
|
||||
let(:otp_enabled) { true }
|
||||
let!(:api_key) { create :api_key, key_holder_account: test_user }
|
||||
let(:otp_code) { '1357' }
|
||||
let(:nonce) { (Time.now.to_f * 1000).to_i }
|
||||
let(:kid) { api_key.kid }
|
||||
let(:secret) { api_key.secret }
|
||||
let(:data) { nonce.to_s + kid }
|
||||
let(:algorithm) { 'SHA' + api_key.algorithm[2..4]}
|
||||
let(:signature) { OpenSSL::HMAC.hexdigest(algorithm, secret, data) }
|
||||
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
SecretStorage.store_secret(secret, api_key.kid)
|
||||
allow(TOTPService).to receive(:validate?)
|
||||
.with(test_user.uid, otp_code) { true }
|
||||
end
|
||||
|
||||
context 'with valid api keys' do
|
||||
it 'works without CSRF' do
|
||||
get auth_request, headers: {
|
||||
'X-Auth-Apikey' => kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to be_empty
|
||||
expect(response.headers['Authorization']).to include 'Bearer'
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
|
||||
get protected_request, headers: { 'Authorization' => response.headers['Authorization'] }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
144
spec/api/v2/auth/rbac_spec.rb
Normal file
144
spec/api/v2/auth/rbac_spec.rb
Normal file
@@ -0,0 +1,144 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe '/api/v2/auth functionality test' do
|
||||
include_context 'geoip mock'
|
||||
|
||||
let(:do_protected_request) { get '/api/v2/auth/api/v2/resource/users/me' }
|
||||
|
||||
describe 'testing rbac workability' do
|
||||
before(:example) do
|
||||
Thread.list.last.kill if Thread.list.last.to_s.include?('activity')
|
||||
end
|
||||
let!(:create_permissions) do
|
||||
Permission.create(role: 'superadmin', action: 'ACCEPT', verb: 'get', path: 'api/v2/admin/users/list')
|
||||
Rails.cache.delete('permissions')
|
||||
@admin = User.create(email: 'superadmin@admin.io', password: 'Tecohvi0', role: 'superadmin', state: 'active')
|
||||
end
|
||||
|
||||
context 'with cookies' do
|
||||
let(:do_create_session_request_superadm) { post '/api/v2/identity/sessions', params: { email: 'superadmin@admin.io', password: 'Tecohvi0' }}
|
||||
|
||||
context 'not enough permissions' do
|
||||
it 'denies access for user with missing cookies' do
|
||||
do_protected_request
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_session\"]}")
|
||||
end
|
||||
|
||||
it 'denies access for non-accountant user with valid cookies trying to GET accountant api' do
|
||||
do_create_session_request_superadm
|
||||
|
||||
get '/api/v2/auth/api/v2/accountant/documents'
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_permission\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'denies POST for endpoint but allowing GET for admin user according to permissions' do
|
||||
do_create_session_request_superadm
|
||||
|
||||
post '/api/v2/auth/api/v2/admin/users/list'
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_permission\"]}")
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
|
||||
get '/api/v2/auth/api/v2/admin/users/list'
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
it 'denies access because of the typo in the path' do
|
||||
do_create_session_request_superadm
|
||||
get '/api/v2/auth/api/v2/admon/users/list'
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_permission\"]}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'enough permissions' do
|
||||
it 'allowes access with for user with valid cookies, verb, role and path' do
|
||||
do_create_session_request_superadm
|
||||
|
||||
get '/api/v2/auth/api/v2/admin/users/list'
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with api_keys' do
|
||||
let!(:admin_api_key) { create :api_key, key_holder_account: @admin }
|
||||
let(:nonce) { (Time.now.to_f * 1000).to_i }
|
||||
let(:secret) { admin_api_key.secret }
|
||||
let(:signature) { OpenSSL::HMAC.hexdigest('SHA256', secret, nonce.to_s + admin_api_key.kid ) }
|
||||
let!(:turn_on_2fa) { @admin.update(otp: true) }
|
||||
|
||||
context 'with valid api key headers' do
|
||||
context 'enough permissions' do
|
||||
it 'allowes access with for api key owner for valid verb, owner role and path' do
|
||||
allow(TOTPService).to receive(:validate?)
|
||||
.with(@admin.uid, '1357') { true }
|
||||
|
||||
get '/api/v2/auth/api/v2/admin/users/list', headers: {
|
||||
'X-Auth-Apikey' => admin_api_key.kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
end
|
||||
|
||||
context 'not enough permissions' do
|
||||
it 'denies access for non-accountant api key owner with valid api_key trying to POST accountant api' do
|
||||
allow(TOTPService).to receive(:validate?)
|
||||
.with(@admin.uid, '1357') { true }
|
||||
allow(SecretStorage).to receive(:get_secret)
|
||||
.with(admin_api_key.kid) { Vault::Secret.new(data: { value: secret }) }
|
||||
|
||||
post '/api/v2/auth/api/v2/accountant/documents', headers: {
|
||||
'X-Auth-Apikey' => admin_api_key.kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_permission\"]}")
|
||||
end
|
||||
|
||||
it 'denies POST for endpoint but allowing GET for api key owner according to permissions' do
|
||||
allow(TOTPService).to receive(:validate?)
|
||||
.with(@admin.uid, '1357') { true }
|
||||
allow(SecretStorage).to receive(:get_secret)
|
||||
.with(admin_api_key.kid) { Vault::Secret.new(data: { value: secret }) }
|
||||
|
||||
post '/api/v2/auth/api/v2/accountant/documents', headers: {
|
||||
'X-Auth-Apikey' => admin_api_key.kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
Rails.cache.delete(admin_api_key.kid)
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.invalid_permission\"]}")
|
||||
|
||||
get '/api/v2/auth/api/v2/admin/users/list', headers: {
|
||||
'X-Auth-Apikey' => admin_api_key.kid,
|
||||
'X-Auth-Nonce' => nonce,
|
||||
'X-Auth-Signature' => signature
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
196
spec/api/v2/auth/restriction_spec.rb
Normal file
196
spec/api/v2/auth/restriction_spec.rb
Normal file
@@ -0,0 +1,196 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe '/api/v2/auth functionality test' do
|
||||
include_context 'geoip mock'
|
||||
|
||||
let(:uri) { '/api/v2/identity/sessions' }
|
||||
let!(:create_permissions) do
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'all', path: 'tasty_endpoint'
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
let!(:user) { create(:user) }
|
||||
let(:params) do
|
||||
{
|
||||
email: user.email,
|
||||
password: user.password
|
||||
}
|
||||
end
|
||||
let(:do_create_session_request) { post uri, params: params }
|
||||
let(:auth_request) { '/api/v2/auth/tasty_endpoint' }
|
||||
let(:auth_session_create_request) { '/api/v2/auth/api/v2/barong/identity/sessions' }
|
||||
|
||||
|
||||
describe 'test blocklogin restriction' do
|
||||
before do
|
||||
allow(Rails.cache).to receive(:delete_matched).and_return(nil)
|
||||
Rails.cache.delete('restrictions')
|
||||
end
|
||||
|
||||
context 'block session creation' do
|
||||
let!(:restriction) { create(:restriction, value: 'EUROPE', scope: 'continent', category: 'blocklogin', code: 425) }
|
||||
before do
|
||||
allow_any_instance_of(Barong::Authorize).to receive(:validate_session!).and_return(true)
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(london_ip)
|
||||
end
|
||||
|
||||
it do
|
||||
post auth_session_create_request, params: params
|
||||
expect(response.status).to eq(restriction.code)
|
||||
end
|
||||
|
||||
it do
|
||||
do_create_session_request # This request will be successful because path doesn't include 'api/v2/auth'
|
||||
get auth_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
describe 'test blacklist restrictions' do
|
||||
before do
|
||||
allow_any_instance_of(Barong::Authorize).to receive(:validate_session!).and_return(true)
|
||||
Rails.cache.delete('restrictions')
|
||||
do_create_session_request
|
||||
end
|
||||
|
||||
context 'restrict by ip' do
|
||||
let!(:restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'blacklist') }
|
||||
let!(:disabled) { create(:restriction, value: '192.168.0.3', scope: 'ip', state: 'disabled', category: 'blacklist') }
|
||||
|
||||
it 'request with restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.0.1')
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'request with non-restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.0.2')
|
||||
get auth_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
it 'request with disabled restriction' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.0.3')
|
||||
get auth_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'restricts with ip subnet' do
|
||||
let!(:restriction) { create(:restriction, value: '192.168.32.0/24', scope: 'ip_subnet', category: 'blacklist') }
|
||||
|
||||
it 'request with restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.32.42')
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.restrict.blacklist\"]}")
|
||||
end
|
||||
|
||||
it 'request with non-restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.33.3')
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'geoip' do
|
||||
context 'restricts with country' do
|
||||
let!(:restriction) { create(:restriction, value: 'japan', scope: 'country', category: 'blacklist') }
|
||||
|
||||
it 'with restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(tokyo_ip)
|
||||
get auth_request
|
||||
expect(response.status).to eq(423)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.restrict.blacklist\"]}")
|
||||
end
|
||||
|
||||
it 'with non-restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(london_ip)
|
||||
get auth_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'restricts with continent' do
|
||||
let!(:restriction) { create(:restriction, value: 'EUROPE', scope: 'continent', category: 'blacklist') }
|
||||
|
||||
it 'with restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(london_ip)
|
||||
get auth_request
|
||||
expect(response.status).to eq(423)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
expect(response.body).to eq("{\"errors\":[\"authz.restrict.blacklist\"]}")
|
||||
end
|
||||
|
||||
it 'with non-restricted ip' do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(tokyo_ip)
|
||||
get auth_request
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'test restriction ierarchy' do
|
||||
before do
|
||||
allow_any_instance_of(Barong::Authorize).to receive(:validate_session!).and_return(true)
|
||||
Rails.cache.delete('restrictions')
|
||||
do_create_session_request
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return('192.168.0.1')
|
||||
end
|
||||
|
||||
context 'whitelist -> maintenance' do
|
||||
let!(:maintenance_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'maintenance') }
|
||||
let!(:whitelist_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'whitelist') }
|
||||
|
||||
it '200' do
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'maintenance -> blacklist' do
|
||||
let!(:blacklist_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'blacklist') }
|
||||
let!(:maintenance_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'maintenance') }
|
||||
|
||||
context 'standard code error' do
|
||||
it '471' do
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(471)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'blacklist' do
|
||||
context 'standard code error' do
|
||||
let!(:blacklist_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'blacklist') }
|
||||
|
||||
it '401' do
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom code error' do
|
||||
let!(:blacklist_restriction) { create(:restriction, value: '192.168.0.1', scope: 'ip', category: 'blacklist', code: 403) }
|
||||
|
||||
it '403' do
|
||||
get auth_request
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
158
spec/api/v2/auth/sessions_spec.rb
Normal file
158
spec/api/v2/auth/sessions_spec.rb
Normal file
@@ -0,0 +1,158 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
include ActiveSupport::Testing::TimeHelpers
|
||||
|
||||
describe '/api/v2/auth functionality test' do
|
||||
include_context 'geoip mock'
|
||||
|
||||
let(:session_expire_time) do
|
||||
Barong::App.config.session_expire_time.to_i.seconds
|
||||
end
|
||||
let!(:create_permissions) do
|
||||
create :permission, role: 'admin'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'all', path: 'not_in_the_rules_path'
|
||||
create :permission, role: 'member', action: 'ACCEPT', verb: 'get', path: '/api/v2/resource/users/me'
|
||||
create :permission, role: 'accountant'
|
||||
end
|
||||
let!(:user) { create(:user) }
|
||||
let(:params) do
|
||||
{
|
||||
email: user.email,
|
||||
password: user.password
|
||||
}
|
||||
end
|
||||
|
||||
let(:do_destroy_session_request) { delete '/api/v2/identity/sessions', headers: { 'HTTP_USER_AGENT': 'legacy-browser' } }
|
||||
let(:do_create_session_request) { post '/api/v2/identity/sessions', params: params, headers: { 'HTTP_USER_AGENT': 'legacy-browser' } }
|
||||
let(:auth_request) { '/api/v2/auth/not_in_the_rules_path' }
|
||||
|
||||
describe 'testing session hash validations' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
context 'with valid ip, browser' do
|
||||
it 'authorize traffic' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when session params has changed after session opening' do
|
||||
it 'return error if USER_AGENT changes' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'new-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'return error if IP changes' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'REMOTE_ADDR': '128.0.0.12' }
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
|
||||
it 'return error if everything changes' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'REMOTE_ADDR': '128.0.0.12', 'HTTP_USER_AGENT': 'new-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.headers['Authorization']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'testing session renewal' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
context 'with valid session' do
|
||||
it 'authorize traffic and renew session every request' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
start_time = Time.current
|
||||
|
||||
30.times do
|
||||
# 5 minute before session will expire
|
||||
travel session_expire_time - 5.minutes
|
||||
|
||||
# renew session with private request
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
end
|
||||
|
||||
expect(Time.current).to be > (start_time + session_expire_time)
|
||||
|
||||
travel session_expire_time + 10.minutes
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'testing session destroy' do
|
||||
before do
|
||||
Rails.cache.delete('permissions')
|
||||
end
|
||||
|
||||
context 'with valid session' do
|
||||
it 'deletes session from cache on #logout' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
|
||||
do_destroy_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid session params' do
|
||||
it 'deletes session from cache on auth if params is wrong' do
|
||||
do_create_session_request
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.headers['Authorization']).not_to be_nil
|
||||
expect(response.headers['Authorization']).to include "Bearer"
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'new-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
|
||||
post auth_request, headers: { 'HTTP_USER_AGENT': 'legacy-browser' }
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user