oidc_provider 0.3.9 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -5
- data/app/controllers/oidc_provider/application_controller.rb +21 -1
- data/app/controllers/oidc_provider/authorizations_controller.rb +30 -13
- data/app/models/oidc_provider/id_token.rb +16 -8
- data/lib/oidc_provider/client.rb +4 -2
- data/lib/oidc_provider/engine.rb +2 -0
- data/lib/oidc_provider/token_endpoint.rb +25 -12
- data/lib/oidc_provider/version.rb +1 -1
- data/lib/oidc_provider.rb +2 -0
- data/lib/tasks/oidc_provider.rake +33 -0
- metadata +8 -9
- data/app/controllers/oidc_provider/concerns/authentication.rb +0 -27
- data/lib/tasks/openid/connect/provider_tasks.rake +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29ccfbd4c57f22b63424ddbd7998bde94566c24e06721b43bfa5b07df0852ef6
|
4
|
+
data.tar.gz: fdeaa21ebbc146987ed9547988d4f7d59449a8dae6609477e72f1f78b47e7f91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82cd93fa057ecf8522d3ae4754360e202da2e102a9ee4b8ac8d52cbfa2df6da8a86532de765cf52ddea63080b182f9605c37c87db8097066ac019b6091e70812
|
7
|
+
data.tar.gz: 5a8cd740d69fb544665b7262ccb8124d4ce51791ca052495b12369b01a5d8b40d4eabf6d0efc2a0b469086a8123d52ad898821083838d6d80e862be475262409
|
data/README.md
CHANGED
@@ -41,14 +41,19 @@ $ rails db:migrate
|
|
41
41
|
|
42
42
|
### Private Key
|
43
43
|
|
44
|
-
|
44
|
+
This gem signs the generated [JWT (JSON Web Tokens)](https://jwt.io/) using a
|
45
|
+
private key that should exist at the path `lib/oidc_provider_key.pem` in your
|
46
|
+
Rails application.
|
47
|
+
|
48
|
+
You can pass its passphrase using the `OIDC_PROVIDER_KEY_PASSPHRASE` environment
|
49
|
+
variable.
|
50
|
+
|
51
|
+
This gem provide a convenient way of generating one if you need it by running :
|
45
52
|
|
46
53
|
```bash
|
47
|
-
$
|
54
|
+
$ rails oidc_provider:generate_key
|
48
55
|
```
|
49
56
|
|
50
|
-
Due to Docker Composes' lack of support for multiline `.env` variables, put a passphrase on it. Then add the key to your application at `lib/oidc_provider_key.pem` and add the passphrase as an environment variables in your application: `ENV["OIDC_PROVIDER_KEY_PASSPHRASE"]`.
|
51
|
-
|
52
57
|
# Testing
|
53
58
|
|
54
59
|
Visit: https://demo.c2id.com/oidc-client/
|
@@ -92,5 +97,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
92
97
|
|
93
98
|
```
|
94
99
|
gem build oidc_provider.gemspec
|
95
|
-
gem push oidc_provider-0.3.
|
100
|
+
gem push oidc_provider-0.3.10.gem
|
96
101
|
```
|
@@ -1,5 +1,25 @@
|
|
1
1
|
module OIDCProvider
|
2
2
|
class ApplicationController < ActionController::Base
|
3
|
-
|
3
|
+
def oidc_current_account
|
4
|
+
send(OIDCProvider.current_account_method)
|
5
|
+
end
|
6
|
+
|
7
|
+
def current_token
|
8
|
+
@current_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
|
9
|
+
end
|
10
|
+
|
11
|
+
def require_authentication
|
12
|
+
send(OIDCProvider.current_authentication_method)
|
13
|
+
end
|
14
|
+
|
15
|
+
def require_access_token
|
16
|
+
unless current_token
|
17
|
+
raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def unauthenticate!
|
22
|
+
send(OIDCProvider.current_unauthenticate_method)
|
23
|
+
end
|
4
24
|
end
|
5
25
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OIDCProvider
|
2
4
|
class AuthorizationsController < ApplicationController
|
3
5
|
include Concerns::ConnectEndpoint
|
@@ -5,16 +7,13 @@ module OIDCProvider
|
|
5
7
|
before_action :require_oauth_request
|
6
8
|
before_action :require_response_type_code
|
7
9
|
before_action :require_client
|
10
|
+
before_action :reset_login_if_necessary
|
8
11
|
before_action :require_authentication
|
9
12
|
|
10
13
|
def create
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
nonce: oauth_request.nonce,
|
15
|
-
scopes: requested_scopes,
|
16
|
-
account: oidc_current_account
|
17
|
-
)
|
14
|
+
Rails.logger.info "scopes: #{requested_scopes}"
|
15
|
+
|
16
|
+
authorization = build_authorization_with(requested_scopes)
|
18
17
|
|
19
18
|
oauth_response.code = authorization.code
|
20
19
|
oauth_response.redirect_uri = @redirect_uri
|
@@ -27,21 +26,39 @@ module OIDCProvider
|
|
27
26
|
|
28
27
|
private
|
29
28
|
|
29
|
+
def build_authorization_with(scopes)
|
30
|
+
Authorization.create(
|
31
|
+
client_id: @client.identifier,
|
32
|
+
nonce: oauth_request.nonce,
|
33
|
+
scopes: scopes,
|
34
|
+
account: oidc_current_account
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
30
38
|
def require_client
|
31
39
|
@client = ClientStore.new.find_by(identifier: oauth_request.client_id) or oauth_request.invalid_request! 'not a valid client'
|
32
|
-
@redirect_uri = oauth_request.verify_redirect_uri!
|
40
|
+
@redirect_uri = oauth_request.verify_redirect_uri! @client.redirect_uri
|
33
41
|
end
|
34
42
|
|
35
43
|
def requested_scopes
|
36
|
-
@requested_scopes ||= ([
|
44
|
+
@requested_scopes ||= (['openid'] + OIDCProvider.supported_scopes.map(&:name)) & oauth_request.scope
|
37
45
|
end
|
38
46
|
helper_method :requested_scopes
|
39
47
|
|
40
48
|
def require_response_type_code
|
41
|
-
|
42
|
-
|
49
|
+
return if oauth_request.response_type == :code
|
50
|
+
|
51
|
+
oauth_request.unsupported_response_type!
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset_login_if_necessary
|
55
|
+
if params[:prompt] == "login"
|
56
|
+
# A `prompt=login` param means that we must prompt the user for sign in.
|
57
|
+
# So we will forcibly sign out the user here and then redirect them so they
|
58
|
+
# don't get redirected back to the url that contains `prompt=login`
|
59
|
+
unauthenticate!
|
60
|
+
redirect_to url_for(request.query_parameters.except(:prompt))
|
43
61
|
end
|
44
62
|
end
|
45
63
|
end
|
46
|
-
|
47
|
-
end
|
64
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OIDCProvider
|
2
4
|
class IdToken < ApplicationRecord
|
5
|
+
PASSPHRASE_ENV_VAR = 'OIDC_PROVIDER_KEY_PASSPHRASE'
|
6
|
+
|
3
7
|
belongs_to :authorization
|
4
8
|
|
5
9
|
attribute :expires_at, :datetime, default: -> { 1.hour.from_now }
|
@@ -24,8 +28,19 @@ module OIDCProvider
|
|
24
28
|
private
|
25
29
|
|
26
30
|
class << self
|
31
|
+
def config
|
32
|
+
{
|
33
|
+
issuer: OIDCProvider.issuer,
|
34
|
+
jwk_set: JSON::JWK::Set.new(public_jwk)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def oidc_provider_key_path
|
39
|
+
Rails.root.join("lib/oidc_provider_key.pem")
|
40
|
+
end
|
41
|
+
|
27
42
|
def key_pair
|
28
|
-
@key_pair ||= OpenSSL::PKey::RSA.new(File.read(
|
43
|
+
@key_pair ||= OpenSSL::PKey::RSA.new(File.read(oidc_provider_key_path), ENV[PASSPHRASE_ENV_VAR])
|
29
44
|
end
|
30
45
|
|
31
46
|
def private_jwk
|
@@ -35,13 +50,6 @@ module OIDCProvider
|
|
35
50
|
def public_jwk
|
36
51
|
JSON::JWK.new key_pair.public_key
|
37
52
|
end
|
38
|
-
|
39
|
-
def config
|
40
|
-
{
|
41
|
-
issuer: OIDCProvider.issuer,
|
42
|
-
jwk_set: JSON::JWK::Set.new(public_jwk)
|
43
|
-
}
|
44
|
-
end
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
data/lib/oidc_provider/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OIDCProvider
|
2
4
|
class Client
|
3
5
|
attr_accessor :identifier, :secret, :redirect_uri, :name
|
@@ -5,10 +7,10 @@ module OIDCProvider
|
|
5
7
|
def initialize(options = {})
|
6
8
|
@identifier = options[:identifier]
|
7
9
|
@secret = options[:secret]
|
8
|
-
@redirect_uri = options[:redirect_uri]
|
10
|
+
@redirect_uri = Array(options[:redirect_uri])
|
9
11
|
@name = options[:name]
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
|
-
require 'oidc_provider/client/builder'
|
16
|
+
require 'oidc_provider/client/builder'
|
data/lib/oidc_provider/engine.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OIDCProvider
|
2
4
|
class TokenEndpoint
|
3
5
|
attr_accessor :app
|
6
|
+
|
4
7
|
delegate :call, to: :app
|
5
8
|
|
6
9
|
def initialize
|
@@ -8,26 +11,36 @@ module OIDCProvider
|
|
8
11
|
Rails.logger.info "Client ID: #{req.client_id}"
|
9
12
|
Rails.logger.info "Client secret: #{req.client_secret}"
|
10
13
|
Rails.logger.info "Redirect URI: #{req.redirect_uri}"
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
) || req.invalid_client!
|
16
|
-
|
17
|
-
Rails.logger.info "Found a client!"
|
14
|
+
|
15
|
+
client = find_valid_client_from(req) || req.invalid_client!
|
16
|
+
|
17
|
+
Rails.logger.info 'Found a client!'
|
18
18
|
|
19
19
|
case req.grant_type
|
20
20
|
when :authorization_code
|
21
|
-
Rails.logger.info
|
21
|
+
Rails.logger.info 'Grant type was an authorization code. Correct!'
|
22
22
|
authorization = Authorization.valid.where(client_id: client.identifier, code: req.code).first || req.invalid_grant!
|
23
|
-
Rails.logger.info
|
23
|
+
Rails.logger.info 'We found an authorization matching this code!'
|
24
24
|
res.access_token = authorization.access_token.to_bearer_token
|
25
|
-
res.id_token = authorization.id_token.to_jwt if authorization.scopes.include?(
|
25
|
+
res.id_token = authorization.id_token.to_jwt if authorization.scopes.include?('openid')
|
26
26
|
else
|
27
|
-
Rails.logger.info "Unsupported grant type"
|
27
|
+
Rails.logger.info "Unsupported grant type: #{req.grant_type.inspect}"
|
28
28
|
req.unsupported_grant_type!
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def find_valid_client_from(req)
|
36
|
+
client = ClientStore.new.find_by(
|
37
|
+
identifier: req.client_id,
|
38
|
+
secret: req.client_secret
|
39
|
+
)
|
40
|
+
|
41
|
+
return nil unless client
|
42
|
+
|
43
|
+
client.redirect_uri.include?(req.redirect_uri) ? client : nil
|
44
|
+
end
|
32
45
|
end
|
33
|
-
end
|
46
|
+
end
|
data/lib/oidc_provider.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :oidc_provider do
|
4
|
+
desc 'Generate the lib/oidc_provider_key.pem key file'
|
5
|
+
task generate_key: :environment do
|
6
|
+
key_filepath = OIDCProvider::IdToken.oidc_provider_key_path
|
7
|
+
|
8
|
+
File.exist?(key_filepath) && raise("ERROR: A key file already exists at #{key_filepath}.")
|
9
|
+
|
10
|
+
passphrase_env_var = OIDCProvider::IdToken::PASSPHRASE_ENV_VAR
|
11
|
+
|
12
|
+
pass_phrase = ENV.fetch(passphrase_env_var, '')
|
13
|
+
|
14
|
+
if pass_phrase == ''
|
15
|
+
puts "\033[33mWARNING: You haven't defined a passphrase to be used to " \
|
16
|
+
'generate the new key which is concidered as insecured. You can ' \
|
17
|
+
"do it by setting the #{passphrase_env_var} environment variable " \
|
18
|
+
"and re-run this task.\033[0m"
|
19
|
+
|
20
|
+
raise
|
21
|
+
end
|
22
|
+
|
23
|
+
key_file_content = OpenSSL::PKey::RSA.new(2048).export(
|
24
|
+
OpenSSL::Cipher.new('AES-128-CBC'),
|
25
|
+
pass_phrase
|
26
|
+
)
|
27
|
+
|
28
|
+
File.write(key_filepath, key_file_content)
|
29
|
+
FileUtils.chmod(0_600, key_filepath)
|
30
|
+
|
31
|
+
puts "SUCCESS: A new key file has been created at #{key_filepath}."
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oidc_provider
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Carey
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- Rakefile
|
51
51
|
- app/controllers/oidc_provider/application_controller.rb
|
52
52
|
- app/controllers/oidc_provider/authorizations_controller.rb
|
53
|
-
- app/controllers/oidc_provider/concerns/authentication.rb
|
54
53
|
- app/controllers/oidc_provider/concerns/connect_endpoint.rb
|
55
54
|
- app/controllers/oidc_provider/discovery_controller.rb
|
56
55
|
- app/controllers/oidc_provider/sessions_controller.rb
|
@@ -74,12 +73,12 @@ files:
|
|
74
73
|
- lib/oidc_provider/token_endpoint.rb
|
75
74
|
- lib/oidc_provider/user_info_builder.rb
|
76
75
|
- lib/oidc_provider/version.rb
|
77
|
-
- lib/tasks/
|
78
|
-
homepage:
|
76
|
+
- lib/tasks/oidc_provider.rake
|
77
|
+
homepage: https://github.com/brandnewbox/oidc_provider
|
79
78
|
licenses:
|
80
79
|
- MIT
|
81
80
|
metadata: {}
|
82
|
-
post_install_message:
|
81
|
+
post_install_message:
|
83
82
|
rdoc_options: []
|
84
83
|
require_paths:
|
85
84
|
- lib
|
@@ -94,8 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
93
|
- !ruby/object:Gem::Version
|
95
94
|
version: '0'
|
96
95
|
requirements: []
|
97
|
-
rubygems_version: 3.
|
98
|
-
signing_key:
|
96
|
+
rubygems_version: 3.3.7
|
97
|
+
signing_key:
|
99
98
|
specification_version: 4
|
100
99
|
summary: Uses the openid_connect gem to turn a Rails app into an OpenID Connect provider.
|
101
100
|
test_files: []
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module OIDCProvider
|
2
|
-
module Concerns
|
3
|
-
module Authentication
|
4
|
-
def oidc_current_account
|
5
|
-
send(OIDCProvider.current_account_method)
|
6
|
-
end
|
7
|
-
|
8
|
-
def current_token
|
9
|
-
@current_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
|
10
|
-
end
|
11
|
-
|
12
|
-
def require_authentication
|
13
|
-
send(OIDCProvider.current_authentication_method)
|
14
|
-
end
|
15
|
-
|
16
|
-
def require_access_token
|
17
|
-
unless current_token
|
18
|
-
raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def unauthenticate!
|
23
|
-
send(OIDCProvider.current_unauthenticate_method)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|