doorkeeper_sso 0.1.0.pre.alpha → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -5
  3. data/app/controllers/sso/application_controller.rb +6 -0
  4. data/app/controllers/sso/sessions_controller.rb +76 -12
  5. data/app/models/sso/client.rb +28 -0
  6. data/app/models/sso/session.rb +65 -41
  7. data/app/serializers/sso/owner_serializer.rb +5 -0
  8. data/app/serializers/sso/session_serializer.rb +7 -0
  9. data/db/migrate/{20150414102248_create_sso_sessions.rb → 20150521102248_create_sso_sessions.rb} +2 -3
  10. data/db/migrate/20150521142926_create_sso_clients.rb +18 -0
  11. data/db/migrate/20150521165143_remove_extra_columns_from_sso_sessions.rb +9 -0
  12. data/lib/doorkeeper_sso.rb +1 -0
  13. data/lib/sso.rb +4 -0
  14. data/lib/sso/doorkeeper/access_grant_mixin.rb +12 -0
  15. data/lib/sso/doorkeeper/access_token_mixin.rb +12 -0
  16. data/lib/sso/doorkeeper/application_mixin.rb +12 -0
  17. data/lib/sso/doorkeeper/authorizations_controller_mixin.rb +16 -4
  18. data/lib/sso/doorkeeper/tokens_controller_mixin.rb +15 -5
  19. data/lib/sso/engine.rb +27 -1
  20. data/lib/sso/engine.rb.orig +46 -0
  21. data/lib/sso/logging.rb +1 -1
  22. data/lib/sso/version.rb +1 -1
  23. data/lib/sso/warden/hooks/after_authentication.rb +17 -2
  24. data/lib/sso/warden/hooks/before_logout.rb +14 -5
  25. data/lib/sso/warden/hooks/session_check.rb +45 -0
  26. data/spec/api/schemas/session.json +35 -0
  27. data/spec/controllers/sso/sessions_controller_spec.rb +49 -9
  28. data/spec/fabricators/api_application_fabricator.rb +2 -2
  29. data/spec/fabricators/sso_client_fabricator.rb +5 -0
  30. data/spec/fabricators/sso_session_fabricator.rb +1 -2
  31. data/spec/fabricators/user_fabricator.rb +5 -3
  32. data/spec/lib/doorkeeper/access_grant_mixin_spec.rb +29 -0
  33. data/spec/lib/doorkeeper/access_token_mixin_spec.rb +29 -0
  34. data/spec/lib/doorkeeper/application_mixin_spec.rb +29 -0
  35. data/spec/lib/sso/warden/hooks/after_authentication_spec.rb +37 -0
  36. data/spec/lib/sso/warden/hooks/before_logout_spec.rb +30 -0
  37. data/spec/models/sso/client_spec.rb +15 -0
  38. data/spec/models/sso/session_spec.rb +108 -71
  39. data/spec/spec_helper.rb +1 -0
  40. data/spec/support/api_schema_matcher.rb +7 -0
  41. data/spec/test_app/Rakefile +5 -0
  42. data/spec/test_app/db/schema.rb +15 -1
  43. metadata +75 -18
@@ -0,0 +1,5 @@
1
+ Fabricator('Sso::Client') do
2
+ application_id { 0 }
3
+ ip { "127.0.0.1" }
4
+ agent { "Mozilla Firefox" }
5
+ end
@@ -1,6 +1,5 @@
1
1
  Fabricator('Sso::Session') do
2
2
  application_id { 0 }
3
- ip { "127.0.0.1" }
4
- agent { "Mozilla Firefox" }
5
3
  owner { Fabricate(:user) }
4
+ clients { [ Fabricate('Sso::Client') ] }
6
5
  end
@@ -1,7 +1,9 @@
1
1
  Fabricator(:user) do
2
- first_name Faker::Name.name
3
- email Faker::Internet.email
4
- password Faker::Internet.password
2
+ first_name { FFaker::Name.name }
3
+ last_name { FFaker::Name.last_name }
4
+ name { |attrs| [attrs[:first_name], attrs[:last_name]].join(" ") }
5
+ email { FFaker::Internet.email }
6
+ password { FFaker::Internet.password }
5
7
  password_confirmation { |attrs| "#{attrs[:password]}" }
6
8
  end
7
9
 
@@ -0,0 +1,29 @@
1
+ require 'rails_helper'
2
+
3
+ # Engine.rb automatically includes the mixin
4
+
5
+ RSpec.describe Doorkeeper::AccessGrant, :type => :model do
6
+ describe "associations" do
7
+ it { is_expected.to have_one(:sso_client).class_name('Sso::Client').with_foreign_key(:access_grant_id) }
8
+ end
9
+
10
+ describe "assignment" do
11
+ let(:user) { Fabricate(:user) }
12
+ let(:application) { Fabricate('Doorkeeper::Application') }
13
+ let(:access_token) { Fabricate('Doorkeeper::AccessToken',
14
+ resource_owner_id: user.id) }
15
+ let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
16
+ application_id: application.id,
17
+ resource_owner_id: user.id,
18
+ redirect_uri: 'http://localhost:3002/oauth/callback'
19
+ ) }
20
+
21
+ let(:session) { Fabricate('Sso::Session', owner: user) }
22
+ let!(:client) { Fabricate('Sso::Client', session: session,
23
+ application_id: application.id,
24
+ access_token_id: access_token.id,
25
+ access_grant_id: access_grant.id) }
26
+
27
+ it { expect(access_grant.sso_client).to eq client }
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails_helper'
2
+
3
+ # Engine.rb automatically includes the mixin
4
+
5
+ RSpec.describe Doorkeeper::AccessToken, :type => :model do
6
+ describe "associations" do
7
+ it { is_expected.to have_one(:sso_client).class_name('Sso::Client').with_foreign_key(:access_token_id) }
8
+ end
9
+
10
+ describe "assignment" do
11
+ let(:user) { Fabricate(:user) }
12
+ let(:application) { Fabricate('Doorkeeper::Application') }
13
+ let(:access_token) { Fabricate('Doorkeeper::AccessToken',
14
+ resource_owner_id: user.id) }
15
+ let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
16
+ application_id: application.id,
17
+ resource_owner_id: user.id,
18
+ redirect_uri: 'http://localhost:3002/oauth/callback'
19
+ ) }
20
+
21
+ let(:session) { Fabricate('Sso::Session', owner: user) }
22
+ let!(:client) { Fabricate('Sso::Client', session: session,
23
+ application_id: application.id,
24
+ access_token_id: access_token.id,
25
+ access_grant_id: access_grant.id) }
26
+
27
+ it { expect(access_token.sso_client).to eq client }
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails_helper'
2
+
3
+ # Engine.rb automatically includes the mixin
4
+
5
+ RSpec.describe Doorkeeper::Application, :type => :model do
6
+ describe "associations" do
7
+ it { is_expected.to have_many(:sso_clients).class_name('Sso::Client').with_foreign_key(:application_id) }
8
+ end
9
+
10
+ describe "assignment" do
11
+ let(:user) { Fabricate(:user) }
12
+ let(:application) { Fabricate('Doorkeeper::Application') }
13
+ let(:access_token) { Fabricate('Doorkeeper::AccessToken',
14
+ resource_owner_id: user.id) }
15
+ let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
16
+ application_id: application.id,
17
+ resource_owner_id: user.id,
18
+ redirect_uri: 'http://localhost:3002/oauth/callback'
19
+ ) }
20
+
21
+ let(:session) { Fabricate('Sso::Session', owner: user) }
22
+ let!(:client) { Fabricate('Sso::Client', session: session,
23
+ application_id: application.id,
24
+ access_token_id: access_token.id,
25
+ access_grant_id: access_grant.id) }
26
+
27
+ it { expect(application.sso_clients).to eq [ client ] }
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Sso::Warden::Hooks::AfterAuthentication do
4
+ #include Warden::Test::Helpers
5
+
6
+ let(:user) { Fabricate(:user) }
7
+ let(:warden_mock) { double }
8
+ let(:attributes) { { :ip => "202.188.0.133", :agent => "Chrome", format: :json } }
9
+
10
+ let(:after_authentication) { Sso::Warden::Hooks::AfterAuthentication.
11
+ new(user: user, warden: warden_mock, options: {} ) }
12
+
13
+
14
+ let(:master_sso_session) { Sso::Session.generate_master(user, attributes) }
15
+ let(:access_token) { Fabricate("Doorkeeper::AccessToken",
16
+ resource_owner_id: user.id) }
17
+ let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
18
+ resource_owner_id: user.id,
19
+ redirect_uri: 'http://localhost:3002/oauth/callback'
20
+ ) }
21
+
22
+ before do
23
+ master_sso_session.access_token_id = access_token.id
24
+ master_sso_session.access_grant_id = access_grant.id
25
+ master_sso_session.save
26
+ end
27
+
28
+ describe 'attributes' do
29
+ it do
30
+ expect(after_authentication.user).to eq user
31
+ expect(after_authentication.warden).to eq warden_mock
32
+ expect(after_authentication.options).to eq({})
33
+ end
34
+ end
35
+
36
+ pending "#call"
37
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Sso::Warden::Hooks::BeforeLogout do
4
+
5
+ let(:proc) { described_class.to_proc }
6
+ let(:calling) { proc.call(user, warden, options) }
7
+ let(:user) { double :user }
8
+ let(:params) { { passport_id: 1337 } } #passport.id } }
9
+ let(:options) { double :options }
10
+ let(:request) { double :request, params: params.stringify_keys }
11
+ let(:warden) { double :warden, request: request, :session => user }
12
+
13
+ before do
14
+ allow(warden).to receive(:authenticated?)
15
+ Timecop.freeze
16
+ end
17
+
18
+ describe '.to_proc' do
19
+ it 'is a proc' do
20
+ expect(proc).to be_instance_of Proc
21
+ end
22
+ end
23
+
24
+ describe '#call' do
25
+ it 'accepts the three warden arguments and returns nothing' do
26
+ expect(calling).to be_nil
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Sso::Client, :type => :model do
4
+ describe "associations" do
5
+ it { is_expected.to belong_to(:session).class_name('Sso::Session').with_foreign_key(:sso_session_id) }
6
+ it { is_expected.to belong_to(:application).class_name('Doorkeeper::Application') }
7
+ it { is_expected.to belong_to(:access_grant).class_name('Doorkeeper::AccessGrant') }
8
+ it { is_expected.to belong_to(:access_token).class_name('Doorkeeper::AccessToken') }
9
+ end
10
+
11
+ describe "validations" do
12
+ it { is_expected.to validate_uniqueness_of(:access_grant_id).allow_nil }
13
+ it { is_expected.to validate_uniqueness_of(:access_token_id).allow_nil }
14
+ end
15
+ end
@@ -6,12 +6,11 @@ RSpec.describe Sso::Session, :type => :model do
6
6
  it { is_expected.to belong_to(:access_grant).class_name('Doorkeeper::AccessGrant') }
