Skip to content

Commit

Permalink
feature: Store and return nonces in IdToken responses
Browse files Browse the repository at this point in the history
- Add migration generator for nonce table
- Abort if Doorkeeper ORM isn't set to ActiveRecord
- Use prepend to extend Doorkeeper classes
  • Loading branch information
toupeira committed Nov 2, 2016
1 parent c73dc98 commit d28ca8c
Show file tree
Hide file tree
Showing 30 changed files with 480 additions and 87 deletions.
80 changes: 15 additions & 65 deletions lib/doorkeeper/openid_connect.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
require 'doorkeeper/openid_connect/version'
require 'doorkeeper'
require 'json/jwt'

require 'doorkeeper/openid_connect/claims_builder'
require 'doorkeeper/openid_connect/config'
require 'doorkeeper/openid_connect/engine'
require 'doorkeeper/openid_connect/version'

require 'doorkeeper/openid_connect/helpers/controller'

Expand All @@ -8,80 +13,25 @@
require 'doorkeeper/openid_connect/models/claims/claim'
require 'doorkeeper/openid_connect/models/claims/normal_claim'

require 'doorkeeper/openid_connect/claims_builder'
require 'doorkeeper/openid_connect/config'
require 'doorkeeper/openid_connect/oauth/authorization/code'
require 'doorkeeper/openid_connect/oauth/authorization_code_request'
require 'doorkeeper/openid_connect/oauth/password_access_token_request'
require 'doorkeeper/openid_connect/oauth/pre_authorization'
require 'doorkeeper/openid_connect/oauth/token_response'

require 'doorkeeper/openid_connect/rails/routes'
require 'doorkeeper/openid_connect/orm/active_record'

require 'doorkeeper'
require 'json/jwt'
require 'doorkeeper/openid_connect/rails/routes'

module Doorkeeper
singleton_class.send :prepend, OpenidConnect::DoorkeeperConfiguration

module OpenidConnect
# TODO: make this configurable
SIGNING_ALGORITHM = 'RS256'

def self.configured?
@config.present?
end

def self.installed?
configured?
end

def self.signing_key
JSON::JWK.new(OpenSSL::PKey.read(configuration.jws_private_key))
end
end
end

module Doorkeeper
class << self
prepend ::Doorkeeper::OpenidConnect::DoorkeeperConfiguration
end

module Helpers::Controller
prepend ::Doorkeeper::OpenidConnect::Helpers::Controller
end
end

module Doorkeeper
module OAuth
class PasswordAccessTokenRequest
private

def after_successful_response
id_token = Doorkeeper::OpenidConnect::Models::IdToken.new(access_token)
@response.id_token = id_token
end
end
end
end

module Doorkeeper
module OAuth
class AuthorizationCodeRequest
private

def after_successful_response
id_token = Doorkeeper::OpenidConnect::Models::IdToken.new(access_token)
@response.id_token = id_token
end
end
end
end

module Doorkeeper
module OAuth
class TokenResponse
attr_accessor :id_token
alias_method :original_body, :body

def body
original_body.
merge({:id_token => id_token.try(:as_jws_token)}).
reject { |_, value| value.blank? }
end
end
end
end
6 changes: 6 additions & 0 deletions lib/doorkeeper/openid_connect/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ module OpenidConnect
module DoorkeeperConfiguration
def configure(&block)
super(&block)

if configuration.orm != :active_record
fail ConfigurationError, 'Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter'
end

configuration.optional_scopes.add :openid
end
end

class ConfigurationError < StandardError; end
class MissingConfiguration < StandardError
def initialize
super('Configuration for Doorkeeper OpenID Connect missing. Do you have doorkeeper_openid_connect initializer?')
Expand Down
2 changes: 2 additions & 0 deletions lib/doorkeeper/openid_connect/helpers/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ def prompt_values
end
end
end

Helpers::Controller.send :prepend, OpenidConnect::Helpers::Controller
end
8 changes: 6 additions & 2 deletions lib/doorkeeper/openid_connect/models/id_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ module Models
class IdToken
include ActiveModel::Validations

def initialize(access_token)
attr_reader :nonce

def initialize(access_token, nonce = nil)
@access_token = access_token
@nonce = nonce
@resource_owner = access_token.instance_eval(&Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token)
@issued_at = Time.now
end
Expand All @@ -16,7 +19,8 @@ def claims
sub: subject,
aud: audience,
exp: expiration,
iat: issued_at
iat: issued_at,
nonce: nonce
}
end

Expand Down
20 changes: 20 additions & 0 deletions lib/doorkeeper/openid_connect/oauth/authorization/code.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Doorkeeper
module OpenidConnect
module OAuth
module Authorization
module Code
def issue_token
super.tap do |access_grant|
::Doorkeeper::OpenidConnect::Nonce.create!(
access_grant: access_grant,
nonce: pre_auth.nonce
)
end
end
end
end
end
end

