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
a0093813
Commit
a0093813
authored
Oct 08, 2018
by
Michael Tsyganov
Committed by
Rémy Coutable
Dec 05, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support RSA and ECDSA algorithms in Omniauth JWT
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
5f1bb1a7
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
100 additions
and
46 deletions
+100
-46
changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml
changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml
+5
-0
config/gitlab.yml.example
config/gitlab.yml.example
+8
-8
doc/administration/auth/README.md
doc/administration/auth/README.md
+1
-1
doc/administration/auth/jwt.md
doc/administration/auth/jwt.md
+18
-18
lib/omni_auth/strategies/jwt.rb
lib/omni_auth/strategies/jwt.rb
+15
-2
spec/lib/omni_auth/strategies/jwt_spec.rb
spec/lib/omni_auth/strategies/jwt_spec.rb
+53
-17
No files found.
changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml
0 → 100644
View file @
a0093813
---
title
:
Support RSA and ECDSA algorithms in Omniauth JWT provider
merge_request
:
23411
author
:
Michael Tsyganov
type
:
fixed
config/gitlab.yml.example
View file @
a0093813
...
@@ -548,15 +548,15 @@ production: &base
...
@@ -548,15 +548,15 @@ production: &base
# app_id: 'YOUR_APP_ID',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' }
# app_secret: 'YOUR_APP_SECRET' }
# - { name: 'jwt',
# - { name: 'jwt',
# app_secret: 'YOUR_APP_SECRET',
# args: {
# args: {
# algorithm: 'HS256',
# secret: 'YOUR_APP_SECRET',
# uid_claim: 'email',
# algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
# required_claims: ["name", "email"],
# uid_claim: 'email',
# info_map: { name: "name", email: "email" },
# required_claims: ['name', 'email'],
# auth_url: 'https://example.com/',
# info_map: { name: 'name', email: 'email' },
# valid_within: null,
# auth_url: 'https://example.com/',
# }
# valid_within: 3600 # 1 hour
# }
# }
# }
# - { name: 'saml',
# - { name: 'saml',
# label: 'Our SAML Provider',
# label: 'Our SAML Provider',
...
...
doc/administration/auth/README.md
View file @
a0093813
...
@@ -10,7 +10,7 @@ providers.
...
@@ -10,7 +10,7 @@ providers.
-
[
LDAP
](
ldap.md
)
Includes Active Directory, Apple Open Directory, Open LDAP,
-
[
LDAP
](
ldap.md
)
Includes Active Directory, Apple Open Directory, Open LDAP,
and 389 Server
and 389 Server
-
[
OmniAuth
](
../../integration/omniauth.md
)
Sign in via Twitter, GitHub, GitLab.com, Google,
-
[
OmniAuth
](
../../integration/omniauth.md
)
Sign in via Twitter, GitHub, GitLab.com, Google,
Bitbucket, Facebook, Shibboleth, Crowd, Azure
and Authentiq ID
Bitbucket, Facebook, Shibboleth, Crowd, Azure
, Authentiq ID, and JWT
-
[
CAS
](
../../integration/cas.md
)
Configure GitLab to sign in using CAS
-
[
CAS
](
../../integration/cas.md
)
Configure GitLab to sign in using CAS
-
[
SAML
](
../../integration/saml.md
)
Configure GitLab as a SAML 2.0 Service Provider
-
[
SAML
](
../../integration/saml.md
)
Configure GitLab as a SAML 2.0 Service Provider
-
[
Okta
](
okta.md
)
Configure GitLab to sign in using Okta
-
[
Okta
](
okta.md
)
Configure GitLab to sign in using Okta
...
...
doc/administration/auth/jwt.md
View file @
a0093813
...
@@ -26,15 +26,15 @@ JWT will provide you with a secret key for you to use.
...
@@ -26,15 +26,15 @@ JWT will provide you with a secret key for you to use.
```ruby
```ruby
gitlab_rails['omniauth_providers'] = [
gitlab_rails['omniauth_providers'] = [
{ name: 'jwt',
{ name: 'jwt',
app_secret: 'YOUR_APP_SECRET',
args: {
args: {
algorithm: 'HS256',
secret: 'YOUR_APP_SECRET',
uid_claim: 'email',
algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
required_claims: ["name", "email"],
uid_claim: 'email',
info_maps: { name: "name", email: "email" },
required_claims: ['name', 'email'],
auth_url: 'https://example.com/',
info_maps: { name: 'name', email: 'email' },
valid_within: nil,
auth_url: 'https://example.com/',
}
valid_within: 3600 # 1 hour
}
}
}
]
]
```
```
...
@@ -43,15 +43,15 @@ JWT will provide you with a secret key for you to use.
...
@@ -43,15 +43,15 @@ JWT will provide you with a secret key for you to use.
```
```
- { name: 'jwt',
- { name: 'jwt',
app_secret: 'YOUR_APP_SECRET',
args: {
args: {
algorithm: 'HS256',
secret: 'YOUR_APP_SECRET',
uid_claim: 'email',
algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
required_claims: ["name", "email"],
uid_claim: 'email',
info_map: { name: "name", email: "email" },
required_claims: ['name', 'email'],
auth_url: 'https://example.com/',
info_map: { name: 'name', email: 'email' },
valid_within: null,
auth_url: 'https://example.com/',
}
valid_within: 3600 # 1 hour
}
}
}
```
```
...
@@ -60,7 +60,7 @@ JWT will provide you with a secret key for you to use.
...
@@ -60,7 +60,7 @@ JWT will provide you with a secret key for you to use.
1.
Change
`YOUR_APP_SECRET`
to the client secret and set
`auth_url`
to your redirect URL.
1.
Change
`YOUR_APP_SECRET`
to the client secret and set
`auth_url`
to your redirect URL.
1.
Save the configuration file.
1.
Save the configuration file.
1.
[
Reconfigure
GitLab
][]
or
[
restart GitLab
][]
for the changes to take effect if you
1.
[
Reconfigure
][]
or
[
restart GitLab
][]
for the changes to take effect if you
installed GitLab via Omnibus or from source respectively.
installed GitLab via Omnibus or from source respectively.
On the sign in page there should now be a JWT icon below the regular sign in form.
On the sign in page there should now be a JWT icon below the regular sign in form.
...
@@ -68,5 +68,5 @@ Click the icon to begin the authentication process. JWT will ask the user to
...
@@ -68,5 +68,5 @@ Click the icon to begin the authentication process. JWT will ask the user to
sign in and authorize the GitLab application. If everything goes well, the user
sign in and authorize the GitLab application. If everything goes well, the user
will be redirected to GitLab and will be signed in.
will be redirected to GitLab and will be signed in.
[
reconfigure
GitLab
]:
../restart_gitlab.md#omnibus-gitlab-reconfigure
[
reconfigure
]:
../restart_gitlab.md#omnibus-gitlab-reconfigure
[
restart GitLab
]:
../restart_gitlab.md#installations-from-source
[
restart GitLab
]:
../restart_gitlab.md#installations-from-source
lib/omni_auth/strategies/jwt.rb
View file @
a0093813
# frozen_string_literal: true
# frozen_string_literal: true
require
'omniauth'
require
'omniauth'
require
'openssl'
require
'jwt'
require
'jwt'
module
OmniAuth
module
OmniAuth
...
@@ -37,7 +38,19 @@ module OmniAuth
...
@@ -37,7 +38,19 @@ module OmniAuth
end
end
def
decoded
def
decoded
@decoded
||=
::
JWT
.
decode
(
request
.
params
[
'jwt'
],
options
.
secret
,
options
.
algorithm
).
first
secret
=
case
options
.
algorithm
when
*
%w[RS256 RS384 RS512]
OpenSSL
::
PKey
::
RSA
.
new
(
options
.
secret
).
public_key
when
*
%w[ES256 ES384 ES512]
OpenSSL
::
PKey
::
EC
.
new
(
options
.
secret
).
tap
{
|
key
|
key
.
private_key
=
nil
}
when
*
%w(HS256 HS384 HS512)
options
.
secret
else
raise
NotImplementedError
,
"Unsupported algorithm:
#{
options
.
algorithm
}
"
end
@decoded
||=
::
JWT
.
decode
(
request
.
params
[
'jwt'
],
secret
,
true
,
{
algorithm:
options
.
algorithm
}).
first
(
options
.
required_claims
||
[]).
each
do
|
field
|
(
options
.
required_claims
||
[]).
each
do
|
field
|
raise
ClaimInvalid
,
"Missing required '
#{
field
}
' claim"
unless
@decoded
.
key?
(
field
.
to_s
)
raise
ClaimInvalid
,
"Missing required '
#{
field
}
' claim"
unless
@decoded
.
key?
(
field
.
to_s
)
...
@@ -45,7 +58,7 @@ module OmniAuth
...
@@ -45,7 +58,7 @@ module OmniAuth
raise
ClaimInvalid
,
"Missing required 'iat' claim"
if
options
.
valid_within
&&
!
@decoded
[
"iat"
]
raise
ClaimInvalid
,
"Missing required 'iat' claim"
if
options
.
valid_within
&&
!
@decoded
[
"iat"
]
if
options
.
valid_within
&&
(
Time
.
now
.
to_i
-
@decoded
[
"iat"
]).
abs
>
options
.
valid_within
if
options
.
valid_within
&&
(
Time
.
now
.
to_i
-
@decoded
[
"iat"
]).
abs
>
options
.
valid_within
.
to_i
raise
ClaimInvalid
,
"'iat' timestamp claim is too skewed from present"
raise
ClaimInvalid
,
"'iat' timestamp claim is too skewed from present"
end
end
...
...
spec/lib/omni_auth/strategies/jwt_spec.rb
View file @
a0093813
...
@@ -4,12 +4,10 @@ describe OmniAuth::Strategies::Jwt do
...
@@ -4,12 +4,10 @@ describe OmniAuth::Strategies::Jwt do
include
Rack
::
Test
::
Methods
include
Rack
::
Test
::
Methods
include
DeviseHelpers
include
DeviseHelpers
context
'
.
decoded'
do
context
'
#
decoded'
do
let
(
:strategy
)
{
described_class
.
new
({})
}
subject
{
described_class
.
new
({})
}
let
(
:timestamp
)
{
Time
.
now
.
to_i
}
let
(
:timestamp
)
{
Time
.
now
.
to_i
}
let
(
:jwt_config
)
{
Devise
.
omniauth_configs
[
:jwt
]
}
let
(
:jwt_config
)
{
Devise
.
omniauth_configs
[
:jwt
]
}
let
(
:key
)
{
JWT
.
encode
(
claims
,
jwt_config
.
strategy
.
secret
)
}
let
(
:claims
)
do
let
(
:claims
)
do
{
{
id:
123
,
id:
123
,
...
@@ -18,19 +16,55 @@ describe OmniAuth::Strategies::Jwt do
...
@@ -18,19 +16,55 @@ describe OmniAuth::Strategies::Jwt do
iat:
timestamp
iat:
timestamp
}
}
end
end
let
(
:algorithm
)
{
'HS256'
}
let
(
:secret
)
{
jwt_config
.
strategy
.
secret
}
let
(
:private_key
)
{
secret
}
let
(
:payload
)
{
JWT
.
encode
(
claims
,
private_key
,
algorithm
)
}
before
do
before
do
allow_any_instance_of
(
OmniAuth
::
Strategy
).
to
receive
(
:options
).
and_return
(
jwt_config
.
strategy
)
subject
.
options
[
:secret
]
=
secret
allow_any_instance_of
(
Rack
::
Request
).
to
receive
(
:params
).
and_return
({
'jwt'
=>
key
})
subject
.
options
[
:algorithm
]
=
algorithm
expect_next_instance_of
(
Rack
::
Request
)
do
|
rack_request
|
expect
(
rack_request
).
to
receive
(
:params
).
and_return
(
'jwt'
=>
payload
)
end
end
end
it
'decodes the user information'
do
ECDSA_NAMED_CURVES
=
{
result
=
strategy
.
decoded
'ES256'
=>
'prime256v1'
,
'ES384'
=>
'secp384r1'
,
'ES512'
=>
'secp521r1'
}.
freeze
expect
(
result
[
"id"
]).
to
eq
(
123
)
{
expect
(
result
[
"name"
]).
to
eq
(
"user_example"
)
OpenSSL
::
PKey
::
RSA
=>
%w[RS256 RS384 RS512]
,
expect
(
result
[
"email"
]).
to
eq
(
"user@example.com"
)
OpenSSL
::
PKey
::
EC
=>
%w[ES256 ES384 ES512]
,
expect
(
result
[
"iat"
]).
to
eq
(
timestamp
)
String
=>
%w[HS256 HS384 HS512]
}.
each
do
|
private_key_class
,
algorithms
|
algorithms
.
each
do
|
algorithm
|
context
"when the
#{
algorithm
}
algorithm is used"
do
let
(
:algorithm
)
{
algorithm
}
let
(
:secret
)
do
if
private_key_class
==
OpenSSL
::
PKey
::
RSA
private_key_class
.
generate
(
2048
)
.
to_pem
elsif
private_key_class
==
OpenSSL
::
PKey
::
EC
private_key_class
.
new
(
ECDSA_NAMED_CURVES
[
algorithm
])
.
tap
{
|
key
|
key
.
generate_key!
}
.
to_pem
else
private_key_class
.
new
(
jwt_config
.
strategy
.
secret
)
end
end
let
(
:private_key
)
{
private_key_class
?
private_key_class
.
new
(
secret
)
:
secret
}
it
'decodes the user information'
do
result
=
subject
.
decoded
expect
(
result
).
to
eq
(
claims
.
stringify_keys
)
end
end
end
end
end
context
'required claims is missing'
do
context
'required claims is missing'
do
...
@@ -43,7 +77,7 @@ describe OmniAuth::Strategies::Jwt do
...
@@ -43,7 +77,7 @@ describe OmniAuth::Strategies::Jwt do
end
end
it
'raises error'
do
it
'raises error'
do
expect
{
s
trategy
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
expect
{
s
ubject
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
end
end
end
end
...
@@ -57,11 +91,12 @@ describe OmniAuth::Strategies::Jwt do
...
@@ -57,11 +91,12 @@ describe OmniAuth::Strategies::Jwt do
end
end
before
do
before
do
jwt_config
.
strategy
.
valid_within
=
Time
.
now
.
to_i
# Omniauth config values are always strings!
subject
.
options
[
:valid_within
]
=
2
.
days
.
to_s
end
end
it
'raises error'
do
it
'raises error'
do
expect
{
s
trategy
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
expect
{
s
ubject
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
end
end
end
end
...
@@ -76,11 +111,12 @@ describe OmniAuth::Strategies::Jwt do
...
@@ -76,11 +111,12 @@ describe OmniAuth::Strategies::Jwt do
end
end
before
do
before
do
jwt_config
.
strategy
.
valid_within
=
2
.
seconds
# Omniauth config values are always strings!
subject
.
options
[
:valid_within
]
=
2
.
seconds
.
to_s
end
end
it
'raises error'
do
it
'raises error'
do
expect
{
s
trategy
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
expect
{
s
ubject
.
decoded
}.
to
raise_error
(
OmniAuth
::
Strategies
::
Jwt
::
ClaimInvalid
)
end
end
end
end
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