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.
- checksums.yaml +4 -4
- data/Rakefile +0 -5
- data/app/controllers/sso/application_controller.rb +6 -0
- data/app/controllers/sso/sessions_controller.rb +76 -12
- data/app/models/sso/client.rb +28 -0
- data/app/models/sso/session.rb +65 -41
- data/app/serializers/sso/owner_serializer.rb +5 -0
- data/app/serializers/sso/session_serializer.rb +7 -0
- data/db/migrate/{20150414102248_create_sso_sessions.rb → 20150521102248_create_sso_sessions.rb} +2 -3
- data/db/migrate/20150521142926_create_sso_clients.rb +18 -0
- data/db/migrate/20150521165143_remove_extra_columns_from_sso_sessions.rb +9 -0
- data/lib/doorkeeper_sso.rb +1 -0
- data/lib/sso.rb +4 -0
- data/lib/sso/doorkeeper/access_grant_mixin.rb +12 -0
- data/lib/sso/doorkeeper/access_token_mixin.rb +12 -0
- data/lib/sso/doorkeeper/application_mixin.rb +12 -0
- data/lib/sso/doorkeeper/authorizations_controller_mixin.rb +16 -4
- data/lib/sso/doorkeeper/tokens_controller_mixin.rb +15 -5
- data/lib/sso/engine.rb +27 -1
- data/lib/sso/engine.rb.orig +46 -0
- data/lib/sso/logging.rb +1 -1
- data/lib/sso/version.rb +1 -1
- data/lib/sso/warden/hooks/after_authentication.rb +17 -2
- data/lib/sso/warden/hooks/before_logout.rb +14 -5
- data/lib/sso/warden/hooks/session_check.rb +45 -0
- data/spec/api/schemas/session.json +35 -0
- data/spec/controllers/sso/sessions_controller_spec.rb +49 -9
- data/spec/fabricators/api_application_fabricator.rb +2 -2
- data/spec/fabricators/sso_client_fabricator.rb +5 -0
- data/spec/fabricators/sso_session_fabricator.rb +1 -2
- data/spec/fabricators/user_fabricator.rb +5 -3
- data/spec/lib/doorkeeper/access_grant_mixin_spec.rb +29 -0
- data/spec/lib/doorkeeper/access_token_mixin_spec.rb +29 -0
- data/spec/lib/doorkeeper/application_mixin_spec.rb +29 -0
- data/spec/lib/sso/warden/hooks/after_authentication_spec.rb +37 -0
- data/spec/lib/sso/warden/hooks/before_logout_spec.rb +30 -0
- data/spec/models/sso/client_spec.rb +15 -0
- data/spec/models/sso/session_spec.rb +108 -71
- data/spec/spec_helper.rb +1 -0
- data/spec/support/api_schema_matcher.rb +7 -0
- data/spec/test_app/Rakefile +5 -0
- data/spec/test_app/db/schema.rb +15 -1
- metadata +75 -18
@@ -1,7 +1,9 @@
|
|
1
1
|
Fabricator(:user) do
|
2
|
-
first_name
|
3
|
-
|
4
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "::update_master_with_access_token" do
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
data/spec/test_app/Rakefile
CHANGED
@@ -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
|