7
7
  it { is_expected.to belong_to(:access_token).class_name('Doorkeeper::AccessToken') }
8
8
  it { is_expected.to belong_to(:owner).class_name('User') }
9
+ it { is_expected.to have_many(:clients).class_name('Sso::Client').with_foreign_key(:sso_session_id) }
9
10
  end
10
11
 
11
12
  describe "validations" do
12
- pending { is_expected.to validate_presence_of(:group_id) }
13
13
  pending { is_expected.to validate_presence_of(:secret) }
14
- pending { is_expected.to validate_uniqueness_of(:access_token_id).scoped_to([:owner_id, :revoked_at, :application_id]) }
15
14
  it { is_expected.to allow_value(nil).for(:access_token_id) }
16
15
  end
17
16
 
@@ -21,6 +20,36 @@ RSpec.describe Sso::Session, :type => :model do
21
20
  it { expect(Sso::Session.master).to eq [session] }
22
21
  end
23
22
 
23
+ describe "token based scopes" do
24
+
25
+ let(:user) { Fabricate(:user) }
26
+ let(:access_token) { Fabricate('Doorkeeper::AccessToken',
27
+ resource_owner_id: user.id) }
28
+ let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
29
+ application_id: nil,
30
+ resource_owner_id: user.id,
31
+ redirect_uri: 'http://localhost:3002/oauth/callback'
32
+ ) }
33
+
34
+ let(:session) { Fabricate('Sso::Session', owner: user) }
35
+ let!(:client) { Fabricate('Sso::Client', session: session,
36
+ access_token_id: access_token.id,
37
+ access_grant_id: access_grant.id) }
38
+
39
+ describe "::with_token_id" do
40
+ it { expect(Sso::Session.with_token_id(access_token.id).first).to eq session }
41
+ end
42
+
43
+ describe "::with_grant_id" do
44
+ it { expect(Sso::Session.with_grant_id(access_grant.id).first).to eq session }
45
+ end
46
+
47
+ describe "::by_access_token" do
48
+ it { expect(Sso::Session.by_access_token(access_token.token).first).to eq session }
49
+ end
50
+ end
51
+
52
+
24
53
  describe "::master_for" do
25
54
  let(:user) { Fabricate(:user) }
26
55
  let(:access_token) { Fabricate('Doorkeeper::AccessToken',
@@ -54,6 +83,11 @@ RSpec.describe Sso::Session, :type => :model do
54
83
  session = Sso::Session.generate_master(user, attributes)
55
84
  expect(session).to eq(Sso::Session.first)
56
85
  end
86
+
87
+ it "creates a new sso_client" do
88
+ session = Sso::Session.generate_master(user, attributes)
89
+ expect(session.clients.first).to eq Sso::Client.first
90
+ end
57
91
  end
58
92
 
59
93
  context "(failure)" do
@@ -63,30 +97,33 @@ RSpec.describe Sso::Session, :type => :model do
63
97
  end
64
98
  end
65
99
 
66
- describe "::generate" do
67
- let(:master_sso_session) { Sso::Session.generate_master(user, attributes) }
68
- let(:user) { Fabricate(:user) }
69
- let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
70
- let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
71
- let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
72
- application_id: nil,
73
- resource_owner_id: user.id,
74
- redirect_uri: 'http://localhost:3002/oauth/callback'
75
- ) }
76
- let(:session) { Sso::Session.generate(user, access_token, attributes) }
77
- before do
78
- # Notice: We assume our warden/doorkeeper is ok and a master with access grant/token is generated
79
- master_sso_session.access_token_id = access_token.id
80
- master_sso_session.access_grant_id = access_grant.id
81
- master_sso_session.save
82
- end
83
-
84
- describe "creates a new session" do
85
- it { expect(session.access_token_id).to eq access_token.id }
86
- it { expect(session.application_id).to eq access_token.application.id }
87
- it { expect(session.group_id).to eq master_sso_session.group_id }
88
- end
89
- end
100
+ # describe "::generate" do
101
+ # let(:master_sso_session) { Fabricate('Sso::Session') }
102
+ # let(:user) { Fabricate(:user) }
103
+ # let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
104
+ # let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
105
+ # let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
106
+ # application_id: nil,
107
+ # resource_owner_id: user.id,
108
+ # redirect_uri: 'http://localhost:3002/oauth/callback'
109
+ # ) }
110
+
111
+ # let(:session) { Sso::Session.generate(user, access_token, attributes) }
112
+
113
+ # before do
114
+ # master_sso_session.clients.create(access_token: access_token, access_grant: access_grant )
115
+ # # Notice: We assume our warden/doorkeeper is ok and a master with access grant/token is generated
116
+ # master_sso_session.access_token_id = access_token.id
117
+ # master_sso_session.access_grant_id = access_grant.id
118
+ # master_sso_session.save
119
+ # end
120
+
121
+ # describe "creates a new session" do
122
+ # it { expect(session.access_token_id).to eq access_token.id }
123
+ # it { expect(session.application_id).to eq access_token.application.id }
124
+ # it { expect(session.group_id).to eq master_sso_session.group_id }
125
+ # end
126
+ # end
90
127
 
91
128
  describe "::logout" do
92
129
  let!(:sso_session) { Fabricate('Sso::Session') }
@@ -100,51 +137,51 @@ RSpec.describe Sso::Session, :type => :model do
100
137
  end
101
138
  end
102
139
 
103
- describe "::update_master_with_grant" do
104
- let(:user) { Fabricate(:user) }
105
- let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
106
- let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
107
- let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
108
- application_id: nil,
109
- resource_owner_id: user.id,
110
- redirect_uri: 'http://localhost:3002/oauth/callback'
111
- ) }
112
- let!(:master_sso_session) { Sso::Session.generate_master(user, attributes) }
113
-
114
- context "successful" do
115
- it "updates master_sso_session.access_grant_id" do
116
- expect{ Sso::Session.update_master_with_grant(master_sso_session.id, access_grant) }.to change{ master_sso_session.reload.access_grant_id }.from(nil).to(access_grant.id)
117
- end
118
- end
119
- end
120
-
121
- describe "::update_master_with_access_token" do
122
- let(:user) { Fabricate(:user) }
123
- let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
124
- let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
125
- let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
126
- application_id: nil,
127
- resource_owner_id: user.id,
128
- redirect_uri: 'http://localhost:3002/oauth/callback'
129
- ) }
130
- let!(:master) { Sso::Session.generate_master(user, attributes) }
131
-
132
- before do
133
- # Notice: We assume our warden/doorkeeper is ok and a master with grant is generated
134
- master.access_grant_id = access_grant.id
135
- master.save
136
- end
137
-
138
- context "oauth_token not available" do
139
- it "returns false" do
140
- expect( Sso::Session.update_master_with_access_token(access_token.token, 123)).to be_falsey
141
- end
142
- end
143
-
144
- it "updates master.access_token_it" do
145
- expect{ Sso::Session.update_master_with_access_token(access_grant.token, access_token.token) }.to change{ master.reload.access_token_id }.from(nil).to(access_token.id)
146
- end
147
- end
140
+ # describe "::update_master_with_grant" do
141
+ # let(:user) { Fabricate(:user) }
142
+ # let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
143
+ # let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
144
+ # let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
145
+ # application_id: nil,
146
+ # resource_owner_id: user.id,
147
+ # redirect_uri: 'http://localhost:3002/oauth/callback'
148
+ # ) }
149
+ # let!(:master_sso_session) { Sso::Session.generate_master(user, attributes) }
150
+
151
+ # context "successful" do
152
+ # it "updates master_sso_session.access_grant_id" do
153
+ # expect{ Sso::Session.update_master_with_grant(master_sso_session.id, access_grant) }.to change{ master_sso_session.reload.access_grant_id }.from(nil).to(access_grant.id)
154
+ # end
155
+ # end
156
+ # end
157
+
158
+ # describe "::update_master_with_access_token" do
159
+ # let(:user) { Fabricate(:user) }
160
+ # let(:attributes) { { ip: "10.1.1.1", agent: "Safari" } }
161
+ # let(:access_token) { Fabricate("Doorkeeper::AccessToken", resource_owner_id: user.id) }
162
+ # let(:access_grant) { Fabricate('Doorkeeper::AccessGrant',
163
+ # application_id: nil,
164
+ # resource_owner_id: user.id,
165
+ # redirect_uri: 'http://localhost:3002/oauth/callback'
166
+ # ) }
167
+ # let!(:master) { Sso::Session.generate_master(user, attributes) }
168
+
169
+ # before do
170
+ # # Notice: We assume our warden/doorkeeper is ok and a master with grant is generated
171
+ # master.access_grant_id = access_grant.id
172
+ # master.save
173
+ # end
174
+
175
+ # context "oauth_token not available" do
176
+ # it "returns false" do
177
+ # expect( Sso::Session.update_master_with_access_token(access_token.token, 123)).to be_falsey
178
+ # end
179
+ # end
180
+
181
+ # it "updates master.access_token_it" do
182
+ # expect{ Sso::Session.update_master_with_access_token(access_grant.token, access_token.token) }.to change{ master.reload.access_token_id }.from(nil).to(access_token.id)
183
+ # end
184
+ # end
148
185
 
149
186
  end
150
187
 
data/spec/spec_helper.rb CHANGED
@@ -15,6 +15,7 @@
15
15
  #
16
16
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
17
 
18
+ require 'ffaker'
18
19
  require 'webmock/rspec'
19
20
 
20
21
  RSpec.configure do |config|
@@ -0,0 +1,7 @@
1
+ RSpec::Matchers.define :match_response_schema do |schema|
2
+ match do |response|
3
+ schema_directory = "#{Dir.pwd}/spec/api/schemas"
4
+ schema_path = "#{schema_directory}/#{schema}.json"
5
+ JSON::Validator.validate!(schema_path, response.body, strict: true)
6
+ end
7
+ end
@@ -1,2 +1,7 @@
1
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
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