osso 0.0.3.5 → 0.0.3.6

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +4 -1
  3. data/Gemfile.lock +1 -1
  4. data/config/database.yml +2 -2
  5. data/db/schema.rb +133 -1
  6. data/lib/osso/db/migrate/20200328143305_create_identity_providers.rb +12 -0
  7. data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +2 -2
  8. data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +1 -1
  9. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_accounts_and_identity_providers.rb +6 -0
  10. data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +17 -0
  11. data/lib/osso/db/migrate/20200715154211_rename_idp_fields_on_identity_provider_to_sso.rb +6 -0
  12. data/lib/osso/db/migrate/20200715205801_add_name_to_enterprise_account.rb +5 -0
  13. data/lib/osso/graphql/mutation.rb +2 -1
  14. data/lib/osso/graphql/mutations.rb +2 -1
  15. data/lib/osso/graphql/mutations/base_mutation.rb +18 -7
  16. data/lib/osso/graphql/mutations/configure_identity_provider.rb +10 -13
  17. data/lib/osso/graphql/mutations/create_enterprise_account.rb +25 -0
  18. data/lib/osso/graphql/mutations/create_identity_provider.rb +9 -7
  19. data/lib/osso/graphql/mutations/{set_saml_provider.rb → set_identity_provider.rb} +4 -4
  20. data/lib/osso/graphql/query.rb +2 -2
  21. data/lib/osso/graphql/resolvers/oauth_clients.rb +1 -1
  22. data/lib/osso/graphql/schema.rb +1 -1
  23. data/lib/osso/graphql/types.rb +1 -0
  24. data/lib/osso/graphql/types/base_input_object.rb +10 -0
  25. data/lib/osso/graphql/types/enterprise_account.rb +1 -5
  26. data/lib/osso/graphql/types/identity_provider.rb +1 -13
  27. data/lib/osso/lib/app_config.rb +1 -1
  28. data/lib/osso/models/enterprise_account.rb +4 -4
  29. data/lib/osso/models/identity_provider.rb +48 -0
  30. data/lib/osso/models/models.rb +1 -1
  31. data/lib/osso/models/oauth_client.rb +1 -1
  32. data/lib/osso/models/saml_provider.rb +13 -16
  33. data/lib/osso/models/saml_providers/azure_saml_provider.rb +1 -1
  34. data/lib/osso/models/saml_providers/okta_saml_provider.rb +1 -1
  35. data/lib/osso/models/user.rb +3 -3
  36. data/lib/osso/routes/auth.rb +4 -4
  37. data/lib/osso/routes/oauth.rb +1 -1
  38. data/lib/osso/version.rb +1 -1
  39. data/spec/factories/enterprise_account.rb +5 -4
  40. data/spec/factories/identity_providers.rb +49 -0
  41. data/spec/factories/user.rb +1 -1
  42. data/spec/graphql/mutations/configure_identity_provider_spec.rb +65 -0
  43. data/spec/graphql/mutations/create_enterprise_account_spec.rb +68 -0
  44. data/spec/graphql/mutations/create_identity_provider_spec.rb +104 -0
  45. data/spec/graphql/query/enterprise_account_spec.rb +68 -0
  46. data/spec/graphql/query/enterprise_accounts_spec.rb +44 -0
  47. data/spec/graphql/query/identity_provider_spec.rb +62 -0
  48. data/spec/graphql/query/oauth_clients_account_spec.rb +48 -0
  49. data/spec/models/azure_saml_provider_spec.rb +14 -14
  50. data/spec/models/identity_provider_spec.rb +17 -0
  51. data/spec/models/okta_saml_provider_spec.rb +15 -15
  52. data/spec/routes/auth_spec.rb +9 -9
  53. data/spec/routes/oauth_spec.rb +1 -1
  54. data/spec/spec_helper.rb +1 -0
  55. metadata +20 -12
  56. data/lib/osso/db/migrate/20200411144528_create_saml_providers.rb +0 -13
  57. data/lib/osso/db/migrate/20200413153029_add_oauth_client_reference_to_saml_providers.rb +0 -5
  58. data/lib/osso/db/migrate/20200501203026_drop_null_constraints_from_saml_provider.rb +0 -7
  59. data/lib/osso/db/migrate/20200501204047_drop_acs_url.rb +0 -5
  60. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_account.rb +0 -5
  61. data/lib/osso/db/migrate/20200601131227_drop_null_constraint_from_saml_providers_provider.rb +0 -7
  62. data/lib/osso/db/schema.rb +0 -132
  63. data/spec/factories/saml_providers.rb +0 -46
  64. data/spec/models/saml_provider_spec.rb +0 -31
