doorkeeper_sso_client 0.0.1.pre.alpha → 0.2.1

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
  SHA1:
3
- metadata.gz: 4cdcda620355889e78cb8e033d7ace6c3312ba0f
4
- data.tar.gz: 91719886d17b09dafc3606b60692c08ea28125ca
3
+ metadata.gz: b20a41c970791aa17e049ba5b375a8745f7c5895
4
+ data.tar.gz: b7c40a6461323545a359b9950ad8533f8a8c1225
5
5
  SHA512:
6
- metadata.gz: d8bfce94aebfd8a72c9677c911b99c92346c5e30ed0cb86908b5e0218b50c7f62d00006615840f81c8944739dcce279dfc0a02a158456d12b3374bb18573eb58
7
- data.tar.gz: edb32e33342910eab0d9f338cae273e012007dd88d74d8d8c02967dc62f84050f08c745e54692fc2669b008c8aef46133bd7aebd2fa1c13080650b8b167b0993
6
+ metadata.gz: b79efaa840dd3e0c778fa178b457c9ef3f3a0abc78148d761dbf5c58994892215769fc594af6519d8fcb3bc1ea3ef81d1c6a9565b8a7a003d4c105e701503e1a
7
+ data.tar.gz: d67a3acf1bb2fa20e2251e62fe2930381d0b2e1e0f458b668c1ef2dd69baa916d8225c3a5bd6667cee8e53ffc44bf58db57c7e3e134c53ec63a96e3443cc1f0d
@@ -0,0 +1,16 @@
1
+ require 'mixlib/config'
2
+
3
+ module DoorkeeperSsoClient
4
+ # Temporary hardcoded config module
5
+ class Config
6
+ extend Mixlib::Config
7
+
8
+ config_strict_mode true
9
+ configurable :oauth_client_id
10
+ configurable :oauth_client_secret
11
+ configurable :base_uri
12
+ default :sessions_path, '/sso/sessions'
13
+ default :passport_verification_timeout_ms, 200
14
+ end
15
+
16
+ end
@@ -0,0 +1,17 @@
1
+ module DoorkeeperSsoClient
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace DoorkeeperSsoClient
4
+
5
+ # New test framework integration
6
+ config.generators do |g|
7
+ g.test_framework :rspec,
8
+ :fixtures => true,
9
+ :view_specs => false,
10
+ :helper_specs => false,
11
+ :routing_specs => false,
12
+ :controller_specs => true,
13
+ :request_specs => false
14
+ g.fixture_replacement :fabrication
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ require 'active_support/concern'
2
+
3
+ module DoorkeeperSsoClient
4
+ # One thing tha bugs me is when I cannot see which part of the code caused a log message.
5
+ # This mixin will include the current class name as Logger `progname` so you can show that it in your logfiles.
6
+ #
7
+ module Logging
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def debug(&block)
12
+ logger && logger.debug(progname, &block)
13
+ end
14
+
15
+ def info(&block)
16
+ logger && logger.info(progname, &block)
17
+ end
18
+
19
+ def warn(&block)
20
+ logger && logger.warn(progname, &block)
21
+ end
22
+
23
+ def error(&block)
24
+ logger && logger.error(progname, &block)
25
+ end
26
+
27
+ def fatal(&block)
28
+ logger && logger.fatal(progname, &block)
29
+ end
30
+
31
+ def progname
32
+ self.to_s
33
+ end
34
+
35
+ def logger
36
+ Rails.logger
37
+ end
38
+ end #class_methods
39
+
40
+ def debug(&block)
41
+ self.class.debug(&block)
42
+ end
43
+
44
+ def info(&block)
45
+ self.class.info(&block)
46
+ end
47
+
48
+ def warn(&block)
49
+ self.class.warn(&block)
50
+ end
51
+
52
+ def error(&block)
53
+ self.class.error(&block)
54
+ end
55
+
56
+ def fatal(&block)
57
+ self.class.fatal(&block)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,146 @@
1
+ module DoorkeeperSsoClient
2
+ class PassportVerifier
3
+
4
+ attr_reader :passport_id, :passport_state, :passport_secret, :user_ip, :user_agent, :device_id
5
+
6
+ def initialize(options = {})
7
+ options = ActionController::Parameters.new(options)
8
+ options.require(:passport_id, :passport_state, :passport_secret, :user_ip)
9
+ options.permit(:user_agent, :device_id)
10
+
11
+ options.each { |k,v| instance_variable_set("@#{k}",v) }
12
+ end
13
+
14
+ def call
15
+ fetch_response { |failure| return failure }
16
+ interpret_response
17
+
18
+ rescue ::JSON::ParserError
19
+ error { 'SSO Server response is not valid JSON.' }
20
+ error { response.inspect }
21
+ Operations.failure :server_response_not_parseable, object: response
22
+ end
23
+
24
+ def human_readable_timeout_in_ms
25
+ "#{timeout_in_milliseconds}ms"
26
+ end
27
+
28
+ private
29
+
30
+ def fetch_response
31
+ yield Operations.failure(:server_unreachable, object: response) unless response.code.to_s == '200'
32
+ yield Operations.failure(:server_response_not_parseable, object: response) unless parsed_response
33
+ yield Operations.failure(:server_response_missing_success_flag, object: response) unless response_has_success_flag?
34
+ Operations.success :server_response_looks_legit
35
+ end
36
+
37
+ def interpret_response
38
+ debug { "Interpreting response code #{response_code.inspect}" }
39
+
40
+ case response_code
41
+ when :passpord_unmodified then Operations.success(:passport_valid)
42
+ when :passport_changed then Operations.success(:passport_valid_and_modified, object: received_passport)
43
+ when :passport_invalid then Operations.failure(:passport_invalid)
44
+ else Operations.failure(:unexpected_server_response_status, object: response)
45
+ end
46
+ end
47
+
48
+ def response_code
49
+ return :unknown_response_code if parsed_response['code'].to_s == ''
50
+ parsed_response['code'].to_s.to_sym
51
+ end
52
+
53
+ def received_passport
54
+ ::DoorkeeperSsoClient::Passport.new received_passport_attributes
55
+
56
+ rescue ArgumentError
57
+ error { "Could not instantiate Passport from serialized response #{received_passport_attributes.inspect}" }
58
+ raise
59
+ end
60
+
61
+ def received_passport_attributes
62
+ attributes = parsed_response['passport']
63
+ attributes.keys.each do |key|
64
+ attributes[(key.to_sym rescue key) || key] = attributes.delete(key)
65
+ end
66
+ attributes
67
+ end
68
+
69
+ def params
70
+ result = { ip: user_ip, agent: user_agent, device_id: device_id, state: passport_state }
71
+ result.merge! insider_id: insider_id, insider_signature: insider_signature
72
+ result
73
+ end
74
+
75
+ def insider_id
76
+ ::Sso.config.oauth_client_id
77
+ end
78
+
79
+ def insider_secret
80
+ ::Sso.config.oauth_client_secret
81
+ end
82
+
83
+ def insider_signature
84
+ ::OpenSSL::HMAC.hexdigest signature_digest, insider_secret, user_ip
85
+ end
86
+
87
+ def signature_digest
88
+ OpenSSL::Digest.new 'sha1'
89
+ end
90
+
91
+ def token
92
+ Signature::Token.new passport_id, passport_secret
93
+ end
94
+
95
+ def signature_request
96
+ Signature::Request.new('GET', path, params)
97
+ end
98
+
99
+ def auth_hash
100
+ signature_request.sign token
101
+ end
102
+
103
+ def timeout_in_milliseconds
104
+ ::Sso.config.passport_verification_timeout_ms.to_i
105
+ end
106
+
107
+ def timeout_in_seconds
108
+ (timeout_in_milliseconds / 1000).round 2
109
+ end
110
+
111
+ # TODO: Needs to be configurable
112
+ def path
113
+ ::OmniAuth::Strategies::DoorkeeperSso.sessions_path
114
+ end
115
+
116
+ def base_endpoint
117
+ ::OmniAuth::Strategies::DoorkeeperSso.endpoint
118
+ end
119
+
120
+ def endpoint
121
+ URI.join(base_endpoint, path).to_s
122
+ end
123
+
124
+ def query_params
125
+ params.merge auth_hash
126
+ end
127
+
128
+ def response
129
+ @response ||= response!
130
+ end
131
+
132
+ def response!
133
+ debug { "Fetching Passport from #{endpoint.inspect}" }
134
+ ::HTTParty.get endpoint, timeout: timeout_in_seconds, query: query_params, headers: { 'Accept' => 'application/json' }
135
+ end
136
+
137
+ def parsed_response
138
+ response.parsed_response
139
+ end
140
+
141
+ def response_has_success_flag?
142
+ parsed_response && parsed_response.respond_to?(:key?) && (parsed_response.key?('success') || parsed_response.key?(:success))
143
+ end
144
+
145
+ end
146
+ end
@@ -1,3 +1,3 @@
1
1
  module DoorkeeperSsoClient
