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
Léo-Paul Géneau
gitlab-ce
Commits
011a905a
Commit
011a905a
authored
May 02, 2016
by
Kamil Trzcinski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split docker authentication service
parent
105017c3
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
162 additions
and
101 deletions
+162
-101
app/controllers/jwt_controller.rb
app/controllers/jwt_controller.rb
+13
-101
app/services/jwt/docker_authentication_service.rb
app/services/jwt/docker_authentication_service.rb
+65
-0
lib/jwt/rsa_token.rb
lib/jwt/rsa_token.rb
+36
-0
lib/jwt/token.rb
lib/jwt/token.rb
+48
-0
No files found.
app/controllers/jwt_controller.rb
View file @
011a905a
...
@@ -2,6 +2,10 @@ class JwtController < ApplicationController
...
@@ -2,6 +2,10 @@ class JwtController < ApplicationController
skip_before_action
:authenticate_user!
skip_before_action
:authenticate_user!
skip_before_action
:verify_authenticity_token
skip_before_action
:verify_authenticity_token
SERVICES
=
{
'docker'
=>
Jwt
::
DockerAuthenticationService
,
}
def
auth
def
auth
@authenticated
=
authenticate_with_http_basic
do
|
login
,
password
|
@authenticated
=
authenticate_with_http_basic
do
|
login
,
password
|
@ci_project
=
ci_project
(
login
,
password
)
@ci_project
=
ci_project
(
login
,
password
)
...
@@ -9,46 +13,22 @@ class JwtController < ApplicationController
...
@@ -9,46 +13,22 @@ class JwtController < ApplicationController
end
end
unless
@authenticated
unless
@authenticated
return
render_403
if
has_basic_credentials?
head
:forbidden
if
ActionController
::
HttpAuthentication
::
Basic
.
has_basic_credentials?
(
request
)
end
case
params
[
:service
]
when
'docker'
docker_token_auth
(
params
[
:scope
],
params
[
:offline_token
])
else
return
render_404
end
end
end
private
service
=
SERVICES
[
params
[
:service
]]
head
:not_found
unless
service
def
render_400
head
:invalid_request
end
def
render_404
result
=
service
.
new
(
@ci_project
,
@user
,
auth_params
).
execute
head
:not_found
return
head
result
[
:http_status
]
if
result
[
:http_status
]
end
def
render_403
render
json:
result
head
:forbidden
end
end
def
docker_token_auth
(
scope
,
offline_token
)
private
payload
=
{
aud:
params
[
:service
],
sub:
@user
.
try
(
:username
)
}
if
offline_token
return
render_403
unless
@user
elsif
scope
access
=
process_access
(
scope
)
return
render_404
unless
access
payload
[
:access
]
=
[
access
]
end
render
json:
{
token:
encode
(
payload
)
}
def
auth_params
params
.
permit
(
:service
,
:scope
,
:offline_token
,
:account
,
:client_id
)
end
end
def
ci_project
(
login
,
password
)
def
ci_project
(
login
,
password
)
...
@@ -102,72 +82,4 @@ class JwtController < ApplicationController
...
@@ -102,72 +82,4 @@ class JwtController < ApplicationController
user
user
end
end
def
process_access
(
scope
)
type
,
name
,
actions
=
scope
.
split
(
':'
,
3
)
actions
=
actions
.
split
(
','
)
case
type
when
'repository'
process_repository_access
(
type
,
name
,
actions
)
end
end
def
process_repository_access
(
type
,
name
,
actions
)
project
=
Project
.
find_with_namespace
(
name
)
return
unless
project
actions
=
actions
.
select
do
|
action
|
can_access?
(
project
,
action
)
end
{
type:
'repository'
,
name:
name
,
actions:
actions
}
if
actions
end
def
default_payload
{
aud:
'docker'
,
sub:
@user
.
try
(
:username
),
aud:
params
[
:service
],
}
end
def
private_key
@private_key
||=
OpenSSL
::
PKey
::
RSA
.
new
File
.
read
Gitlab
.
config
.
registry
.
key
end
def
encode
(
payload
)
issued_at
=
Time
.
now
payload
=
payload
.
merge
(
iss:
Gitlab
.
config
.
registry
.
issuer
,
iat:
issued_at
.
to_i
,
nbf:
issued_at
.
to_i
-
5
.
seconds
.
to_i
,
exp:
issued_at
.
to_i
+
60
.
minutes
.
to_i
,
jti:
SecureRandom
.
uuid
,
)
headers
=
{
kid:
kid
(
private_key
)
}
JWT
.
encode
(
payload
,
private_key
,
'RS256'
,
headers
)
end
def
can_access?
(
project
,
action
)
case
action
when
'pull'
project
==
@ci_project
||
can?
(
@user
,
:download_code
,
project
)
when
'push'
project
==
@ci_project
||
can?
(
@user
,
:push_code
,
project
)
else
false
end
end
def
kid
(
private_key
)
sha256
=
Digest
::
SHA256
.
new
sha256
.
update
(
private_key
.
public_key
.
to_der
)
payload
=
StringIO
.
new
(
sha256
.
digest
).
read
(
30
)
Base32
.
encode
(
payload
).
split
(
''
).
each_slice
(
4
).
each_with_object
([])
do
|
slice
,
mem
|
mem
<<
slice
.
join
end
.
join
(
':'
)
end
end
end
app/services/jwt/docker_authentication_service.rb
0 → 100644
View file @
011a905a
module
Jwt
class
DockerAuthenticationService
<
BaseService
def
execute
if
params
[
:offline_token
]
return
error
(
'forbidden'
,
403
)
unless
current_user
end
{
token:
token
.
encoded
}
end
private
def
token
token
=
::
Jwt
::
RSAToken
.
new
(
registry
.
key
)
token
.
issuer
=
registry
.
issuer
token
.
audience
=
params
[
:service
]
token
.
subject
=
current_user
.
try
(
:username
)
token
[
:access
]
=
access
token
end
def
access
return
unless
params
[
:scope
]
scope
=
process_scope
(
params
[
:scope
])
[
scope
].
compact
end
def
process_scope
(
scope
)
type
,
name
,
actions
=
scope
.
split
(
':'
,
3
)
actions
=
actions
.
split
(
','
)
case
type
when
'repository'
process_repository_access
(
type
,
name
,
actions
)
end
end
def
process_repository_access
(
type
,
name
,
actions
)
current_project
=
Project
.
find_with_namespace
(
name
)
return
unless
current_project
actions
=
actions
.
select
do
|
action
|
can_access?
(
current_project
,
action
)
end
{
type:
type
,
name:
name
,
actions:
actions
}
if
actions
end
def
can_access?
(
current_project
,
action
)
case
action
when
'pull'
current_project
==
project
||
can?
(
current_user
,
:download_code
,
current_project
)
when
'push'
current_project
==
project
||
can?
(
current_user
,
:push_code
,
current_project
)
else
false
end
end
def
registry
Gitlab
.
config
.
registry
end
end
end
lib/jwt/rsa_token.rb
0 → 100644
View file @
011a905a
module
Jwt
class
RSAToken
<
Token
attr_reader
:key_file
def
initialize
(
key_file
)
super
()
@key_file
=
key_file
end
def
encoded
headers
=
{
kid:
kid
}
JWT
.
encode
(
payload
,
key
,
'RS256'
,
headers
)
end
private
def
key_data
@key_data
||=
File
.
read
(
key_file
)
end
def
key
@key
||=
OpenSSL
::
PKey
::
RSA
.
new
(
key_data
)
end
def
kid
sha256
=
Digest
::
SHA256
.
new
sha256
.
update
(
key
.
public_key
.
to_der
)
payload
=
StringIO
.
new
(
sha256
.
digest
).
read
(
30
)
Base32
.
encode
(
payload
).
split
(
''
).
each_slice
(
4
).
each_with_object
([])
do
|
slice
,
mem
|
mem
<<
slice
.
join
end
.
join
(
':'
)
end
end
end
lib/jwt/token.rb
0 → 100644
View file @
011a905a
module
Jwt
class
Token
attr_accessor
:issuer
,
:subject
,
:audience
,
:id
attr_accessor
:issued_at
,
:not_before
,
:expire_time
def
initialize
@payload
=
{}
@id
=
SecureRandom
.
uuid
@issued_at
=
Time
.
now
@not_before
=
issued_at
-
5
.
seconds
@expire_time
=
issued_at
+
1
.
minute
end
def
[]
(
key
)
@payload
[
key
]
end
def
[]=
(
key
,
value
)
@payload
[
key
]
=
value
end
def
encoded
raise
NotImplementedError
end
def
payload
@payload
.
merge
(
default_payload
)
end
def
to_json
payload
.
to_json
end
private
def
default_payload
{
jti:
id
,
aud:
audience
,
sub:
subject
,
iss:
issuer
,
iat:
issued_at
.
to_i
,
nbf:
not_before
.
to_i
,
exp:
expire_time
.
to_i
}.
compact
end
end
end
\ No newline at end of file
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