@@ -31,7 +31,7 @@ module Osso
31
31
  case obj
32
32
  when Osso::Models::EnterpriseAccount
33
33
  Types::EnterpriseAccount
34
- when Osso::Models::SamlProvider
34
+ when Osso::Models::IdentityProvider
35
35
  Types::IdentityProvider
36
36
  else
37
37
  raise("Unexpected object: #{obj}")
@@ -7,6 +7,7 @@ end
7
7
 
8
8
  require_relative 'types/base_object'
9
9
  require_relative 'types/base_enum'
10
+ require_relative 'types/base_input_object'
10
11
  require_relative 'types/identity_provider_service'
11
12
  require_relative 'types/identity_provider'
12
13
  require_relative 'types/enterprise_account'
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Types
6
+ class BaseInputObject < ::GraphQL::Schema::InputObject
7
+ end
8
+ end
9
+ end
10
+ end
@@ -16,16 +16,12 @@ module Osso
16
16
  field :identity_providers, [Types::IdentityProvider], null: true
17
17
  field :status, String, null: false
18
18
 
19
- def name
20
- object.domain.gsub('.com', '')
21
- end
22
-
23
19
  def status
24
20
  'active'
25
21
  end
26
22
 
27
23
  def identity_providers
28
- object.saml_providers
24
+ object.identity_providers
29
25
  end
30
26
  end
31
27
  end
@@ -19,20 +19,8 @@ module Osso
19
19
  field :sso_cert, String, null: true
20
20
  field :configured, Boolean, null: false
21
21
 
22
- def service
23
- @object.provider
24
- end
25
-
26
22
  def configured
27
- @object.idp_sso_target_url && @object.idp_cert
28
- end
29
-
30
- def sso_cert
31
- @object.idp_cert
32
- end
33
-
34
- def sso_url
35
- @object.idp_sso_target_url
23
+ !!(@object.sso_url && @object.sso_cert)
36
24
  end
37
25
  end
38
26
  end
@@ -7,7 +7,7 @@ module Osso
7
7
  def self.included(klass)
8
8
  klass.class_eval do
9
9
  use Rack::JSONBodyParser
10
- use Rack::Session::Cookie, secret: ENV.fetch('SESSION_SECRET')
10
+ use Rack::Session::Cookie, secret: ENV['SESSION_SECRET']
11
11
 
12
12
  error ActiveRecord::RecordNotFound do
13
13
  status 404
@@ -10,19 +10,19 @@ module Osso
10
10
  class EnterpriseAccount < ActiveRecord::Base
11
11
  belongs_to :oauth_client
12
12
  has_many :users
13
- has_many :saml_providers
13
+ has_many :identity_providers
14
14
 
15
15
  def single_provider?
16
- saml_providers.one?
16
+ identity_providers.one?
17
17
  end
18
18
 
19
19
  def provider
20
20
  return nil unless single_provider?
21
21
 
22
- saml_providers.first
22
+ identity_providers.first
23
23
  end
24
24
 
25
- alias saml_provider provider
25
+ alias identity_provider provider
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ # Base class for SAML Providers
6
+ class IdentityProvider < ActiveRecord::Base
7
+ NAME_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
8
+ belongs_to :enterprise_account
9
+ belongs_to :oauth_client
10
+ has_many :users
11
+
12
+ def name
13
+ service.titlecase
14
+ # raise(
15
+ # NoMethodError,
16
+ # '#name must be defined on each provider specific subclass',
17
+ # )
18
+ end
19
+
20
+ def saml_options
21
+ attributes.slice(
22
+ 'domain',
23
+ 'idp_cert',
24
+ 'idp_sso_target_url',
25
+ ).symbolize_keys
26
+ end
27
+
28
+ # def saml_options
29
+ # raise(
30
+ # NoMethodError,
31
+ # '#saml_options must be defined on each provider specific subclass',
32
+ # )
33
+ # end
34
+
35
+ def assertion_consumer_service_url
36
+ [
37
+ ENV.fetch('BASE_URL'),
38
+ 'auth',
39
+ 'saml',
40
+ id,
41
+ 'callback',
42
+ ].join('/')
43
+ end
44
+
45
+ alias acs_url assertion_consumer_service_url
46
+ end
47
+ end
48
+ end
@@ -12,5 +12,5 @@ require_relative 'authorization_code'
12
12
  require_relative 'enterprise_account'
13
13
  require_relative 'oauth_client'
14
14
  require_relative 'redirect_uri'
15
- require_relative 'saml_provider'
15
+ require_relative 'identity_provider'
16
16
  require_relative 'user'
@@ -6,7 +6,7 @@ module Osso
6
6
  class OauthClient < ActiveRecord::Base
7
7
  has_many :access_tokens
8
8
  has_many :refresh_tokens
9
- has_many :saml_providers
9
+ has_many :identity_providers
10
10
  has_many :redirect_uris
11
11
 
12
12
  before_validation :setup, on: :create
@@ -3,28 +3,27 @@
3
3
  module Osso
4
4
  module Models
5
5
  # Base class for SAML Providers
6
- class SamlProvider < ActiveRecord::Base
6
+ class IdentityProvider < ActiveRecord::Base
7
7
  NAME_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
8
- self.inheritance_column = :provider
9
8
  belongs_to :enterprise_account
10
9
  belongs_to :oauth_client
11
10
  has_many :users
12
11
 
13
12
  before_create :create_enterprise_account
14
13
 
15
- def name
16
- raise(
17
- NoMethodError,
18
- '#name must be defined on each provider specific subclass',
19
- )
20
- end
14
+ # def name
15
+ # raise(
16
+ # NoMethodError,
17
+ # '#name must be defined on each provider specific subclass',
18
+ # )
19
+ # end
21
20
 
22
- def saml_options
23
- raise(
24
- NoMethodError,
25
- '#saml_options must be defined on each provider specific subclass',
26
- )
27
- end
21
+ # def saml_options
22
+ # raise(
23
+ # NoMethodError,
24
+ # '#saml_options must be defined on each provider specific subclass',
25
+ # )
26
+ # end
28
27
 
29
28
  def assertion_consumer_service_url
30
29
  [
@@ -48,5 +47,3 @@ module Osso
48
47
  end
49
48
  end
50
49
  end
51
- require_relative 'saml_providers/azure_saml_provider'
52
- require_relative 'saml_providers/okta_saml_provider'
@@ -3,7 +3,7 @@
3
3
  module Osso
4
4
  module Models
5
5
  # Subclass for Azure / ADFS IDP instances
6
- class AzureSamlProvider < Models::SamlProvider
6
+ class AzureSamlProvider < Models::IdentityProvider
7
7
  def name
8
8
  'Azure'
9
9
  end
@@ -3,7 +3,7 @@
3
3
  module Osso
4
4
  module Models
5
5
  # Subclass for Okta IDP instances
6
- class OktaSamlProvider < Models::SamlProvider
6
+ class OktaSamlProvider < Models::IdentityProvider
7
7
  def name
8
8
  'Okta'
9
9
  end
@@ -4,19 +4,19 @@ module Osso
4
4
  module Models
5
5
  class User < ActiveRecord::Base
6
6
  belongs_to :enterprise_account
7
- belongs_to :saml_provider
7
+ belongs_to :identity_provider
8
8
  has_many :authorization_codes, dependent: :delete_all
9
9
  has_many :access_tokens, dependent: :delete_all
10
10
 
11
11
  def oauth_client
12
- saml_provider.oauth_client
12
+ identity_provider.oauth_client
13
13
  end
14
14
 
15
15
  def as_json(*)
16
16
  {
17
17
  email: email,
18
18
  id: id,
19
- idp: saml_provider.name,
19
+ idp: identity_provider.name,
20
20
  }
21
21
  end
22
22
  end
@@ -25,8 +25,8 @@ module Osso
25
25
  identity_provider_id_regex: UUID_REGEXP,
26
26
  path_prefix: '/saml',
27
27
  callback_suffix: 'callback',
28
- ) do |saml_provider_id, _env|
29
- provider = Models::SamlProvider.find(saml_provider_id)
28
+ ) do |identity_provider_id, _env|
29
+ provider = Models::IdentityProvider.find(identity_provider_id)
30
30
  provider.saml_options
31
31
  end
32
32
  end
@@ -38,7 +38,7 @@ module Osso
38
38
  # is redirected back to your application with this code
39
39
  # as a URL query param, which you then exhange for an access token
40
40
  post '/saml/:id/callback' do
41
- provider = Models::SamlProvider.find(params[:id])
41
+ provider = Models::IdentityProvider.find(params[:id])
42
42
  oauth_client = provider.oauth_client
43
43
  redirect_uri = env['redirect_uri'] || oauth_client.default_redirect_uri.uri
44
44
 
@@ -52,7 +52,7 @@ module Osso
52
52
  idp_id: attributes[:id],
53
53
  ).first_or_create! do |new_user|
54
54
  new_user.enterprise_account_id = provider.enterprise_account_id
55
- new_user.saml_provider_id = provider.id
55
+ new_user.identity_provider_id = provider.id
56
56
  end
57
57
 
58
58
  authorization_code = user.authorization_codes.create!(
@@ -14,7 +14,7 @@ module Osso
14
14
  # of the user who wants to sign in.
15
15
  get '/authorize' do
16
16
  @enterprise = Models::EnterpriseAccount.
17
- includes(:saml_providers).
17
+ includes(:identity_providers).
18
18
  find_by!(domain: params[:domain])
19
19
 
20
20
  Rack::OAuth2::Server::Authorize.new do |req, _res|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Osso
4
- VERSION = '0.0.3.5'
4
+ VERSION = '0.0.3.6'
5
5
  end
@@ -3,6 +3,7 @@
3
3
  FactoryBot.define do
4
4
  factory :enterprise_account, class: Osso::Models::EnterpriseAccount do
5
5
  id { SecureRandom.uuid }
6
+ name { Faker::Company.name }
6
7
  domain { Faker::Internet.domain_name }
7
8
  oauth_client
8
9
  end
@@ -10,7 +11,7 @@ FactoryBot.define do
10
11
  factory :enterprise_with_okta, parent: :enterprise_account do
11
12
  after :create do |enterprise|
12
13
  create(
13
- :okta_saml_provider,
14
+ :okta_identity_provider,
14
15
  domain: enterprise.domain,
15
16
  enterprise_account_id: enterprise.id,
16
17
  )
@@ -20,7 +21,7 @@ FactoryBot.define do
20
21
  factory :enterprise_with_azure, parent: :enterprise_account do
21
22
  after :create do |enterprise|
22
23
  create(
23
- :azure_saml_provider,
24
+ :azure_identity_provider,
24
25
  domain: enterprise.domain,
25
26
  enterprise_account_id: enterprise.id,
26
27
  )
@@ -30,13 +31,13 @@ FactoryBot.define do
30
31
  factory :enterprise_with_multiple_providers, parent: :enterprise_account do
31
32
  after :create do |enterprise|
32
33
  create(
33
- :okta_saml_provider,
34
+ :okta_identity_provider,
34
35
  domain: enterprise.domain,
35
36
  enterprise_account_id: enterprise.id,
36
37
  )
37
38
 
38
39
  create(
39
- :azure_saml_provider,
40
+ :azure_identity_provider,
40
41
  domain: enterprise.domain,
41
42
  enterprise_account_id: enterprise.id,
42
43
  )
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :identity_provider, class: Osso::Models::IdentityProvider do
5
+ id { SecureRandom.uuid }
6
+ domain { Faker::Internet.domain_name }
7
+ oauth_client
8
+
9
+ factory :okta_identity_provider, parent: :identity_provider do
10
+ service { 'OKTA' }
11
+ sso_url do
12
+ 'https://dev-162024.okta.com/app/vcardmedev162024_rubydemo2_1/exk51326b3U1941Hf4x6/sso/saml'
13
+ end
14
+ end
15
+
16
+ factory :azure_identity_provider, parent: :identity_provider do
17
+ service { 'AZURE' }
18
+ sso_url do
19
+ 'https://login.microsoftonline.com/0af6c610-c40c-4683-9ea4-f25e509b8172/saml2'
20
+ end
21
+ end
22
+
23
+ factory :configured_identity_provider, parent: :identity_provider do
24
+ sso_cert do
25
+ <<~CERT
26
+ -----BEGIN CERTIFICATE-----
27
+ MIIDpDCCAoygAwIBAgIGAXEiD4LlMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
28
+ A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
29
+ MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi0xNjIwMjQxHDAaBgkqhkiG9w0BCQEW
30
+ DWluZm9Ab2t0YS5jb20wHhcNMjAwMzI4MTY1MTU0WhcNMzAwMzI4MTY1MjU0WjCBkjELMAkGA1UE
31
+ BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
32
+ BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtMTYyMDI0MRwwGgYJ
33
+ KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
34
+ wsnP4UTfv3bxR5Jh0at51Dqjj+fKxFznzFW3XA5NbF2SlRLjeYcvj3+47TC0eP6xOsLWfnvdnx4v
35
+ dd9Ufn7jDCo5pL3JykMVEh2I0szF3RLC+a532ArcwgU9Px48+rWVwPkASS7l4NHAM4+gOBHJMQt2
36
+ AMohPT0kU41P8BEPzfwhNyiEXR66JNZIJUE8fM3Vpgnxm/VSwYzJf0NfOyfxv8JczF0zkDbpE7Tk
37
+ 3Ww/PFFLoMxWzanWGJQ+blnhv6UV6H4fcfAbcwAplOdIVHjS2ghYBvYNGahuFxjia0+6csyZGrt8
38
+ H4XmR5Dr+jXY5K1b1VOA0k19/FCnHHN/smn25wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBgD9NE
39
+ 4OCuR1+vucV8S1T6XXIL2hB7bXBAZEVHZ1aErRzktgXAMgVwG267vIkD5VOXBiTy9yNU5LK6G3k2
40
+ zewU190sL1dMfyPnoVZyn94nvwe9A+on0tmZdmk00xirKk3FJdacnZNE9Dl/afIrcNf6xAm0WsU9
41
+ kbMiRwwvjO4TAiygDQzbrRC8ZfmT3hpBa3aTUzAccrvEQcgarLk4r7UjXP7a2mCN3UIIh+snN2Ms
42
+ vXHL0r6fM3xbniz+5lleWtPFw73yySBc8znkWZ4Tn8Lh0r6o5nCRYbr2REUB7ZIfiIyBbZxIp4kv
43
+ a+habbnQDFiNVzEd8OPXHh4EqLxOPDRW
44
+ -----END CERTIFICATE-----
45
+ CERT
46
+ end
47
+ end
48
+ end
49
+ end
@@ -5,7 +5,7 @@ FactoryBot.define do
5
5
  id { SecureRandom.uuid }
6
6
  email { Faker::Internet.email }
7
7
  idp_id { SecureRandom.hex(32) }
8
- saml_provider { create(:okta_saml_provider) }
8
+ identity_provider { create(:okta_identity_provider) }
9
9
  enterprise_account
10
10
  after(:create) do |user|
11
11
  create(
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Osso::GraphQL::Schema do
6
+ describe 'ConfigureIdentityProvider' do
7
+ let(:enterprise_account) { create(:enterprise_account) }
8
+ let(:identity_provider) { create(:identity_provider, enterprise_account: enterprise_account) }
9
+ let(:variables) do
10
+ {
11
+ input: {
12
+ id: identity_provider.id,
13
+ service: 'OKTA',
14
+ ssoUrl: 'https://example.com',
15
+ ssoCert: 'BEGIN_CERTIFICATE',
16
+ },
17
+ }
18
+ end
19
+ let(:mutation) do
20
+ <<~GRAPHQL
21
+ mutation ConfigureIdentityProvider($input: ConfigureIdentityProviderInput!) {
22
+ configureIdentityProvider(input: $input) {
23
+ identityProvider {
24
+ id
25
+ domain
26
+ configured
27
+ enterpriseAccountId
28
+ service
29
+ acsUrl
30
+ ssoCert
31
+ ssoUrl
32
+ }
33
+ }
34
+ }
35
+ GRAPHQL
36
+ end
37
+
38
+ subject do
39
+ described_class.execute(
40
+ mutation,
41
+ variables: variables,
42
+ context: { scope: current_scope },
43
+ )
44
+ end
45
+
46
+ describe 'for an admin user' do
47
+ let(:current_scope) { :admin }
48
+ it 'configures an identity provider' do
49
+ expect(subject.dig('data', 'configureIdentityProvider', 'identityProvider', 'configured')).
50
+ to be true
51
+ end
52
+ end
53
+
54
+ describe 'for an email scoped user' do
55
+ let(:domain) { Faker::Internet.domain_name }
56
+ let(:current_scope) { domain }
57
+ let(:enterprise_account) { create(:enterprise_account, domain: domain) }
58
+
59
+ it 'creates an identity provider' do
60
+ expect(subject.dig('data', 'configureIdentityProvider', 'identityProvider', 'domain')).
61
+ to eq(domain)
62
+ end
63
+ end
64
+ end
65
+ end