2
- VERSION = "0.0.1-alpha"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -0,0 +1,134 @@
1
+ module DoorkeeperSsoClient
2
+ module Warden
3
+ module Hooks
4
+ # This is a helpful `Warden::Manager.after_fetch` hook for Alpha and Beta.
5
+ # Whenever Carol is fetched out of the session, we also verify her resource.
6
+ #
7
+ # Usage:
8
+ #
9
+ # SSO::Client::Warden::Hooks::AfterFetch.activate scope: :vip
10
+ #
11
+ class AfterFetch
12
+ include ::DoorkeeperSsoClient::Logging
13
+
14
+ attr_reader :resource, :warden, :options
15
+ delegate :request, to: :warden
16
+ delegate :params, to: :request
17
+
18
+ def self.activate(warden_options)
19
+ ::Warden::Manager.after_fetch(warden_options) do |resource, warden, options|
20
+ self.new(resource, warden, options).call
21
+ end
22
+ end
23
+
24
+ def initialize(resource, warden, options)
25
+ @resource, @warden, @options = resource, warden, options
26
+ end
27
+
28
+ def call
29
+ return unless resource.is_a?(Session)
30
+ verify
31
+
32
+ rescue ::Timeout::Error
33
+ error { 'SSO Server timed out. Continuing with last known authentication/authorization...' }
34
+ Operations.failure :server_request_timed_out
35
+
36
+ rescue => exception
37
+ raise exception
38
+ Operations.failure :client_exception_caught
39
+ end
40
+
41
+ private
42
+
43
+ def verifier
44
+ ::DoorkeeperSsoClient::PassportVerifier.new resource_id: resource.id, resource_state: resource.state, resource_secret: resource.secret, user_ip: ip, user_agent: agent, device_id: device_id
45
+ end
46
+
47
+ def verification
48
+ @verification ||= verifier.call
49
+ end
50
+
51
+ def verification_code
52
+ verification.code
53
+ end
54
+
55
+ def verification_object
56
+ verification.object
57
+ end
58
+
59
+ def verify
60
+ debug { "Validating Passport #{resource.id.inspect} of logged in #{resource.user.class} in scope #{warden_scope.inspect}" }
61
+
62
+ case verification_code
63
+ when :server_unreachable then server_unreachable!
64
+ when :server_response_not_parseable then server_response_not_parseable!
65
+ when :server_response_missing_success_flag then server_response_missing_success_flag!
66
+ when :resource_valid then resource_valid!
67
+ when :resource_valid_and_modified then resource_valid_and_modified!(verification.object)
68
+ when :resource_invalid then resource_invalid!
69
+ else unexpected_server_response_status!
70
+ end
71
+ end
72
+
73
+ def resource_valid_and_modified!(modified_resource)
74
+ debug { 'Valid resource, but state changed' }
75
+ resource.verified!
76
+ resource.modified!
77
+ resource.user = modified_resource.user
78
+ resource.state = modified_resource.state
79
+ Operations.success :valid_and_modified
80
+ end
81
+
82
+ def resource_valid!
83
+ debug { 'Valid resource, no changes' }
84
+ resource.verified!
85
+ Operations.success :valid
86
+ end
87
+
88
+ def resource_invalid!
89
+ info { 'Your Passport is not valid any more.' }
90
+ warden.logout warden_scope
91
+ Operations.failure :invalid
92
+ end
93
+
94
+ def server_unreachable!
95
+ error { "SSO Server responded with an unexpected HTTP status code (#{verification_code.inspect} instead of 200). #{verification_object.inspect}" }
96
+ Operations.failure :server_unreachable
97
+ end
98
+
99
+ def server_response_missing_success_flag!
100
+ error { 'SSO Server response did not include the expected success flag.' }
101
+ Operations.failure :server_response_missing_success_flag
102
+ end
103
+
104
+ def unexpected_server_response_status!
105
+ error { "SSO Server response did not include a known resource status code. #{verification_code.inspect}" }
106
+ Operations.failure :unexpected_server_response_status
107
+ end
108
+
109
+ def server_response_not_parseable!
110
+ error { 'SSO Server response could not be parsed at all.' }
111
+ Operations.failure :server_response_not_parseable
112
+ end
113
+
114
+ # TODO: Use ActionDispatch remote IP or you might get the Load Balancer's IP instead :(
115
+ def ip
116
+ request.ip
117
+ end
118
+
119
+ def agent
120
+ request.user_agent
121
+ end
122
+
123
+ def device_id
124
+ params['device_id']
125
+ end
126
+
127
+ def warden_scope
128
+ options[:scope]
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
@@ -1,2 +1,13 @@
1
+ require "doorkeeper_sso_client/engine"
2
+ require 'doorkeeper_sso_client/config'
3
+ require 'doorkeeper_sso_client/logging'
4
+ require 'doorkeeper_sso_client/passport_verifier'
5
+ require 'doorkeeper_sso_client/warden/hooks/after_fetch'
6
+ require 'doorkeeper_sso_client/version'
7
+ require 'omniauth/strategies/doorkeeper_sso'
8
+
1
9
  module DoorkeeperSsoClient
10
+ def self.table_name_prefix
11
+ 'sso_client_'
12
+ end
2
13
  end
@@ -0,0 +1,62 @@
1
+ require 'omniauth-oauth2'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ class DoorkeeperSso < OmniAuth::Strategies::OAuth2
6
+ option :name, :doorkeeper_sso
7
+ option :client_options, {
8
+ site: 'https://sso.example.com',
9
+ authorize_path: '/oauth/authorize',
10
+ sso_sessions_path: '/sso/sessions',
11
+ user_info_path: nil
12
+ }
13
+
14
+ option :fields, [:email, :name, :first_name, :last_name]
15
+ option :uid_field, :id
16
+
17
+ attr_accessor :passport
18
+
19
+ uid do
20
+ user_info[options.uid_field.to_s]
21
+ end
22
+
23
+ info do
24
+ options.fields.inject({}) do |hash, field|
25
+ hash[field] = user_info[field.to_s]
26
+ hash
27
+ end
28
+ end
29
+
30
+ extra do
31
+ {
32
+ :passport_id => passport_info["id"],
33
+ :passport_secret => passport_info["secret"]
34
+ }
35
+ end
36
+
37
+ def user_info
38
+ @user_info ||= if options.client_options.user_info_path
39
+ access_token.get(options.client_options.user_info_path).parsed["response"]
40
+ else
41
+ passport_info["owner"]
42
+ end
43
+ end
44
+
45
+ def passport_info
46
+ params = { ip: request.ip, agent: request.user_agent }
47
+ @passport_info ||= access_token.post(options.client_options.sso_sessions_path, params: params).parsed
48
+ end
49
+
50
+ def call_app!
51
+ self.passport = create_passport
52
+ super
53
+ end
54
+
55
+ protected
56
+ def create_passport
57
+ ::DoorkeeperSsoClient::Passport.create_from_omniauth(env['omniauth.auth'])
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ module DoorkeeperSsoClient
4
+ RSpec.describe CallbacksController, type: :controller do
5
+
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ Fabricator(:user) do
2
+ first_name { FFaker::Name.first_name }
3
+ last_name { FFaker::Name.last_name }
4
+ name { |attrs| [attrs[:first_name], attrs[:last_name]].join(" ") }
5
+ email { FFaker::Internet.email }
6
+ end
@@ -0,0 +1,35 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ::DoorkeeperSsoClient::Config do
4
+
5
+ before(:each) do
6
+ ::DoorkeeperSsoClient::Config.reset
7
+ end
8
+
9
+ pending "no config" do
10
+ it { expect(::DoorkeeperSsoClient::Config.oauth_client_id).to raise_error }
11
+ end
12
+
13
+ context "with config" do
14
+
15
+ before(:each) do
16
+ ::DoorkeeperSsoClient::Config.reset
17
+ ::DoorkeeperSsoClient::Config.configure do |config|
18
+ config[:oauth_client_id] = 123
19
+ config[:oauth_client_secret] = 'abc'
20
+ config[:base_uri] = 'http://localhost'
21
+ end
22
+ end
23
+
24
+ describe "stores config" do
25
+ it { expect(::DoorkeeperSsoClient::Config.oauth_client_id).to eq 123 }
26
+ it { expect(::DoorkeeperSsoClient::Config.oauth_client_secret).to eq 'abc' }
27
+ it { expect(::DoorkeeperSsoClient::Config.base_uri).to eq 'http://localhost' }
28
+ end
29
+
30
+ describe "have default values" do
31
+ it { expect(::DoorkeeperSsoClient::Config.sessions_path).to eq '/sso/sessions' }
32
+ it { expect(::DoorkeeperSsoClient::Config.passport_verification_timeout_ms).to eq 200 }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe DoorkeeperSsoClient::Passport, :type => :model do
4
+ let(:user) { Fabricate(:user) }
5
+
6
+ describe "associations" do
7
+ it { is_expected.to belong_to(:identity) }
8
+ end
9
+
10
+ describe "validations" do
11
+ it { is_expected.to validate_presence_of(:uid) }
12
+ it { is_expected.to validate_uniqueness_of(:uid) }
13
+ end
14
+
15
+ end
@@ -0,0 +1,75 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+
4
+ # SimpleCov for rails
5
+ require 'simplecov'
6
+ SimpleCov.start 'rails'
7
+
8
+ require 'spec_helper'
9
+ # require File.expand_path("../test_app/config/environment", __FILE__)
10
+
11
+ # Combustion ordering for requires
12
+ require 'combustion'
13
+ # require 'capybara/rspec'
14
+
15
+ Combustion.path = 'spec/test_app'
16
+ Combustion.initialize! :all
17
+
18
+
19
+ require 'rspec/rails'
20
+ # require 'capybara/rails'
21
+ require 'shoulda/matchers'
22
+ require 'fabrication'
23
+ require 'vcr'
24
+
25
+ # Add additional requires below this line. Rails is not loaded until this point!
26
+
27
+ # Requires supporting ruby files with custom matchers and macros, etc, in
28
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
29
+ # run as spec files by default. This means that files in spec/support that end
30
+ # in _spec.rb will both be required and run as specs, causing the specs to be
31
+ # run twice. It is recommended that you do not name files matching this glob to
32
+ # end with _spec.rb. You can configure this pattern with the --pattern
33
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
34
+ #
35
+ # The following line is provided for convenience purposes. It has the downside
36
+ # of increasing the boot-up time by auto-requiring all files in the support
37
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
38
+ # require only the support files necessary.
39
+ #
40
+ Dir[Rails.root.join("../support/**/*.rb")].each { |f| require f }
41
+
42
+ # Require fabricators manually
43
+ Dir[Rails.root.join("../fabricators/**/*fabricator.rb")].each { |f| require f }
44
+
45
+ # Checks for pending migrations before tests are run.
46
+ # If you are not using ActiveRecord, you can remove this line.
47
+ ActiveRecord::Migration.maintain_test_schema!
48
+
49
+ RSpec.configure do |config|
50
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
51
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
52
+
53
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
54
+ # examples within a transaction, remove the following line or assign false
55
+ # instead of true.
56
+ config.use_transactional_fixtures = true
57
+
58
+ # RSpec Rails can automatically mix in different behaviours to your tests
59
+ # based on their file location, for example enabling you to call `get` and
60
+ # `post` in specs under `spec/controllers`.
61
+ #
62
+ # You can disable this behaviour by removing the line below, and instead
63
+ # explicitly tag your specs with their type, e.g.:
64
+ #
65
+ # RSpec.describe UsersController, :type => :controller do
66
+ # # ...
67
+ # end
68
+ #
69
+ # The different available types are documented in the features, such as in
70
+ # https://relishapp.com/rspec/rspec-rails/docs
71
+ config.infer_spec_type_from_file_location!
72
+
73
+ # Include named routes
74
+ config.include Rails.application.routes.url_helpers
75
+ end
@@ -0,0 +1,84 @@
1
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, consider making
10
+ # a separate helper file that requires the additional dependencies and performs
11
+ # the additional setup, and require it from the spec files that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+
18
+ require 'webmock/rspec'
19
+
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ end
34
+
35
+ # rspec-mocks config goes here. You can use an alternate test double
36
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
37
+ config.mock_with :rspec do |mocks|
38
+ # Prevents you from mocking or stubbing a method that does not exist on
39
+ # a real object. This is generally recommended, and will default to
40
+ # `true` in RSpec 4.
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+
44
+ # These two settings work together to allow you to limit a spec run
45
+ # to individual examples or groups you care about by tagging them with
46
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
47
+ # get run.
48
+ config.filter_run :focus
49
+ config.run_all_when_everything_filtered = true
50
+
51
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
52
+ # For more details, see:
53
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
54
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
55
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
56
+ config.disable_monkey_patching!
57
+
58
+ # Many RSpec users commonly either run the entire suite or an individual
59
+ # file, and it's useful to allow more verbose output when running an
60
+ # individual spec file.
61
+ if config.files_to_run.one?
62
+ # Use the documentation formatter for detailed output,
63
+ # unless a formatter has already been configured
64
+ # (e.g. via a command-line flag).
65
+ config.default_formatter = 'NyanCatWideFormatter'
66
+ end
67
+
68
+ # Print the 10 slowest examples and example groups at the
69
+ # end of the spec run, to help surface which specs are running
70
+ # particularly slow.
71
+ config.profile_examples = 10
72
+
73
+ # Run specs in random order to surface order dependencies. If you find an
74
+ # order dependency and want to debug it, you can fix the order by providing
75
+ # the seed, which is printed after each run.
76
+ # --seed 1234
77
+ config.order = :random
78
+
79
+ # Seed global randomization in this process using the `--seed` CLI option.
80
+ # Setting this allows you to use `--seed` to deterministically reproduce
81
+ # test failures related to randomization by passing the same `--seed` value
82
+ # as the one that triggered the failure.
83
+ Kernel.srand config.seed
84
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.configure do |config|
2
+
3
+ config.before(:suite) do
4
+ DatabaseCleaner.clean_with(:truncation)
5
+ end
6
+
7
+ config.before(:each) do
8
+ DatabaseCleaner.strategy = :truncation
9
+ end
10
+
11
+ config.before(:each, :js => true) do
12
+ DatabaseCleaner.strategy = :truncation
13
+ end
14
+
15
+ config.before(:each) do
16
+ DatabaseCleaner.start
17
+ end
18
+
19
+ config.after(:each) do
20
+ DatabaseCleaner.clean
21
+ end
22
+
23
+ end
@@ -0,0 +1,4 @@
1
+ Fabrication.configure do |config|
2
+ config.path_prefix = Rails.root
3
+ config.sequence_start = 1
4
+ end
@@ -0,0 +1,8 @@
1
+ VCR.configure do |c|
2
+ #the directory where your cassettes will be saved
3
+ c.cassette_library_dir = 'spec/cassette_library'
4
+ # your HTTP request service. You can also use fakeweb, webmock, and more
5
+ c.hook_into :webmock
6
+ c.configure_rspec_metadata!
7
+ c.ignore_hosts 'codeclimate.com'
8
+ end
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+ require 'combustion'
4
+
5
+ Combustion.path = 'spec/test_app'
6
+ Combustion.initialize! :all
7
+ Combustion::Application.load_tasks
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,7 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ has_one :passport, as: :identity
4
+
5
+ validates :email, :first_name, presence: true
6
+
7
+ end
@@ -0,0 +1,10 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ # For details on connection pooling, see rails configuration guide
5
+ # http://guides.rubyonrails.org/configuring.html#database-pooling
6
+ pool: 5
7
+
8
+ test:
9
+ <<: *default
10
+ database: doorkeeper_sso_client_test
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20150603155315) do
15
+
16
+ # These are extensions that must be enabled in order to support this database
17
+ enable_extension "plpgsql"
18
+
19
+ create_table "sso_client_passports", force: :cascade do |t|
20
+ t.integer "identity_id"
21
+ t.string "identity_type"
22
+ t.string "secret"
23
+ t.string "state"
24
+ t.string "chip"
25
+ t.string "user"
26
+ t.boolean "verified", default: false
27
+ t.boolean "modified", default: false
28
+ t.datetime "created_at", null: false
29
+ t.datetime "updated_at", null: false
30
+ t.integer "expiry"
31
+ t.string "uid", null: false
32
+ t.string "token"
33
+ t.string "refresh_token"
34
+ t.integer "token_expiry"
35
+ t.datetime "revoked_at"
36
+ t.string "revoke_reason"
37
+ t.datetime "last_login_at"
38
+ end
39
+
40
+ add_index "sso_client_passports", ["identity_type", "identity_id"], name: "index_sso_client_passports_on_identity_type_and_identity_id", using: :btree
41
+
42
+ create_table "users", force: :cascade do |t|
43
+ t.string "email", null: false
44
+ t.string "name"
45
+ t.string "first_name"
46
+ t.string "last_name"
47
+ t.string "lang", default: "EN"
48
+ t.datetime "created_at"
49
+ t.datetime "updated_at"
50
+ end
51
+
52
+ add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
53
+
54
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper_sso_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre.alpha
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Wong
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-01 00:00:00.000000000 Z
11
+ date: 2015-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: omniauth
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mixlib-config
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.2'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: omniauth-oauth2
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">"
74
+ - !ruby/object:Gem::Version
75
+ version: '3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: '3'
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: warden
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -53,19 +95,201 @@ dependencies:
53
95
  - !ruby/object:Gem::Version
54
96
  version: '1'
55
97
  - !ruby/object:Gem::Dependency
56
- name: sqlite3
98
+ name: operation
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.0.3
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.0.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: api-auth
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.3.1
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.3.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: database_cleaner
57
127
  requirement: !ruby/object:Gem::Requirement
58
128
  requirements:
59
129
  - - ">="
60
130
  - !ruby/object:Gem::Version
61
- version: '0'
131
+ version: '1.4'
62
132
  type: :development
63
133
  prerelease: false
64
134
  version_requirements: !ruby/object:Gem::Requirement
65
135
  requirements:
66
136
  - - ">="
67
137
  - !ruby/object:Gem::Version
68
- version: '0'
138
+ version: '1.4'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pg
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.18'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.18'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-rails
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '3.0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '3.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: shoulda-matchers
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '2.8'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '2.8'
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 0.9.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: 0.9.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: timecop
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0.7'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0.7'
209
+ - !ruby/object:Gem::Dependency
210
+ name: webmock
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '1.2'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '1.2'
223
+ - !ruby/object:Gem::Dependency
224
+ name: fabrication
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '2.0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '2.0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: vcr
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '2.9'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '2.9'
251
+ - !ruby/object:Gem::Dependency
252
+ name: nyan-cat-formatter
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0.11'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: '0.11'
265
+ - !ruby/object:Gem::Dependency
266
+ name: combustion
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - "~>"
270
+ - !ruby/object:Gem::Version
271
+ version: 0.5.3
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - "~>"
277
+ - !ruby/object:Gem::Version
278
+ version: 0.5.3
279
+ - !ruby/object:Gem::Dependency
280
+ name: ffaker
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '1'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '1'
69
293
  description: Provides SSO auth functionality based on Omniauth
