Fixes issue #2983 - HTTP 401 responses causing issues with Basic Authentication.

This commit is contained in:
Thorsten Eckel 2021-02-04 09:28:41 +01:00
parent 5a65e5bfcf
commit 876c0b18fd
52 changed files with 370 additions and 291 deletions

View File

@ -148,8 +148,8 @@ class ProfileOutOfOffice extends App.ControllerSubContent
data = JSON.parse(xhr.responseText)
# show error message
if xhr.status is 401 || error is 'Unauthorized'
message = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
if xhr.status is 403 || error is 'Not authorized'
message = '» ' + App.i18n.translateInline('Not authorized') + ' «'
else if xhr.status is 404 || error is 'Not Found'
message = '» ' + App.i18n.translateInline('Not Found') + ' «'
else if data.error

View File

@ -115,8 +115,8 @@ class App.TicketZoom extends App.Controller
return
# show error message
if status is 401 || statusText is 'Unauthorized'
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
if status is 403 || statusText is 'Not authorized'
@taskHead = '» ' + App.i18n.translateInline('Not authorized') + ' «'
@taskIconClass = 'diagonal-cross'
@renderScreenUnauthorized(objectName: 'Ticket')
else if status is 404 || statusText is 'Not Found'

View File

@ -93,8 +93,9 @@ class _ajaxSingleton
# 200, all is fine
return if status is 200
# do not show any error message with code 401/404 (handled by controllers)
# do not show any error message for various 4** codes (handled by controllers)
return if status is 401
return if status is 403
return if status is 404
return if status is 422

View File

@ -14,12 +14,12 @@ module ApplicationController::Authenticates
)
return false if user
raise Exceptions::NotAuthorized, 'Not authorized (token)!'
raise Exceptions::Forbidden, 'Not authorized (token)!'
end
return false if current_user&.permissions?(key)
raise Exceptions::NotAuthorized, 'Not authorized (user)!'
raise Exceptions::Forbidden, 'Not authorized (user)!'
end
def authentication_check(auth_param = {})
@ -33,7 +33,7 @@ module ApplicationController::Authenticates
# return auth not ok
if !user
raise Exceptions::NotAuthorized, 'authentication failed'
raise Exceptions::Forbidden, 'Authentication required'
end
# return auth ok
@ -45,12 +45,15 @@ module ApplicationController::Authenticates
#logger.debug params.inspect
#logger.debug session.inspect
#logger.debug cookies.inspect
authentication_errors = []
# already logged in, early exit
if session.id && session[:user_id]
logger.debug { 'session based auth check' }
user = User.lookup(id: session[:user_id])
return authentication_check_prerequesits(user, 'session', auth_param) if user
authentication_errors.push("Can't find User with ID #{session[:user_id]} from Session")
end
# check http basic based authentication
@ -58,11 +61,13 @@ module ApplicationController::Authenticates
request.session_options[:skip] = true # do not send a session cookie
logger.debug { "http basic auth check '#{username}'" }
if Setting.get('api_password_access') == false
raise Exceptions::NotAuthorized, 'API password access disabled!'
raise Exceptions::Forbidden, 'API password access disabled!'
end
user = User.authenticate(username, password)
return authentication_check_prerequesits(user, 'basic_auth', auth_param) if user
authentication_errors.push('Invalid BasicAuth credentials')
end
# check http token based authentication
@ -70,7 +75,7 @@ module ApplicationController::Authenticates
logger.debug { "http token auth check '#{token_string}'" }
request.session_options[:skip] = true # do not send a session cookie
if Setting.get('api_token_access') == false
raise Exceptions::NotAuthorized, 'API token access disabled!'
raise Exceptions::Forbidden, 'API token access disabled!'
end
user = Token.check(
@ -106,13 +111,15 @@ module ApplicationController::Authenticates
@_token_auth = token_string # remember for permission_check
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
authentication_errors.push("Can't find User for Token")
end
# check oauth2 token based authentication
token = Doorkeeper::OAuth::Token.from_bearer_authorization(request)
if token
request.session_options[:skip] = true # do not send a session cookie
logger.debug { "oauth2 token auth check '#{token}'" }
logger.debug { "OAuth2 token auth check '#{token}'" }
access_token = Doorkeeper::AccessToken.by_token(token)
raise Exceptions::NotAuthorized, 'Invalid token!' if !access_token
@ -128,9 +135,13 @@ module ApplicationController::Authenticates
user = User.find(access_token.resource_owner_id)
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
authentication_errors.push("Can't find User with ID #{access_token.resource_owner_id} for OAuth2 token")
end
false
return false if authentication_errors.blank?
raise Exceptions::NotAuthorized, authentication_errors.join(', ')
end
def authenticate_with_password
@ -142,7 +153,7 @@ module ApplicationController::Authenticates
end
def authentication_check_prerequesits(user, auth_type, auth_param)
raise Exceptions::NotAuthorized, 'Maintenance mode enabled!' if in_maintenance_mode?(user)
raise Exceptions::Forbidden, 'Maintenance mode enabled!' if in_maintenance_mode?(user)
raise_unified_login_error if !user.active
@ -150,7 +161,7 @@ module ApplicationController::Authenticates
ActiveSupport::Deprecation.warn("Parameter ':permission' is deprecated. Use Pundit policy and `authorize!` instead.")
if !user.permissions?(auth_param[:permission])
raise Exceptions::NotAuthorized, 'Not authorized (user)!'
raise Exceptions::Forbidden, 'Not authorized (user)!'
end
end

View File

@ -11,7 +11,7 @@ module ApplicationController::Authorizes
def authorized?(record = policy_record, query = nil)
authorize!(record, query)
true
rescue Exceptions::NotAuthorized, Pundit::NotAuthorizedError
rescue Exceptions::Forbidden, Pundit::NotAuthorizedError
false
end

View File

@ -11,6 +11,7 @@ module ApplicationController::HandlesErrors
rescue_from ArgumentError, with: :unprocessable_entity
rescue_from Exceptions::UnprocessableEntity, with: :unprocessable_entity
rescue_from Exceptions::NotAuthorized, with: :unauthorized
rescue_from Exceptions::Forbidden, with: :forbidden
rescue_from Pundit::NotAuthorizedError, with: :pundit_not_authorized_error
end
@ -40,13 +41,21 @@ module ApplicationController::HandlesErrors
http_log
end
def forbidden(e)
logger.info { e }
error = humanize_error(e)
response.headers['X-Failure'] = error.fetch(:error_human, error[:error])
respond_to_exception(e, :forbidden)
http_log
end
def pundit_not_authorized_error(e)
logger.info { e }
# check if a special authorization_error should be shown in the result payload
# which was raised in one of the policies. Fall back to a simple "Not authorized"
# error to hide actual cause for security reasons.
exeption = e.policy.custom_exception || Exceptions::NotAuthorized.new
unauthorized(exeption)
exeption = e.policy&.custom_exception || Exceptions::Forbidden.new('Not authorized')
forbidden(exeption)
end
private
@ -79,10 +88,13 @@ module ApplicationController::HandlesErrors
data[:error_human] = 'Object already exists!'
elsif e.message =~ /null value in column "(.+?)" violates not-null constraint/i || e.message =~ /Field '(.+?)' doesn't have a default value/i
data[:error_human] = "Attribute '#{$1}' required!"
elsif e.message == 'Exceptions::NotAuthorized'
elsif e.message == 'Exceptions::Forbidden'
data[:error] = 'Not authorized'
data[:error_human] = data[:error]
elsif [ActionController::RoutingError, ActiveRecord::RecordNotFound, Exceptions::UnprocessableEntity, Exceptions::NotAuthorized].include?(e.class)
elsif e.message == 'Exceptions::NotAuthorized'
data[:error] = 'Authorization failed'
data[:error_human] = data[:error]
elsif [ActionController::RoutingError, ActiveRecord::RecordNotFound, Exceptions::UnprocessableEntity, Exceptions::NotAuthorized, Exceptions::Forbidden].include?(e.class)
data[:error_human] = data[:error]
end

View File

@ -43,7 +43,7 @@ module ApplicationController::HasUser
return if !user_real
# check if the user has admin rights
raise Exceptions::NotAuthorized, "Current user has no permission to use 'X-On-Behalf-Of'!" if !user_real.permissions?('admin.user')
raise Exceptions::Forbidden, "Current user has no permission to use 'X-On-Behalf-Of'!" if !user_real.permissions?('admin.user')
# find user for execution based on the header
%i[id login email].each do |field|
@ -55,7 +55,7 @@ module ApplicationController::HasUser
end
# no behalf of user found
raise Exceptions::NotAuthorized, "No such user '#{request.headers['X-On-Behalf-Of']}'"
raise Exceptions::Forbidden, "No such user '#{request.headers['X-On-Behalf-Of']}'"
end
def search_attributes(field)

View File

@ -75,7 +75,7 @@ class AttachmentsController < ApplicationController
valid_disposition = %w[inline attachment]
return disposition if valid_disposition.include?(disposition)
raise Exceptions::NotAuthorized, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
end
def verify_object_permissions

View File

@ -7,7 +7,8 @@ class CalendarSubscriptionsController < ApplicationController
# @summary Returns an iCal file with all objects matching the calendar subscriptions preferences of the current user as events.
#
# @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied.
# @response_message 403 Forbidden / Invalid session.
# @response_message 422 Unprocessable Entity.
def all
calendar_subscriptions = CalendarSubscriptions.new(current_user)
ical = calendar_subscriptions.all
@ -29,7 +30,8 @@ class CalendarSubscriptionsController < ApplicationController
# @summary Returns an iCal file of the given object (and method) matching the calendar subscriptions preferences of the current user as events.
#
# @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied.
# @response_message 403 Forbidden / Invalid session.
# @response_message 422 Unprocessable Entity.
def object
calendar_subscriptions = CalendarSubscriptions.new(current_user)
ical = calendar_subscriptions.generic(params[:object], params[:method])

View File

@ -267,7 +267,7 @@ class ChannelsEmailController < ApplicationController
def check_online_service
return true if !Setting.get('system_online_service')
raise Exceptions::NotAuthorized
raise Exceptions::Forbidden
end
def check_access(id = nil)
@ -279,6 +279,6 @@ class ChannelsEmailController < ApplicationController
channel = Channel.find(id)
return true if channel.preferences && !channel.preferences[:online_service_disable]
raise Exceptions::NotAuthorized
raise Exceptions::Forbidden
end
end

View File

@ -149,7 +149,7 @@ class FormController < ApplicationController
def authorize!(*)
super
rescue Pundit::NotAuthorizedError
raise Exceptions::NotAuthorized
raise Exceptions::Forbidden
end
def token_gen(fingerprint)
@ -161,7 +161,7 @@ class FormController < ApplicationController
def token_valid?(token, fingerprint)
if token.blank?
Rails.logger.info 'No token for form!'
raise Exceptions::NotAuthorized
raise Exceptions::Forbidden
end
begin
crypt = ActiveSupport::MessageEncryptor.new(Setting.get('application_secret')[0, 32])
@ -205,15 +205,15 @@ class FormController < ApplicationController
# in elasticsearch7 "created_at:>now-1h" is not working. Needed to catch -2h
form_limit_by_ip_per_hour = Setting.get('form_ticket_create_by_ip_per_hour') || 20
result = SearchIndexBackend.search("preferences.form.remote_ip:'#{remote_ip}' AND created_at:>now-2h", 'Ticket', limit: form_limit_by_ip_per_hour)
raise Exceptions::NotAuthorized if result.count >= form_limit_by_ip_per_hour.to_i
raise Exceptions::Forbidden if result.count >= form_limit_by_ip_per_hour.to_i
form_limit_by_ip_per_day = Setting.get('form_ticket_create_by_ip_per_day') || 240
result = SearchIndexBackend.search("preferences.form.remote_ip:'#{remote_ip}' AND created_at:>now-1d", 'Ticket', limit: form_limit_by_ip_per_day)
raise Exceptions::NotAuthorized if result.count >= form_limit_by_ip_per_day.to_i
raise Exceptions::Forbidden if result.count >= form_limit_by_ip_per_day.to_i
form_limit_per_day = Setting.get('form_ticket_create_per_day') || 5000
result = SearchIndexBackend.search('preferences.form.remote_ip:* AND created_at:>now-1d', 'Ticket', limit: form_limit_per_day)
raise Exceptions::NotAuthorized if result.count >= form_limit_per_day.to_i
raise Exceptions::Forbidden if result.count >= form_limit_per_day.to_i
false
end
@ -222,6 +222,6 @@ class FormController < ApplicationController
return true if params[:fingerprint].present? && params[:fingerprint].length > 30
Rails.logger.info 'No fingerprint given!'
raise Exceptions::NotAuthorized
raise Exceptions::Forbidden
end
end

View File

@ -265,7 +265,7 @@ curl http://localhost/api/v1/organization/{id} -v -u #{login}:#{password} -H "Co
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/organizations/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_example
send_data(
Organization.csv_example,
@ -283,7 +283,7 @@ curl http://localhost/api/v1/organization/{id} -v -u #{login}:#{password} -H "Co
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/organizations.csv' 'https://your.zammad/api/v1/organizations/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_start
string = params[:data]
if string.blank? && params[:file].present?

View File

@ -16,7 +16,7 @@ class SessionsController < ApplicationController
end
def create_sso
raise Exceptions::NotAuthorized, 'SSO authentication disabled!' if !Setting.get('auth_sso')
raise Exceptions::Forbidden, 'SSO authentication disabled!' if !Setting.get('auth_sso')
user = begin
login = request.env['REMOTE_USER'] ||
@ -150,7 +150,7 @@ class SessionsController < ApplicationController
def switch_back_to_user
# check if it's a switch back
raise Exceptions::NotAuthorized if !session[:switched_from_user_id]
raise Exceptions::Forbidden if !session[:switched_from_user_id]
user = User.lookup(id: session[:switched_from_user_id])
if !user

View File

@ -21,7 +21,7 @@ class SettingsController < ApplicationController
# POST /settings
def create
raise Exceptions::NotAuthorized, 'Not authorized (feature not possible)'
raise Exceptions::Forbidden, 'Not authorized (feature not possible)'
end
# PUT /settings/1
@ -84,7 +84,7 @@ class SettingsController < ApplicationController
# DELETE /settings/1
def destroy
raise Exceptions::NotAuthorized, 'Not authorized (feature not possible)'
raise Exceptions::Forbidden, 'Not authorized (feature not possible)'
end
private

View File

@ -155,7 +155,7 @@ curl http://localhost/api/v1/text_modules.json -v -u #{login}:#{password} -H "Co
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/text_modules/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_example
csv_string = TextModule.csv_example(
col_sep: params[:col_sep] || ',',
@ -177,7 +177,7 @@ curl http://localhost/api/v1/text_modules.json -v -u #{login}:#{password} -H "Co
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/Textbausteine_final2.csv' 'https://your.zammad/api/v1/text_modules/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_start
string = params[:data]
if string.blank? && params[:file].present?

View File

@ -159,7 +159,7 @@ class TicketArticlesController < ApplicationController
# check if requested ticket got merged
if ticket.state.state_type.name != 'merged'
raise Exceptions::NotAuthorized, 'No access, article_id/ticket_id is not matching.'
raise Exceptions::Forbidden, 'No access, article_id/ticket_id is not matching.'
end
ticket = article.ticket
@ -173,7 +173,7 @@ class TicketArticlesController < ApplicationController
access = true
end
end
raise Exceptions::NotAuthorized, 'Requested file id is not linked with article_id.' if !access
raise Exceptions::Forbidden, 'Requested file id is not linked with article_id.' if !access
# find file
file = Store.find(params[:id])
@ -226,7 +226,7 @@ class TicketArticlesController < ApplicationController
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/ticket_articles/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_example
csv_string = Ticket::Article.csv_example(
col_sep: ',',
@ -248,7 +248,7 @@ class TicketArticlesController < ApplicationController
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/ticket_articles.csv' 'https://your.zammad/api/v1/ticket_articles/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_start
if Setting.get('import_mode') != true
raise 'Only can import tickets if system is in import mode.'
@ -286,6 +286,6 @@ class TicketArticlesController < ApplicationController
valid_disposition = %w[inline attachment]
return disposition if valid_disposition.include?(disposition)
raise Exceptions::NotAuthorized, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
end
end

View File

@ -624,7 +624,7 @@ class TicketsController < ApplicationController
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/tickets/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_example
csv_string = Ticket.csv_example(
col_sep: ',',
@ -646,7 +646,7 @@ class TicketsController < ApplicationController
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/tickets.csv' 'https://your.zammad/api/v1/tickets/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_start
if Setting.get('import_mode') != true
raise 'Only can import tickets if system is in import mode.'

View File

@ -15,7 +15,7 @@ class UsersController < ApplicationController
# role 'Customer' only just the own User record will be returned.
#
# @response_message 200 [Array<User>] List of matching User records.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def index
offset = 0
per_page = 500
@ -71,7 +71,7 @@ class UsersController < ApplicationController
# @parameter full [Bool] If set a Asset structure with all connected Assets gets returned.
#
# @response_message 200 [User] User record matching the requested identifier.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def show
user = User.find(params[:id])
authorize!(user)
@ -120,7 +120,7 @@ class UsersController < ApplicationController
# @parameter User(required,body) [User] The attribute value structure needed to update a User record.
#
# @response_message 200 [User] Updated User record.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def update
user = User.find(params[:id])
authorize!(user)
@ -169,7 +169,7 @@ class UsersController < ApplicationController
# @parameter id(required) [User] The identifier matching the requested User record.
#
# @response_message 200 User successfully deleted.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def destroy
user = User.find(params[:id])
authorize!(user)
@ -186,7 +186,7 @@ class UsersController < ApplicationController
# @parameter full [Bool] If set a Asset structure with all connected Assets gets returned.
#
# @response_message 200 [User] User record matching the requested identifier.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def me
if response_expand?
@ -225,7 +225,7 @@ class UsersController < ApplicationController
# or false: [{:id => user.id, :label => "firstname lastname <email>", :value => "firstname lastname <email>"},...].
#
# @response_message 200 [Array<User>] A list of User records matching the search term.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def search
per_page = params[:per_page] || params[:limit] || 100
per_page = per_page.to_i
@ -328,7 +328,7 @@ class UsersController < ApplicationController
# @parameter id(required) [Integer] The identifier matching the requested User record.
#
# @response_message 200 [History] The History records of the requested User record.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def history
# get user data
user = User.find(params[:id])
@ -847,7 +847,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/users/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_example
send_data(
User.csv_example,
@ -865,7 +865,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/users.csv' 'https://your.zammad/api/v1/users/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def import_start
string = params[:data]
if string.blank? && params[:file].present?
@ -896,7 +896,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
# @parameter User(required,body) [User] The attribute value structure needed to create a User record.
#
# @response_message 200 [User] Created User record.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def create_internal
# permission check
check_attributes_by_current_user_permission(params)
@ -947,7 +947,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
# @parameter User(required,body) [User] The attribute value structure needed to create a User record.
#
# @response_message 200 [User] Created User record.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def create_signup
# check if feature is enabled
if !Setting.get('user_create_account')
@ -1013,7 +1013,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
# @parameter User(required,body) [User] The attribute value structure needed to create a User record.
#
# @response_message 200 [User] Created User record.
# @response_message 401 Invalid session.
# @response_message 403 Forbidden / Invalid session.
def create_admin
if User.count > 2 # system and example users
raise Exceptions::UnprocessableEntity, 'Administrator account already created'

View File

@ -16,7 +16,7 @@ module PunditPolicy
def user_required!
return if user
raise Exceptions::NotAuthorized, 'authentication failed'
raise Exceptions::Forbidden, 'Authentication required'
end
private
@ -25,7 +25,7 @@ module PunditPolicy
if details
details = "Not authorized (#{details})!"
end
@custom_exception = Exceptions::NotAuthorized.new(details)
@custom_exception = Exceptions::Forbidden.new(details)
false
end

View File

@ -14,7 +14,7 @@ class Auth
password_verified = PasswordHash.verified?(user.password, password)
raise Exceptions::NotAuthorized, 'Please verify your account before you can login!' if !user.verified && user.source == 'signup' && password_verified
raise Exceptions::Forbidden, 'Please verify your account before you can login!' if !user.verified && user.source == 'signup' && password_verified
password_verified
end

View File

@ -2,6 +2,8 @@ module Exceptions
class NotAuthorized < StandardError; end
class Forbidden < StandardError; end
class UnprocessableEntity < StandardError; end
end

View File

@ -15,18 +15,18 @@ class UserContext < Delegator
end
def permissions!(permissions)
raise Exceptions::NotAuthorized, 'authentication failed' if !@user
raise Exceptions::NotAuthorized, 'Not authorized (user)!' if !@user.permissions?(permissions)
raise Exceptions::Forbidden, 'Authentication required' if !@user
raise Exceptions::Forbidden, 'Not authorized (user)!' if !@user.permissions?(permissions)
return if !@token
return if @token.with_context(user: @user) { permissions?(permissions) }
raise Exceptions::NotAuthorized, 'Not authorized (token)!'
raise Exceptions::Forbidden, 'Not authorized (token)!'
end
def permissions?(permissions)
permissions!(permissions)
true
rescue Exceptions::NotAuthorized
rescue Exceptions::Forbidden
false
end
end

View File

@ -10,7 +10,7 @@
<% end %>
<% if !@traceback %>
<div class="error-image" style="background-image: url(/assets/error/error-1.svg)"></div>
<p>Sorry, but you're not allowed to access this page. If you're registered please log in and refresh this page.</p>
<p>Sorry, but your authentication failed. Double check your credentials and try again.</p>
<% else %>
<div><%= @exception.message %></div>
<% if @exception.backtrace %>
@ -21,4 +21,4 @@
<% end %>
<% end %>
</body>
</html>
</html>

24
public/403.html Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="dark">
<meta charset="utf-8">
<title>403: Forbidden</title>
<link rel="stylesheet" href="/assets/error/style.css">
<body <% if @traceback %>class="error-message"<% end %>>
<h1>403: Forbidden</h1>
<% if @message.present? %>
<div><%= @message %></div>
<% end %>
<% if !@traceback %>
<div class="error-image" style="background-image: url(/assets/error/error-1.svg)"></div>
<p>Sorry, but you're not allowed to access this page. If you're registered please log in and refresh this page.</p>
<% else %>
<div><%= @exception.message %></div>
<% if @exception.backtrace %>
<pre><code>
<% @exception.backtrace.each {|row| %>
<%= row %>
<% } %></code></pre>
<% end %>
<% end %>
</body>
</html>

View File

@ -251,7 +251,10 @@ $(function() {
_this._config = data
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 401) {
_this.log('error', 'Faild to load form config, feature is disabled!')
_this.log('error', 'Faild to load form config, wrong authentication data!')
}
else if (jqXHR.status == 403) {
_this.log('error', 'Faild to load form config, feature is disabled or request is wrong!')
}
else {
_this.log('error', 'Faild to load form config!')

View File

@ -137,7 +137,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
}
authenticated_as(admin, on_behalf_of: 99_449_494_949)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(@response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq("No such user '99449494949'")
@ -156,7 +156,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
}
authenticated_as(customer, on_behalf_of: admin.email)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(@response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq("Current user has no permission to use 'X-On-Behalf-Of'!")

View File

@ -30,7 +30,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_password_access', false)
authenticated_as(admin)
get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API password access disabled!')
@ -51,7 +51,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_password_access', false)
authenticated_as(agent)
get '/api/v1/tickets', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API password access disabled!')
@ -72,7 +72,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_password_access', false)
authenticated_as(customer)
get '/api/v1/tickets', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API password access disabled!')
@ -104,7 +104,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_token_access', false)
get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API token access disabled!')
@ -124,7 +124,7 @@ RSpec.describe 'Api Auth', type: :request do
admin_token.save!
get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (token)!')
@ -132,7 +132,7 @@ RSpec.describe 'Api Auth', type: :request do
admin_token.save!
get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (token)!')
@ -161,7 +161,7 @@ RSpec.describe 'Api Auth', type: :request do
expect(json_response).to be_truthy
get '/api/v1/roles', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (token)!')
@ -254,7 +254,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_token_access', false)
get '/api/v1/tickets', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API token access disabled!')
@ -276,7 +276,7 @@ RSpec.describe 'Api Auth', type: :request do
name = "some org name #{rand(999_999_999)}"
post '/api/v1/organizations', params: { name: name }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
@ -293,7 +293,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_token_access', false)
get '/api/v1/tickets', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API token access disabled!')
@ -315,7 +315,7 @@ RSpec.describe 'Api Auth', type: :request do
name = "some org name #{rand(999_999_999)}"
post '/api/v1/organizations', params: { name: name }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does token auth - invalid user - admin', last_admin_check: false do
@ -334,7 +334,7 @@ RSpec.describe 'Api Auth', type: :request do
Setting.set('api_token_access', false)
get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('API token access disabled!')

View File

@ -10,22 +10,22 @@ RSpec.describe 'Calendars', type: :request do
it 'does calendar index with nobody' do
get '/api/v1/calendars', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
get '/api/v1/calendars_init', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
get '/api/v1/calendars/timezones', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
it 'does calendar index with admin' do

View File

@ -104,10 +104,11 @@ RSpec.describe 'Error handling', type: :request do
context 'request is not authenticated' do
before do
authenticated_as(create(:agent), password: 'wrongpw')
get '/api/v1/organizations', as: as
end
let(:message) { 'authentication failed' }
let(:message) { 'Invalid BasicAuth credentials' }
let(:http_status) { :unauthorized }
context 'requesting JSON' do
@ -122,6 +123,27 @@ RSpec.describe 'Error handling', type: :request do
end
end
context 'request is forbidden' do
before do
get '/api/v1/organizations', as: as
end
let(:message) { 'Authentication required' }
let(:http_status) { :forbidden }
context 'requesting JSON' do
include_examples 'JSON response format'
end
context 'requesting HTML' do
let(:title) { '403: Forbidden' }
let(:headline) { '403: Forbidden' }
include_examples 'HTML response format'
end
end
context 'exception is raised' do
before do
@ -148,8 +170,8 @@ RSpec.describe 'Error handling', type: :request do
end
end
shared_examples 'handles exception' do |exception, http_status, title, headline|
include_examples 'exception check', 'some error message', exception, http_status, title, headline
shared_examples 'handles exception' do |exception, http_status, title, headline, message = 'some error message'|
include_examples 'exception check', message, exception, http_status, title, headline
end
shared_examples 'masks exception' do |exception, http_status, title, headline|
@ -157,6 +179,8 @@ RSpec.describe 'Error handling', type: :request do
end
include_examples 'handles exception', Exceptions::NotAuthorized, :unauthorized, '401: Unauthorized', '401: Unauthorized'
include_examples 'handles exception', Exceptions::Forbidden, :forbidden, '403: Forbidden', '403: Forbidden'
include_examples 'handles exception', Pundit::NotAuthorizedError, :forbidden, '403: Forbidden', '403: Forbidden', 'Not authorized'
include_examples 'handles exception', ActiveRecord::RecordNotFound, :not_found, '404: Not Found', '404: Requested resource was not found'
include_examples 'handles exception', Exceptions::UnprocessableEntity, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'
include_examples 'masks exception', ArgumentError, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'

View File

@ -5,38 +5,38 @@ RSpec.describe 'External Credentials', type: :request do
context 'without authentication' do
describe '#index' do
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/api/v1/external_credentials', as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to include('error' => 'authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Authentication required')
end
end
describe '#app_verify' do
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
post '/api/v1/external_credentials/facebook/app_verify', as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to include('error' => 'authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Authentication required')
end
end
describe '#link_account' do
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/api/v1/external_credentials/facebook/link_account', as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to include('error' => 'authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Authentication required')
end
end
describe '#callback' do
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/api/v1/external_credentials/facebook/callback', as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to include('error' => 'authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Authentication required')
end
end
end
@ -72,9 +72,9 @@ RSpec.describe 'External Credentials', type: :request do
context 'when permission for Facebook channel is deactivated' do
before { Permission.find_by(name: 'admin.channel_facebook').update(active: false) }
it 'returns 401 unauthorized with internal (Zammad) error' do
it 'returns 403 Forbidden with internal (Zammad) error' do
post '/api/v1/external_credentials/facebook/app_verify', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Not authorized (user)!')
end
end
@ -207,7 +207,7 @@ RSpec.describe 'External Credentials', type: :request do
before { Permission.find_by(name: 'admin.channel_twitter').update(active: false) }
include_examples 'for failure cases' do
let(:status) { :unauthorized }
let(:status) { :forbidden }
let(:error_message) { 'Not authorized (user)!' }
end
end

View File

@ -11,7 +11,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
it 'does get config call' do
post '/api/v1/form_config', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
end
@ -19,7 +19,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
it 'does get config call' do
Setting.set('form_ticket_create', true)
post '/api/v1/form_config', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
@ -40,7 +40,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: 'invalid' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
expect(json_response['error']).to eq('Authorization failed')
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: token }, as: :json
expect(response).to have_http_status(:ok)
@ -105,7 +105,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: 'invalid' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
expect(json_response['error']).to eq('Authorization failed')
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: token }, as: :json
expect(response).to have_http_status(:ok)
@ -164,7 +164,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
sleep 10 # wait until elasticsearch is index
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: token, name: 'Bob Smith', email: 'discard@znuny.com', title: 'test-last', body: 'hello' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to be_truthy
@ -184,7 +184,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
sleep 10 # wait until elasticsearch is index
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: token, name: 'Bob Smith', email: 'discard@znuny.com', title: 'test-2-last', body: 'hello' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to be_truthy
@ -204,7 +204,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
sleep 10 # wait until elasticsearch is index
post '/api/v1/form_submit', params: { fingerprint: fingerprint, token: token, name: 'Bob Smith', email: 'discard@znuny.com', title: 'test-2-last', body: 'hello' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to be_truthy
end
@ -229,7 +229,7 @@ RSpec.describe 'Form', type: :request, searchindex: true do
post '/api/v1/form_submit', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
end
end

View File

@ -612,7 +612,7 @@ RSpec.describe 'Integration CTI', type: :request do
expect(log.duration_talking_time).to be_nil
get '/api/v1/cti/log'
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
# get caller list
authenticated_as(agent)

View File

@ -38,7 +38,7 @@ RSpec.describe 'Idoit', type: :request do
}
authenticated_as(agent)
post '/api/v1/integration/idoit/verify', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response).not_to be_blank
expect(json_response['error']).to eq('Not authorized (user)!')

View File

@ -48,7 +48,7 @@ RSpec.describe 'Monitoring', type: :request do
# health_check
get '/api/v1/monitoring/health_check', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['healthy']).to be_falsey
@ -56,7 +56,7 @@ RSpec.describe 'Monitoring', type: :request do
# status
get '/api/v1/monitoring/status', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['agents']).to be_falsey
@ -67,11 +67,11 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
@ -79,7 +79,7 @@ RSpec.describe 'Monitoring', type: :request do
# health_check
get '/api/v1/monitoring/health_check?token=abc', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['healthy']).to be_falsey
@ -87,7 +87,7 @@ RSpec.describe 'Monitoring', type: :request do
# status
get '/api/v1/monitoring/status?token=abc', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['agents']).to be_falsey
@ -98,11 +98,11 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: { token: 'abc' }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
@ -221,11 +221,11 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: { token: token }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
@ -267,7 +267,7 @@ RSpec.describe 'Monitoring', type: :request do
# health_check
authenticated_as(agent)
get '/api/v1/monitoring/health_check', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['healthy']).to be_falsey
@ -275,7 +275,7 @@ RSpec.describe 'Monitoring', type: :request do
# status
get '/api/v1/monitoring/status', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['agents']).to be_falsey
@ -286,7 +286,7 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: { token: token }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
@ -303,7 +303,7 @@ RSpec.describe 'Monitoring', type: :request do
# health_check
authenticated_as(admin)
get '/api/v1/monitoring/health_check', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['healthy']).to be_falsey
@ -311,7 +311,7 @@ RSpec.describe 'Monitoring', type: :request do
# status
get '/api/v1/monitoring/status', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['agents']).to be_falsey
@ -322,7 +322,7 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: { token: token }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
@ -360,11 +360,11 @@ RSpec.describe 'Monitoring', type: :request do
# token
post '/api/v1/monitoring/token', params: { token: token }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['token']).to be_falsey
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
permission.active = true
permission.save!

View File

@ -512,7 +512,7 @@ RSpec.describe 'Integration Placetel', type: :request do
# get caller list
get '/api/v1/cti/log'
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
authenticated_as(agent)
get '/api/v1/cti/log', as: :json

View File

@ -442,7 +442,7 @@ RSpec.describe 'Integration Sipgate', type: :request do
# get caller list
get '/api/v1/cti/log'
expect(@response).to have_http_status(:unauthorized)
expect(@response).to have_http_status(:forbidden)
authenticated_as(agent)
get '/api/v1/cti/log', as: :json

View File

@ -55,6 +55,6 @@ RSpec.describe 'KnowledgeBase loading initial data', type: :request, searchindex
end
describe 'for guests without authorization' do
it { expect(response).to have_http_status(:unauthorized) }
it { expect(response).to have_http_status(:forbidden) }
end
end

View File

@ -67,17 +67,17 @@ RSpec.describe 'KnowledgeBase translation update', type: :request, authenticated
describe 'as reader' do
let(:user_identifier) { :agent }
it { expect(response).to have_http_status(:unauthorized) }
it { expect(response).to have_http_status(:forbidden) }
end
describe 'as non-KB user' do
let(:user_identifier) { :customer }
it { expect(response).to have_http_status(:unauthorized) }
it { expect(response).to have_http_status(:forbidden) }
end
describe 'as a guest' do
it { expect(response).to have_http_status(:unauthorized) }
it { expect(response).to have_http_status(:forbidden) }
end
end
end

View File

@ -152,7 +152,7 @@ RSpec.describe 'Organization', type: :request, searchindex: true do
# search
Scheduler.worker(true)
get "/api/v1/organizations/search?query=#{CGI.escape('Zammad')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does index with customer2' do
@ -171,14 +171,14 @@ RSpec.describe 'Organization', type: :request, searchindex: true do
expect('Rest Org #1').to eq(json_response['name'])
get "/api/v1/organizations/#{organization2.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['name']).to be_nil
# search
Scheduler.worker(true)
get "/api/v1/organizations/search?query=#{CGI.escape('Zammad')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does organization search sortable' do
@ -474,7 +474,7 @@ RSpec.describe 'Organization', type: :request, searchindex: true do
it 'does csv example - customer no access' do
authenticated_as(customer)
get '/api/v1/organizations/import_example', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
end

View File

@ -37,7 +37,7 @@ RSpec.describe 'Overviews', type: :request do
post '/api/v1/overviews', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does create overviews' do

View File

@ -16,11 +16,11 @@ RSpec.describe 'Packages', type: :request do
it 'does packages index with nobody' do
get '/api/v1/packages', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['packages']).to be_falsey
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
it 'does packages index with admin' do
@ -38,7 +38,7 @@ RSpec.describe 'Packages', type: :request do
expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does packages index with inactive admin' do
@ -49,14 +49,14 @@ RSpec.describe 'Packages', type: :request do
expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does packages index with agent' do
authenticated_as(agent)
get '/api/v1/packages', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['packages']).to be_falsey
expect(json_response['error']).to eq('Not authorized (user)!')
@ -66,7 +66,7 @@ RSpec.describe 'Packages', type: :request do
authenticated_as(customer)
get '/api/v1/packages', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['packages']).to be_falsey
expect(json_response['error']).to eq('Not authorized (user)!')

View File

@ -98,22 +98,22 @@ RSpec.describe 'Search', type: :request, searchindex: true do
}
post '/api/v1/search/ticket', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response).not_to be_blank
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
post '/api/v1/search/user', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response).not_to be_blank
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
post '/api/v1/search', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response).not_to be_blank
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
it 'does settings index with admin' do

View File

@ -47,7 +47,7 @@ RSpec.describe 'Sessions endpoints', type: :request do
it 'returns a new user-session response' do
get '/auth/sso', as: :json, headers: headers
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
end
@ -86,7 +86,7 @@ RSpec.describe 'Sessions endpoints', type: :request do
end
context 'with valid user login' do
let(:user) { User.last }
let(:user) { create(:agent) }
let(:login) { user.login }
context 'in Maintenance Mode' do
@ -95,10 +95,10 @@ RSpec.describe 'Sessions endpoints', type: :request do
context 'in "REMOTE_USER" request env var' do
let(:env) { { 'REMOTE_USER' => login } }
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/auth/sso', as: :json, env: env
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Maintenance mode enabled!')
end
end
@ -106,10 +106,10 @@ RSpec.describe 'Sessions endpoints', type: :request do
context 'in "HTTP_REMOTE_USER" request env var' do
let(:env) { { 'HTTP_REMOTE_USER' => login } }
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/auth/sso', as: :json, env: env
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Maintenance mode enabled!')
end
end
@ -117,10 +117,10 @@ RSpec.describe 'Sessions endpoints', type: :request do
context 'in "X-Forwarded-User" request header' do
let(:headers) { { 'X-Forwarded-User' => login } }
it 'returns 401 unauthorized' do
it 'returns 403 Forbidden' do
get '/auth/sso', as: :json, headers: headers
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to include('error' => 'Maintenance mode enabled!')
end
end

