Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
3f24f9ed
Commit
3f24f9ed
authored
Oct 12, 2017
by
Douwe Maan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add sudo API scope
parent
a1781a49
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
74 additions
and
98 deletions
+74
-98
app/controllers/admin/impersonation_tokens_controller.rb
app/controllers/admin/impersonation_tokens_controller.rb
+1
-1
app/controllers/profiles/personal_access_tokens_controller.rb
...controllers/profiles/personal_access_tokens_controller.rb
+1
-1
app/services/access_token_validation_service.rb
app/services/access_token_validation_service.rb
+2
-5
config/locales/doorkeeper.en.yml
config/locales/doorkeeper.en.yml
+3
-2
lib/api/api_guard.rb
lib/api/api_guard.rb
+38
-66
lib/api/helpers.rb
lib/api/helpers.rb
+12
-8
lib/gitlab/auth.rb
lib/gitlab/auth.rb
+5
-3
spec/lib/gitlab/auth_spec.rb
spec/lib/gitlab/auth_spec.rb
+2
-2
spec/requests/api/doorkeeper_access_spec.rb
spec/requests/api/doorkeeper_access_spec.rb
+4
-4
spec/requests/api/helpers_spec.rb
spec/requests/api/helpers_spec.rb
+4
-4
spec/requests/api/users_spec.rb
spec/requests/api/users_spec.rb
+2
-2
No files found.
app/controllers/admin/impersonation_tokens_controller.rb
View file @
3f24f9ed
...
...
@@ -44,7 +44,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
end
def
set_index_vars
@scopes
=
Gitlab
::
Auth
::
API_SCOPES
@scopes
=
Gitlab
::
Auth
.
available_scopes
(
current_user
)
@impersonation_token
||=
finder
.
build
@inactive_impersonation_tokens
=
finder
(
state:
'inactive'
).
execute
...
...
app/controllers/profiles/personal_access_tokens_controller.rb
View file @
3f24f9ed
...
...
@@ -39,7 +39,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
end
def
set_index_vars
@scopes
=
Gitlab
::
Auth
.
available_scopes
@scopes
=
Gitlab
::
Auth
.
available_scopes
(
current_user
)
@inactive_personal_access_tokens
=
finder
(
state:
'inactive'
).
execute
@active_personal_access_tokens
=
finder
(
state:
'active'
).
execute
.
order
(
:expires_at
)
...
...
app/services/access_token_validation_service.rb
View file @
3f24f9ed
...
...
@@ -39,11 +39,8 @@ class AccessTokenValidationService
token_scopes
=
token
.
scopes
.
map
(
&
:to_sym
)
required_scopes
.
any?
do
|
scope
|
if
scope
.
respond_to?
(
:sufficient?
)
scope
.
sufficient?
(
token_scopes
,
request
)
else
API
::
Scope
.
new
(
scope
).
sufficient?
(
token_scopes
,
request
)
end
scope
=
API
::
Scope
.
new
(
scope
)
unless
scope
.
is_a?
(
API
::
Scope
)
scope
.
sufficient?
(
token_scopes
,
request
)
end
end
end
...
...
config/locales/doorkeeper.en.yml
View file @
3f24f9ed
...
...
@@ -58,9 +58,10 @@ en:
expired
:
"
The
access
token
expired"
unknown
:
"
The
access
token
is
invalid"
scopes
:
api
:
Access
your
API
read_user
:
Read
user
information
api
:
Access
the authenticated user's
API
read_user
:
Read
the authenticated user's personal
information
openid
:
Authenticate using OpenID Connect
sudo
:
Perform API actions as any user in the system (if the authenticated user is an admin)
flash
:
applications
:
...
...
lib/api/api_guard.rb
View file @
3f24f9ed
...
...
@@ -42,62 +42,42 @@ module API
# Helper Methods for Grape Endpoint
module
HelperMethods
def
find_current_user
user
=
find_user_from_personal_access_token
||
find_user_from_oauth_token
||
find_user_from_warden
def
find_current_user!
user
=
find_user_from_access_token
||
find_user_from_warden
return
unless
user
return
nil
unless
user
raise
UnauthorizedError
unless
Gitlab
::
UserAccess
.
new
(
user
).
allowed?
&&
user
.
can?
(
:access_api
)
forbidden!
(
'User is blocked'
)
unless
Gitlab
::
UserAccess
.
new
(
user
).
allowed?
&&
user
.
can?
(
:access_api
)
user
end
def
private_token
params
[
PRIVATE_TOKEN_PARAM
]
||
env
[
PRIVATE_TOKEN_HEADER
]
end
private
def
find_user_from_personal_access_token
token_string
=
private_token
.
to_s
return
nil
unless
token_string
.
present?
def
access_token
return
@access_token
if
defined?
(
@access_token
)
access_token
=
PersonalAccessToken
.
find_by_token
(
token_string
)
raise
UnauthorizedError
unless
access_token
user
=
find_user_by_access_token
(
access_token
)
@access_token
=
find_oauth_access_token
||
find_personal_access_token
end
raise
UnauthorizedError
unless
user
def
validate_access_token!
(
scopes:
[])
return
unless
access_token
user
case
AccessTokenValidationService
.
new
(
access_token
,
request:
request
).
validate
(
scopes:
scopes
)
when
AccessTokenValidationService
::
INSUFFICIENT_SCOPE
raise
InsufficientScopeError
.
new
(
scopes
)
when
AccessTokenValidationService
::
EXPIRED
raise
ExpiredError
when
AccessTokenValidationService
::
REVOKED
raise
RevokedError
end
end
# Invokes the doorkeeper guard.
#
# If token is presented and valid, then it sets @current_user.
#
# If the token does not have sufficient scopes to cover the requred scopes,
# then it raises InsufficientScopeError.
#
# If the token is expired, then it raises ExpiredError.
#
# If the token is revoked, then it raises RevokedError.
#
# If the token is not found (nil), then it returns nil
#
# Arguments:
#
# scopes: (optional) scopes required for this guard.
# Defaults to empty array.
#
def
find_user_from_oauth_token
access_token
=
find_oauth_access_token
private
def
find_user_from_access_token
return
unless
access_token
find_user_by_access_token
(
access_token
)
validate_access_token!
access_token
.
user
||
raise
(
UnauthorizedError
)
end
# Check the Rails session for valid authentication details
...
...
@@ -115,34 +95,26 @@ module API
end
def
find_oauth_access_token
return
@oauth_access_token
if
defined?
(
@oauth_access_token
)
token
=
Doorkeeper
::
OAuth
::
Token
.
from_request
(
doorkeeper_request
,
*
Doorkeeper
.
configuration
.
access_token_methods
)
return
@oauth_access_token
=
nil
unless
token
return
unless
token
@oauth_access_token
=
OauthAccessToken
.
by_token
(
token
)
raise
UnauthorizedError
unless
@oauth_access_token
# Expiration, revocation and scopes are verified in `find_user_by_access_token`
access_token
=
OauthAccessToken
.
by_token
(
token
)
raise
UnauthorizedError
unless
access_token
@oauth_
access_token
.
revoke_previous_refresh_token!
@oauth_
access_token
access_token
.
revoke_previous_refresh_token!
access_token
end
def
find_user_by_access_token
(
access_token
)
scopes
=
scopes_registered_for_endpoint
def
find_personal_access_token
token
=
(
params
[
PRIVATE_TOKEN_PARAM
]
||
env
[
PRIVATE_TOKEN_HEADER
]).
to_s
return
unless
token
.
present?
case
AccessTokenValidationService
.
new
(
access_token
,
request:
request
).
validate
(
scopes:
scopes
)
when
AccessTokenValidationService
::
INSUFFICIENT_SCOPE
raise
InsufficientScopeError
.
new
(
scopes
)
when
AccessTokenValidationService
::
EXPIRED
raise
ExpiredError
when
AccessTokenValidationService
::
REVOKED
raise
RevokedError
# Expiration, revocation and scopes are verified in `find_user_by_access_token`
access_token
=
PersonalAccessToken
.
find_by
(
token:
token
)
raise
UnauthorizedError
unless
access_token
when
AccessTokenValidationService
::
VALID
access_token
.
user
end
access_token
end
def
doorkeeper_request
...
...
@@ -226,7 +198,7 @@ module API
class
InsufficientScopeError
<
StandardError
attr_reader
:scopes
def
initialize
(
scopes
)
@scopes
=
scopes
@scopes
=
scopes
.
map
{
|
s
|
s
.
try
(
:name
)
||
s
}
end
end
end
...
...
lib/api/helpers.rb
View file @
3f24f9ed
...
...
@@ -41,6 +41,8 @@ module API
sudo!
validate_access_token!
(
scopes:
scopes_registered_for_endpoint
)
unless
sudo?
@current_user
end
...
...
@@ -385,7 +387,7 @@ module API
return
@initial_current_user
if
defined?
(
@initial_current_user
)
begin
@initial_current_user
=
Gitlab
::
Auth
::
UniqueIpsLimiter
.
limit_user!
{
find_current_user
}
@initial_current_user
=
Gitlab
::
Auth
::
UniqueIpsLimiter
.
limit_user!
{
find_current_user
!
}
rescue
APIGuard
::
UnauthorizedError
unauthorized!
end
...
...
@@ -393,24 +395,26 @@ module API
def
sudo!
return
unless
sudo_identifier
return
unless
initial_current_user
raise
UnauthorizedError
unless
initial_current_user
unless
initial_current_user
.
admin?
forbidden!
(
'Must be admin to use sudo'
)
end
# Only private tokens should be used for the SUDO feature
unless
private_token
==
initial_current_user
.
private_token
forbidden!
(
'Private token must be specified in order to use sudo'
)
unless
access_token
forbidden!
(
'Must be authenticated using an OAuth or Personal Access Token to use sudo'
)
end
validate_access_token!
(
scopes:
[
:sudo
])
sudoed_user
=
find_user
(
sudo_identifier
)
if
sudoed_user
@current_user
=
sudoed_user
else
unless
sudoed_user
not_found!
(
"No user id or username for:
#{
sudo_identifier
}
"
)
end
@current_user
=
sudoed_user
end
def
sudo_identifier
...
...
lib/gitlab/auth.rb
View file @
3f24f9ed
...
...
@@ -5,7 +5,7 @@ module Gitlab
REGISTRY_SCOPES
=
[
:read_registry
].
freeze
# Scopes used for GitLab API access
API_SCOPES
=
[
:api
,
:read_user
].
freeze
API_SCOPES
=
[
:api
,
:read_user
,
:sudo
].
freeze
# Scopes used for OpenID Connect
OPENID_SCOPES
=
[
:openid
].
freeze
...
...
@@ -226,8 +226,10 @@ module Gitlab
[]
end
def
available_scopes
API_SCOPES
+
registry_scopes
def
available_scopes
(
current_user
=
nil
)
scopes
=
API_SCOPES
+
registry_scopes
scopes
.
delete
(
:sudo
)
if
current_user
&&
!
current_user
.
admin?
scopes
end
# Other available scopes
...
...
spec/lib/gitlab/auth_spec.rb
View file @
3f24f9ed
...
...
@@ -5,7 +5,7 @@ describe Gitlab::Auth do
describe
'constants'
do
it
'API_SCOPES contains all scopes for API access'
do
expect
(
subject
::
API_SCOPES
).
to
eq
[
:api
,
:read_user
]
expect
(
subject
::
API_SCOPES
).
to
eq
%i[api read_user sudo
]
end
it
'OPENID_SCOPES contains all scopes for OpenID Connect'
do
...
...
@@ -19,7 +19,7 @@ describe Gitlab::Auth do
it
'optional_scopes contains all non-default scopes'
do
stub_container_registry_config
(
enabled:
true
)
expect
(
subject
.
optional_scopes
).
to
eq
%i[read_user read_registry openid]
expect
(
subject
.
optional_scopes
).
to
eq
%i[read_user
sudo
read_registry openid]
end
context
'registry_scopes'
do
...
...
spec/requests/api/doorkeeper_access_spec.rb
View file @
3f24f9ed
...
...
@@ -39,20 +39,20 @@ describe 'doorkeeper access' do
end
describe
"when user is blocked"
do
it
"returns auth
entic
ation error"
do
it
"returns auth
oriz
ation error"
do
user
.
block
get
api
(
"/user"
),
access_token:
token
.
token
expect
(
response
).
to
have_gitlab_http_status
(
40
1
)
expect
(
response
).
to
have_gitlab_http_status
(
40
3
)
end
end
describe
"when user is ldap_blocked"
do
it
"returns auth
entic
ation error"
do
it
"returns auth
oriz
ation error"
do
user
.
ldap_block
get
api
(
"/user"
),
access_token:
token
.
token
expect
(
response
).
to
have_gitlab_http_status
(
40
1
)
expect
(
response
).
to
have_gitlab_http_status
(
40
3
)
end
end
end
spec/requests/api/helpers_spec.rb
View file @
3f24f9ed
...
...
@@ -173,18 +173,18 @@ describe API::Helpers do
expect
{
current_user
}.
to
raise_error
/401/
end
it
"returns a 40
1
response for a user without access"
do
it
"returns a 40
3
response for a user without access"
do
env
[
API
::
APIGuard
::
PRIVATE_TOKEN_HEADER
]
=
personal_access_token
.
token
allow_any_instance_of
(
Gitlab
::
UserAccess
).
to
receive
(
:allowed?
).
and_return
(
false
)
expect
{
current_user
}.
to
raise_error
/40
1
/
expect
{
current_user
}.
to
raise_error
/40
3
/
end
it
'returns a 40
1
response for a user who is blocked'
do
it
'returns a 40
3
response for a user who is blocked'
do
user
.
block!
env
[
API
::
APIGuard
::
PRIVATE_TOKEN_HEADER
]
=
personal_access_token
.
token
expect
{
current_user
}.
to
raise_error
/40
1
/
expect
{
current_user
}.
to
raise_error
/40
3
/
end
it
"leaves user as is when sudo not specified"
do
...
...
spec/requests/api/users_spec.rb
View file @
3f24f9ed
...
...
@@ -127,8 +127,8 @@ describe API::Users do
context
"when admin"
do
context
'when sudo is defined'
do
it
'does not return 500'
do
admin_personal_access_token
=
create
(
:personal_access_token
,
user:
admin
).
token
get
api
(
"/users?
private_token=
#{
admin_personal_access_token
}
&sudo=
#{
user
.
id
}
"
,
admi
n
)
admin_personal_access_token
=
create
(
:personal_access_token
,
user:
admin
,
scopes:
[
:sudo
])
get
api
(
"/users?
sudo=
#{
user
.
id
}
"
,
admin
,
personal_access_token:
admin_personal_access_toke
n
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment