Added api setting to admin interface and tokens to user preferences.
This commit is contained in:
parent
42d0cd1f8f
commit
e200378dd6
23 changed files with 617 additions and 39 deletions
|
@ -66,7 +66,7 @@ class CalendarSubscriptions extends App.Controller
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'preferences'
|
id: 'preferences'
|
||||||
type: 'PUT'
|
type: 'PUT'
|
||||||
url: @apiPath + '/users/preferences'
|
url: "#{@apiPath}/users/preferences"
|
||||||
data: JSON.stringify data
|
data: JSON.stringify data
|
||||||
success: @success
|
success: @success
|
||||||
error: @error
|
error: @error
|
||||||
|
|
|
@ -15,12 +15,17 @@ class Index extends App.Controller
|
||||||
)
|
)
|
||||||
|
|
||||||
# fetch data, render view
|
# fetch data, render view
|
||||||
load: =>
|
load: (force = false) =>
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'user_devices'
|
id: 'user_devices'
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: "#{@apiPath}/user_devices"
|
url: "#{@apiPath}/user_devices"
|
||||||
success: (data) =>
|
success: (data) =>
|
||||||
|
|
||||||
|
# verify is rerender is needed
|
||||||
|
if !force && @lastestUpdated && data && data[0] && @lastestUpdated.updated_at is data[0].updated_at
|
||||||
|
return
|
||||||
|
@lastestUpdated = data[0]
|
||||||
@data = data
|
@data = data
|
||||||
@render()
|
@render()
|
||||||
)
|
)
|
||||||
|
@ -39,7 +44,8 @@ class Index extends App.Controller
|
||||||
type: 'DELETE'
|
type: 'DELETE'
|
||||||
url: "#{@apiPath}/user_devices/#{id}"
|
url: "#{@apiPath}/user_devices/#{id}"
|
||||||
processData: true
|
processData: true
|
||||||
success: @load
|
success: =>
|
||||||
|
@load(true)
|
||||||
error: @error
|
error: @error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
class Index extends App.Controller
|
||||||
|
events:
|
||||||
|
'click [data-type=delete]': 'delete'
|
||||||
|
'submit form.js-create': 'create'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
return if !@authenticate()
|
||||||
|
@title 'Token Access', true
|
||||||
|
|
||||||
|
@load()
|
||||||
|
@interval(
|
||||||
|
=>
|
||||||
|
@load()
|
||||||
|
12000
|
||||||
|
)
|
||||||
|
|
||||||
|
# fetch data, render view
|
||||||
|
load: (force = false) =>
|
||||||
|
@ajax(
|
||||||
|
id: 'user_access_token'
|
||||||
|
type: 'GET'
|
||||||
|
url: "#{@apiPath}/user_access_token"
|
||||||
|
success: (data) =>
|
||||||
|
|
||||||
|
# verify is rerender is needed
|
||||||
|
if !force && @lastestUpdated && data && data[0] && @lastestUpdated.updated_at is data[0].updated_at
|
||||||
|
return
|
||||||
|
@lastestUpdated = data[0]
|
||||||
|
@data = data
|
||||||
|
@render()
|
||||||
|
)
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
@html App.view('profile/token_access')(
|
||||||
|
tokens: @data
|
||||||
|
)
|
||||||
|
|
||||||
|
create: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
params = @formParam(e.target)
|
||||||
|
|
||||||
|
@ajax(
|
||||||
|
id: 'user_access_token_create'
|
||||||
|
type: 'POST'
|
||||||
|
url: "#{@apiPath}/user_access_token"
|
||||||
|
data: JSON.stringify(params)
|
||||||
|
processData: true
|
||||||
|
success: @show
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
show: (data) =>
|
||||||
|
@load()
|
||||||
|
ui = @
|
||||||
|
new App.ControllerModal(
|
||||||
|
head: 'Your New Personal Access Token'
|
||||||
|
buttonSubmit: 'OK, I\'ve copied my token'
|
||||||
|
content: ->
|
||||||
|
App.view('profile/token_access_created')(
|
||||||
|
name: data.name
|
||||||
|
)
|
||||||
|
post: ->
|
||||||
|
@el.find('.js-select').on('click', ui.selectAll)
|
||||||
|
onCancel: ->
|
||||||
|
@close()
|
||||||
|
onSubmit: ->
|
||||||
|
@close()
|
||||||
|
)
|
||||||
|
|
||||||
|
delete: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
return if !confirm(App.i18n.translateInline('Sure?'))
|
||||||
|
id = $(e.target).closest('a').data('token-id')
|
||||||
|
@ajax(
|
||||||
|
id: 'user_access_token_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/user_access_token/#{id}"
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load(true)
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
error: (xhr, status, error) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
|
@notify(
|
||||||
|
type: 'error'
|
||||||
|
msg: App.i18n.translateContent(data.message)
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Config.set('Token Access', { prio: 3200, name: 'Token Access', parent: '#profile', target: '#profile/token_access', controller: Index, role: [ 'Agent', 'Admin' ] }, 'NavBarProfile')
|
|
@ -58,4 +58,4 @@ class Index extends App.ControllerContent
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set('Packages', { prio: 1000, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, role: ['Admin'] }, 'NavBarAdmin')
|
App.Config.set('Packages', { prio: 3600, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, role: ['Admin'] }, 'NavBarAdmin')
|
||||||
|
|
|
@ -53,4 +53,4 @@ class Index extends App.ControllerContent
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set('Session', { prio: 3700, name: 'Sessions', parent: '#system', target: '#system/sessions', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
App.Config.set('Session', { prio: 3800, name: 'Sessions', parent: '#system', target: '#system/sessions', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
|
@ -63,8 +63,8 @@ class Widget extends App.Controller
|
||||||
App.i18n.setMap(source, translation_new)
|
App.i18n.setMap(source, translation_new)
|
||||||
|
|
||||||
# replace rest in page
|
# replace rest in page
|
||||||
source = source.replace('\'', '\\\'')
|
sourceQuoted = source.replace('\'', '\\\'')
|
||||||
$(".translation[title='#{source}']").text(translation_new)
|
$(".translation[title='#{sourceQuoted}']").text(translation_new)
|
||||||
|
|
||||||
# update permanent translation mapString
|
# update permanent translation mapString
|
||||||
translation = App.Translation.findByAttribute('source', source)
|
translation = App.Translation.findByAttribute('source', source)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="page-header-title"><h1><%- @T('Token Access') %></h1></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><%- @T('You can generate a personal access token for each application you use that needs access to the Zammad API.') %></p>
|
||||||
|
|
||||||
|
<h2><%- @T('Add a Personal Access Token') %></h2>
|
||||||
|
|
||||||
|
<p><%- @T('Pick a name for the application, and we\'ll give you a unique token.') %></p>
|
||||||
|
<form class="page-content js-create">
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for="token-label"><%- @T('Name') %></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls"><input id="token-label" type="text" name="label" value="" class="form-control js-input" required></div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--primary js-submit"><%- @T('Create') %></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><%- @T('Personal Access Tokens') %></h2>
|
||||||
|
<table class="settings-list js-tokenList">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%- @T('Name') %></th>
|
||||||
|
<th><%- @T('Created') %></th>
|
||||||
|
<!--
|
||||||
|
<th><%- @T('Expires') %></th>
|
||||||
|
<th><%- @T('Last used') %></th>
|
||||||
|
-->
|
||||||
|
<th><%- @T('Delete') %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% if _.isEmpty(@tokens): %>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><%- @T('none') %>
|
||||||
|
<% else: %>
|
||||||
|
<% for token in @tokens: %>
|
||||||
|
<tr>
|
||||||
|
<td><%= token.label %></td>
|
||||||
|
<td><%- @humanTime(token.created_at) %></td>
|
||||||
|
<!--
|
||||||
|
<td><%- @humanTime(token.expired_at) %></td>
|
||||||
|
<td><%- @humanTime(token.last_used_at) %></td>
|
||||||
|
-->
|
||||||
|
<td class="settings-list-controls">
|
||||||
|
<div>
|
||||||
|
<a class="settings-list-control" href="#" data-token-id="<%- token.id %>" data-type="delete" title="<%- @Ti('Delete') %>"><%- @Icon('trash') %></a>
|
||||||
|
</div>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<%- @T('For security reasons, the API token is shown only once. You\'ll need to copy it somewhere safe before continuing.') %>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="controls"><input type="text" value="<%= @name %>" class="form-control input js-select" readonly></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
|
@ -260,6 +260,12 @@ class ApplicationController < ActionController::Base
|
||||||
# check http basic based authentication
|
# check http basic based authentication
|
||||||
authenticate_with_http_basic do |username, password|
|
authenticate_with_http_basic do |username, password|
|
||||||
logger.debug "http basic auth check '#{username}'"
|
logger.debug "http basic auth check '#{username}'"
|
||||||
|
if Setting.get('api_password_access') == false
|
||||||
|
return {
|
||||||
|
auth: false,
|
||||||
|
message: 'API password access disabled!',
|
||||||
|
}
|
||||||
|
end
|
||||||
userdata = User.authenticate(username, password)
|
userdata = User.authenticate(username, password)
|
||||||
next if !userdata
|
next if !userdata
|
||||||
if check_maintenance_only(userdata)
|
if check_maintenance_only(userdata)
|
||||||
|
@ -276,10 +282,10 @@ class ApplicationController < ActionController::Base
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# check http token based authentication
|
# check http token action based authentication
|
||||||
if auth_param[:token_action]
|
if auth_param[:token_action]
|
||||||
authenticate_with_http_token do |token, _options|
|
authenticate_with_http_token do |token, _options|
|
||||||
logger.debug "token auth check '#{token}'"
|
logger.debug "token action auth check '#{token}'"
|
||||||
userdata = Token.check(
|
userdata = Token.check(
|
||||||
action: auth_param[:token_action],
|
action: auth_param[:token_action],
|
||||||
name: token,
|
name: token,
|
||||||
|
@ -293,12 +299,40 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
user_device_log(userdata, 'token_auth')
|
user_device_log(userdata, 'token_auth')
|
||||||
|
logger.debug "token action auth for '#{userdata.login}'"
|
||||||
|
return {
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# check http token based authentication
|
||||||
|
authenticate_with_http_token do |token, _options|
|
||||||
|
logger.debug "token auth check '#{token}'"
|
||||||
|
if Setting.get('api_token_access') == false
|
||||||
|
return {
|
||||||
|
auth: false,
|
||||||
|
message: 'API token access disabled!',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
userdata = Token.check(
|
||||||
|
action: 'api',
|
||||||
|
name: token,
|
||||||
|
)
|
||||||
|
next if !userdata
|
||||||
|
if check_maintenance_only(userdata)
|
||||||
|
return {
|
||||||
|
auth: false,
|
||||||
|
message: 'Maintenance mode enabled!',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
current_user_set(userdata)
|
||||||
|
user_device_log(userdata, 'token_auth')
|
||||||
logger.debug "token auth for '#{userdata.login}'"
|
logger.debug "token auth for '#{userdata.login}'"
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
logger.debug error_message
|
logger.debug error_message
|
||||||
{
|
{
|
||||||
|
|
43
app/controllers/user_access_token_controller.rb
Normal file
43
app/controllers/user_access_token_controller.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class UserAccessTokenController < ApplicationController
|
||||||
|
before_action :authentication_check
|
||||||
|
|
||||||
|
def index
|
||||||
|
tokens = Token.where(action: 'api', persistent: true, user_id: current_user.id).order('updated_at DESC, label ASC')
|
||||||
|
token_list = []
|
||||||
|
tokens.each { |token|
|
||||||
|
attributes = token.attributes
|
||||||
|
attributes.delete('persistent')
|
||||||
|
attributes.delete('name')
|
||||||
|
token_list.push attributes
|
||||||
|
}
|
||||||
|
model_index_render_result(token_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
if Setting.get('api_token_access') == false
|
||||||
|
raise Exceptions::UnprocessableEntity, 'API token access disabled!'
|
||||||
|
end
|
||||||
|
if params[:label].empty?
|
||||||
|
raise Exceptions::UnprocessableEntity, 'Need label!'
|
||||||
|
end
|
||||||
|
token = Token.create(
|
||||||
|
action: 'api',
|
||||||
|
label: params[:label],
|
||||||
|
persistent: true,
|
||||||
|
user_id: current_user.id,
|
||||||
|
)
|
||||||
|
render json: {
|
||||||
|
name: token.name,
|
||||||
|
}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
token = Token.find_by(action: 'api', user_id: current_user.id, id: params[:id])
|
||||||
|
raise Exceptions::UnprocessableEntity, 'Unable to find api token!' if !token
|
||||||
|
token.destroy
|
||||||
|
render json: {}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -80,7 +80,7 @@ cleanup old token
|
||||||
def generate_token
|
def generate_token
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
self.name = SecureRandom.hex(30)
|
self.name = SecureRandom.urlsafe_base64(48)
|
||||||
break if !Token.exists?(name: name)
|
break if !Token.exists?(name: name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
9
config/routes/user_access_token.rb
Normal file
9
config/routes/user_access_token.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
# access token
|
||||||
|
match api_path + '/user_access_token', to: 'user_access_token#index', via: :get
|
||||||
|
match api_path + '/user_access_token', to: 'user_access_token#create', via: :post
|
||||||
|
match api_path + '/user_access_token/:id', to: 'user_access_token#destroy', via: :delete
|
||||||
|
|
||||||
|
end
|
|
@ -188,6 +188,7 @@ class CreateBase < ActiveRecord::Migration
|
||||||
t.boolean :persistent
|
t.boolean :persistent
|
||||||
t.string :name, limit: 100, null: false
|
t.string :name, limit: 100, null: false
|
||||||
t.string :action, limit: 40, null: false
|
t.string :action, limit: 40, null: false
|
||||||
|
t.string :label, limit: 255, null: true
|
||||||
t.timestamps null: false
|
t.timestamps null: false
|
||||||
end
|
end
|
||||||
add_index :tokens, :user_id
|
add_index :tokens, :user_id
|
||||||
|
|
53
db/migrate/20160727000001_update_setting_api.rb
Normal file
53
db/migrate/20160727000001_update_setting_api.rb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
class UpdateSettingApi < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
# return if it's a new setup
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
Setting.create_or_update(
|
||||||
|
title: 'API Token Access',
|
||||||
|
name: 'api_token_access',
|
||||||
|
area: 'API::Base',
|
||||||
|
description: 'Enable REST API using tokens (not username/email addeess and password). Each user need to create own access tokens in user profile.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'api_token_access',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: true,
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
Setting.create_or_update(
|
||||||
|
title: 'API Password Access',
|
||||||
|
name: 'api_password_access',
|
||||||
|
area: 'API::Base',
|
||||||
|
description: 'Enable REST API access using the username/email address and password for the authentication user.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'api_password_access',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: true,
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
add_column :tokens, :label, :string, limit: 255, null: true
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
49
db/seeds.rb
49
db/seeds.rb
|
@ -554,7 +554,7 @@ Setting.create_if_not_exists(
|
||||||
title: 'Authentication via Google',
|
title: 'Authentication via Google',
|
||||||
name: 'auth_google_oauth2',
|
name: 'auth_google_oauth2',
|
||||||
area: 'Security::ThirdPartyAuthentication',
|
area: 'Security::ThirdPartyAuthentication',
|
||||||
description: 'Enables user authentication via Google.',
|
description: 'Enables user authentication via Google. Register your app first at [Google API Console Site](https://console.developers.google.com/apis/credentials)',
|
||||||
options: {
|
options: {
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -601,7 +601,7 @@ Setting.create_if_not_exists(
|
||||||
title: 'Authentication via LinkedIn',
|
title: 'Authentication via LinkedIn',
|
||||||
name: 'auth_linkedin',
|
name: 'auth_linkedin',
|
||||||
area: 'Security::ThirdPartyAuthentication',
|
area: 'Security::ThirdPartyAuthentication',
|
||||||
description: 'Enables user authentication via LinkedIn.',
|
description: 'Enables user authentication via LinkedIn. Register your app first at [Linkedin Developer Site](https://www.linkedin.com/developer/apps)',
|
||||||
options: {
|
options: {
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -1210,6 +1210,51 @@ Setting.create_if_not_exists(
|
||||||
frontend: false
|
frontend: false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Setting.create_or_update(
|
||||||
|
title: 'API Token Access',
|
||||||
|
name: 'api_token_access',
|
||||||
|
area: 'API::Base',
|
||||||
|
description: 'Enable REST API using tokens (not username/email addeess and password). Each user need to create own access tokens in user profile.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'api_token_access',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: true,
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
Setting.create_or_update(
|
||||||
|
title: 'API Password Access',
|
||||||
|
name: 'api_password_access',
|
||||||
|
area: 'API::Base',
|
||||||
|
description: 'Enable REST API access using the username/email address and password for the authentication user.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'api_password_access',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: true,
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Enable Chat',
|
title: 'Enable Chat',
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
|
|
|
@ -27,6 +27,10 @@ class PreferencesTest < TestCase
|
||||||
css: '.content .NavBarProfile',
|
css: '.content .NavBarProfile',
|
||||||
value: 'Calendar',
|
value: 'Calendar',
|
||||||
)
|
)
|
||||||
|
match(
|
||||||
|
css: '.content .NavBarProfile',
|
||||||
|
value: 'Token Access',
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_permission_customer
|
def test_permission_customer
|
||||||
|
@ -54,9 +58,13 @@ class PreferencesTest < TestCase
|
||||||
css: '.content .NavBarProfile',
|
css: '.content .NavBarProfile',
|
||||||
value: 'Calendar',
|
value: 'Calendar',
|
||||||
)
|
)
|
||||||
|
match_not(
|
||||||
|
css: '.content .NavBarProfile',
|
||||||
|
value: 'Token Access',
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_preferences
|
def test_lang_change
|
||||||
@browser = browser_instance
|
@browser = browser_instance
|
||||||
login(
|
login(
|
||||||
username: 'master@example.com',
|
username: 'master@example.com',
|
||||||
|
@ -369,4 +377,57 @@ class PreferencesTest < TestCase
|
||||||
value: 'Meine'
|
value: 'Meine'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_token_access
|
||||||
|
@browser = browser_instance
|
||||||
|
login(
|
||||||
|
username: 'agent1@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
tasks_close_all()
|
||||||
|
click(css: 'a[href="#current_user"]')
|
||||||
|
click(css: 'a[href="#profile"]')
|
||||||
|
click(css: 'a[href="#profile/token_access"]')
|
||||||
|
|
||||||
|
set(
|
||||||
|
css: '#content .js-create .js-input',
|
||||||
|
value: 'Some App#1',
|
||||||
|
)
|
||||||
|
click(css: '#content .js-create .js-submit')
|
||||||
|
watch_for(
|
||||||
|
css: '.modal .modal-title',
|
||||||
|
value: 'Your New Personal Access Token'
|
||||||
|
)
|
||||||
|
click(css: '.modal .js-submit')
|
||||||
|
watch_for(
|
||||||
|
css: '#content .js-tokenList',
|
||||||
|
value: 'Some App#1'
|
||||||
|
)
|
||||||
|
|
||||||
|
set(
|
||||||
|
css: '#content .js-create .js-input',
|
||||||
|
value: 'Some App#2',
|
||||||
|
)
|
||||||
|
click(css: '#content .js-create .js-submit')
|
||||||
|
watch_for(
|
||||||
|
css: '.modal .modal-title',
|
||||||
|
value: 'Your New Personal Access Token'
|
||||||
|
)
|
||||||
|
click(css: '.modal .js-submit')
|
||||||
|
watch_for(
|
||||||
|
css: '#content .js-tokenList',
|
||||||
|
value: 'Some App#2'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: '#content .js-tokenList a')
|
||||||
|
sleep 1
|
||||||
|
alert = @browser.switch_to.alert
|
||||||
|
alert.accept()
|
||||||
|
watch_for_disappear(
|
||||||
|
css: '#content .js-tokenList',
|
||||||
|
value: 'Some App#2'
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
170
test/controllers/api_auth_controller_test.rb
Normal file
170
test/controllers/api_auth_controller_test.rb
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ApiAuthControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
|
||||||
|
# set accept header
|
||||||
|
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: %w(Admin Agent))
|
||||||
|
groups = Group.all
|
||||||
|
|
||||||
|
UserInfo.current_user_id = 1
|
||||||
|
@admin = User.create_or_update(
|
||||||
|
login: 'api-admin',
|
||||||
|
firstname: 'API',
|
||||||
|
lastname: 'Admin',
|
||||||
|
email: 'api-admin@example.com',
|
||||||
|
password: 'adminpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: 'Agent')
|
||||||
|
@agent = User.create_or_update(
|
||||||
|
login: 'api-agent@example.com',
|
||||||
|
firstname: 'API',
|
||||||
|
lastname: 'Agent',
|
||||||
|
email: 'api-agent@example.com',
|
||||||
|
password: 'agentpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create customer without org
|
||||||
|
roles = Role.where(name: 'Customer')
|
||||||
|
@customer = User.create_or_update(
|
||||||
|
login: 'api-customer1@example.com',
|
||||||
|
firstname: 'API',
|
||||||
|
lastname: 'Customer1',
|
||||||
|
email: 'api-customer1@example.com',
|
||||||
|
password: 'customer1pw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'basic auth - admin' do
|
||||||
|
|
||||||
|
admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('api-admin@example.com', 'adminpw')
|
||||||
|
|
||||||
|
Setting.set('api_password_access', false)
|
||||||
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => admin_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_password_access', true)
|
||||||
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => admin_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'basic auth - agent' do
|
||||||
|
|
||||||
|
agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('api-agent@example.com', 'agentpw')
|
||||||
|
|
||||||
|
Setting.set('api_password_access', false)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_password_access', true)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'basic auth - customer' do
|
||||||
|
|
||||||
|
customer_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('api-customer1@example.com', 'customer1pw')
|
||||||
|
|
||||||
|
Setting.set('api_password_access', false)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_password_access', true)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'token auth - admin' do
|
||||||
|
|
||||||
|
admin_token = Token.create(
|
||||||
|
action: 'api',
|
||||||
|
persistent: true,
|
||||||
|
user_id: @admin.id,
|
||||||
|
)
|
||||||
|
admin_credentials = "Token token=#{admin_token.name}"
|
||||||
|
|
||||||
|
Setting.set('api_token_access', false)
|
||||||
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => admin_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_token_access', true)
|
||||||
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => admin_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'token auth - agent' do
|
||||||
|
|
||||||
|
agent_token = Token.create(
|
||||||
|
action: 'api',
|
||||||
|
persistent: true,
|
||||||
|
user_id: @agent.id,
|
||||||
|
)
|
||||||
|
agent_credentials = "Token token=#{agent_token.name}"
|
||||||
|
|
||||||
|
Setting.set('api_token_access', false)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_token_access', true)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => agent_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'token auth - customer' do
|
||||||
|
|
||||||
|
customer_token = Token.create(
|
||||||
|
action: 'api',
|
||||||
|
persistent: true,
|
||||||
|
user_id: @customer.id,
|
||||||
|
)
|
||||||
|
customer_credentials = "Token token=#{customer_token.name}"
|
||||||
|
|
||||||
|
Setting.set('api_token_access', false)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
Setting.set('api_token_access', true)
|
||||||
|
get '/api/v1/tickets', {}, @headers.merge('Authorization' => customer_credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Array, result.class)
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -13,10 +13,10 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
UserInfo.current_user_id = 1
|
UserInfo.current_user_id = 1
|
||||||
@admin = User.create_or_update(
|
@admin = User.create_or_update(
|
||||||
login: 'packages-admin',
|
login: 'setting-admin',
|
||||||
firstname: 'Packages',
|
firstname: 'Setting',
|
||||||
lastname: 'Admin',
|
lastname: 'Admin',
|
||||||
email: 'packages-admin@example.com',
|
email: 'setting-admin@example.com',
|
||||||
password: 'adminpw',
|
password: 'adminpw',
|
||||||
active: true,
|
active: true,
|
||||||
roles: roles,
|
roles: roles,
|
||||||
|
@ -26,10 +26,10 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
# create agent
|
# create agent
|
||||||
roles = Role.where(name: 'Agent')
|
roles = Role.where(name: 'Agent')
|
||||||
@agent = User.create_or_update(
|
@agent = User.create_or_update(
|
||||||
login: 'packages-agent@example.com',
|
login: 'setting-agent@example.com',
|
||||||
firstname: 'Rest',
|
firstname: 'Setting',
|
||||||
lastname: 'Agent',
|
lastname: 'Agent',
|
||||||
email: 'packages-agent@example.com',
|
email: 'setting-agent@example.com',
|
||||||
password: 'agentpw',
|
password: 'agentpw',
|
||||||
active: true,
|
active: true,
|
||||||
roles: roles,
|
roles: roles,
|
||||||
|
@ -39,10 +39,10 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
# create customer without org
|
# create customer without org
|
||||||
roles = Role.where(name: 'Customer')
|
roles = Role.where(name: 'Customer')
|
||||||
@customer_without_org = User.create_or_update(
|
@customer_without_org = User.create_or_update(
|
||||||
login: 'packages-customer1@example.com',
|
login: 'setting-customer1@example.com',
|
||||||
firstname: 'Packages',
|
firstname: 'Setting',
|
||||||
lastname: 'Customer1',
|
lastname: 'Customer1',
|
||||||
email: 'packages-customer1@example.com',
|
email: 'setting-customer1@example.com',
|
||||||
password: 'customer1pw',
|
password: 'customer1pw',
|
||||||
active: true,
|
active: true,
|
||||||
roles: roles,
|
roles: roles,
|
||||||
|
@ -63,7 +63,7 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
test 'settings index with admin' do
|
test 'settings index with admin' do
|
||||||
|
|
||||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-admin@example.com', 'adminpw')
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('setting-admin@example.com', 'adminpw')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||||
|
@ -76,7 +76,7 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
test 'settings index with agent' do
|
test 'settings index with agent' do
|
||||||
|
|
||||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-agent@example.com', 'adminpw')
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('setting-agent@example.com', 'agentpw')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||||
|
@ -89,7 +89,7 @@ class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
test 'settings index with customer' do
|
test 'settings index with customer' do
|
||||||
|
|
||||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-customer1@example.com', 'customer1pw')
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('setting-customer1@example.com', 'customer1pw')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||||
|
|
|
@ -99,7 +99,7 @@ class TokenTest < ActiveSupport::TestCase
|
||||||
if test[:name]
|
if test[:name]
|
||||||
#puts test[:test_name] + ': deleting token '+ test[:name]
|
#puts test[:test_name] + ': deleting token '+ test[:name]
|
||||||
|
|
||||||
token = Token.where( name: test[:name] ).first
|
token = Token.find_by(name: test[:name])
|
||||||
|
|
||||||
if token
|
if token
|
||||||
token.destroy
|
token.destroy
|
||||||
|
|
Loading…
Reference in a new issue