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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4da8e2299c7665d720c58eac0e36869b933d65295ce2e90ec5362431bdcb22aa
4
- data.tar.gz: 5b6d2d403368ec78709ce3e9ccedd0cf0ffe267d778db03e0c673c4402b85ea6
3
+ metadata.gz: 29ccfbd4c57f22b63424ddbd7998bde94566c24e06721b43bfa5b07df0852ef6
4
+ data.tar.gz: fdeaa21ebbc146987ed9547988d4f7d59449a8dae6609477e72f1f78b47e7f91
5
5
  SHA512:
6
- metadata.gz: a2d92c3d60315fe73a367de0447f0f9f7155f12062b90e9440560e6d5d5011c21914ea16ba085381b8a5fa8ca23f9b0570e936c63893d27090f88924d20b4e84
7
- data.tar.gz: 3ede21e99bfc0cf3b48145ac28889a4ddef6ddeac15ac931030bcf67f18d6df16b055ccf9338751df687dad8c949f616fe5e184300a2e9e230baee14395e6537
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
- You will need to generate a unique private key per application.
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
- $ ssh-keygen
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.2.gem
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
- include Concerns::Authentication
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
- puts "scopes: #{requested_scopes}"
12
- authorization = Authorization.create(
13
- client_id: @client.identifier,
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! [oauth_request.redirect_uri, @client.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 ||= (["openid"] + OIDCProvider.supported_scopes.map(&:name)) & oauth_request.scope
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
- unless oauth_request.response_type == :code
42
- oauth_request.unsupported_response_type!
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(Rails.root.join("lib/oidc_provider_key.pem")), ENV["OIDC_PROVIDER_KEY_PASSPHRASE"])
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
@@ -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'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/oauth2'
2
4
 
3
5
  module OIDCProvider
@@ -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
- client = ClientStore.new.find_by(
12
- identifier: req.client_id,
13
- secret: req.client_secret,
14
- redirect_uri: req.redirect_uri
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 "Grant type was an authorization code. Correct!"
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 "We found an authorization matching this code!"
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?("openid")
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
@@ -1,3 +1,3 @@
1
1
  module OIDCProvider
2
- VERSION = '0.3.9'
2
+ VERSION = '0.4.0'
3
3
  end
data/lib/oidc_provider.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "openid_connect"
2
4
  require "oidc_provider/engine"
3
5
 
@@ -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.3.9
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: 2021-09-30 00:00:00.000000000 Z
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/openid/connect/provider_tasks.rake
78
- homepage: http://brandnewbox.com
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.0.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
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :openid_connect_provider do
3
- # # Task goes here
4
- # end