mirror of
https://github.com/redmine/redmine.git
synced 2026-04-13 07:58:18 +02:00
Track last usage of API access keys (#43938).
Patch by Vincent Robert (user:Nanego). git-svn-id: https://svn.redmine.org/redmine/trunk@24576 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -94,9 +94,15 @@ class Token < ApplicationRecord
|
||||
|
||||
# Returns the active user who owns the key for the given action
|
||||
def self.find_active_user(action, key, validity_days=nil)
|
||||
user = find_user(action, key, validity_days)
|
||||
if user && user.active?
|
||||
user
|
||||
token = find_token(action, key, validity_days)
|
||||
if token
|
||||
user = token.user
|
||||
if user&.active?
|
||||
if token.updated_on.nil? || token.updated_on <= 1.minute.ago
|
||||
token.update_column(:updated_on, Time.now.utc)
|
||||
end
|
||||
user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -38,9 +38,14 @@
|
||||
<%= javascript_tag("$('#api-access-key').hide();") %>
|
||||
<p>
|
||||
<% if @user.api_token %>
|
||||
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %>
|
||||
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %><br />
|
||||
<% if @user.api_token.updated_on > @user.api_token.created_on %>
|
||||
<%= l(:label_api_access_key_last_used_on, distance_of_time_in_words(Time.now, @user.api_token.updated_on)) %>
|
||||
<% else %>
|
||||
<%= l(:label_api_access_key_never_used) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= l(:label_missing_api_access_key) %>
|
||||
<%= l(:label_missing_api_access_key) %>
|
||||
<% end %>
|
||||
(<%= link_to l(:button_reset), my_api_key_path, :method => :post %>)
|
||||
</p>
|
||||
|
||||
@@ -434,6 +434,8 @@ de:
|
||||
label_any_issues_not_in_project: irgendein Ticket nicht im Projekt
|
||||
label_api_access_key: API-Zugriffsschlüssel
|
||||
label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt
|
||||
label_api_access_key_last_used_on: "Zuletzt verwendet: vor %{value}"
|
||||
label_api_access_key_never_used: Nie verwendet
|
||||
label_applied_status: Zugewiesener Status
|
||||
label_ascending: Aufsteigend
|
||||
label_ask: Nachfragen
|
||||
|
||||
@@ -1035,6 +1035,8 @@ en:
|
||||
label_api_access_key: API access key
|
||||
label_missing_api_access_key: Missing an API access key
|
||||
label_api_access_key_created_on: "API access key created %{value} ago"
|
||||
label_api_access_key_last_used_on: "Last used: %{value} ago"
|
||||
label_api_access_key_never_used: Never used
|
||||
label_profile: Profile
|
||||
label_subtask: Subtask
|
||||
label_subtask_plural: Subtasks
|
||||
|
||||
@@ -921,6 +921,8 @@ fr:
|
||||
label_api_access_key: Clé d'accès API
|
||||
label_missing_api_access_key: Clé d'accès API manquante
|
||||
label_api_access_key_created_on: Clé d'accès API créée il y a %{value}
|
||||
label_api_access_key_last_used_on: "Dernier usage : il y a %{value}"
|
||||
label_api_access_key_never_used: Jamais utilisée
|
||||
label_profile: Profil
|
||||
label_subtask_plural: Sous-tâches
|
||||
label_project_copy_notifications: Envoyer les notifications durant la copie du projet
|
||||
|
||||
@@ -806,6 +806,8 @@ ja:
|
||||
label_api_access_key: APIアクセスキー
|
||||
label_missing_api_access_key: APIアクセスキーが見つかりません
|
||||
label_api_access_key_created_on: "APIアクセスキーは%{value}前に作成されました"
|
||||
label_api_access_key_last_used_on: "最終使用:%{value}前"
|
||||
label_api_access_key_never_used: 未使用
|
||||
label_subtask_plural: 子チケット
|
||||
label_project_copy_notifications: コピーしたチケットのメール通知を送信する
|
||||
label_principal_search: "ユーザーまたはグループの検索:"
|
||||
|
||||
@@ -161,4 +161,40 @@ class Redmine::ApiTest::AuthenticationTest < Redmine::ApiTest::Base
|
||||
assert_response :success
|
||||
assert_select 'h2', :text => "#{user.initials} #{user.name}"
|
||||
end
|
||||
|
||||
def test_api_key_usage_via_header_should_update_updated_on
|
||||
user = User.generate!
|
||||
token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
get '/users/current.xml', :headers => {'X-Redmine-API-Key' => token.value}
|
||||
assert_response :ok
|
||||
assert token.reload.updated_on > updated
|
||||
end
|
||||
|
||||
def test_api_key_usage_via_parameter_should_update_updated_on
|
||||
user = User.generate!
|
||||
token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
get "/users/current.xml?key=#{token.value}"
|
||||
assert_response :ok
|
||||
assert token.reload.updated_on > updated
|
||||
end
|
||||
|
||||
def test_api_key_usage_via_basic_auth_should_update_updated_on
|
||||
user = User.generate!
|
||||
token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
get '/users/current.xml', :headers => credentials(token.value, 'X')
|
||||
assert_response :ok
|
||||
assert token.reload.updated_on > updated
|
||||
end
|
||||
|
||||
def test_failed_api_auth_should_not_update_updated_on
|
||||
user = User.generate!
|
||||
token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
get '/users/current.xml', :headers => {'X-Redmine-API-Key' => 'wrong_key'}
|
||||
assert_response :unauthorized
|
||||
assert_equal updated.to_i, token.reload.updated_on.to_i
|
||||
end
|
||||
end
|
||||
|
||||
@@ -137,4 +137,25 @@ class TokenTest < ActiveSupport::TestCase
|
||||
token = Token.create!(:user_id => 999, :action => 'api', :created_on => 2.days.ago)
|
||||
assert_nil Token.find_token('api', token.value, 1)
|
||||
end
|
||||
|
||||
def test_find_active_user_should_bump_updated_on_when_not_recently_updated
|
||||
token = Token.create!(:user_id => 1, :action => 'api', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
Token.find_active_user('api', token.value)
|
||||
assert token.reload.updated_on > updated
|
||||
end
|
||||
|
||||
def test_find_active_user_should_not_bump_updated_on_within_one_minute
|
||||
token = Token.create!(:user_id => 1, :action => 'api', :updated_on => 1.second.ago)
|
||||
updated = token.reload.updated_on
|
||||
Token.find_active_user('api', token.value)
|
||||
assert_equal updated.to_i, token.reload.updated_on.to_i
|
||||
end
|
||||
|
||||
def test_find_active_user_should_bump_updated_on_for_feeds_token
|
||||
token = Token.create!(:user_id => 1, :action => 'feeds', :updated_on => 2.minutes.ago)
|
||||
updated = token.updated_on
|
||||
Token.find_active_user('feeds', token.value)
|
||||
assert token.reload.updated_on > updated
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user