Improved session validation and usage of cors headers.

This commit is contained in:
Martin Edenhofer 2017-02-15 13:29:25 +01:00
parent fc13598f79
commit cd28e904ac
64 changed files with 195 additions and 121 deletions

View file

@ -34,6 +34,8 @@ class App.UiElement.textarea
'<div class="btn btn-default qq-upload-icon2 qq-upload-button pull-right" style="">{uploadButtonText}</div>' +
'<ul class="qq-upload-list span5" style="margin-top: 10px;"></ul>' +
'</div>',
customHeaders:
'X-CSRF-Token': App.Ajax.token()
classes:
success: ''
fail: ''

View file

@ -40,16 +40,22 @@ class App.Ajax
_instance ?= new _ajaxSingleton
_instance.current()
@token: ->
if _instance == undefined
_instance ?= new _ajaxSingleton
_instance.token()
# The actual Singleton class
class _ajaxSingleton
defaults:
contentType: 'application/json'
dataType: 'json'
processData: false
headers: {'X-Requested-With': 'XMLHttpRequest'}
headers:
'X-Requested-With': 'XMLHttpRequest'
cache: false
async: true
currentToken: null
currentRequest: {}
queueList: []
queueRunning: false
@ -63,8 +69,15 @@ class _ajaxSingleton
# bindings
$(document).bind('ajaxSend', =>
@_show_spinner()
).bind('ajaxComplete', =>
).bind('ajaxComplete', (request, xhr, settings) =>
@_hide_spinner()
# remeber XSRF-TOKEN for later
CSRFToken = xhr.getResponseHeader('CSRF-TOKEN')
return if !CSRFToken
@currentToken = CSRFToken
@defaults.headers['X-CSRF-Token'] = CSRFToken
Spine.Ajax.defaults.headers['X-CSRF-Token'] = CSRFToken
)
# show error messages
@ -170,6 +183,9 @@ class _ajaxSingleton
current: =>
@currentRequest
token: =>
@currentToken
_show_spinner: =>
@count++
$('.spinner').show()

View file

