Added token attributes last_used_at and expires_at.
This commit is contained in:
parent
105fca030d
commit
fa4e953423
10 changed files with 101 additions and 15 deletions
|
@ -81,9 +81,14 @@ class Create extends App.ControllerModal
|
|||
shown: true
|
||||
|
||||
content: ->
|
||||
App.view('profile/token_access_create')(
|
||||
content = $(App.view('profile/token_access_create')(
|
||||
permissions: @permissions
|
||||
))
|
||||
datepicker = App.UiElement.date.render(
|
||||
name: 'expires_at',
|
||||
)
|
||||
content.find('.js-date').html(datepicker)
|
||||
content
|
||||
|
||||
onSubmit: (e) =>
|
||||
e.preventDefault()
|
||||
|
|
|
@ -16,27 +16,23 @@
|
|||
<th><%- @T('Name') %></th>
|
||||
<th><%- @T('Permission') %></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') %>
|
||||
<td colspan="6"><%- @T('none') %>
|
||||
<% else: %>
|
||||
<% for token in @tokens: %>
|
||||
<tr>
|
||||
<td><%= token.label %></td>
|
||||
<td><% if token.preferences && token.preferences.permission: %><%= token.preferences.permission.join(', ') %><% end %></td>
|
||||
<td><%- @humanTime(token.created_at) %></td>
|
||||
<!--
|
||||
<td><%- @humanTime(token.expired_at) %></td>
|
||||
<td><%- @Tdate(token.expires_at) %></td>
|
||||
<td><%- @humanTime(token.last_used_at) %></td>
|
||||
-->
|
||||
<td class="settings-list-controls">
|
||||
<div>
|
||||
<a class="settings-list-control js-delete" href="#" data-token-id="<%- token.id %>" title="<%- @Ti('Delete') %>"><%- @Icon('trash') %></a>
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
<div class="controls"><input id="token-label" type="text" name="label" value="" class="form-control js-input" required></div>
|
||||
</div>
|
||||
|
||||
<div class="input form-group">
|
||||
<div class="formGroup-label">
|
||||
<label for="token-label"><%- @T('Expires') %></label>
|
||||
</div>
|
||||
<div class="controls js-date"></div>
|
||||
</div>
|
||||
|
||||
<div class="permission form-group checkbox">
|
||||
<div class="checkbox">
|
||||
<% for permission in @permissions: %>
|
||||
|
|
|
@ -260,27 +260,40 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
# check http token based authentication
|
||||
authenticate_with_http_token do |token, _options|
|
||||
logger.debug "http token auth check '#{token}'"
|
||||
authenticate_with_http_token do |token_string, _options|
|
||||
logger.debug "http token auth check '#{token_string}'"
|
||||
request.session_options[:skip] = true # do not send a session cookie
|
||||
if Setting.get('api_token_access') == false
|
||||
raise Exceptions::NotAuthorized, 'API token access disabled!'
|
||||
end
|
||||
user = Token.check(
|
||||
action: 'api',
|
||||
name: token,
|
||||
name: token_string,
|
||||
inactive_user: true,
|
||||
)
|
||||
if user && auth_param[:permission]
|
||||
user = Token.check(
|
||||
action: 'api',
|
||||
name: token,
|
||||
name: token_string,
|
||||
permission: auth_param[:permission],
|
||||
inactive_user: true,
|
||||
)
|
||||
raise Exceptions::NotAuthorized, 'Not authorized (token)!' if !user
|
||||
end
|
||||
@_token_auth = token # remember for permission_check
|
||||
|
||||
if user
|
||||
token = Token.find_by(name: token_string)
|
||||
|
||||
token.last_used_at = Time.zone.now
|
||||
token.save!
|
||||
|
||||
if token.expires_at &&
|
||||
Time.zone.today >= token.expires_at
|
||||
raise Exceptions::NotAuthorized, 'Not authorized (token expired)!'
|
||||
end
|
||||
end
|
||||
|
||||
@_token_auth = token_string # remember for permission_check
|
||||
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
|
||||
end
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ class UserAccessTokenController < ApplicationController
|
|||
label: params[:label],
|
||||
persistent: true,
|
||||
user_id: current_user.id,
|
||||
expires_at: params[:expires_at],
|
||||
preferences: {
|
||||
permission: params[:permission]
|
||||
}
|
||||
|
|
|
@ -40,11 +40,11 @@ returns
|
|||
|
||||
check token
|
||||
|
||||
user = Token.check(action: 'PasswordReset', name: 'TheTokenItSelf')
|
||||
user = Token.check(action: 'PasswordReset', name: '123abc12qweads')
|
||||
|
||||
check api token with permissions
|
||||
|
||||
user = Token.check(action: 'api', name: 'TheTokenItSelf', permission: 'admin.session')
|
||||
user = Token.check(action: 'api', name: '123abc12qweads', permission: 'admin.session')
|
||||
|
||||
returns
|
||||
|
||||
|
@ -70,7 +70,7 @@ returns
|
|||
|
||||
user = token.user
|
||||
|
||||
# persistent token not valid if user is inative
|
||||
# persistent token not valid if user is inactive
|
||||
if !data[:inactive_user]
|
||||
return if token.persistent && user.active == false
|
||||
end
|
||||
|
|
|
@ -205,6 +205,8 @@ class CreateBase < ActiveRecord::Migration
|
|||
t.string :action, limit: 40, null: false
|
||||
t.string :label, limit: 255, null: true
|
||||
t.text :preferences, limit: 500.kilobytes + 1, null: true
|
||||
t.timestamp :last_used_at, null: true
|
||||
t.date :expires_at, null: true
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_index :tokens, :user_id
|
||||
|
|
9
db/migrate/20160830000001_token_attributes.rb
Normal file
9
db/migrate/20160830000001_token_attributes.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class TokenAttributes < ActiveRecord::Migration
|
||||
def up
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
add_column :tokens, :last_used_at, :datetime, null: true
|
||||
add_column :tokens, :expires_at, :date, null: true
|
||||
end
|
||||
end
|
|
@ -417,6 +417,11 @@ class PreferencesTest < TestCase
|
|||
css: '#content .modal .js-input',
|
||||
value: 'Some App#1',
|
||||
)
|
||||
set(
|
||||
css: '#content .modal .js-datepicker',
|
||||
value: '05/15/2022',
|
||||
)
|
||||
sendkey(value: :tab)
|
||||
click(css: '#content .modal input[value="ticket.agent"] ~ .label-text')
|
||||
click(css: '#content .modal .js-submit')
|
||||
watch_for(
|
||||
|
@ -428,6 +433,10 @@ class PreferencesTest < TestCase
|
|||
css: '#content .js-tokenList',
|
||||
value: 'Some App#1'
|
||||
)
|
||||
watch_for(
|
||||
css: '#content .js-tokenList',
|
||||
value: '05/15/2022'
|
||||
)
|
||||
|
||||
click(css: '#content .js-create')
|
||||
watch_for(
|
||||
|
|
|
@ -270,4 +270,48 @@ class ApiAuthControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_equal('User is inactive!', result['error'])
|
||||
end
|
||||
|
||||
test 'token auth - expired' do
|
||||
|
||||
Setting.set('api_token_access', true)
|
||||
|
||||
admin_token = Token.create(
|
||||
action: 'api',
|
||||
persistent: true,
|
||||
user_id: @admin.id,
|
||||
expires_at: Time.zone.today
|
||||
)
|
||||
admin_credentials = "Token token=#{admin_token.name}"
|
||||
|
||||
get '/api/v1/tickets', {}, @headers.merge('Authorization' => admin_credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal('Not authorized (token expired)!', result['error'])
|
||||
|
||||
admin_token.reload
|
||||
assert_in_delta(admin_token.last_used_at, Time.zone.now, 1.second)
|
||||
end
|
||||
|
||||
test 'token auth - not expired' do
|
||||
|
||||
Setting.set('api_token_access', true)
|
||||
|
||||
admin_token = Token.create(
|
||||
action: 'api',
|
||||
persistent: true,
|
||||
user_id: @admin.id,
|
||||
expires_at: Time.zone.tomorrow
|
||||
)
|
||||
admin_credentials = "Token token=#{admin_token.name}"
|
||||
|
||||
get '/api/v1/tickets', {}, @headers.merge('Authorization' => admin_credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Array, result.class)
|
||||
assert(result)
|
||||
|
||||
admin_token.reload
|
||||
assert_in_delta(admin_token.last_used_at, Time.zone.now, 1.second)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue