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
1
Merge Requests
1
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
nexedi
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
...
@@ -44,7 +44,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
end
end
def
set_index_vars
def
set_index_vars
@scopes
=
Gitlab
::
Auth
::
API_SCOPES
@scopes
=
Gitlab
::
Auth
.
available_scopes
(
current_user
)
@impersonation_token
||=
finder
.
build
@impersonation_token
||=
finder
.
build
@inactive_impersonation_tokens
=
finder
(
state:
'inactive'
).
execute
@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
...
@@ -39,7 +39,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
end
end
def
set_index_vars
def
set_index_vars
@scopes
=
Gitlab
::
Auth
.
available_scopes
@scopes
=
Gitlab
::
Auth
.
available_scopes
(
current_user
)
@inactive_personal_access_tokens
=
finder
(
state:
'inactive'
).
execute
@inactive_personal_access_tokens
=
finder
(
state:
'inactive'
).
execute
@active_personal_access_tokens
=
finder
(
state:
'active'
).
execute
.
order
(
:expires_at
)
@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
...
@@ -39,11 +39,8 @@ class AccessTokenValidationService
token_scopes
=
token
.
scopes
.
map
(
&
:to_sym
)
token_scopes
=
token
.
scopes
.
map
(
&
:to_sym
)
required_scopes
.
any?
do
|
scope
|
required_scopes
.
any?
do
|
scope
|
if
scope
.
respond_to?
(
:sufficient?
)
scope
=
API
::
Scope
.
new
(
scope
)
unless
scope
.
is_a?
(
API
::
Scope
)
scope
.
sufficient?
(
token_scopes
,
request
)
scope
.
sufficient?
(
token_scopes
,
request
)
else
API
::
Scope
.
new
(
scope
).
sufficient?
(
token_scopes
,
request
)
end
end
end
end
end
end
end
...
...
config/locales/doorkeeper.en.yml
View file @
3f24f9ed
...
@@ -58,9 +58,10 @@ en:
...
@@ -58,9 +58,10 @@ en:
expired
:
"
The
access
token
expired"
expired
:
"
The
access
token
expired"
unknown
:
"
The
access
token
is
invalid"
unknown
:
"
The
access
token
is
invalid"
scopes
:
scopes
:
api
:
Access
your
API
api
:
Access
the authenticated user's
API
read_user
:
Read
user
information
read_user
:
Read
the authenticated user's personal
information
openid
:
Authenticate using OpenID Connect
openid
:
Authenticate using OpenID Connect
sudo
:
Perform API actions as any user in the system (if the authenticated user is an admin)
flash
:
flash
:
applications
:
applications
:
...
...
lib/api/api_guard.rb
View file @
3f24f9ed
...
@@ -42,62 +42,42 @@ module API
...
@@ -42,62 +42,42 @@ module API
# Helper Methods for Grape Endpoint
# Helper Methods for Grape Endpoint
module
HelperMethods
module
HelperMethods
def
find_current_user
def
find_current_user!
user
=
user
=
find_user_from_access_token
||
find_user_from_warden
find_user_from_personal_access_token
||
return
unless
user
find_user_from_oauth_token
||
find_user_from_warden
return
nil
unless
user
forbidden!
(
'User is blocked'
)
unless
Gitlab
::
UserAccess
.
new
(
user
).
allowed?
&&
user
.
can?
(
:access_api
)
raise
UnauthorizedError
unless
Gitlab
::
UserAccess
.
new
(
user
).
allowed?
&&
user
.
can?
(
:access_api
)
user
user
end
end
def
private_token
def
access_token
params
[
PRIVATE_TOKEN_PARAM
]
||
env
[
PRIVATE_TOKEN_HEADER
]
return
@access_token
if
defined?
(
@access_token
)
end
private
def
find_user_from_personal_access_token
token_string
=
private_token
.
to_s
return
nil
unless
token_string
.
present?
access_token
=
PersonalAccessToken
.
find_by_token
(
token_string
)
@access_token
=
find_oauth_access_token
||
find_personal_access_token
raise
UnauthorizedError
unless
access_token
end
user
=
find_user_by_access_token
(
access_token
)
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
end
# Invokes the doorkeeper guard.
private
#
# If token is presented and valid, then it sets @current_user.
def
find_user_from_access_token
#
# 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
return
unless
access_token
return
unless
access_token
find_user_by_access_token
(
access_token
)
validate_access_token!
access_token
.
user
||
raise
(
UnauthorizedError
)
end
end
# Check the Rails session for valid authentication details
# Check the Rails session for valid authentication details
...
@@ -115,34 +95,26 @@ module API
...
@@ -115,34 +95,26 @@ module API
end
end
def
find_oauth_access_token
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
)
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
)
# Expiration, revocation and scopes are verified in `find_user_by_access_token`
raise
UnauthorizedError
unless
@oauth_access_token
access_token
=
OauthAccessToken
.
by_token
(
token
)
raise
UnauthorizedError
unless
access_token
@oauth_
access_token
.
revoke_previous_refresh_token!
access_token
.
revoke_previous_refresh_token!
@oauth_
access_token
access_token
end
end
def
find_user_by_access_token
(
access_token
)
def
find_personal_access_token
scopes
=
scopes_registered_for_endpoint
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
)
# Expiration, revocation and scopes are verified in `find_user_by_access_token`
when
AccessTokenValidationService
::
INSUFFICIENT_SCOPE
access_token
=
PersonalAccessToken
.
find_by
(
token:
token
)
raise
InsufficientScopeError
.
new
(
scopes
)
raise
UnauthorizedError
unless
access_token
when
AccessTokenValidationService
::
EXPIRED
raise
ExpiredError
when
AccessTokenValidationService
::
REVOKED
raise
RevokedError
when
AccessTokenValidationService
::
VALID
access_token
access_token
.
user
end
end
end
def
doorkeeper_request
def
doorkeeper_request
...
@@ -226,7 +198,7 @@ module API
...
@@ -226,7 +198,7 @@ module API
class
InsufficientScopeError
<
StandardError
class
InsufficientScopeError
<
StandardError
attr_reader
:scopes
attr_reader
:scopes
def
initialize
(
scopes
)
def
initialize
(
scopes
)
@scopes
=
scopes
@scopes
=
scopes
.
map
{
|
s
|
s
.
try
(
:name
)
||
s
}
end
end
end
end
end
end
...
...
lib/api/helpers.rb
View file @
3f24f9ed
...
@@ -41,6 +41,8 @@ module API
...
@@ -41,6 +41,8 @@ module API
sudo!
sudo!
validate_access_token!
(
scopes:
scopes_registered_for_endpoint
)
unless
sudo?
@current_user
@current_user
end
end
...
@@ -385,7 +387,7 @@ module API
...
@@ -385,7 +387,7 @@ module API
return
@initial_current_user
if
defined?
(
@initial_current_user
)
return
@initial_current_user
if
defined?
(
@initial_current_user
)
begin
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
rescue
APIGuard
::
UnauthorizedError
unauthorized!
unauthorized!
end
end
...
@@ -393,24 +395,26 @@ module API
...
@@ -393,24 +395,26 @@ module API
def
sudo!
def
sudo!
return
unless
sudo_identifier
return
unless
sudo_identifier
return
unless
initial_current_user
raise
UnauthorizedError
unless
initial_current_user
unless
initial_current_user
.
admin?
unless
initial_current_user
.
admin?
forbidden!
(
'Must be admin to use sudo'
)
forbidden!
(
'Must be admin to use sudo'
)
end
end
# Only private tokens should be used for the SUDO feature
unless
access_token
unless
private_token
==
initial_current_user
.
private_token
forbidden!
(
'Must be authenticated using an OAuth or Personal Access Token to use sudo'
)
forbidden!
(
'Private token must be specified in order to use sudo'
)
end
end
validate_access_token!
(
scopes:
[
:sudo
])
sudoed_user
=
find_user
(
sudo_identifier
)
sudoed_user
=
find_user
(
sudo_identifier
)
if
sudoed_user
unless
sudoed_user
@current_user
=
sudoed_user
else
not_found!
(
"No user id or username for:
#{
sudo_identifier
}
"
)
not_found!
(
"No user id or username for:
#{
sudo_identifier
}
"
)
end
end
@current_user
=
sudoed_user
end
end
def
sudo_identifier
def
sudo_identifier
...
...
lib/gitlab/auth.rb
View file @
3f24f9ed
...
@@ -5,7 +5,7 @@ module Gitlab
...
@@ -5,7 +5,7 @@ module Gitlab
REGISTRY_SCOPES
=
[
:read_registry
].
freeze
REGISTRY_SCOPES
=
[
:read_registry
].
freeze
# Scopes used for GitLab API access
# Scopes used for GitLab API access
API_SCOPES
=
[
:api
,
:read_user
].
freeze
API_SCOPES
=
[
:api
,
:read_user
,
:sudo
].
freeze
# Scopes used for OpenID Connect
# Scopes used for OpenID Connect
OPENID_SCOPES
=
[
:openid
].
freeze
OPENID_SCOPES
=
[
:openid
].
freeze
...
@@ -226,8 +226,10 @@ module Gitlab
...
@@ -226,8 +226,10 @@ module Gitlab
[]
[]
end
end
def
available_scopes
def
available_scopes
(
current_user
=
nil
)
API_SCOPES
+
registry_scopes
scopes
=
API_SCOPES
+
registry_scopes
scopes
.
delete
(
:sudo
)
if
current_user
&&
!
current_user
.
admin?
scopes
end
end
# Other available scopes
# Other available scopes
...
...
spec/lib/gitlab/auth_spec.rb
View file @
3f24f9ed
...
@@ -5,7 +5,7 @@ describe Gitlab::Auth do
...
@@ -5,7 +5,7 @@ describe Gitlab::Auth do
describe
'constants'
do
describe
'constants'
do
it
'API_SCOPES contains all scopes for API access'
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
end
it
'OPENID_SCOPES contains all scopes for OpenID Connect'
do
it
'OPENID_SCOPES contains all scopes for OpenID Connect'
do
...
@@ -19,7 +19,7 @@ describe Gitlab::Auth do
...
@@ -19,7 +19,7 @@ describe Gitlab::Auth do
it
'optional_scopes contains all non-default scopes'
do
it
'optional_scopes contains all non-default scopes'
do
stub_container_registry_config
(
enabled:
true
)
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
end
context
'registry_scopes'
do
context
'registry_scopes'
do
...
...
spec/requests/api/doorkeeper_access_spec.rb
View file @
3f24f9ed
...
@@ -39,20 +39,20 @@ describe 'doorkeeper access' do
...
@@ -39,20 +39,20 @@ describe 'doorkeeper access' do
end
end
describe
"when user is blocked"
do
describe
"when user is blocked"
do
it
"returns auth
entic
ation error"
do
it
"returns auth
oriz
ation error"
do
user
.
block
user
.
block
get
api
(
"/user"
),
access_token:
token
.
token
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
end
describe
"when user is ldap_blocked"
do
describe
"when user is ldap_blocked"
do
it
"returns auth
entic
ation error"
do
it
"returns auth
oriz
ation error"
do
user
.
ldap_block
user
.
ldap_block
get
api
(
"/user"
),
access_token:
token
.
token
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
end
end
end
spec/requests/api/helpers_spec.rb
View file @
3f24f9ed
...
@@ -173,18 +173,18 @@ describe API::Helpers do
...
@@ -173,18 +173,18 @@ describe API::Helpers do
expect
{
current_user
}.
to
raise_error
/401/
expect
{
current_user
}.
to
raise_error
/401/
end
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
env
[
API
::
APIGuard
::
PRIVATE_TOKEN_HEADER
]
=
personal_access_token
.
token
allow_any_instance_of
(
Gitlab
::
UserAccess
).
to
receive
(
:allowed?
).
and_return
(
false
)
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
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!
user
.
block!
env
[
API
::
APIGuard
::
PRIVATE_TOKEN_HEADER
]
=
personal_access_token
.
token
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
end
it
"leaves user as is when sudo not specified"
do
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
...
@@ -127,8 +127,8 @@ describe API::Users do
context
"when admin"
do
context
"when admin"
do
context
'when sudo is defined'
do
context
'when sudo is defined'
do
it
'does not return 500'
do
it
'does not return 500'
do
admin_personal_access_token
=
create
(
:personal_access_token
,
user:
admin
).
token
admin_personal_access_token
=
create
(
:personal_access_token
,
user:
admin
,
scopes:
[
:sudo
])
get
api
(
"/users?
private_token=
#{
admin_personal_access_token
}
&sudo=
#{
user
.
id
}
"
,
admi
n
)
get
api
(
"/users?
sudo=
#{
user
.
id
}
"
,
admin
,
personal_access_token:
admin_personal_access_toke
n
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
end
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