@ -155,9 +155,7 @@
uploadCancel: function () {
var manager = this;
//manager.uploadsQueue.shift()
console.log(99999, manager._xhrs)
_.each( manager._xhrs, function(xhr){
console.log(888, xhr)
xhr.abort()
})
manager._xhrs = []
@ -198,6 +196,11 @@
xhr.open('POST', manager.uploadUrl);
// add csrf token
if (App.Ajax && App.Ajax.token) {
xhr.setRequestHeader('X-CSRF-Token', App.Ajax.token());
}
// Triggered when upload starts:
xhr.upload.onloadstart = function () {
// File size is not reported during start!

View file

@ -11,6 +11,7 @@
-->
<p>
<form action="<%= App.Config.get('api_path') %>/packages" method="post" enctype="multipart/form-data" class="horizontal center">
<input type="hidden" name="authenticity_token" value="<%= App.Ajax.token() %>"/>
<input type="file" name="file_upload"/>
<button class="align-right btn btn--primary" type="submit"><%- @T('Install Package') %></button>
</form>

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ActivityStreamController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /api/v1/activity_stream
def show

View file

@ -4,8 +4,6 @@ require 'exceptions'
class ApplicationController < ActionController::Base
include ErrorHandling
# http_basic_authenticate_with :name => "test", :password => "ttt"
helper_method :current_user,
:authentication_check,
:config_frontend,
@ -17,36 +15,53 @@ class ApplicationController < ActionController::Base
:model_index_render
skip_before_action :verify_authenticity_token
before_action :transaction_begin, :set_user, :session_update, :user_device_check, :cors_preflight_check
after_action :transaction_end, :http_log, :set_access_control_headers
before_action :verify_csrf_token, :transaction_begin, :set_user, :session_update, :user_device_check, :cors_preflight_check
after_action :transaction_end, :http_log, :set_access_control_headers, :set_csrf_token_headers
# For all responses in this controller, return the CORS access control headers.
def set_access_control_headers
return if @_auth_type != 'token_auth' && @_auth_type != 'basic_auth'
set_access_control_headers_execute
end
def set_access_control_headers_execute
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, OPTIONS'
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, PATCH, OPTIONS'
headers['Access-Control-Max-Age'] = '1728000'
headers['Access-Control-Allow-Headers'] = 'Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Accept-Language'
headers['Access-Control-Allow-Credentials'] = 'true'
end
# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.
def cors_preflight_check
return true if @_auth_type != 'token_auth' && @_auth_type != 'basic_auth'
cors_preflight_check_execute
end
return if request.method != 'OPTIONS'
def cors_preflight_check_execute
return true if request.method != 'OPTIONS'
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, OPTIONS'
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, PATCH, OPTIONS'
headers['Access-Control-Allow-Headers'] = 'Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Accept-Language'
headers['Access-Control-Max-Age'] = '1728000'
headers['Access-Control-Allow-Credentials'] = 'true'
render text: '', content_type: 'text/plain'
false
end
def set_csrf_token_headers
return true if @_auth_type.present? && @_auth_type != 'session'
headers['CSRF-TOKEN'] = form_authenticity_token
end
def verify_csrf_token
return true if request.method != 'POST' && request.method != 'PUT' && request.method != 'DELETE' && request.method != 'PATCH'
return true if @_auth_type == 'token_auth' || @_auth_type == 'basic_auth'
return true if valid_authenticity_token?(session, params[:authenticity_token] || request.headers['X-CSRF-Token'])
logger.info 'CSRF token verification failed'
raise Exceptions::NotAuthorized, 'CSRF token verification failed!'
end
def http_log_config(config)
@http_log_support = config
end
@ -74,8 +89,9 @@ class ApplicationController < ActionController::Base
@_current_user = User.lookup(id: session[:user_id])
end
def current_user_set(user)
def current_user_set(user, auth_type = 'session')
session[:user_id] = user.id
@_auth_type = auth_type
@_current_user = user
set_user
end
@ -224,7 +240,7 @@ class ApplicationController < ActionController::Base
)
end
def authentication_check_only(auth_param)
def authentication_check_only(auth_param = {})
#logger.debug 'authentication_check'
#logger.debug params.inspect
#logger.debug session.inspect
@ -336,7 +352,7 @@ class ApplicationController < ActionController::Base
raise Exceptions::NotAuthorized, 'Not authorized (user)!'
end
current_user_set(user)
current_user_set(user, auth_type)
user_device_log(user, auth_type)
logger.debug "#{auth_type} for '#{user.login}'"
true

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ApplicationsController < ApplicationController
before_action { authentication_check(permission: 'admin.api') }
prepend_before_action { authentication_check(permission: 'admin.api') }
def index
all = Doorkeeper::Application.all

View file

@ -3,7 +3,7 @@
require 'icalendar'
class CalendarSubscriptionsController < ApplicationController
before_action { authentication_check( { basic_auth_promt: true, permission: 'user_preferences.calendar' } ) }
prepend_before_action { authentication_check( { basic_auth_promt: true, permission: 'user_preferences.calendar' } ) }
# @path [GET] /calendar_subscriptions
#

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class CalendarsController < ApplicationController
before_action { authentication_check(permission: 'admin.calendar') }
prepend_before_action { authentication_check(permission: 'admin.calendar') }
def index

View file

@ -1,10 +1,9 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChannelsEmailController < ApplicationController
before_action :authentication_check
prepend_before_action { authentication_check(permission: 'admin.channel_email') }
def index
permission_check('admin.channel_email')
system_online_service = Setting.get('system_online_service')
account_channel_ids = []
notification_channel_ids = []
@ -54,9 +53,6 @@ class ChannelsEmailController < ApplicationController
def probe
# check admin permissions
permission_check('admin.channel_email')
# probe settings based on email and password
result = EmailHelper::Probe.full(
email: params[:email],
@ -74,9 +70,6 @@ class ChannelsEmailController < ApplicationController
def outbound
# check admin permissions
permission_check('admin.channel_email')
# verify access
return if params[:channel_id] && !check_access(params[:channel_id])
@ -86,9 +79,6 @@ class ChannelsEmailController < ApplicationController
def inbound
# check admin permissions
permission_check('admin.channel_email')
# verify access
return if params[:channel_id] && !check_access(params[:channel_id])
@ -103,9 +93,6 @@ class ChannelsEmailController < ApplicationController
def verify
# check admin permissions
permission_check('admin.channel_email')
email = params[:email] || params[:meta][:email]
email = email.downcase
channel_id = params[:channel_id]
@ -195,7 +182,6 @@ class ChannelsEmailController < ApplicationController
end
def enable
permission_check('admin.channel_email')
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
channel.active = true
channel.save!
@ -203,7 +189,6 @@ class ChannelsEmailController < ApplicationController
end
def disable
permission_check('admin.channel_email')
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
channel.active = false
channel.save!
@ -211,7 +196,6 @@ class ChannelsEmailController < ApplicationController
end
def destroy
permission_check('admin.channel_email')
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
channel.destroy
render json: {}
@ -229,9 +213,6 @@ class ChannelsEmailController < ApplicationController
check_online_service
# check admin permissions
permission_check('admin.channel_email')
adapter = params[:adapter].downcase
email = Setting.get('notification_sender')

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChannelsFacebookController < ApplicationController
before_action { authentication_check(permission: 'admin.channel_facebook') }
prepend_before_action { authentication_check(permission: 'admin.channel_facebook') }
def index
assets = {}

View file

@ -1,7 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChannelsTelegramController < ApplicationController
before_action -> { authentication_check(permission: 'admin.channel_telegram') }, except: [:webhook]
prepend_before_action -> { authentication_check(permission: 'admin.channel_telegram') }, except: [:webhook]
skip_before_action :verify_csrf_token, only: [:webhook]
def index
assets = {}

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChannelsTwitterController < ApplicationController
before_action { authentication_check(permission: 'admin.channel_twitter') }
prepend_before_action { authentication_check(permission: 'admin.channel_twitter') }
def index
assets = {}

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChatsController < ApplicationController
before_action { authentication_check(permission: 'admin.chat') }
prepend_before_action { authentication_check(permission: 'admin.chat') }
def index
chat_ids = []

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class CtiController < ApplicationController
before_action { authentication_check(permission: 'cti.agent') }
prepend_before_action { authentication_check(permission: 'cti.agent') }
# list current caller log
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class EmailAddressesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ExternalCredentialsController < ApplicationController
before_action { authentication_check(permission: ['admin.channel_twitter', 'admin.channel_facebook']) }
prepend_before_action { authentication_check(permission: ['admin.channel_twitter', 'admin.channel_facebook']) }
def index
model_index_render(ExternalCredential, params)

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class FirstStepsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
def index
return if !access?

View file

@ -1,6 +1,9 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class FormController < ApplicationController
skip_before_action :verify_csrf_token
before_action :cors_preflight_check_execute
after_action :set_access_control_headers_execute
def config
return if !enabled?

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class GroupsController < ApplicationController
before_action { authentication_check(permission: 'admin.group') }
prepend_before_action { authentication_check(permission: 'admin.group') }
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class HttpLogsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /http_logs/:facility
def index

View file

@ -3,7 +3,7 @@
require 'builder'
class Integration::SipgateController < ApplicationController
skip_before_action :verify_csrf_token
before_action :check_configured
# notify about inbound call / block inbound call

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class JobsController < ApplicationController
before_action { authentication_check(permission: 'admin.scheduler') }
prepend_before_action { authentication_check(permission: 'admin.scheduler') }
def index
model_index_render(Job, params)

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class KarmaController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
def index
render json: {

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class LinksController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /api/v1/links
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class MacrosController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class MonitoringController < ApplicationController
before_action -> { authentication_check(permission: 'admin.monitoring') }, except: [:health_check, :status]
prepend_before_action -> { authentication_check(permission: 'admin.monitoring') }, except: [:health_check, :status]
skip_before_action :verify_csrf_token
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class NetworksController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /networks
# GET /networks.json

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class OnlineNotificationsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class OrganizationsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class OverviewsController < ApplicationController
before_action { authentication_check(permission: 'admin.overview') }
prepend_before_action { authentication_check(permission: 'admin.overview') }
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class PackagesController < ApplicationController
before_action { authentication_check(permission: 'admin.package') }
prepend_before_action { authentication_check(permission: 'admin.package') }
# GET /api/v1/packages
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class PostmasterFiltersController < ApplicationController
before_action { authentication_check(permission: 'admin.channel_email') }
prepend_before_action { authentication_check(permission: 'admin.channel_email') }
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ProxyController < ApplicationController
before_action { authentication_check(permission: 'admin.system') }
prepend_before_action { authentication_check(permission: 'admin.system') }
# POST /api/v1/proxy
def test

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class RecentViewController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,5 +1,5 @@
class ReportProfilesController < ApplicationController
before_action { authentication_check(permission: 'admin.report_profile') }
prepend_before_action { authentication_check(permission: 'admin.report_profile') }
=begin

View file

@ -3,7 +3,7 @@
require 'tempfile'
class ReportsController < ApplicationController
before_action { authentication_check(permission: 'report') }
prepend_before_action { authentication_check(permission: 'report') }
# GET /api/reports/config
def reporting_config

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class RolesController < ApplicationController
before_action { authentication_check(permission: 'admin.role') }
prepend_before_action { authentication_check(permission: 'admin.role') }
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SearchController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET|POST /api/v1/search
# GET|POST /api/v1/search/:objects

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SessionsController < ApplicationController
prepend_before_action :authentication_check, only: [:switch_to_user, :list, :delete]
skip_before_action :verify_csrf_token, only: [:create, :show, :destroy, :create_omniauth, :create_sso]
# "Create" a login, aka "log the user in"
def create
@ -18,12 +20,11 @@ class SessionsController < ApplicationController
raise Exceptions::NotAuthorized, 'Wrong Username and Password combination.' if !user
# remember me - set session cookie to expire later
request.env['rack.session.options'][:expire_after] = if params[:remember_me]
1.year
expire_after = nil
if params[:remember_me]
expire_after = 1.year
end
# both not needed to set :expire_after works fine
# request.env['rack.session.options'][:renew] = true
# reset_session
env['rack.session.options'][:expire_after] = expire_after
# set session user
current_user_set(user)
@ -114,11 +115,11 @@ class SessionsController < ApplicationController
def destroy
# Remove the user id from the session
@_current_user = session[:user_id] = nil
@_current_user = nil
# reset session cookie (reset :expire_after in case remember_me is active)
request.env['rack.session.options'][:expire_after] = -1.years
request.env['rack.session.options'][:renew] = true
# reset session
request.env['rack.session.options'][:expire_after] = nil
session.clear
render json: {}
end
@ -195,7 +196,6 @@ class SessionsController < ApplicationController
# "switch" to user
def switch_to_user
authentication_check
permission_check('admin.session')
# check user
@ -278,7 +278,6 @@ class SessionsController < ApplicationController
end
def list
authentication_check
permission_check('admin.session')
assets = {}
sessions_clean = []
@ -297,7 +296,6 @@ class SessionsController < ApplicationController
end
def delete
authentication_check
permission_check('admin.session')
SessionHelper.destroy(params[:id])
render json: {}

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SettingsController < ApplicationController
before_action { authentication_check(permission: 'admin.*') }
prepend_before_action { authentication_check(permission: 'admin.*') }
# GET /settings
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SignaturesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SlasController < ApplicationController
before_action { authentication_check(permission: 'admin.sla') }
prepend_before_action { authentication_check(permission: 'admin.sla') }
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TagsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /api/v1/tag_search?term=abc
def search

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TaskbarController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
def index
current_user_tasks = Taskbar.where(user_id: current_user.id)

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TemplatesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TextModulesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
=begin

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TicketArticlesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /articles
def index

View file

@ -3,7 +3,7 @@
require 'ticket/overviews'
class TicketOverviewsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /api/v1/ticket_overviews
def show

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TicketPrioritiesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /ticket_priorities
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TicketStatesController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /ticket_states
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TicketsController < ApplicationController
before_action :authentication_check
prepend_before_action :authentication_check
# GET /api/v1/tickets
def index

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TimeAccountingsController < ApplicationController
before_action { authentication_check(permission: 'admin.time_accounting') }
prepend_before_action { authentication_check(permission: 'admin.time_accounting') }
def by_ticket

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TranslationsController < ApplicationController
before_action :authentication_check, except: [:lang]
prepend_before_action :authentication_check, except: [:lang]
# GET /translations/lang/:locale
def lang

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class TriggersController < ApplicationController
before_action { authentication_check(permission: 'admin.trigger') }
prepend_before_action { authentication_check(permission: 'admin.trigger') }
def index
model_index_render(Trigger, params)

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class UserAccessTokenController < ApplicationController
before_action { authentication_check(permission: 'user_preferences.access_token') }
prepend_before_action { authentication_check(permission: 'user_preferences.access_token') }
def index
tokens = Token.where(action: 'api', persistent: true, user_id: current_user.id).order('updated_at DESC, label ASC')

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class UserDevicesController < ApplicationController
before_action { authentication_check(permission: 'user_preferences.device') }
prepend_before_action { authentication_check(permission: 'user_preferences.device') }
def index
devices = UserDevice.where(user_id: current_user.id).order('updated_at DESC, name ASC')

View file

@ -1,7 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class UsersController < ApplicationController
before_action :authentication_check, except: [:create, :password_reset_send, :password_reset_verify, :image]
prepend_before_action :authentication_check, except: [:create, :password_reset_send, :password_reset_verify, :image]
prepend_before_action :authentication_check_only, only: [:create]
# @path [GET] /users
#
@ -105,10 +106,6 @@ class UsersController < ApplicationController
# @response_message 200 [User] Created User record.
# @response_message 401 Invalid session.
def create
# in case of authentication, set current_user to access later
authentication_check_only({})
clean_params = User.association_name_to_id_convert(params)
clean_params = User.param_cleanup(clean_params, true)
user = User.new(clean_params)

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2017 Zammad Foundation, http://zammad-foundation.org/
class VersionController < ApplicationController
before_action { authentication_check(permission: 'admin.version') }
prepend_before_action { authentication_check(permission: 'admin.version') }
# GET /api/v1/version
def index

View file

@ -93,7 +93,7 @@ get all roles with permission "admin.session" or "ticket.agent"
returns
[user1, user2, ...]
[role1, role2, ...]
=end

View file

@ -0,0 +1,8 @@
class ReloadOnlineBrowserAfterCorsCsrfChanges < ActiveRecord::Migration
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
AppVersion.set(true, 'app_version')
end
end

View file

@ -77,9 +77,11 @@ class AuthTest < TestCase
logout()
# verify session cookie
sleep 2
cookie(
name: '^_zammad.+?',
should_not_exist: true,
value: '.+?',
expires: '',
)
end

View file

@ -57,6 +57,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', false)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API password access disabled!', result['error'])
@ -64,6 +65,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', true)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert(result)
@ -76,6 +78,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', false)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API password access disabled!', result['error'])
@ -83,6 +86,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', true)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Array, result.class)
assert(result)
@ -95,6 +99,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', false)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API password access disabled!', result['error'])
@ -102,6 +107,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_password_access', true)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Array, result.class)
assert(result)
@ -122,6 +128,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', false)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API token access disabled!', result['error'])
@ -129,6 +136,8 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', true)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert(result)
@ -207,6 +216,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', false)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API token access disabled!', result['error'])
@ -214,6 +224,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', true)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Array, result.class)
assert(result)
@ -231,12 +242,14 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', false)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API token access disabled!', result['error'])
Setting.set('api_token_access', true)
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Array, result.class)
@ -258,6 +271,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', false)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('API token access disabled!', result['error'])
@ -265,6 +279,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
Setting.set('api_token_access', true)
get '/api/v1/sessions', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('User is inactive!', result['error'])
@ -284,6 +299,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
get '/api/v1/tickets', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(401)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('Not authorized (token expired)!', result['error'])
@ -306,6 +322,7 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
get '/api/v1/tickets', {}, @headers.merge('Authorization' => admin_credentials)
assert_response(200)
assert_equal('*', @response.header['Access-Control-Allow-Origin'])
result = JSON.parse(@response.body)
assert_equal(Array, result.class)
assert(result)
@ -314,4 +331,18 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
assert_in_delta(admin_token.last_used_at, Time.zone.now, 1.second)
end
test 'session auth - admin' do
post '/api/v1/signin', { username: 'api-admin@example.com', password: 'adminpw', fingerprint: '123456789' }
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
assert_response(201)
get '/api/v1/sessions', {}
assert_response(200)
assert_not(@response.header.key?('Access-Control-Allow-Origin'))
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert(result)
end
end

