Maintenance: Show less error details to non-admin users

This commit is contained in:
Mantas Masalskis 2020-08-14 14:52:20 +02:00 committed by Thorsten Eckel
parent 1c96163ada
commit 9dd2b59037
10 changed files with 521 additions and 256 deletions

View file

@ -394,6 +394,7 @@ Metrics/BlockLength:
- 'config/environments/development.rb' - 'config/environments/development.rb'
- 'config/initializers/omniauth.rb' - 'config/initializers/omniauth.rb'
- 'config/routes/knowledge_base.rb' - 'config/routes/knowledge_base.rb'
- 'config/routes/user.rb'
- 'config/routes/test.rb' - 'config/routes/test.rb'
- 'config/routes/ticket.rb' - 'config/routes/ticket.rb'
- 'db/migrate/20120101000001_create_base.rb' - 'db/migrate/20120101000001_create_base.rb'

View file

@ -96,15 +96,12 @@ class Index extends App.ControllerContent
if !_.isEmpty(detailsRaw) if !_.isEmpty(detailsRaw)
details = JSON.parse(detailsRaw) details = JSON.parse(detailsRaw)
# add notify errorMessage = App.i18n.translateContent(details.error || 'Could not process your request')
@notify
type: 'error'
msg: App.i18n.translateContent(details.error || 'Wrong Username or Password combination.')
removeAll: true
# rerender login page # rerender login page
@render( @render(
username: @username username: @username
errorMessage: errorMessage
) )
# login shake # login shake

View file

@ -114,7 +114,7 @@ class Index extends App.ControllerContent
@notify @notify
type: 'error' type: 'error'
msg: App.i18n.translateContent(details.error || 'Wrong Username or Password combination.') msg: App.i18n.translateContent(details.error || 'Could not process your request')
removeAll: true removeAll: true
App.Config.set('signup', Index, 'Routes') App.Config.set('signup', Index, 'Routes')

View file

@ -13,6 +13,12 @@
<div class="hero-unit"> <div class="hero-unit">
<img class="company-logo" src="<%= @logoUrl %>" alt="<%= @C('product_name') %>"> <img class="company-logo" src="<%= @logoUrl %>" alt="<%= @C('product_name') %>">
<form id="login"> <form id="login">
<% if @item.errorMessage: %>
<div class="alert alert--danger" role="alert">
<%= @item.errorMessage %>
</div>
<% end %>
<div class="form-group"> <div class="form-group">
<div class="formGroup-label"> <div class="formGroup-label">
<label for="username"><%- @Ti('Username / email') %></label> <label for="username"><%- @Ti('Username / email') %></label>

View file

@ -135,7 +135,7 @@ module ApplicationController::Authenticates
def authenticate_with_password def authenticate_with_password
user = User.authenticate(params[:username], params[:password]) user = User.authenticate(params[:username], params[:password])
raise Exceptions::NotAuthorized, 'Wrong Username or Password combination.' if !user raise_unified_login_error if !user
session.delete(:switched_from_user_id) session.delete(:switched_from_user_id)
authentication_check_prerequesits(user, 'session', {}) authentication_check_prerequesits(user, 'session', {})
@ -158,7 +158,8 @@ module ApplicationController::Authenticates
def authentication_check_prerequesits(user, auth_type, auth_param) def authentication_check_prerequesits(user, auth_type, auth_param)
raise Exceptions::NotAuthorized, 'Maintenance mode enabled!' if in_maintenance_mode?(user) raise Exceptions::NotAuthorized, 'Maintenance mode enabled!' if in_maintenance_mode?(user)
raise Exceptions::NotAuthorized, 'User is inactive!' if !user.active
raise_unified_login_error if !user.active
if auth_param[:permission] if auth_param[:permission]
ActiveSupport::Deprecation.warn("Parameter ':permission' is deprecated. Use Pundit policy and `authorize!` instead.") ActiveSupport::Deprecation.warn("Parameter ':permission' is deprecated. Use Pundit policy and `authorize!` instead.")
@ -173,4 +174,8 @@ module ApplicationController::Authenticates
logger.debug { "#{auth_type} for '#{user.login}'" } logger.debug { "#{auth_type} for '#{user.login}'" }
user user
end end
def raise_unified_login_error
raise Exceptions::NotAuthorized, 'Login failed. Have you double-checked your credentials and completed the email verification step?'
end
end end

View file

@ -5,7 +5,7 @@ class UsersController < ApplicationController
prepend_before_action -> { authorize! }, only: %i[import_example import_start search history] prepend_before_action -> { authorize! }, only: %i[import_example import_start search history]
prepend_before_action :authentication_check, except: %i[create password_reset_send password_reset_verify image email_verify email_verify_send] prepend_before_action :authentication_check, except: %i[create password_reset_send password_reset_verify image email_verify email_verify_send]
prepend_before_action :authentication_check_only, only: [:create] prepend_before_action :authentication_check_only, only: %i[create]
# @path [GET] /users # @path [GET] /users
# #
@ -99,158 +99,16 @@ class UsersController < ApplicationController
# @path [POST] /users # @path [POST] /users
# #
# @summary Creates a User record with the provided attribute values. # @summary processes requests as CRUD-like record creation, admin creation or user signup depending on circumstances
# @notes TODO. # @see #create_internal #create_admin #create_signup
#
# @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.
def create def create
clean_params = User.association_name_to_id_convert(params) if current_user
clean_params = User.param_cleanup(clean_params, true) create_internal
elsif params[:signup]
# check if it's first user, the admin user create_signup
# initial admin account
count = User.all.count
admin_account_exists = true
if count <= 2
admin_account_exists = false
end
# if it's a signup, add user to customer role
if !current_user
# check if feature is enabled
if admin_account_exists && !Setting.get('user_create_account')
raise Exceptions::UnprocessableEntity, 'Feature not enabled!'
end
# check signup option only after admin account is created
if admin_account_exists && !params[:signup]
raise Exceptions::UnprocessableEntity, 'Only signup with not authenticate user possible!'
end
# check if user already exists
if clean_params[:email].blank?
raise Exceptions::UnprocessableEntity, 'Attribute \'email\' required!'
end
# check if user already exists
exists = User.exists?(email: clean_params[:email].downcase.strip)
raise Exceptions::UnprocessableEntity, "Email address '#{clean_params[:email].downcase.strip}' is already used for other user." if exists
# check password policy
if clean_params[:password].present?
result = password_policy(clean_params[:password])
raise Exceptions::UnprocessableEntity, result if result != true
end
user = User.new(clean_params)
user.associations_from_param(params)
user.updated_by_id = 1
user.created_by_id = 1
# add first user as admin/agent and to all groups
group_ids = []
role_ids = []
if count <= 2
Role.where(name: %w[Admin Agent]).each do |role|
role_ids.push role.id
end
Group.all.each do |group|
group_ids.push group.id
end
# everybody else will go as customer per default
else
role_ids = Role.signup_role_ids
end
user.role_ids = role_ids
user.group_ids = group_ids
# remember source (in case show email verify banner)
# if not initial user creation
if admin_account_exists
user.source = 'signup'
end
# else do assignment as defined
else else
create_admin
# permission check
check_attributes_by_current_user_permission(params)
user = User.new(clean_params)
user.associations_from_param(params)
end end
user.save!
# if first user was added, set system init done
if !admin_account_exists
Setting.set('system_init_done', true)
# fetch org logo
if user.email.present?
Service::Image.organization_suggest(user.email)
end
# load calendar
Calendar.init_setup(request.remote_ip)
# load text modules
begin
TextModule.load(request.env['HTTP_ACCEPT_LANGUAGE'] || 'en-us')
rescue => e
logger.error "Unable to load text modules #{request.env['HTTP_ACCEPT_LANGUAGE'] || 'en-us'}: #{e.message}"
end
end
# send invitation if needed / only if session exists
if params[:invite].present? && current_user
sleep 5 if ENV['REMOTE_URL'].present?
token = Token.create(action: 'PasswordReset', user_id: user.id)
NotificationFactory::Mailer.notification(
template: 'user_invite',
user: user,
objects: {
token: token,
user: user,
current_user: current_user,
}
)
end
# send email verify
if params[:signup].present? && !current_user
result = User.signup_new_token(user)
NotificationFactory::Mailer.notification(
template: 'signup',
user: user,
objects: result,
)
end
if response_expand?
user = user.reload.attributes_with_association_names
user.delete('password')
render json: user, status: :created
return
end
if response_full?
result = {
id: user.id,
assets: user.assets({}),
}
render json: result, status: :created
return
end
user = user.reload.attributes_with_association_ids
user.delete('password')
render json: user, status: :created
end end
# @path [PUT] /users/{id} # @path [PUT] /users/{id}
@ -1043,4 +901,173 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
true true
end end
def clean_user_params
User.param_cleanup(User.association_name_to_id_convert(params), true)
end
# @summary Creates a User record with the provided attribute values.
# @notes For creating a user via agent interface
#
# @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.
def create_internal
# permission check
check_attributes_by_current_user_permission(params)
user = User.new(clean_user_params)
user.associations_from_param(params)
user.save!
if params[:invite].present?
sleep 5 if ENV['REMOTE_URL'].present?
token = Token.create(action: 'PasswordReset', user_id: user.id)
NotificationFactory::Mailer.notification(
template: 'user_invite',
user: user,
objects: {
token: token,
user: user,
current_user: current_user,
}
)
end
if response_expand?
user = user.reload.attributes_with_association_names
user.delete('password')
render json: user, status: :created
return
end
if response_full?
result = {
id: user.id,
assets: user.assets({}),
}
render json: result, status: :created
return
end
user = user.reload.attributes_with_association_ids
user.delete('password')
render json: user, status: :created
end
# @summary Creates a User record with the provided attribute values.
# @notes For creating a user via public signup form
#
# @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.
def create_signup
# check if feature is enabled
if !Setting.get('user_create_account')
raise Exceptions::UnprocessableEntity, 'Feature not enabled!'
end
# check signup option only after admin account is created
if !params[:signup]
raise Exceptions::UnprocessableEntity, 'Only signup with not authenticate user possible!'
end
# check if user already exists
if clean_user_params[:email].blank?
raise Exceptions::UnprocessableEntity, 'Attribute \'email\' required!'
end
email_taken_by = User.find_by email: clean_user_params[:email].downcase.strip
result = (password = clean_user_params[:password]) && password_policy(password)
raise Exceptions::UnprocessableEntity, 'Only signup with a password!' if result.nil?
raise Exceptions::UnprocessableEntity, result if result != true
user = User.new(clean_user_params)
user.associations_from_param(params)
user.role_ids = Role.signup_role_ids
user.source = 'signup'
if email_taken_by # show fake OK response to avoid leaking that email is already in use
User.without_callback :validation, :before, :ensure_uniq_email do # skip unique email validation
user.valid? # trigger errors raised in validations
end
result = User.password_reset_new_token(email_taken_by.email)
NotificationFactory::Mailer.notification(
template: 'signup_taken_reset',
user: email_taken_by,
objects: result,
)
render json: { message: 'ok' }, status: :created
return
end
UserInfo.ensure_current_user_id do
user.save!
end
result = User.signup_new_token(user)
NotificationFactory::Mailer.notification(
template: 'signup',
user: user,
objects: result,
)
render json: { message: 'ok' }, status: :created
end
# @summary Creates a User record with the provided attribute values.
# @notes For creating an administrator account when setting up the system
#
# @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.
def create_admin
if User.count > 2 # system and example users
raise Exceptions::UnprocessableEntity, 'Administrator account already created'
end
# check if user already exists
if clean_user_params[:email].blank?
raise Exceptions::UnprocessableEntity, 'Attribute \'email\' required!'
end
# check password policy
result = (password = clean_user_params[:password]) && password_policy(password)
raise Exceptions::UnprocessableEntity, result if result != true
user = User.new(clean_user_params)
user.associations_from_param(params)
user.role_ids = Role.where(name: %w[Admin Agent]).pluck(:id)
user.group_ids = Group.all.pluck(:id)
UserInfo.ensure_current_user_id do
user.save!
end
Setting.set('system_init_done', true)
# fetch org logo
if user.email.present?
Service::Image.organization_suggest(user.email)
end
# load calendar
Calendar.init_setup(request.remote_ip)
# load text modules
begin
TextModule.load(request.env['HTTP_ACCEPT_LANGUAGE'] || 'en-us')
rescue => e
logger.error "Unable to load text modules #{request.env['HTTP_ACCEPT_LANGUAGE'] || 'en-us'}: #{e.message}"
end
render json: { message: 'ok' }, status: :created
end
end end

View file

@ -0,0 +1,15 @@
Reset your #{config.product_name} password
<div>Hi #{user.firstname},</div>
<br>
<div>You or someone else tried to sign up with this email address. However, this email is already being used.</div>
<br>
<div>If you want to reset your password, click on the link below (or copy and paste the URL into your browser):</div>
<br>
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
<br>
<div>This link takes you to a page where you can change your password.</div>
<br>
<div>If you don't want to reset your password, please ignore this message. Your password will not be reset.</div>
<br>
<div>Your #{config.product_name} Team</div>

View file

@ -142,7 +142,7 @@ RSpec.describe 'Api Auth', type: :request do
get '/api/v1/sessions', params: {}, as: :json get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash) expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('User is inactive!') expect(json_response['error']).to eq('Login failed. Have you double-checked your credentials and completed the email verification step?')
admin_token.preferences[:permission] = ['admin.session'] admin_token.preferences[:permission] = ['admin.session']
admin_token.save! admin_token.save!
@ -150,7 +150,7 @@ RSpec.describe 'Api Auth', type: :request do
get '/api/v1/sessions', params: {}, as: :json get '/api/v1/sessions', params: {}, as: :json
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(json_response).to be_a_kind_of(Hash) expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('User is inactive!') expect(json_response['error']).to eq('Login failed. Have you double-checked your credentials and completed the email verification step?')
admin.active = true admin.active = true
admin.save! admin.save!
@ -344,7 +344,7 @@ RSpec.describe 'Api Auth', type: :request do
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(response.header).not_to be_key('Access-Control-Allow-Origin') expect(response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash) expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq('User is inactive!') expect(json_response['error']).to eq('Login failed. Have you double-checked your credentials and completed the email verification step?')
end end
it 'does token auth - expired' do it 'does token auth - expired' do

View file

@ -1,82 +1,71 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'User', type: :request, searchindex: true do RSpec.describe 'User', type: :request do
let!(:admin) do describe 'request handling', searchindex: true do
create( let!(:admin) do
:admin, create(
groups: Group.all, :admin,
login: 'rest-admin', groups: Group.all,
firstname: 'Rest', login: 'rest-admin',
lastname: 'Agent', firstname: 'Rest',
email: 'rest-admin@example.com', lastname: 'Agent',
) email: 'rest-admin@example.com',
end )
let!(:admin_with_pw) do end
create( let!(:admin_with_pw) do
:admin, create(
groups: Group.all, :admin,
login: 'rest-admin-pw', groups: Group.all,
firstname: 'Rest', login: 'rest-admin-pw',
lastname: 'Agent', firstname: 'Rest',
email: 'rest-admin-pw@example.com', lastname: 'Agent',
password: 'adminpw', email: 'rest-admin-pw@example.com',
) password: 'adminpw',
end )
let!(:agent) do end
create( let!(:agent) do
:agent, create(
groups: Group.all, :agent,
login: 'rest-agent@example.com', groups: Group.all,
firstname: 'Rest', login: 'rest-agent@example.com',
lastname: 'Agent', firstname: 'Rest',
email: 'rest-agent@example.com', lastname: 'Agent',
) email: 'rest-agent@example.com',
end )
let!(:customer) do end
create( let!(:customer) do
:customer, create(
login: 'rest-customer1@example.com', :customer,
firstname: 'Rest', login: 'rest-customer1@example.com',
lastname: 'Customer1', firstname: 'Rest',
email: 'rest-customer1@example.com', lastname: 'Customer1',
) email: 'rest-customer1@example.com',
end )
let!(:organization) do end
create(:organization, name: 'Rest Org') let!(:organization) do
end create(:organization, name: 'Rest Org')
let!(:organization2) do end
create(:organization, name: 'Rest Org #2') let!(:organization2) do
end create(:organization, name: 'Rest Org #2')
let!(:organization3) do end
create(:organization, name: 'Rest Org #3') let!(:organization3) do
end create(:organization, name: 'Rest Org #3')
let!(:customer2) do end
create( let!(:customer2) do
:customer, create(
organization: organization, :customer,
login: 'rest-customer2@example.com', organization: organization,
firstname: 'Rest', login: 'rest-customer2@example.com',
lastname: 'Customer2', firstname: 'Rest',
email: 'rest-customer2@example.com', lastname: 'Customer2',
) email: 'rest-customer2@example.com',
end )
before do
configure_elasticsearch do
travel 1.minute
rebuild_searchindex
# execute background jobs
Scheduler.worker(true)
sleep 6
end end
end
describe 'request handling' do before do
configure_elasticsearch(rebuild: true)
end
it 'does user create tests - no user' do it 'does user create tests - no user' do
@ -87,7 +76,7 @@ RSpec.describe 'User', type: :request, searchindex: true do
token = @response.headers['CSRF-TOKEN'] token = @response.headers['CSRF-TOKEN']
# token based on form # token based on form
params = { email: 'some_new_customer@example.com', authenticity_token: token } params = { email: 'some_new_customer@example.com', signup: true, authenticity_token: token }
post '/api/v1/users', params: params, as: :json post '/api/v1/users', params: params, as: :json
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(json_response['error']).to be_truthy expect(json_response['error']).to be_truthy
@ -95,7 +84,7 @@ RSpec.describe 'User', type: :request, searchindex: true do
# token based on headers # token based on headers
headers = { 'X-CSRF-Token' => token } headers = { 'X-CSRF-Token' => token }
params = { email: 'some_new_customer@example.com' } params = { email: 'some_new_customer@example.com', signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(json_response['error']).to be_truthy expect(json_response['error']).to be_truthy
@ -103,19 +92,18 @@ RSpec.describe 'User', type: :request, searchindex: true do
Setting.set('user_create_account', true) Setting.set('user_create_account', true)
# no signup param with enabled feature # no signup param without password
params = { email: 'some_new_customer@example.com' } params = { email: 'some_new_customer@example.com', signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(json_response['error']).to be_truthy expect(json_response['error']).to be_truthy
expect(json_response['error']).to eq('Only signup with not authenticate user possible!') expect(json_response['error']).to eq('Only signup with a password!')
# already existing user with enabled feature # already existing user with enabled feature, pretend signup is successful
params = { email: 'rest-customer1@example.com', signup: true } params = { email: 'rest-customer1@example.com', password: 'asd1ASD', signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:created)
expect(json_response['error']).to be_truthy expect(json_response).to be_truthy
expect(json_response['error']).to eq("Email address 'rest-customer1@example.com' is already used for other user.")
# email missing with enabled feature # email missing with enabled feature
params = { firstname: 'some firstname', signup: true } params = { firstname: 'some firstname', signup: true }
@ -132,38 +120,35 @@ RSpec.describe 'User', type: :request, searchindex: true do
expect(json_response['error']).to eq('Attribute \'email\' required!') expect(json_response['error']).to eq('Attribute \'email\' required!')
# create user with enabled feature (take customer role) # create user with enabled feature (take customer role)
params = { firstname: 'Me First', lastname: 'Me Last', email: 'new_here@example.com', signup: true } params = { firstname: 'Me First', lastname: 'Me Last', password: 'asd1ASD', email: 'new_here@example.com', signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:created) expect(response).to have_http_status(:created)
expect(json_response).to be_truthy expect(json_response).to be_truthy
expect(json_response['message']).to eq('ok')
expect(json_response['firstname']).to eq('Me First') user = User.find_by email: 'new_here@example.com'
expect(json_response['lastname']).to eq('Me Last')
expect(json_response['login']).to eq('new_here@example.com')
expect(json_response['email']).to eq('new_here@example.com')
user = User.find(json_response['id'])
expect(user).not_to be_role('Admin') expect(user).not_to be_role('Admin')
expect(user).not_to be_role('Agent') expect(user).not_to be_role('Agent')
expect(user).to be_role('Customer') expect(user).to be_role('Customer')
# create user with admin role (not allowed for signup, take customer role) # create user with admin role (not allowed for signup, take customer role)
role = Role.lookup(name: 'Admin') role = Role.lookup(name: 'Admin')
params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin@example.com', role_ids: [ role.id ], signup: true } params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin@example.com', password: 'asd1ASD', role_ids: [ role.id ], signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:created) expect(response).to have_http_status(:created)
expect(json_response).to be_truthy expect(json_response).to be_truthy
user = User.find(json_response['id']) user = User.find_by email: 'new_admin@example.com'
expect(user).not_to be_role('Admin') expect(user).not_to be_role('Admin')
expect(user).not_to be_role('Agent') expect(user).not_to be_role('Agent')
expect(user).to be_role('Customer') expect(user).to be_role('Customer')
# create user with agent role (not allowed for signup, take customer role) # create user with agent role (not allowed for signup, take customer role)
role = Role.lookup(name: 'Agent') role = Role.lookup(name: 'Agent')
params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent@example.com', role_ids: [ role.id ], signup: true } params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent@example.com', password: 'asd1ASD', role_ids: [ role.id ], signup: true }
post '/api/v1/users', params: params, headers: headers, as: :json post '/api/v1/users', params: params, headers: headers, as: :json
expect(response).to have_http_status(:created) expect(response).to have_http_status(:created)
expect(json_response).to be_truthy expect(json_response).to be_truthy
user = User.find(json_response['id']) user = User.find_by email: 'new_agent@example.com'
expect(user).not_to be_role('Admin') expect(user).not_to be_role('Admin')
expect(user).not_to be_role('Agent') expect(user).not_to be_role('Agent')
expect(user).to be_role('Customer') expect(user).to be_role('Customer')
@ -1142,4 +1127,222 @@ RSpec.describe 'User', type: :request, searchindex: true do
end end
end end
end end
describe 'POST /api/v1/users', authenticated_as: -> { create(:admin) }, searchindex: false do
def make_request(params)
post '/api/v1/users', params: params, as: :json
end
let(:successful_params) { { email: 'non_existant@example.com' } }
let(:params_with_role) { successful_params.merge({ role_ids: [Role.find_by(name: 'Admin').id] } ) }
let(:params_with_invite) { successful_params.merge({ invite: true } ) }
it 'succeeds' do
make_request successful_params
expect(response).to have_http_status(:created)
end
it 'returns user data' do
make_request successful_params
expect(json_response).to have_key('email').and(have_value(successful_params[:email]))
end
it 'no session treated as signup', authenticated_as: false do
make_request successful_params
expect(response).to have_http_status(:unprocessable_entity)
end
it 'does not accept requests from customers', authenticated_as: -> { create(:customer) } do
make_request successful_params
expect(response).to have_http_status(:unauthorized)
end
it 'admins can give any role', authenticated_as: -> { create(:admin) } do
make_request params_with_role
expect(User.last).to be_role 'Admin'
end
it 'agents can not give roles', authenticated_as: -> { create(:agent) } do
make_request params_with_role
expect(User.last).not_to be_role 'Admin'
end
it 'does not send email verification notifications' do
allow(NotificationFactory::Mailer).to receive(:notification)
make_request successful_params
expect(NotificationFactory::Mailer).not_to have_received(:notification) { |arguments| arguments[:template] == 'signup' }
end
it 'does not send invitation notification by default' do
allow(NotificationFactory::Mailer).to receive(:notification)
make_request successful_params
expect(NotificationFactory::Mailer).not_to have_received(:notification) { |arguments| arguments[:template] == 'user_invite' }
end
it 'sends invitation notification when required' do
allow(NotificationFactory::Mailer).to receive(:notification)
make_request params_with_invite
expect(NotificationFactory::Mailer).to have_received(:notification) { |arguments| arguments[:template] == 'user_invite' }
end
it 'requires at least one identifier' do
make_request({ web: 'example.com' })
expect(json_response['error']).to start_with('Minimum one identifier')
end
it 'takes first name as identifier' do
make_request({ firstname: 'name' })
expect(response).to have_http_status(:created)
end
it 'takes last name as identifier' do
make_request({ lastname: 'name' })
expect(response).to have_http_status(:created)
end
it 'takes login as identifier' do
make_request({ login: 'name' })
expect(response).to have_http_status(:created)
end
it 'requires valid email if present' do
make_request({ email: 'not_valid_email' })
expect(response).to have_http_status(:unprocessable_entity)
end
end
describe 'POST /api/v1/users processed by #create_admin' do
before do
User.all[2...].each(&:destroy) # destroy previously created users
end
def make_request(params)
post '/api/v1/users', params: params, as: :json
end
let(:successful_params) { { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin@example.com', password: 'asd1ASD' } }
it 'succeds' do
make_request successful_params
expect(response).to have_http_status(:created)
end
it 'returns success message' do
make_request successful_params
expect(json_response).to have_key('message').and(have_value('ok'))
end
it 'does not allow to create 2nd administrator account' do
create(:admin)
make_request successful_params
expect(response).to have_http_status(:unprocessable_entity)
end
it 'requires email' do
make_request successful_params.merge(email: nil)
expect(response).to have_http_status(:unprocessable_entity)
end
it 'requires valid email' do
make_request successful_params.merge(email: 'invalid_email')
expect(response).to have_http_status(:unprocessable_entity)
end
it 'loads calendar' do
allow(Calendar).to receive(:init_setup)
make_request successful_params
expect(Calendar).to have_received(:init_setup)
end
it 'loads text module' do
allow(TextModule).to receive(:load)
make_request successful_params
expect(TextModule).to have_received(:load)
end
it 'does not send any notifications' do
allow(NotificationFactory::Mailer).to receive(:notification)
make_request successful_params
expect(NotificationFactory::Mailer).not_to have_received(:notification)
end
end
describe 'POST /api/v1/users processed by #create_signup', authenticated_as: false do
def make_request(params)
post '/api/v1/users', params: params, as: :json
end
let(:successful_params) { { firstname: 'Customer First', lastname: 'Customer Last', email: 'new_customer@example.com', password: 'asd1ASD', signup: true } }
before do
create(:admin) # simulate functional system with admin created
end
it 'succeeds' do
make_request successful_params
expect(response).to have_http_status(:created)
end
it 'requires csrf', allow_forgery_protection: true do
make_request successful_params
expect(response).to have_http_status(:unauthorized)
end
it 'requires honeypot attribute' do
params = successful_params.clone
params.delete :signup
make_request params
expect(response).to have_http_status(:unprocessable_entity)
end
it 'requires signup to be enabled' do
Setting.set('user_create_account', false)
make_request successful_params
expect(response).to have_http_status(:unprocessable_entity)
end
it 'requires email' do
make_request successful_params.merge(email: nil)
expect(response).to have_http_status(:unprocessable_entity)
end
it 'requires valid email' do
make_request successful_params.merge(email: 'not_valid_email')
expect(response).to have_http_status(:unprocessable_entity)
end
it 'returns false positive when email already used' do
create(:customer, email: successful_params[:email])
make_request successful_params
expect(response).to have_http_status(:created)
end
it 'sends email verification notifications' do
allow(NotificationFactory::Mailer).to receive(:notification)
make_request successful_params
expect(NotificationFactory::Mailer).to have_received(:notification) { |arguments| arguments[:template] == 'signup' }
end
it 'sends password reset notification when email already used' do
create(:customer, email: successful_params[:email])
allow(NotificationFactory::Mailer).to receive(:notification)
make_request successful_params
expect(NotificationFactory::Mailer).to have_received(:notification) { |arguments| arguments[:template] == 'signup_taken_reset' }
end
it 'sets role to Customer' do
make_request successful_params
expect(User.last).to be_role('Customer')
end
it 'ignores given Agent role' do
make_request successful_params.merge(role_ids: [Role.find_by(name: 'Agent').id])
expect(User.last).not_to be_role('Agent')
end
end
end end

View file

@ -0,0 +1,11 @@
RSpec.configure do |config|
config.around(:each, :allow_forgery_protection) do |example|
orig = ActionController::Base.allow_forgery_protection
ActionController::Base.allow_forgery_protection = true
example.run
ensure
ActionController::Base.allow_forgery_protection = orig
end
end