osso 0.0.5.pre.zeta → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +4 -2
  3. data/.rubocop.yml +4 -1
  4. data/Gemfile.lock +48 -32
  5. data/LICENSE +21 -23
  6. data/bin/annotate +3 -1
  7. data/db/schema.rb +41 -3
  8. data/lib/osso/db/migrate/20200929154117_add_users_count_to_identity_providers_and_enterprise_accounts.rb +6 -0
  9. data/lib/osso/db/migrate/20201023142158_add_rodauth_tables.rb +47 -0
  10. data/lib/osso/db/migrate/20201105122026_add_token_index_to_access_tokens.rb +5 -0
  11. data/lib/osso/db/migrate/20201106154936_add_requested_to_authorization_codes_and_access_tokens.rb +6 -0
  12. data/lib/osso/db/migrate/20201109160851_add_sso_issuer_to_identity_providers.rb +12 -0
  13. data/lib/osso/db/migrate/20201110190754_remove_oauth_client_id_from_enterprise_accounts.rb +9 -0
  14. data/lib/osso/db/migrate/20201112160120_add_ping_to_identity_provider_service_enum.rb +28 -0
  15. data/lib/osso/error/account_configuration_error.rb +1 -0
  16. data/lib/osso/error/oauth_error.rb +6 -3
  17. data/lib/osso/graphql/mutation.rb +2 -0
  18. data/lib/osso/graphql/mutations.rb +2 -0
  19. data/lib/osso/graphql/mutations/create_enterprise_account.rb +0 -7
  20. data/lib/osso/graphql/mutations/create_identity_provider.rb +7 -6
  21. data/lib/osso/graphql/mutations/delete_identity_provider.rb +24 -0
  22. data/lib/osso/graphql/mutations/invite_admin_user.rb +43 -0
  23. data/lib/osso/graphql/query.rb +8 -0
  24. data/lib/osso/graphql/resolvers/enterprise_accounts.rb +3 -3
  25. data/lib/osso/graphql/types.rb +2 -2
  26. data/lib/osso/graphql/types/admin_user.rb +9 -0
  27. data/lib/osso/graphql/types/base_object.rb +1 -1
  28. data/lib/osso/graphql/types/enterprise_account.rb +1 -0
  29. data/lib/osso/graphql/types/identity_provider.rb +3 -0
  30. data/lib/osso/graphql/types/identity_provider_service.rb +2 -1
  31. data/lib/osso/helpers/auth.rb +1 -1
  32. data/lib/osso/lib/route_map.rb +0 -15
  33. data/lib/osso/lib/saml_handler.rb +5 -0
  34. data/lib/osso/models/access_token.rb +4 -2
  35. data/lib/osso/models/account.rb +34 -0
  36. data/lib/osso/models/authorization_code.rb +2 -1
  37. data/lib/osso/models/enterprise_account.rb +3 -1
  38. data/lib/osso/models/identity_provider.rb +23 -5
  39. data/lib/osso/models/models.rb +1 -0
  40. data/lib/osso/models/oauth_client.rb +0 -1
  41. data/lib/osso/models/user.rb +2 -2
  42. data/lib/osso/routes/admin.rb +39 -33
  43. data/lib/osso/routes/auth.rb +9 -9
  44. data/lib/osso/routes/oauth.rb +35 -17
  45. data/lib/osso/version.rb +1 -1
  46. data/lib/osso/views/admin.erb +5 -0
  47. data/lib/osso/views/error.erb +1 -0
  48. data/lib/osso/views/layout.erb +0 -0
  49. data/lib/osso/views/multiple_providers.erb +1 -0
  50. data/lib/osso/views/welcome.erb +0 -0
  51. data/lib/tasks/bootstrap.rake +18 -4
  52. data/osso-rb.gemspec +5 -0
  53. data/spec/factories/account.rb +24 -0
  54. data/spec/factories/enterprise_account.rb +11 -3
  55. data/spec/factories/identity_providers.rb +10 -2
  56. data/spec/factories/user.rb +4 -0
  57. data/spec/graphql/mutations/configure_identity_provider_spec.rb +1 -1
  58. data/spec/graphql/mutations/create_enterprise_account_spec.rb +0 -14
  59. data/spec/graphql/mutations/create_identity_provider_spec.rb +59 -8
  60. data/spec/graphql/query/identity_provider_spec.rb +3 -2
  61. data/spec/models/enterprise_account_spec.rb +18 -0
  62. data/spec/models/identity_provider_spec.rb +35 -1
  63. data/spec/routes/admin_spec.rb +7 -41
  64. data/spec/routes/auth_spec.rb +17 -18
  65. data/spec/routes/oauth_spec.rb +88 -5
  66. data/spec/spec_helper.rb +3 -3
  67. data/spec/support/views/layout.erb +1 -0
  68. data/spec/support/views/multiple_providers.erb +1 -0
  69. metadata +92 -5
  70. data/spec/helpers/auth_spec.rb +0 -97
@@ -3,15 +3,16 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Osso::Oauth do
6
+ before do
7
+ described_class.set(:views, spec_views)
8
+ end
9
+
6
10
  let(:client) { create(:oauth_client) }
7
11
 
8
12
  describe 'get /oauth/authorize' do
9
13
  describe 'with a valid client ID and redirect URI' do
10
14
  describe 'for a domain that does not belong to an enterprise' do
11
- # TODO: better error handling and test
12
15
  it 'renders an error page' do
13
- described_class.set(:views, spec_views)
14
-
15
16
  create(:enterprise_with_okta, domain: 'foo.com')
16
17
 
17
18
  get(
@@ -48,7 +49,7 @@ describe Osso::Oauth do
48
49
 
49
50
  describe 'for an enterprise domain with multiple SAML providers' do
50
51
  it 'renders the multiple providers screen' do
51
- enterprise = create(:enterprise_with_multiple_providers)
52
+ enterprise = create(:enterprise_with_multiple_providers, oauth_client: client)
52
53
 
53
54
  get(
54
55
  '/oauth/authorize',
@@ -59,6 +60,64 @@ describe Osso::Oauth do
59
60
  )
60
61
 
61
62
  expect(last_response).to be_ok
63
+ expect(last_response.body).to eq('MULITPLE PROVIDERS')
64
+ end
65
+ end
66
+
67
+ describe "for an existing user's email address" do
68
+ it 'redirects to /auth/saml/:provider_id' do
69
+ enterprise = create(:enterprise_with_okta, oauth_client: client)
70
+ provider_id = enterprise.identity_providers.first.id
71
+ user = create(:user, email: "user@#{enterprise.domain}", identity_provider_id: provider_id)
72
+
73
+ get(
74
+ '/oauth/authorize',
75
+ email: user.email,
76
+ client_id: client.identifier,
77
+ response_type: 'code',
78
+ redirect_uri: client.redirect_uri_values.sample,
79
+ )
80
+
81
+ expect(last_response).to be_redirect
82
+ follow_redirect!
83
+ expect(last_request.url).to match("auth/saml/#{provider_id}")
84
+ end
85
+ end
86
+
87
+ describe "for a new user's email address belonging to an enterprise with one SAML provider" do
88
+ it 'redirects to /auth/saml/:provider_id' do
89
+ enterprise = create(:enterprise_with_okta, oauth_client: client)
90
+
91
+ get(
92
+ '/oauth/authorize',
93
+ email: "user@#{enterprise.domain}",
94
+ client_id: client.identifier,
95
+ response_type: 'code',
96
+ redirect_uri: client.redirect_uri_values.sample,
97
+ )
98
+
99
+ provider_id = enterprise.identity_providers.first.id
100
+
101
+ expect(last_response).to be_redirect
102
+ follow_redirect!
103
+ expect(last_request.url).to match("auth/saml/#{provider_id}")
104
+ end
105
+ end
106
+
107
+ describe "for a new user's email address belonging to an enterprise with multiple SAML providers" do
108
+ it 'renders the multiple providers screen' do
109
+ enterprise = create(:enterprise_with_multiple_providers, oauth_client: client)
110
+
111
+ get(
112
+ '/oauth/authorize',
113
+ email: "user@#{enterprise.domain}",
114
+ client_id: client.identifier,
115
+ response_type: 'code',
116
+ redirect_uri: client.redirect_uri_values.sample,
117
+ )
118
+
119
+ expect(last_response).to be_ok
120
+ expect(last_response.body).to eq('MULITPLE PROVIDERS')
62
121
  end
63
122
  end
64
123
  end
@@ -90,7 +149,7 @@ describe Osso::Oauth do
90
149
  end
91
150
 
92
151
  describe 'get /oauth/me' do
93
- describe 'with a valid unexpired access token' do
152
+ describe 'with a valid unexpired access token in params' do
94
153
  it 'returns the user' do
95
154
  user = create(:user)
96
155
  code = user.authorization_codes.valid.first
@@ -105,6 +164,30 @@ describe Osso::Oauth do
105
164
  email: user.email,
106
165
  id: user.id,
107
166
  idp: 'Okta',
167
+ requested: code.requested.symbolize_keys,
168
+ )
169
+ end
170
+ end
171
+
172
+ describe 'with a valid unexpired access token in headers' do
173
+ it 'returns the user' do
174
+ user = create(:user)
175
+ code = user.authorization_codes.valid.first
176
+
177
+ get(
178
+ '/oauth/me',
179
+ nil,
180
+ {
181
+ 'HTTP_AUTHORIZATION' => "Bearer: #{code.access_token.to_bearer_token}",
182
+ },
183
+ )
184
+
185
+ expect(last_response.status).to eq(200)
186
+ expect(last_json_response).to eq(
187
+ email: user.email,
188
+ id: user.id,
189
+ idp: 'Okta',
190
+ requested: code.requested.symbolize_keys,
108
191
  )
109
192
  end
110
193
  end
@@ -15,9 +15,9 @@ require 'webmock/rspec'
15
15
  ENV['RACK_ENV'] = 'test'
16
16
  ENV['SESSION_SECRET'] = 'supersecret'
17
17
  ENV['BASE_URL'] = 'https://example.com'
18
+ ENV['RODAUTH_VIEWS'] = "#{File.dirname(__FILE__)}/support/views"
18
19
 
19
20
  require File.expand_path '../lib/osso.rb', __dir__
20
-
21
21
  require File.expand_path 'support/spec_app', __dir__
22
22
 
23
23
  module RSpecMixin
@@ -47,11 +47,11 @@ module RSpecMixin
47
47
  end
48
48
 
49
49
  def spec_views
50
- File.dirname(__FILE__) + '/support/views'
50
+ "#{File.dirname(__FILE__)}/support/views"
51
51
  end
52
52
 
53
53
  def valid_x509_pem
54
- raw = File.read(File.dirname(__FILE__) + '/support/fixtures/test.pem')
54
+ raw = File.read("#{File.dirname(__FILE__)}/support/fixtures/test.pem")
55
55
  OpenSSL::X509::Certificate.new(raw).to_pem
56
56
  end
57
57
 
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1 @@
1
+ MULITPLE PROVIDERS
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5.pre.zeta
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Bauch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-21 00:00:00.000000000 Z
11
+ date: 2020-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.3.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bcrypt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.13
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.1.13
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: graphql
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mail
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.7.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.7.1
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: omniauth-multi-provider
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +164,48 @@ dependencies:
136
164
  - - ">="
137
165
  - !ruby/object:Gem::Version
138
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rodauth
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 2.5.0
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 2.5.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: sequel
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 5.37.0
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 5.37.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: sequel-activerecord_connection
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '0.3'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '0.3'
139
209
  - !ruby/object:Gem::Dependency
140
210
  name: sinatra
141
211
  requirement: !ruby/object:Gem::Requirement
@@ -273,6 +343,13 @@ files:
273
343
  - lib/osso/db/migrate/20200826201852_create_app_config.rb
274
344
  - lib/osso/db/migrate/20200913154919_add_one_login_to_identity_provider_service_enum.rb
275
345
  - lib/osso/db/migrate/20200916125543_add_google_to_identity_provider_service_enum.rb
346
+ - lib/osso/db/migrate/20200929154117_add_users_count_to_identity_providers_and_enterprise_accounts.rb
347
+ - lib/osso/db/migrate/20201023142158_add_rodauth_tables.rb
348
+ - lib/osso/db/migrate/20201105122026_add_token_index_to_access_tokens.rb
349
+ - lib/osso/db/migrate/20201106154936_add_requested_to_authorization_codes_and_access_tokens.rb
350
+ - lib/osso/db/migrate/20201109160851_add_sso_issuer_to_identity_providers.rb
351
+ - lib/osso/db/migrate/20201110190754_remove_oauth_client_id_from_enterprise_accounts.rb
352
+ - lib/osso/db/migrate/20201112160120_add_ping_to_identity_provider_service_enum.rb
276
353
  - lib/osso/error/account_configuration_error.rb
277
354
  - lib/osso/error/error.rb
278
355
  - lib/osso/error/missing_saml_attribute_error.rb
@@ -287,7 +364,9 @@ files:
287
364
  - lib/osso/graphql/mutations/create_identity_provider.rb
288
365
  - lib/osso/graphql/mutations/create_oauth_client.rb
289
366
  - lib/osso/graphql/mutations/delete_enterprise_account.rb
367
+ - lib/osso/graphql/mutations/delete_identity_provider.rb
290
368
  - lib/osso/graphql/mutations/delete_oauth_client.rb
369
+ - lib/osso/graphql/mutations/invite_admin_user.rb
291
370
  - lib/osso/graphql/mutations/regenerate_oauth_credentials.rb
292
371
  - lib/osso/graphql/mutations/set_redirect_uris.rb
293
372
  - lib/osso/graphql/mutations/update_app_config.rb
@@ -320,6 +399,7 @@ files:
320
399
  - lib/osso/lib/route_map.rb
321
400
  - lib/osso/lib/saml_handler.rb
322
401
  - lib/osso/models/access_token.rb
402
+ - lib/osso/models/account.rb
323
403
  - lib/osso/models/app_config.rb
324
404
  - lib/osso/models/authorization_code.rb
325
405
  - lib/osso/models/enterprise_account.rb
@@ -334,8 +414,14 @@ files:
334
414
  - lib/osso/routes/oauth.rb
335
415
  - lib/osso/routes/routes.rb
336
416
  - lib/osso/version.rb
417
+ - lib/osso/views/admin.erb
418
+ - lib/osso/views/error.erb
419
+ - lib/osso/views/layout.erb
420
+ - lib/osso/views/multiple_providers.erb
421
+ - lib/osso/views/welcome.erb
337
422
  - lib/tasks/bootstrap.rake
338
423
  - osso-rb.gemspec
424
+ - spec/factories/account.rb
339
425
  - spec/factories/authorization_code.rb
340
426
  - spec/factories/enterprise_account.rb
341
427
  - spec/factories/identity_providers.rb
@@ -352,8 +438,8 @@ files:
352
438
  - spec/graphql/query/enterprise_accounts_spec.rb
353
439
  - spec/graphql/query/identity_provider_spec.rb
354
440
  - spec/graphql/query/oauth_clients_spec.rb
355
- - spec/helpers/auth_spec.rb
356
441
  - spec/lib/saml_handler_spec.rb
442
+ - spec/models/enterprise_account_spec.rb
357
443
  - spec/models/identity_provider_spec.rb
358
444
  - spec/routes/admin_spec.rb
359
445
  - spec/routes/app_spec.rb
@@ -364,6 +450,7 @@ files:
364
450
  - spec/support/spec_app.rb
365
451
  - spec/support/views/admin.erb
366
452
  - spec/support/views/error.erb
453
+ - spec/support/views/layout.erb
367
454
  - spec/support/views/multiple_providers.erb
368
455
  homepage: https://github.com/enterprise-oss/osso-rb
369
456
  licenses:
@@ -380,9 +467,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
380
467
  version: 2.3.0
381
468
  required_rubygems_version: !ruby/object:Gem::Requirement
382
469
  requirements:
383
- - - ">"
470
+ - - ">="
384
471
  - !ruby/object:Gem::Version
385
- version: 1.3.1
472
+ version: '0'
386
473
  requirements: []
387
474
  rubygems_version: 3.0.3
388
475
  signing_key:
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Osso::Helpers::Auth do
6
- before do
7
- ENV['JWT_HMAC_SECRET'] = 'super-secret'
8
- end
9
-
10
- subject(:app) do
11
- Class.new { include Osso::Helpers::Auth }
12
- end
13
-
14
- describe 'with the token as a header' do
15
- before do
16
- allow_any_instance_of(subject).to receive(:request) do
17
- double('Request', env: { 'admin_token' => token }, post?: false)
18
- end
19
-
20
- allow_any_instance_of(subject).to receive(:redirect) do
21
- false
22
- end
23
- end
24
-
25
- describe 'with an admin token' do
26
- let(:token) { encode({ scope: 'admin' }) }
27
-
28
- it 'allows #token_protected! methods' do
29
- expect(subject.new.token_protected!).to_not be(false)
30
- end
31
-
32
- it 'allows #enterprise_protected! methods' do
33
- expect(subject.new.enterprise_protected!).to_not be(false)
34
- end
35
-
36
- it 'allows #internal_protected! methods' do
37
- expect(subject.new.internal_protected!).to_not be(false)
38
- end
39
-
40
- it 'allows #admin_protected! methods' do
41
- expect(subject.new.admin_protected!).to_not be(false)
42
- end
43
- end
44
-
45
- describe 'with an internal token' do
46
- let(:token) { encode({ scope: 'internal' }) }
47
-
48
- it 'allows #token_protected! methods' do
49
- expect(subject.new.token_protected!).to_not be(false)
50
- end
51
-
52
- it 'allows #enterprise_protected! methods' do
53
- expect(subject.new.enterprise_protected!).to_not be(false)
54
- end
55
-
56
- it 'allows #internal_protected! methods' do
57
- expect(subject.new.internal_protected!).to_not be(false)
58
- end
59
-
60
- it 'allows #admin_protected! methods' do
61
- expect(subject.new.admin_protected!).to be(false)
62
- end
63
- end
64
-
65
- describe 'with an end-user token' do
66
- let(:token) { encode({ scope: 'end-user', email: 'user@example.com' }) }
67
-
68
- it 'allows #token_protected! methods' do
69
- expect(subject.new.token_protected!).to_not be(false)
70
- end
71
-
72
- it 'allows #enterprise_protected! methods for the scoped domain' do
73
- expect(subject.new.enterprise_protected!('example.com')).to_not be(false)
74
- end
75
-
76
- it 'halts #enterprise_protected! methods for the wrong scoped domain' do
77
- expect(subject.new.enterprise_protected!('foo.com')).to be(false)
78
- end
79
-
80
- it 'halts #internal_protected! methods' do
81
- expect(subject.new.internal_protected!).to be(false)
82
- end
83
-
84
- it 'halts #admin_protected! methods' do
85
- expect(subject.new.admin_protected!).to be(false)
86
- end
87
- end
88
- end
89
-
90
- def encode(payload)
91
- JWT.encode(
92
- payload,
93
- ENV['JWT_HMAC_SECRET'],
94
- 'HS256',
95
- )
96
- end
97
- end