View file

@ -75,20 +75,34 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
test 'user create tests - no user' do
post '/api/v1/signshow', {}, @headers
# create user with disabled feature
Setting.set('user_create_account', false)
params = { email: 'some_new_customer@example.com' }
token = @response.headers['CSRF-TOKEN']
# token based on form
params = { email: 'some_new_customer@example.com', authenticity_token: token }
post '/api/v1/users', params.to_json, @headers
assert_response(422)
result = JSON.parse(@response.body)
assert(result['error'])
assert_equal('Feature not enabled!', result['error'])
# token based on headers
headers = @headers.merge('X-CSRF-Token' => token)
params = { email: 'some_new_customer@example.com' }
post '/api/v1/users', params.to_json, headers
assert_response(422)
result = JSON.parse(@response.body)
assert(result['error'])
assert_equal('Feature not enabled!', result['error'])
Setting.set('user_create_account', true)
# no signup param with enabled feature
params = { email: 'some_new_customer@example.com' }
post '/api/v1/users', params.to_json, @headers
post '/api/v1/users', params.to_json, headers
assert_response(422)
result = JSON.parse(@response.body)
assert(result['error'])
@ -96,7 +110,7 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
# already existing user with enabled feature
params = { email: 'rest-customer1@example.com', signup: true }
post '/api/v1/users', params.to_json, @headers
post '/api/v1/users', params.to_json, headers
assert_response(422)
result = JSON.parse(@response.body)
assert(result['error'])
@ -104,7 +118,7 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
# create user with enabled feature (take customer role)
params = { firstname: 'Me First', lastname: 'Me Last', email: 'new_here@example.com', signup: true }
post '/api/v1/users', params.to_json, @headers
post '/api/v1/users', params.to_json, headers
assert_response(201)
result = JSON.parse(@response.body)
assert(result)
@ -121,7 +135,7 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
# create user with admin role (not allowed for signup, take customer role)
role = Role.lookup(name: 'Admin')
params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin@example.com', role_ids: [ role.id ], signup: true }
post '/api/v1/users', params.to_json, @headers
post '/api/v1/users', params.to_json, headers
assert_response(201)
result = JSON.parse(@response.body)
assert(result)
@ -133,7 +147,7 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
# create user with agent role (not allowed for signup, take customer role)
role = Role.lookup(name: 'Agent')
params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent@example.com', role_ids: [ role.id ], signup: true }
post '/api/v1/users', params.to_json, @headers
post '/api/v1/users', params.to_json, headers
assert_response(201)
result = JSON.parse(@response.body)
assert(result)
@ -143,13 +157,13 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
assert(user.role?('Customer'))
# no user (because of no session)
get '/api/v1/users', {}, @headers
get '/api/v1/users', {}, headers
assert_response(401)
result = JSON.parse(@response.body)
assert_equal('authentication failed', result['error'])
# me
get '/api/v1/users/me', {}, @headers
get '/api/v1/users/me', {}, headers
assert_response(401)
result = JSON.parse(@response.body)
assert_equal('authentication failed', result['error'])