Maintenance: Show less error details to non-admin users
This commit is contained in:
parent
1c96163ada
commit
9dd2b59037
10 changed files with 521 additions and 256 deletions
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
15
app/views/mailer/signup_taken_reset/en.html.erb
Normal file
15
app/views/mailer/signup_taken_reset/en.html.erb
Normal 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>
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
11
spec/support/allow_forgery_protection.rb
Normal file
11
spec/support/allow_forgery_protection.rb
Normal 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
|
Loading…
Reference in a new issue