70
294
  email:
71
295
  - john@flexnode.com
@@ -74,8 +298,28 @@ extensions: []
74
298
  extra_rdoc_files: []
75
299
  files:
76
300
  - lib/doorkeeper_sso_client.rb
301
+ - lib/doorkeeper_sso_client/config.rb
302
+ - lib/doorkeeper_sso_client/engine.rb
303
+ - lib/doorkeeper_sso_client/logging.rb
304
+ - lib/doorkeeper_sso_client/passport_verifier.rb
77
305
  - lib/doorkeeper_sso_client/version.rb
306
+ - lib/doorkeeper_sso_client/warden/hooks/after_fetch.rb
307
+ - lib/omniauth/strategies/doorkeeper_sso.rb
78
308
  - lib/tasks/doorkeeper_sso_client_tasks.rake
309
+ - spec/controllers/doorkeeper_sso_client/callbacks_controller_spec.rb
310
+ - spec/fabricators/user_fabricator.rb
311
+ - spec/lib/doorkeeper_sso_client/config_spec.rb
312
+ - spec/models/passport_spec.rb
313
+ - spec/rails_helper.rb
314
+ - spec/spec_helper.rb
315
+ - spec/support/database_cleaner.rb
316
+ - spec/support/fabrication.rb
317
+ - spec/support/vcr.rb
318
+ - spec/test_app/Rakefile
319
+ - spec/test_app/app/controllers/application_controller.rb
320
+ - spec/test_app/app/models/user.rb
321
+ - spec/test_app/config/database.yml
322
+ - spec/test_app/db/schema.rb
79
323
  homepage: https://github.com/flexnode/sso_client
80
324
  licenses:
81
325
  - MIT
@@ -91,14 +335,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
335
  version: '1.9'
92
336
  required_rubygems_version: !ruby/object:Gem::Requirement
93
337
  requirements:
94
- - - ">"
338
+ - - ">="
95
339
  - !ruby/object:Gem::Version
96
- version: 1.3.1
340
+ version: '0'
97
341
  requirements: []
98
342
  rubyforge_project:
99
343
  rubygems_version: 2.4.5
100
344
  signing_key:
101
345
  specification_version: 4
102
346
  summary: Client gem for flexnode/doorkeeper_sso
103
- test_files: []
347
+ test_files:
348
+ - spec/controllers/doorkeeper_sso_client/callbacks_controller_spec.rb
349
+ - spec/fabricators/user_fabricator.rb
350
+ - spec/lib/doorkeeper_sso_client/config_spec.rb
351
+ - spec/models/passport_spec.rb
352
+ - spec/rails_helper.rb
353
+ - spec/spec_helper.rb
354
+ - spec/support/database_cleaner.rb
355
+ - spec/support/fabrication.rb
356
+ - spec/support/vcr.rb
357
+ - spec/test_app/app/controllers/application_controller.rb
358
+ - spec/test_app/app/models/user.rb
359
+ - spec/test_app/config/database.yml
360
+ - spec/test_app/db/schema.rb
361
+ - spec/test_app/Rakefile
104
362
  has_rdoc: