oidc_provider 0.1.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.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +75 -0
  4. data/Rakefile +32 -0
  5. data/app/controllers/oidc_provider/application_controller.rb +5 -0
  6. data/app/controllers/oidc_provider/authorizations_controller.rb +47 -0
  7. data/app/controllers/oidc_provider/concerns/authentication.rb +23 -0
  8. data/app/controllers/oidc_provider/concerns/connect_endpoint.rb +41 -0
  9. data/app/controllers/oidc_provider/discovery_controller.rb +46 -0
  10. data/app/controllers/oidc_provider/user_infos_controller.rb +9 -0
  11. data/app/models/oidc_provider/access_token.rb +17 -0
  12. data/app/models/oidc_provider/application_record.rb +5 -0
  13. data/app/models/oidc_provider/authorization.rb +41 -0
  14. data/app/models/oidc_provider/id_token.rb +47 -0
  15. data/config/initializers/inflections.rb +3 -0
  16. data/config/routes.rb +7 -0
  17. data/lib/generators/oidc_provider/install_generator.rb +35 -0
  18. data/lib/generators/oidc_provider/orm_helpers.rb +40 -0
  19. data/lib/generators/oidc_provider/templates/initializer.rb +30 -0
  20. data/lib/oidc_provider/account_to_user_info.rb +12 -0
  21. data/lib/oidc_provider/client/builder.rb +21 -0
  22. data/lib/oidc_provider/client.rb +14 -0
  23. data/lib/oidc_provider/client_store.rb +13 -0
  24. data/lib/oidc_provider/engine.rb +13 -0
  25. data/lib/oidc_provider/scope.rb +10 -0
  26. data/lib/oidc_provider/token_endpoint.rb +33 -0
  27. data/lib/oidc_provider/user_info_builder.rb +18 -0
  28. data/lib/oidc_provider/version.rb +3 -0
  29. data/lib/oidc_provider.rb +48 -0
  30. data/lib/tasks/openid/connect/provider_tasks.rake +4 -0
  31. metadata +101 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9ecb70ab0d1be5f3dae4837a3e073a1360e0bba