OAuth::Authorization::Code.send :prepend, OpenidConnect::OAuth::Authorization::Code
end
17 changes: 17 additions & 0 deletions lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Doorkeeper
module OpenidConnect
module OAuth
module AuthorizationCodeRequest
private

def after_successful_response
super
id_token = Doorkeeper::OpenidConnect::Models::IdToken.new(access_token, grant.openid_connect_nonce.use!)
@response.id_token = id_token
end
end
end
end

OAuth::AuthorizationCodeRequest.send :prepend, OpenidConnect::OAuth::AuthorizationCodeRequest
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Doorkeeper
module OpenidConnect
module OAuth
module PasswordAccessTokenRequest
def self.prepended(base)
base.class_eval do
attr_reader :nonce
end
end

def initialize(server, client, resource_owner, parameters = {})
super
@nonce = parameters[:nonce]
end

private

def after_successful_response
super
id_token = Doorkeeper::OpenidConnect::Models::IdToken.new(access_token, nonce)
@response.id_token = id_token
end
end
end
end

OAuth::PasswordAccessTokenRequest.send :prepend, OpenidConnect::OAuth::PasswordAccessTokenRequest
end
20 changes: 20 additions & 0 deletions lib/doorkeeper/openid_connect/oauth/pre_authorization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Doorkeeper
module OpenidConnect
module OAuth
module PreAuthorization
def self.prepended(base)
base.class_eval do
attr_reader :nonce
end
end

def initialize(server, client, attrs = {})
super
@nonce = attrs[:nonce]
end
end
end
end

OAuth::PreAuthorization.send :prepend, OpenidConnect::OAuth::PreAuthorization
end
25 changes: 25 additions & 0 deletions lib/doorkeeper/openid_connect/oauth/token_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Doorkeeper
module OpenidConnect
module OAuth
module TokenResponse
def self.prepended(base)
base.class_eval do
attr_accessor :id_token
end
end

def body
if token.includes_scope? 'openid'
super.
merge({:id_token => id_token.try(:as_jws_token)}).
reject { |_, value| value.blank? }
else
super
end
end
end
end
end

OAuth::TokenResponse.send :prepend, OpenidConnect::OAuth::TokenResponse
end
21 changes: 21 additions & 0 deletions lib/doorkeeper/openid_connect/orm/active_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Doorkeeper
module OpenidConnect
module Orm
module ActiveRecord
def initialize_models!
super
require 'doorkeeper/openid_connect/orm/active_record/access_grant'
require 'doorkeeper/openid_connect/orm/active_record/nonce'

if Doorkeeper.configuration.active_record_options[:establish_connection]
[Doorkeeper::OpenidConnect::Nonce].each do |c|
c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection]
end
end
end
end
end
end

Orm::ActiveRecord.singleton_class.send :prepend, OpenidConnect::Orm::ActiveRecord
end
16 changes: 16 additions & 0 deletions lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Doorkeeper
module OpenidConnect
module AccessGrant
def self.prepended(base)
base.class_eval do
has_one :openid_connect_nonce,
class_name: 'Doorkeeper::OpenidConnect::Nonce',
inverse_of: :access_grant,
dependent: :delete
end
end
end
end

AccessGrant.send :prepend, OpenidConnect::AccessGrant
end
17 changes: 17 additions & 0 deletions lib/doorkeeper/openid_connect/orm/active_record/nonce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Doorkeeper
module OpenidConnect
class Nonce < ActiveRecord::Base
self.table_name = "#{table_name_prefix}oauth_openid_connect_nonces#{table_name_suffix}".to_sym

validates :access_grant_id, :nonce, presence: true
belongs_to :access_grant,
class_name: 'Doorkeeper::AccessGrant',
inverse_of: :openid_connect_nonce

def use!
destroy!
nonce
end
end
end
end
15 changes: 15 additions & 0 deletions lib/generators/doorkeeper/openid_connect/migration_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'rails/generators/active_record'

class Doorkeeper::OpenidConnect::MigrationGenerator < ::Rails::Generators::Base
include Rails::Generators::Migration
source_root File.expand_path('../templates', __FILE__)
desc 'Installs Doorkeeper OpenID Connect migration file.'

def install
migration_template 'migration.rb', 'db/migrate/create_doorkeeper_openid_connect_tables.rb'
end

def self.next_migration_number(dirname)
ActiveRecord::Generators::Base.next_migration_number(dirname)
end
end
14 changes: 14 additions & 0 deletions lib/generators/doorkeeper/openid_connect/templates/migration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration
def change
create_table :oauth_openid_connect_nonces do |t|
t.integer :access_grant_id, null: false
t.string :nonce, null: false
end

add_foreign_key(
:oauth_openid_connect_nonces,
:oauth_access_grants,
column: :access_grant_id
)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration
def change
create_table :oauth_openid_connect_nonces do |t|
t.integer :access_grant_id, null: false
t.string :nonce, null: false
end

add_foreign_key(
:oauth_openid_connect_nonces,
:oauth_access_grants,
column: :access_grant_id
)
end
end
Loading

0 comments on commit d28ca8c

Please sign in to comment.