Allow creating personal access tokens / OAuth applications with scopes.
This commit is contained in:
parent
1d0ccec6dd
commit
6c809dfae8
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
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
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
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
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
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'
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
= 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!
|
||||
|
|
Loading…
Reference in New Issue