doorkeeper_sso_client 0.0.1.pre.alpha → 0.2.1

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