<%= token.label %> |
<% if token.preferences && token.preferences.permission: %><%= token.preferences.permission.join(', ') %><% end %> |
<%- @humanTime(token.created_at) %> |
-
+
+
<% for permission in @permissions: %>
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 2c4bad688..8db91f5ea 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -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
diff --git a/app/controllers/user_access_token_controller.rb b/app/controllers/user_access_token_controller.rb
index ce965d91a..33d9e291c 100644
--- a/app/controllers/user_access_token_controller.rb
+++ b/app/controllers/user_access_token_controller.rb
@@ -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]
}
diff --git a/app/models/token.rb b/app/models/token.rb
index fc02570ee..909f38f64 100644
--- a/app/models/token.rb
+++ b/app/models/token.rb
@@ -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
diff --git a/db/migrate/20120101000001_create_base.rb b/db/migrate/20120101000001_create_base.rb
index 67f458be9..586527349 100644
--- a/db/migrate/20120101000001_create_base.rb
+++ b/db/migrate/20120101000001_create_base.rb
@@ -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
diff --git a/db/migrate/20160830000001_token_attributes.rb b/db/migrate/20160830000001_token_attributes.rb
new file mode 100644
index 000000000..b29d6d135
--- /dev/null
+++ b/db/migrate/20160830000001_token_attributes.rb
@@ -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
diff --git a/test/browser/preferences_test.rb b/test/browser/preferences_test.rb
index 9d67948bb..f6856e554 100644
--- a/test/browser/preferences_test.rb
+++ b/test/browser/preferences_test.rb
@@ -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(
diff --git a/test/controllers/api_auth_controller_test.rb b/test/controllers/api_auth_controller_test.rb
index 1e69c0272..e7d274673 100644
--- a/test/controllers/api_auth_controller_test.rb
+++ b/test/controllers/api_auth_controller_test.rb
@@ -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
|