summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/pages/profile.scss4
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb2
-rw-r--r--app/models/personal_access_token.rb2
-rw-r--r--app/views/profiles/personal_access_tokens/index.html.haml20
-rw-r--r--db/migrate/20160418085954_add_column_expires_at_to_personal_access_tokens.rb5
-rw-r--r--spec/factories/personal_access_tokens.rb9
-rw-r--r--spec/requests/api/api_authentication_spec.rb72
7 files changed, 94 insertions, 20 deletions
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 5a4d0a5c8b0..8c62c97215f 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -207,4 +207,8 @@
}
.personal-access-tokens-revoked-label {
color: #bbb;
+}
+
+.personal-access-tokens-never-expires-label {
+ color: #bbb;
} \ No newline at end of file
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index 59de0b26eee..d01afbfe119 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -31,6 +31,6 @@ class Profiles::PersonalAccessTokensController < ApplicationController
private
def personal_access_token_params
- params.require(:personal_access_token).permit(:name)
+ params.require(:personal_access_token).permit(:name, :expires_at)
end
end
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index e5f1f9749f8..dd64374481f 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -1,7 +1,7 @@
class PersonalAccessToken < ActiveRecord::Base
belongs_to :user
- scope :active, -> { where.not(revoked: true) }
+ scope :active, -> { where.not(revoked: true).where("expires_at >= :current", current: Time.current) }
def self.generate(params)
personal_access_token = self.new(params)
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 02d15269c85..f3d5f07cdd3 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -18,6 +18,10 @@
= f.label :name, class: 'label-light'
= f.text_field :name, class: "form-control", required: true
+ .form-group
+ = f.label :expires_at, class: 'label-light'
+ = f.text_field :expires_at, class: "form-control datepicker", required: false
+
.prepend-top-default
= f.submit 'Add Personal Access Token', class: "btn btn-create"
@@ -34,13 +38,19 @@
%th Name
%th Token
%th Created At
+ %th Expires At
%th Actions
%tbody
- - @user.personal_access_tokens.order(:revoked).each do |token|
+ - @user.personal_access_tokens.order("revoked, expires_at").each do |token|
%tr
%td= token.name
%td= token.token
%td= token.created_at
+ - if token.expires_at.present?
+ %td= token.expires_at.to_date
+ - else
+ %td
+ %span.personal-access-tokens-never-expires-label Never
- if token.revoked?
%td
%span.personal-access-tokens-revoked-label Revoked
@@ -48,4 +58,10 @@
%td= link_to "Revoke", revoke_profile_personal_access_token_path(token), method: :put, class: "btn btn-danger", data: {confirm: t('profile.personal_access_tokens.revoke.confirmation')}
- else
- %span You don't have any tokens yet. \ No newline at end of file
+ %span You don't have any tokens yet.
+
+:javascript
+ $(".datepicker").datepicker({
+ dateFormat: "yy-mm-dd",
+ onSelect: function(dateText, inst) { $("#personal_access_token_expires_at").val(dateText) }
+ }).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#personal_access_token_expires_at').val())); \ No newline at end of file
diff --git a/db/migrate/20160418085954_add_column_expires_at_to_personal_access_tokens.rb b/db/migrate/20160418085954_add_column_expires_at_to_personal_access_tokens.rb
new file mode 100644
index 00000000000..9d99ebeadf5
--- /dev/null
+++ b/db/migrate/20160418085954_add_column_expires_at_to_personal_access_tokens.rb
@@ -0,0 +1,5 @@
+class AddColumnExpiresAtToPersonalAccessTokens < ActiveRecord::Migration
+ def change
+ add_column :personal_access_tokens, :expires_at, :datetime
+ end
+end
diff --git a/spec/factories/personal_access_tokens.rb b/spec/factories/personal_access_tokens.rb
new file mode 100644
index 00000000000..da4c72bcb5b
--- /dev/null
+++ b/spec/factories/personal_access_tokens.rb
@@ -0,0 +1,9 @@
+FactoryGirl.define do
+ factory :personal_access_token do
+ user
+ token { SecureRandom.hex(50) }
+ name { FFaker::Product.brand }
+ revoked false
+ expires_at { 5.days.from_now }
+ end
+end
diff --git a/spec/requests/api/api_authentication_spec.rb b/spec/requests/api/api_authentication_spec.rb
index 8bed3bb119b..0416e57c68b 100644
--- a/spec/requests/api/api_authentication_spec.rb
+++ b/spec/requests/api/api_authentication_spec.rb
@@ -41,24 +41,64 @@ describe API::Helpers::Authentication, api: true do
end
describe ".current_user" do
- it "should return nil for an invalid token" do
- env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = 'invalid token'
- allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
- expect(current_user).to be_nil
+ describe "when authenticating using a user's private token" do
+ it "should return nil for an invalid token" do
+ env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = 'invalid token'
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ expect(current_user).to be_nil
+ end
+
+ it "should return nil for a user without access" do
+ env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = user.private_token
+ allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
+ expect(current_user).to be_nil
+ end
+
+ it "should leave user as is when sudo not specified" do
+ env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = user.private_token
+ expect(current_user).to eq(user)
+ clear_env
+ params[API::Helpers::Authentication::PRIVATE_TOKEN_PARAM] = user.private_token
+ expect(current_user).to eq(user)
+ end
end
- it "should return nil for a user without access" do
- env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = user.private_token
- allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
- expect(current_user).to be_nil
- end
-
- it "should leave user as is when sudo not specified" do
- env[API::Helpers::Authentication::PRIVATE_TOKEN_HEADER] = user.private_token
- expect(current_user).to eq(user)
- clear_env
- params[API::Helpers::Authentication::PRIVATE_TOKEN_PARAM] = user.private_token
- expect(current_user).to eq(user)
+ describe "when authenticating using a user's personal access tokens" do
+ let(:personal_access_token) { create(:personal_access_token, user: user) }
+
+ it "should return nil for an invalid token" do
+ env[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_HEADER] = 'invalid token'
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ expect(current_user).to be_nil
+ end
+
+ it "should return nil for a user without access" do
+ env[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_HEADER] = personal_access_token.token
+ allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
+ expect(current_user).to be_nil
+ end
+
+ it "should leave user as is when sudo not specified" do
+ env[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_HEADER] = personal_access_token.token
+ expect(current_user).to eq(user)
+ clear_env
+ params[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_PARAM] = personal_access_token.token
+ expect(current_user).to eq(user)
+ end
+
+ it 'does not allow revoked tokens' do
+ personal_access_token.revoke!
+ env[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_HEADER] = personal_access_token.token
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ expect(current_user).to be_nil
+ end
+
+ it 'does not allow expired tokens' do
+ personal_access_token.update_attributes!(expires_at: 1.day.ago)
+ env[API::Helpers::Authentication::PERSONAL_ACCESS_TOKEN_HEADER] = personal_access_token.token
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ expect(current_user).to be_nil
+ end
end
it "should change current user to sudo when admin" do