Browse Source

Added token attributes last_used_at and expires_at.

Thorsten Eckel 8 years ago
parent
commit
fa4e953423

+ 6 - 1
app/assets/javascripts/app/controllers/_profile/token_access.coffee

@@ -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()

+ 2 - 6
app/assets/javascripts/app/views/profile/token_access.jst.eco

@@ -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>

+ 7 - 0
app/assets/javascripts/app/views/profile/token_access_create.jst.eco

@@ -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: %>

+ 18 - 5
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
 

+ 1 - 0
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]
       }

+ 3 - 3
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

+ 2 - 0
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

+ 9 - 0
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

+ 9 - 0
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(

+ 44 - 0
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