Commit 6c809dfa authored by Timothy Andrew's avatar Timothy Andrew

Allow creating personal access tokens / OAuth applications with scopes.

parent 1d0ccec6
......@@ -262,3 +262,13 @@ table.u2f-registrations {
border-right: solid 1px transparent;
}
}
.oauth-application-show {
.scope-name {
font-weight: 600;
}
.scopes-list {
padding-left: 18px;
}
}
\ No newline at end of file
class Admin::ApplicationsController < Admin::ApplicationController
include OauthApplications
before_action :set_application, only: [:show, :edit, :update, :destroy]
def index
......@@ -10,9 +12,11 @@ class Admin::ApplicationsController < Admin::ApplicationController
def new
@application = Doorkeeper::Application.new
@scopes = Doorkeeper.configuration.scopes
end
def edit
@scopes = Doorkeeper.configuration.scopes
end
def create
......@@ -47,6 +51,6 @@ class Admin::ApplicationsController < Admin::ApplicationController
# Only allow a trusted parameter "white list" through.
def application_params
params[:doorkeeper_application].permit(:name, :redirect_uri)
params[:doorkeeper_application].permit(:name, :redirect_uri, :scopes)
end
end
module OauthApplications
extend ActiveSupport::Concern
included do
before_action :prepare_scopes, only: [:create, :update]
end
def prepare_scopes
scopes = params.dig(:doorkeeper_application, :scopes)
if scopes
params[:doorkeeper_application][:scopes] = scopes.join(' ')
end
end
end
......@@ -2,6 +2,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
include Gitlab::CurrentSettings
include Gitlab::GonHelper
include PageLayoutHelper
include OauthApplications
before_action :verify_user_oauth_applications_enabled
before_action :authenticate_user!
......@@ -13,6 +14,10 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
set_index_vars
end
def edit
@scopes = Doorkeeper.configuration.scopes
end
def create
@application = Doorkeeper::Application.new(application_params)
......@@ -40,6 +45,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
@authorized_tokens = current_user.oauth_authorized_tokens
@authorized_anonymous_tokens = @authorized_tokens.reject(&:application)
@authorized_apps = @authorized_tokens.map(&:application).uniq.reject(&:nil?)
@scopes = Doorkeeper.configuration.scopes
# Don't overwrite a value possibly set by `create`
@application ||= Doorkeeper::Application.new
......
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
before_action :load_personal_access_tokens, only: :index
def index
@personal_access_token = current_user.personal_access_tokens.build
set_index_vars
end
def create
......@@ -12,7 +10,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
flash[:personal_access_token] = @personal_access_token.token
redirect_to profile_personal_access_tokens_path, notice: "Your new personal access token has been created."
else
load_personal_access_tokens
set_index_vars
render :index
end
end
......@@ -32,10 +30,12 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
private
def personal_access_token_params
params.require(:personal_access_token).permit(:name, :expires_at)
params.require(:personal_access_token).permit(:name, :expires_at, scopes: [])
end
def load_personal_access_tokens
def set_index_vars
@personal_access_token ||= current_user.personal_access_tokens.build
@scopes = Gitlab::Auth::SCOPES
@active_personal_access_tokens = current_user.personal_access_tokens.active.order(:expires_at)
@inactive_personal_access_tokens = current_user.personal_access_tokens.inactive
end
......
......@@ -18,6 +18,16 @@
Use
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
.form-group
= f.label :scopes, class: 'col-sm-2 control-label'
.col-sm-10
- @scopes.each do |scope|
%fieldset
= check_box_tag 'doorkeeper_application[scopes][]', scope, application.scopes.include?(scope), id: "doorkeeper_application_scopes_#{scope}"
= label_tag "doorkeeper_application_scopes_#{scope}", scope
%span= "(#{t(scope, scope: [:doorkeeper, :scopes])})"
.form-actions
= f.submit 'Submit', class: "btn btn-save wide"
= link_to "Cancel", admin_applications_path, class: "btn btn-default"
......@@ -2,8 +2,7 @@
%h3.page-title
Application: #{@application.name}
.table-holder
.table-holder.oauth-application-show
%table.table
%tr
%td
......@@ -23,6 +22,18 @@
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
- if @application.scopes.present?
%tr
%td
Scopes
%td
%ul.scopes-list.append-bottom-0
- @application.scopes.each do |scope|
%li
%span.scope-name= scope
= "(#{t(scope, scope: [:doorkeeper, :scopes])})"
.form-actions
= link_to 'Edit', edit_admin_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
......@@ -17,5 +17,14 @@
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
.form-group
= f.label :scopes, class: 'label-light'
- @scopes.each do |scope|
%fieldset
= check_box_tag 'doorkeeper_application[scopes][]', scope, application.scopes.include?(scope), id: "doorkeeper_application_scopes_#{scope}"
= label_tag "doorkeeper_application_scopes_#{scope}", scope
%span= "(#{t(scope, scope: [:doorkeeper, :scopes])})"
.prepend-top-default
= f.submit 'Save application', class: "btn btn-create"
......@@ -2,7 +2,7 @@
%h3.page-title
Application: #{@application.name}
.table-holder
.table-holder.oauth-application-show
%table.table
%tr
%td
......@@ -22,6 +22,19 @@
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
- if @application.scopes.present?
%tr
%td
Scopes
%td
%ul.scopes-list.append-bottom-0
- @application.scopes.each do |scope|
%li
%span.scope-name= scope
= "(#{t(scope, scope: [:doorkeeper, :scopes])})"
.form-actions
= link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
= form_for [:profile, @personal_access_token], method: :post, html: { class: 'js-requires-input' } do |f|
= form_errors(@personal_access_token)
.form-group
= 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: "datepicker form-control", required: false
.form-group
= f.label :scopes, class: 'label-light'
- @scopes.each do |scope|
%fieldset
= check_box_tag 'personal_access_token[scopes][]', scope, @personal_access_token.scopes.include?(scope), id: "personal_access_token_scopes_#{scope}"
= label_tag "personal_access_token_scopes_#{scope}", scope
%span= "(#{t(scope, scope: [:doorkeeper, :scopes])})"
.prepend-top-default
= f.submit 'Create Personal Access Token', class: "btn btn-create"
......@@ -28,21 +28,8 @@
Add a Personal Access Token
%p.profile-settings-content
Pick a name for the application, and we'll give you a unique token.
= form_for [:profile, @personal_access_token],
method: :post, html: { class: 'js-requires-input' } do |f|
= form_errors(@personal_access_token)
.form-group
= 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: "datepicker form-control", required: false
.prepend-top-default
= f.submit 'Create Personal Access Token', class: "btn btn-create"
= render "form"
%hr
......@@ -56,6 +43,7 @@
%th Name
%th Created
%th Expires
%th Scopes
%th
%tbody
- @active_personal_access_tokens.each do |token|
......@@ -67,6 +55,7 @@
= token.expires_at.to_date.to_s(:medium)
- else
%span.personal-access-tokens-never-expires-label Never
%td= token.scopes.present? ? token.scopes.join(", ") : "<no scopes selected>"
%td= link_to "Revoke", revoke_profile_personal_access_token_path(token), method: :put, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to revoke this token? This action cannot be undone." }
- else
......
......@@ -51,6 +51,32 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
expect(active_personal_access_tokens).to have_text(Date.today.next_month.at_beginning_of_month.to_s(:medium))
end
context "scopes" do
it "allows creation of a token with scopes" do
visit profile_personal_access_tokens_path
fill_in "Name", with: FFaker::Product.brand
check "api"
check "read_user"
expect {click_on "Create Personal Access Token"}.to change { PersonalAccessToken.count }.by(1)
expect(created_personal_access_token).to eq(PersonalAccessToken.last.token)
expect(PersonalAccessToken.last.scopes).to match_array(['api', 'read_user'])
expect(active_personal_access_tokens).to have_text('api')
expect(active_personal_access_tokens).to have_text('read_user')
end
it "allows creation of a token with no scopes" do
visit profile_personal_access_tokens_path
fill_in "Name", with: FFaker::Product.brand
expect {click_on "Create Personal Access Token"}.to change { PersonalAccessToken.count }.by(1)
expect(created_personal_access_token).to eq(PersonalAccessToken.last.token)
expect(PersonalAccessToken.last.scopes).to eq([])
expect(active_personal_access_tokens).to have_text('no scopes')
end
end
context "when creation fails" do
it "displays an error message" do
disallow_personal_access_token_saves!
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment