doorkeeper_sso 0.1.0.pre.alpha → 0.2.0

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