oidc_provider 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []