osso 0.0.5.pre.zeta → 0.0.5

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 (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