4
+ data.tar.gz: 0e1f83398394d4441377dd28e48401ccfcd891f9
5
+ SHA512:
6
+ metadata.gz: 05b71caa7fe69bd7162beb297d509e586f2e5a37f1520b5362549e8a31aeb0a654269f80fb24bac832fd4991a0634d59a481cd58fa36b62a50e65ddfc1d3df2f
7
+ data.tar.gz: '088d8b1ceb4d00dbc3de928187017e9f72505f73e15564a519083addb9409e9b814f31199b7c32bb1d20494bb5932bea3f477a9f204de4572576ab3d16c2f90e'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # OIDCProvider
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ Use your application as an Open ID provider.
6
+
7
+ You'll need some kind of user authentication to exist on you application first. Normally we use Devise.
8
+
9
+ ## Installation
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'oidc_provider'
14
+ ```
15
+
16
+ And then execute:
17
+ ```bash
18
+ $ bundle
19
+ ```
20
+
21
+ Or install it yourself as:
22
+ ```bash
23
+ $ gem install oidc_provider
24
+ ```
25
+
26
+ Install the support stuffs:
27
+
28
+ * an initializer
29
+ * default routes to your routes file
30
+
31
+ ```bash
32
+ $ rails generate oidc_provider:install
33
+ ```
34
+
35
+ Migrations next:
36
+
37
+ ```bash
38
+ $ rails oidc_provider:install:migrations
39
+ $ rails db:migrate
40
+ ```
41
+
42
+ ### Private Key
43
+
44
+ You will need to generate a unique private key per application.
45
+
46
+ ```bash
47
+ $ ssh-keygen
48
+ ```
49
+
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
+ # Testing configuration
53
+
54
+ Visit: https://demo.c2id.com/oidc-client/
55
+
56
+ Click "OpenID provider details"
57
+
58
+ Put in your website as the issuer and click "Query"
59
+
60
+ You should see values generated for all 4 endpoints below.
61
+
62
+
63
+ ## Contributing
64
+ Contribution directions go here.
65
+
66
+ ## License
67
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
68
+
69
+ ## How to build this gem
70
+
71
+ ```
72
+ gem build oidc_provider.gemspec
73
+ gem push channel_research_stationery-2.10.gem
74
+ gem yank -v 2.10 channel_research_stationery
75
+ ```
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Openid::Connect::Provider'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,5 @@
1
+ module OIDCProvider
2
+ class ApplicationController < ActionController::Base
3
+ include Concerns::Authentication
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ module OIDCProvider
2
+ class AuthorizationsController < ApplicationController
3
+ include Concerns::ConnectEndpoint
4
+
5
+ before_action :require_oauth_request
6
+ before_action :require_response_type_code
7
+ before_action :require_client
8
+ before_action :require_authentication
9
+
10
+ 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: current_account
17
+ )
18
+
19
+ oauth_response.code = authorization.code
20
+ oauth_response.redirect_uri = @redirect_uri
21
+ oauth_response.approve!
22
+ redirect_to oauth_response.location
23
+
24
+ # If we ever need to support denied authorizations that is done by:
25
+ # oauth_request.access_denied!
26
+ end
27
+
28
+ private
29
+
30
+ def require_client
31
+ @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]
33
+ end
34
+
35
+ def requested_scopes
36
+ @requested_scopes ||= (["openid"] + OIDCProvider.supported_scopes.map(&:name)) & oauth_request.scope
37
+ end
38
+ helper_method :requested_scopes
39
+
40
+ def require_response_type_code
41
+ unless oauth_request.response_type == :code
42
+ oauth_request.unsupported_response_type!
43
+ end
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,23 @@
1
+ module OIDCProvider
2
+ module Concerns
3
+ module Authentication
4
+ def 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
+ authenticate_user!
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
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ module OIDCProvider
2
+ module Concerns
3
+ module ConnectEndpoint
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :oauth_request
8
+ rescue_from Rack::OAuth2::Server::Authorize::BadRequest, with: :handle_oauth_error!
9
+ end
10
+
11
+ def oauth_request
12
+ request.env[Rack::OAuth2::Server::Rails::REQUEST]
13
+ end
14
+
15
+ def oauth_response
16
+ request.env[Rack::OAuth2::Server::Rails::RESPONSE]
17
+ end
18
+
19
+ def oauth_error
20
+ request.env[Rack::OAuth2::Server::Rails::ERROR]
21
+ end
22
+
23
+ def handle_oauth_error!(e)
24
+ if e.redirect?
25
+ raise e # NOTE: rack middleware should handle this error.
26
+ else
27
+ render plain: e.message, status: e.status
28
+ end
29
+ end
30
+
31
+ def require_oauth_request
32
+ if oauth_error
33
+ raise oauth_error
34
+ end
35
+ unless oauth_request && oauth_response
36
+ raise 'should\'t happen'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module OIDCProvider
2
+ class DiscoveryController < ApplicationController
3
+ def show
4
+ case params[:id]
5
+ when 'webfinger'
6
+ webfinger_discovery
7
+ when 'openid-configuration'
8
+ openid_configuration
9
+ else
10
+ render plain: "Not found", status: :not_found
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def webfinger_discovery
17
+ jrd = {
18
+ links: [{
19
+ rel: OpenIDConnect::Discovery::Provider::Issuer::REL_VALUE,
20
+ href: OIDCProvider.issuer
21
+ }]
22
+ }
23
+ jrd[:subject] = params[:resource] if params[:resource].present?
24
+ render json: jrd, content_type: Mime::JRD
25
+ end
26
+
27
+ def openid_configuration
28
+ config = OpenIDConnect::Discovery::Provider::Config::Response.new(
29
+ issuer: OIDCProvider.issuer,
30
+ authorization_endpoint: authorizations_url,
31
+ token_endpoint: tokens_url,
32
+ userinfo_endpoint: user_info_url,
33
+ jwks_uri: jwks_url,
34
+ scopes_supported: ["openid"] + OIDCProvider.supported_scopes.map(&:name),
35
+ response_types_supported: [:code],
36
+ grant_types_supported: [:authorization_code],
37
+ subject_types_supported: [:public],
38
+ id_token_signing_alg_values_supported: [:RS256],
39
+ token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],
40
+ claims_supported: ['sub', 'iss', 'name', 'email']
41
+ )
42
+ render json: config
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,9 @@
1
+ module OIDCProvider
2
+ class UserInfosController < ApplicationController
3
+ before_action :require_access_token
4
+
5
+ def show
6
+ render json: AccountToUserInfo.new.(current_token.authorization.account, current_token.authorization.scopes)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module OIDCProvider
2
+ class AccessToken < ApplicationRecord
3
+ belongs_to :authorization
4
+
5
+ scope :valid, -> { where(arel_table[:expires_at].gteq(Time.now.utc)) }
6
+
7
+ attribute :token, :string, default: -> { SecureRandom.hex 32 }
8
+ attribute :expires_at, :datetime, default: -> { 1.hours.from_now }
9
+
10
+ def to_bearer_token
11
+ Rack::OAuth2::AccessToken::Bearer.new(
12
+ access_token: token,
13
+ expires_in: (expires_at - Time.now).to_i
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module OIDCProvider
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ module OIDCProvider
2
+ class Authorization < ApplicationRecord
3
+ belongs_to :account, class_name: OIDCProvider.account_class
4
+ has_one :access_token
5
+ has_one :id_token
6
+
7
+ scope :valid, -> { where(arel_table[:expires_at].gteq(Time.now.utc)) }
8
+
9
+ attribute :code, :string, default: -> { SecureRandom.hex 32 }
10
+ attribute :expires_at, :datetime, default: -> { 5.minutes.from_now }
11
+
12
+ serialize :scopes, JSON
13
+
14
+ def expire!
15
+ self.expires_at = Time.now
16
+ self.save!
17
+ end
18
+
19
+ def access_token
20
+ super || expire! && generate_access_token!
21
+ end
22
+
23
+ def id_token
24
+ super || generate_id_token!
25
+ end
26
+
27
+ private
28
+
29
+ def generate_access_token!
30
+ token = create_access_token!
31
+ token
32
+ end
33
+
34
+ def generate_id_token!
35
+ token = build_id_token
36
+ token.nonce = nonce
37
+ token.save!
38
+ token
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ module OIDCProvider
2
+ class IdToken < ApplicationRecord
3
+ belongs_to :authorization
4
+
5
+ attribute :expires_at, :datetime, default: -> { 1.hour.from_now }
6
+
7
+ delegate :account, to: :authorization
8
+
9
+ def to_response_object
10
+ OpenIDConnect::ResponseObject::IdToken.new(
11
+ iss: OIDCProvider.issuer,
12
+ sub: account.send(OIDCProvider.account_identifier),
13
+ aud: authorization.client_id,
14
+ nonce: nonce,
15
+ exp: expires_at.to_i,
16
+ iat: created_at.to_i
17
+ )
18
+ end
19
+
20
+ def to_jwt
21
+ to_response_object.to_jwt(self.class.private_jwk)
22
+ end
23
+
24
+ private
25
+
26
+ class << self
27
+ 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"])
29
+ end
30
+
31
+ def private_jwk
32
+ JSON::JWK.new key_pair
33
+ end
34
+
35
+ def public_jwk
36
+ JSON::JWK.new key_pair.public_key
37
+ end
38
+
39
+ def config
40
+ {
41
+ issuer: OIDCProvider.issuer,
42
+ jwk_set: JSON::JWK::Set.new(public_jwk)
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.acronym 'OIDC'
3
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ OIDCProvider::Engine.routes.draw do
2
+ match 'authorizations' => 'authorizations#create', via: [:get, :post]
3
+ resource :user_info, only: :show
4
+
5
+ post 'tokens', to: proc { |env| OIDCProvider::TokenEndpoint.new.call(env) }
6
+ get 'jwks.json', as: :jwks, to: proc { |env| [200, {'Content-Type' => 'application/json'}, [OIDCProvider::IdToken.config[:jwk_set].to_json]] }
7
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require 'rails/generators/base'
4
+ # require 'securerandom'
5
+
6
+ module OidcProvider
7
+
8
+ class InstallGenerator < Rails::Generators::Base
9
+ source_root File.expand_path('templates', __dir__)
10
+
11
+ desc "Creates a OIDCProvider initializer."
12
+
13
+ def copy_initializer_file
14
+ copy_file "initializer.rb", "config/initializers/oidc_provider.rb"
15
+ end
16
+
17
+ def setup_routes
18
+ route "get '/.well-known/:id', to: 'oidc_provider/discovery#show'"
19
+ route "mount OIDCProvider::Engine, at: '/accounts/oauth'"
20
+ end
21
+
22
+
23
+ # def copy_locale
24
+ # copy_file "../../../config/locales/en.yml", "config/locales/devise.en.yml"
25
+ # end
26
+
27
+ # def show_readme
28
+ # readme "README" if behavior == :invoke
29
+ # end
30
+
31
+ # def rails_4?
32
+ # Rails::VERSION::MAJOR == 4
33
+ # end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OIDCProvider
4
+ module Generators
5
+ module OrmHelpers
6
+ # def model_contents
7
+ # buffer = <<-CONTENT
8
+ # # Include default devise modules. Others available are:
9
+ # # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
10
+ # devise :database_authenticatable, :registerable,
11
+ # :recoverable, :rememberable, :validatable
12
+
13
+ # CONTENT
14
+ # buffer
15
+ # end
16
+
17
+ private
18
+
19
+ # def model_exists?
20
+ # File.exist?(File.join(destination_root, model_path))
21
+ # end
22
+
23
+ # def migration_exists?(table_name)
24
+ # Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_to_#{table_name}.rb$/).first
25
+ # end
26
+
27
+ def migration_path
28
+ if Rails.version >= '5.0.3'
29
+ db_migrate_path
30
+ else
31
+ @migration_path ||= File.join("db", "migrate")
32
+ end
33
+ end
34
+
35
+ # def model_path
36
+ # @model_path ||= File.join("app", "models", "#{file_path}.rb")
37
+ # end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ OIDCProvider.configure do |config|
2
+ config.issuer = "https://myoidcprovider.org"
3
+ # config.account_class = "Administrator"
4
+
5
+ config.add_client do
6
+ name "Test Client"
7
+ identifier '0001'
8
+ secret '27ffb...'
9
+ redirect_uri 'https://demo.c2id.com/oidc-client/cb'
10
+ end
11
+
12
+ config.add_client do
13
+ name "Client 1"
14
+ identifier "client_01"
15
+ secret "6f14c..."
16
+ redirect_uri "https://clientone.com/TDE/openid_connect_login"
17
+ end
18
+
19
+ config.add_scope OIDCProvider::Scopes::Profile do |user|
20
+ name user.full_name
21
+ given_name user.first_name
22
+ family_name user.last_name
23
+ end
24
+
25
+ config.add_scope OIDCProvider::Scopes::Email do |user|
26
+ email user.email
27
+ email_verified false
28
+ end
29
+
30
+ end
@@ -0,0 +1,12 @@
1
+ module OIDCProvider
2
+ class AccountToUserInfo
3
+ def call(account, scope_names)
4
+ scopes = scope_names.map { |name| OIDCProvider.supported_scopes.detect { |scope| scope.name == name } }.compact
5
+ OpenIDConnect::ResponseObject::UserInfo.new(sub: account.send(OIDCProvider.account_identifier)).tap do |user_info|
6
+ scopes.each do |scope|
7
+ UserInfoBuilder.new(user_info, account).run(&scope.work)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module OIDCProvider
2
+ class Client
3
+ class Builder
4
+ def initialize(&block)
5
+ @client = Client.new
6
+ @operation = block
7
+ end
8
+
9
+ def build
10
+ instance_exec(&@operation)
11
+ @client
12
+ end
13
+
14
+ [:identifier, :secret, :redirect_uri, :name].each do |attr|
15
+ define_method attr do |val|
16
+ @client.send("#{attr}=", val)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ module OIDCProvider
2
+ class Client
3
+ attr_accessor :identifier, :secret, :redirect_uri, :name
4
+
5
+ def initialize(options = {})
6
+ @identifier = options[:identifier]
7
+ @secret = options[:secret]
8
+ @redirect_uri = options[:redirect_uri]
9
+ @name = options[:name]
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'oidc_provider/client/builder'
@@ -0,0 +1,13 @@
1
+ module OIDCProvider
2
+ class ClientStore
3
+ attr_reader :clients
4
+
5
+ def initialize(clients = OIDCProvider.clients)
6
+ @clients = clients
7
+ end
8
+
9
+ def find_by(attrs)
10
+ clients.detect { |client| attrs.all? { |key, value| client.send(key) == value } }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'rack/oauth2'
2
+
3
+ module OIDCProvider
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace OIDCProvider
6
+
7
+ config.middleware.use Rack::OAuth2::Server::Rails::Authorize
8
+ config.middleware.use Rack::OAuth2::Server::Resource::Bearer, 'OpenID Connect' do |req|
9
+ AccessToken.valid.find_by(token: req.access_token) ||
10
+ req.invalid_token!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module OIDCProvider
2
+ class Scope
3
+ attr_accessor :name, :work
4
+
5
+ def initialize(name, &block)
6
+ @name = name
7
+ @work = block
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ module OIDCProvider
2
+ class TokenEndpoint
3
+ attr_accessor :app
4
+ delegate :call, to: :app
5
+
6
+ def initialize
7
+ @app = Rack::OAuth2::Server::Token.new do |req, res|
8
+ Rails.logger.info "Client ID: #{req.client_id}"
9
+ Rails.logger.info "Client secret: #{req.client_secret}"
10
+ 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!"
18
+
19
+ case req.grant_type
20
+ when :authorization_code
21
+ Rails.logger.info "Grant type was an authorization code. Correct!"
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!"
24
+ res.access_token = authorization.access_token.to_bearer_token
25
+ res.id_token = authorization.id_token.to_jwt if authorization.scopes.include?("openid")
26
+ else
27
+ Rails.logger.info "Unsupported grant type"
28
+ req.unsupported_grant_type!
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ module OIDCProvider
2
+ class UserInfoBuilder
3
+ attr_reader :user_info
4
+
5
+ def initialize(user_info, account)
6
+ @user_info = user_info
7
+ @account = account
8
+ end
9
+
10
+ def run(&block)
11
+ instance_exec(@account, &block)
12
+ end
13
+
14
+ def method_missing(sym, *args)
15
+ @user_info.send("#{sym}=", *args)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module OIDCProvider
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,48 @@
1
+ require "openid_connect"
2
+ require "oidc_provider/engine"
3
+
4
+ module OIDCProvider
5
+
6
+ module Scopes
7
+ OpenID = "openid"
8
+ Profile = "profile"
9
+ Email = "email"
10
+ Address = "address"
11
+ end
12
+
13
+ autoload :TokenEndpoint, 'oidc_provider/token_endpoint'
14
+ autoload :ClientStore, 'oidc_provider/client_store'
15
+ autoload :Client, 'oidc_provider/client'
16
+ autoload :AccountToUserInfo, 'oidc_provider/account_to_user_info'
17
+ autoload :Scope, 'oidc_provider/scope'
18
+ autoload :UserInfoBuilder, 'oidc_provider/user_info_builder'
19
+
20
+ mattr_accessor :issuer
21
+
22
+ mattr_accessor :supported_scopes
23
+ @@supported_scopes = []
24
+
25
+ mattr_accessor :clients
26
+ @@clients = []
27
+
28
+ mattr_accessor :account_class
29
+ @@account_class = "User"
30
+
31
+ mattr_accessor :current_account_method
32
+ @@current_account_method = :current_user
33
+
34
+ mattr_accessor :account_identifier
35
+ @@account_identifier = :id
36
+
37
+ def self.add_client(&block)
38
+ @@clients << Client::Builder.new(&block).build
39
+ end
40
+
41
+ def self.add_scope(name, &block)
42
+ @@supported_scopes << Scope.new(name, &block)
43
+ end
44
+
45
+ def self.configure
46
+ yield self
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :openid_connect_provider do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oidc_provider
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - William Carey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: openid_connect
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.3
41
+ description: A Rails engine for providing OpenID Connect authorization.
42
+ email:
43
+ - willtcarey@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/controllers/oidc_provider/application_controller.rb
52
+ - app/controllers/oidc_provider/authorizations_controller.rb
53
+ - app/controllers/oidc_provider/concerns/authentication.rb
54
+ - app/controllers/oidc_provider/concerns/connect_endpoint.rb
55
+ - app/controllers/oidc_provider/discovery_controller.rb
56
+ - app/controllers/oidc_provider/user_infos_controller.rb
57
+ - app/models/oidc_provider/access_token.rb
58
+ - app/models/oidc_provider/application_record.rb
59
+ - app/models/oidc_provider/authorization.rb
60
+ - app/models/oidc_provider/id_token.rb
61
+ - config/initializers/inflections.rb
62
+ - config/routes.rb
63
+ - lib/generators/oidc_provider/install_generator.rb
64
+ - lib/generators/oidc_provider/orm_helpers.rb
65
+ - lib/generators/oidc_provider/templates/initializer.rb
66
+ - lib/oidc_provider.rb
67
+ - lib/oidc_provider/account_to_user_info.rb
68
+ - lib/oidc_provider/client.rb
69
+ - lib/oidc_provider/client/builder.rb
70
+ - lib/oidc_provider/client_store.rb
71
+ - lib/oidc_provider/engine.rb
72
+ - lib/oidc_provider/scope.rb
73
+ - lib/oidc_provider/token_endpoint.rb
74
+ - lib/oidc_provider/user_info_builder.rb
75
+ - lib/oidc_provider/version.rb
76
+ - lib/tasks/openid/connect/provider_tasks.rake
77
+ homepage: http://brandnewbox.com
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.5.2
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Uses the openid_connect gem to turn a Rails app into an OpenID Connect provider.
101
+ test_files: []