View File

@ -24,15 +24,15 @@ RSpec.describe 'Settings', type: :request do
# index
get '/api/v1/settings', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['settings']).to be_falsey
# show
setting = Setting.find_by(name: 'product_name')
get "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Authentication required')
end
it 'does settings index with admin' do
@ -108,7 +108,7 @@ RSpec.describe 'Settings', type: :request do
# delete
setting = Setting.find_by(name: 'product_name')
delete "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (feature not possible)')
end
@ -136,7 +136,7 @@ RSpec.describe 'Settings', type: :request do
# show
setting = Setting.find_by(name: 'product_name')
get "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (required ["admin.branding"])!')
setting = Setting.find_by(name: 'api_token_access')
@ -156,7 +156,7 @@ RSpec.describe 'Settings', type: :request do
}
}
put "/api/v1/settings/#{setting.id}", params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (required ["admin.branding"])!')
# update
@ -180,7 +180,7 @@ RSpec.describe 'Settings', type: :request do
# delete
setting = Setting.find_by(name: 'product_name')
delete "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (feature not possible)')
end
@ -189,7 +189,7 @@ RSpec.describe 'Settings', type: :request do
# index
authenticated_as(agent)
get '/api/v1/settings', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['settings']).to be_falsey
expect(json_response['error']).to eq('Not authorized (user)!')
@ -197,7 +197,7 @@ RSpec.describe 'Settings', type: :request do
# show
setting = Setting.find_by(name: 'product_name')
get "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
end
@ -206,7 +206,7 @@ RSpec.describe 'Settings', type: :request do
# index
authenticated_as(customer)
get '/api/v1/settings', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['settings']).to be_falsey
expect(json_response['error']).to eq('Not authorized (user)!')
@ -214,13 +214,13 @@ RSpec.describe 'Settings', type: :request do
# show
setting = Setting.find_by(name: 'product_name')
get "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
# delete
setting = Setting.find_by(name: 'product_name')
delete "/api/v1/settings/#{setting.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
end
end

View File

@ -10,10 +10,10 @@ RSpec.describe 'SLAs', type: :request do
it 'does index sla with nobody' do
get '/api/v1/slas', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Authentication required')
end
it 'does index sla with admin' do

View File

@ -18,7 +18,7 @@ RSpec.describe 'Text Module', type: :request do
it 'does csv example - customer no access' do
authenticated_as(customer)
get '/api/v1/text_modules/import_example', as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
end

View File

@ -33,8 +33,8 @@ RSpec.describe 'Ticket Article Attachments', type: :request do
authenticated_as(agent)
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store1.id}", params: {}
expect(response).to have_http_status(:unauthorized)
expect(@response.body).to match(/401: Unauthorized/)
expect(response).to have_http_status(:forbidden)
expect(@response.body).to match(/403: Forbidden/)
ticket2 = create(:ticket, group: group)
ticket1.merge_to(
@ -49,8 +49,8 @@ RSpec.describe 'Ticket Article Attachments', type: :request do
authenticated_as(agent)
get "/api/v1/ticket_attachment/#{ticket2.id}/#{article2.id}/#{store1.id}", params: {}
expect(response).to have_http_status(:unauthorized)
expect(@response.body).to match(/401: Unauthorized/)
expect(response).to have_http_status(:forbidden)
expect(@response.body).to match(/403: Forbidden/)
# allow access via merged ticket id also
authenticated_as(agent)
@ -60,8 +60,8 @@ RSpec.describe 'Ticket Article Attachments', type: :request do
authenticated_as(agent)
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store1.id}", params: {}
expect(response).to have_http_status(:unauthorized)
expect(@response.body).to match(/401: Unauthorized/)
expect(response).to have_http_status(:forbidden)
expect(@response.body).to match(/403: Forbidden/)
end

View File

@ -262,12 +262,12 @@ AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
expect(ticket.articles[4].attachments.count).to eq(0)
get "/api/v1/ticket_articles/#{article.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
put "/api/v1/ticket_articles/#{article.id}", params: { internal: false }, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')

View File

@ -84,7 +84,7 @@ RSpec.describe 'Ticket', type: :request do
}
authenticated_as(agent_change_only)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
end
@ -772,7 +772,7 @@ RSpec.describe 'Ticket', type: :request do
)
authenticated_as(agent)
get "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
@ -780,12 +780,12 @@ RSpec.describe 'Ticket', type: :request do
title: 'ticket with wrong ticket id - 2',
}
put "/api/v1/tickets/#{ticket.id}", params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
delete "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
end
@ -923,12 +923,12 @@ RSpec.describe 'Ticket', type: :request do
expect(json_response['internal']).to eq(false)
delete "/api/v1/ticket_articles/#{json_response['id']}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (communication articles cannot be deleted)!')
delete "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (admin permission required)!')
end
@ -1022,7 +1022,7 @@ RSpec.describe 'Ticket', type: :request do
expect(json_response['type_id']).to eq(Ticket::Article::Type.lookup(name: 'email').id)
delete "/api/v1/ticket_articles/#{json_response['id']}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
delete "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:ok)
@ -1177,7 +1177,7 @@ RSpec.describe 'Ticket', type: :request do
)
authenticated_as(customer)
get "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
@ -1185,12 +1185,12 @@ RSpec.describe 'Ticket', type: :request do
title: 'ticket with wrong ticket id - 2',
}
put "/api/v1/tickets/#{ticket.id}", params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
delete "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
end
@ -1266,7 +1266,7 @@ RSpec.describe 'Ticket', type: :request do
expect(json_response['tickets_count']).to eq(1)
delete "/api/v1/ticket_articles/#{article_json_response['id']}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (agent permission required)!')
@ -1290,7 +1290,7 @@ RSpec.describe 'Ticket', type: :request do
expect(json_response['type_id']).to eq(Ticket::Article::Type.lookup(name: 'note').id)
delete "/api/v1/ticket_articles/#{json_response['id']}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (agent permission required)!')
@ -1321,12 +1321,12 @@ RSpec.describe 'Ticket', type: :request do
subject: 'new subject',
}
put "/api/v1/ticket_articles/#{json_response['id']}", params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (ticket.agent or admin permission required)!')
delete "/api/v1/tickets/#{ticket.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized (admin permission required)!')
end
@ -1826,7 +1826,7 @@ RSpec.describe 'Ticket', type: :request do
authenticated_as(customer)
get "/api/v1/ticket_split?ticket_id=#{ticket.id}&article_id=#{article.id}&form_id=new_form_id123", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
authenticated_as(agent)
get "/api/v1/ticket_split?ticket_id=#{ticket.id}&article_id=#{article.id}&form_id=new_form_id123", params: {}, as: :json
@ -1955,7 +1955,7 @@ RSpec.describe 'Ticket', type: :request do
authenticated_as(customer)
put "/api/v1/ticket_merge/#{ticket2.id}/#{ticket1.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
authenticated_as(agent)
put "/api/v1/ticket_merge/#{ticket2.id}/#{ticket1.id}", params: {}, as: :json
@ -1965,13 +1965,13 @@ RSpec.describe 'Ticket', type: :request do
expect(json_response['message']).to eq('No such master ticket number!')
put "/api/v1/ticket_merge/#{ticket3.id}/#{ticket1.number}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
expect(json_response['error_human']).to eq('Not authorized')
put "/api/v1/ticket_merge/#{ticket1.id}/#{ticket3.number}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('Not authorized')
expect(json_response['error_human']).to eq('Not authorized')
@ -2110,7 +2110,7 @@ RSpec.describe 'Ticket', type: :request do
authenticated_as(customer)
get "/api/v1/ticket_history/#{ticket1.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does ticket related' do
@ -2127,7 +2127,7 @@ RSpec.describe 'Ticket', type: :request do
authenticated_as(customer)
get "/api/v1/ticket_related/#{ticket1.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does ticket recent' do
@ -2137,7 +2137,7 @@ RSpec.describe 'Ticket', type: :request do
authenticated_as(customer)
get '/api/v1/ticket_recent', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
end

View File

@ -133,7 +133,7 @@ RSpec.describe 'User Organization', type: :request, searchindex: true do
# search
Scheduler.worker(true)
get "/api/v1/organizations/search?query=#{CGI.escape('Zammad')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does organization index with customer2' do
@ -150,14 +150,14 @@ RSpec.describe 'User Organization', type: :request, searchindex: true do
expect('Rest Org').to eq(json_response['name'])
get "/api/v1/organizations/#{organization2.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['name']).to be_nil
# search
Scheduler.worker(true)
get "/api/v1/organizations/search?query=#{CGI.escape('Zammad')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
end
end

View File

@ -20,7 +20,7 @@ RSpec.describe 'User endpoint', type: :request do
let(:attributes) { attributes_params_for(:user) }
it 'responds unauthorized for customer' do
it 'responds forbidden for customer' do
requester = create(:customer)
authenticated_as(requester)
@ -30,7 +30,7 @@ RSpec.describe 'User endpoint', type: :request do
User.count
}
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
context 'privileged attributes' do
@ -58,7 +58,7 @@ RSpec.describe 'User endpoint', type: :request do
expect(User.last.send(map_method_id)).to eq(send(map_method_id))
end
it 'responds unauthorized for sub admin without admin.user' do
it 'responds forbidden for sub admin without admin.user' do
authenticated_as(admin_without_admin_user_permissions)
expect do
@ -67,7 +67,7 @@ RSpec.describe 'User endpoint', type: :request do
User.count
}
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'responds successful for agent but removes assignment' do
@ -131,7 +131,7 @@ RSpec.describe 'User endpoint', type: :request do
expect(User.last.roles).to eq(privileged)
end
it 'responds unauthorized for sub admin without admin.user' do
it 'responds forbidden for sub admin without admin.user' do
authenticated_as(admin_without_admin_user_permissions)
expect do
@ -140,7 +140,7 @@ RSpec.describe 'User endpoint', type: :request do
User.count
}
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'responds successful for agent but removes assignment' do
@ -193,7 +193,7 @@ RSpec.describe 'User endpoint', type: :request do
expect(response).to have_http_status(:success)
end
def unauthorized_update_request(requester:, requested:)
def forbidden_update_request(requester:, requested:)
authenticated_as(requester)
expect do
@ -211,7 +211,7 @@ RSpec.describe 'User endpoint', type: :request do
end
}
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
context 'request by admin.user' do
@ -251,29 +251,29 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { admin_without_admin_user_permissions }
it 'is unauthorized for same admin' do
unauthorized_update_request(
it 'is forbidden for same admin' do
forbidden_update_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other admin' do
unauthorized_update_request(
it 'is forbidden for other admin' do
forbidden_update_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized for agent' do
unauthorized_update_request(
it 'is forbidden for agent' do
forbidden_update_request(
requester: requester,
requested: create(:agent),
)
end
it 'is unauthorized for customer' do
unauthorized_update_request(
it 'is forbidden for customer' do
forbidden_update_request(
requester: requester,
requested: create(:customer),
)
@ -284,22 +284,22 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { create(:agent) }
it 'is unauthorized for admin' do
unauthorized_update_request(
it 'is forbidden for admin' do
forbidden_update_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized same agent' do
unauthorized_update_request(
it 'is forbidden same agent' do
forbidden_update_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other agent' do
unauthorized_update_request(
it 'is forbidden for other agent' do
forbidden_update_request(
requester: requester,
requested: create(:agent),
)
@ -317,40 +317,40 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { create(:customer) }
it 'is unauthorized for admin' do
unauthorized_update_request(
it 'is forbidden for admin' do
forbidden_update_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized for agent' do
unauthorized_update_request(
it 'is forbidden for agent' do
forbidden_update_request(
requester: requester,
requested: create(:agent),
)
end
it 'is unauthorized for same customer' do
unauthorized_update_request(
it 'is forbidden for same customer' do
forbidden_update_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other customer' do
unauthorized_update_request(
it 'is forbidden for other customer' do
forbidden_update_request(
requester: requester,
requested: create(:customer),
)
end
it 'is unauthorized for same organization' do
it 'is forbidden for same organization' do
same_organization = create(:organization)
requester.update!(organization: same_organization)
unauthorized_update_request(
forbidden_update_request(
requester: requester,
requested: create(:customer, organization: same_organization),
)
@ -383,7 +383,7 @@ RSpec.describe 'User endpoint', type: :request do
expect(response).to have_http_status(:success)
end
it 'responds unauthorized for sub admin without admin.user' do
it 'responds forbidden for sub admin without admin.user' do
authenticated_as(admin_without_admin_user_permissions)
expect do
@ -392,7 +392,7 @@ RSpec.describe 'User endpoint', type: :request do
value_of_attribute
}
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
end
@ -522,12 +522,12 @@ RSpec.describe 'User endpoint', type: :request do
expect(requested).not_to exist_in_database
end
def unauthorized_destroy_request(requester:, requested:)
def forbidden_destroy_request(requester:, requested:)
authenticated_as(requester)
delete api_v1_delete_user_path(requested)
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(requested).to exist_in_database
end
@ -568,29 +568,29 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { admin_without_admin_user_permissions }
it 'is unauthorized for same admin' do
unauthorized_destroy_request(
it 'is forbidden for same admin' do
forbidden_destroy_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other admin' do
unauthorized_destroy_request(
it 'is forbidden for other admin' do
forbidden_destroy_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized for agent' do
unauthorized_destroy_request(
it 'is forbidden for agent' do
forbidden_destroy_request(
requester: requester,
requested: create(:agent),
)
end
it 'is unauthorized for customer' do
unauthorized_destroy_request(
it 'is forbidden for customer' do
forbidden_destroy_request(
requester: requester,
requested: create(:customer),
)
@ -601,29 +601,29 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { create(:agent) }
it 'is unauthorized for admin' do
unauthorized_destroy_request(
it 'is forbidden for admin' do
forbidden_destroy_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized same agent' do
unauthorized_destroy_request(
it 'is forbidden same agent' do
forbidden_destroy_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other agent' do
unauthorized_destroy_request(
it 'is forbidden for other agent' do
forbidden_destroy_request(
requester: requester,
requested: create(:agent),
)
end
it 'is unauthorized for customer' do
unauthorized_destroy_request(
it 'is forbidden for customer' do
forbidden_destroy_request(
requester: requester,
requested: create(:customer),
)
@ -634,40 +634,40 @@ RSpec.describe 'User endpoint', type: :request do
let(:requester) { create(:customer) }
it 'is unauthorized for admin' do
unauthorized_destroy_request(
it 'is forbidden for admin' do
forbidden_destroy_request(
requester: requester,
requested: create(:admin),
)
end
it 'is unauthorized for agent' do
unauthorized_destroy_request(
it 'is forbidden for agent' do
forbidden_destroy_request(
requester: requester,
requested: create(:agent),
)
end
it 'is unauthorized for same customer' do
unauthorized_destroy_request(
it 'is forbidden for same customer' do
forbidden_destroy_request(
requester: requester,
requested: requester,
)
end
it 'is unauthorized for other customer' do
unauthorized_destroy_request(
it 'is forbidden for other customer' do
forbidden_destroy_request(
requester: requester,
requested: create(:customer),
)
end
it 'is unauthorized for same organization' do
it 'is forbidden for same organization' do
same_organization = create(:organization)
requester.update!(organization: same_organization)
unauthorized_destroy_request(
forbidden_destroy_request(
requester: requester,
requested: create(:customer, organization: same_organization),
)

View File

@ -154,13 +154,13 @@ RSpec.describe 'User', type: :request do
# no user (because of no session)
get '/api/v1/users', params: {}, headers: headers, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Authentication required')
# me
get '/api/v1/users/me', params: {}, headers: headers, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Authentication required')
end
context 'password security' do
@ -182,25 +182,25 @@ RSpec.describe 'User', type: :request do
authenticated_as(nil, login: 'not_existing@example.com', password: 'adminpw')
get '/api/v1/users/me', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
get '/api/v1/users', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does auth tests - username auth, wrong pw' do
authenticated_as(admin, password: 'not_existing')
get '/api/v1/users', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does auth tests - email auth, wrong pw' do
authenticated_as(nil, login: 'rest-admin@example.com', password: 'not_existing')
get '/api/v1/users', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(json_response['error']).to eq('authentication failed')
expect(json_response['error']).to eq('Invalid BasicAuth credentials')
end
it 'does auth tests - username auth' do
@ -507,7 +507,7 @@ RSpec.describe 'User', type: :request do
expect('rest-customer1@example.com').to eq(json_response['email'])
get "/api/v1/users/#{customer2.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(Hash).to eq(json_response.class)
expect(json_response['error']).to be_truthy
@ -515,18 +515,18 @@ RSpec.describe 'User', type: :request do
role = Role.lookup(name: 'Admin')
params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin_by_customer1@example.com', role_ids: [ role.id ] }
post '/api/v1/users', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
# create user with agent role
role = Role.lookup(name: 'Agent')
params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent_by_customer1@example.com', role_ids: [ role.id ] }
post '/api/v1/users', params: params, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
# search
Scheduler.worker(true)
get "/api/v1/users/search?query=#{CGI.escape('First')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does user index with customer2' do
@ -549,14 +549,14 @@ RSpec.describe 'User', type: :request do
expect('rest-customer2@example.com').to eq(json_response['email'])
get "/api/v1/users/#{customer.id}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(Hash).to eq(json_response.class)
expect(json_response['error']).to be_truthy
# search
Scheduler.worker(true)
get "/api/v1/users/search?query=#{CGI.escape('First')}", params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'does users show and response format (04.01)' do
@ -847,7 +847,7 @@ RSpec.describe 'User', type: :request do
authenticated_as(customer)
get '/api/v1/users/import_example', params: {}, as: :json
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
expect(json_response['error']).to eq('Not authorized (user)!')
end
@ -1172,7 +1172,7 @@ RSpec.describe 'User', type: :request do
it 'does not accept requests from customers', authenticated_as: -> { create(:customer) } do
make_request successful_params
expect(response).to have_http_status(:unauthorized)
expect(response).to have_http_status(:forbidden)
end
it 'admins can give any role', authenticated_as: -> { create(:admin) } do