oidc_provider 0.3.10 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da21094ceda40451619c72e143399acf170b98f031eae7e0db2ec7e0e7dd97a6
4
- data.tar.gz: 41be8a950f2a1c96afae1c8db4e2ea8f3ac1629419ef206c4123580426f5a125
3
+ metadata.gz: 29ccfbd4c57f22b63424ddbd7998bde94566c24e06721b43bfa5b07df0852ef6
4
+ data.tar.gz: fdeaa21ebbc146987ed9547988d4f7d59449a8dae6609477e72f1f78b47e7f91
5
5
  SHA512:
6
- metadata.gz: 76a5ece3b674d0ab2e72af183c3333dcbe3fbb347f0503ce1aafc09b0cfbd1ba7e66ebe3f0ad2393953a5686875cc2f5f22e5dc557e6bc37de204c2b7ec2cd41
7
- data.tar.gz: eb859617ee41d779fc5e34ac2af239ab2d87b48634c5639080496930aff58cab487292660c520a3f336d451f40ea87f1fb32ec0cfb5beb4c14d9ffb636331ad2
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/
@@ -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.10'
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.10
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Carey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-03 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
@@ -73,7 +73,7 @@ files:
73
73
  - lib/oidc_provider/token_endpoint.rb
74
74
  - lib/oidc_provider/user_info_builder.rb
75
75
  - lib/oidc_provider/version.rb
76
- - lib/tasks/openid/connect/provider_tasks.rake
76
+ - lib/tasks/oidc_provider.rake
77
77
  homepage: https://github.com/brandnewbox/oidc_provider
78
78
  licenses:
79
79
  - MIT
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :openid_connect_provider do
3
- # # Task goes here
4
- # end