osso 0.0.3.6 → 0.0.3.11

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +5 -3
  3. data/Gemfile.lock +5 -1
  4. data/bin/annotate +1 -0
  5. data/db/schema.rb +11 -54
  6. data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +1 -1
  7. data/lib/osso/db/migrate/20200722230116_add_identity_provider_status_enum_and_use_on_identity_providers.rb +15 -0
  8. data/lib/osso/db/migrate/20200723153750_add_missing_timestamps.rb +35 -0
  9. data/lib/osso/db/migrate/20200723162228_drop_unneeded_tables.rb +9 -0
  10. data/lib/osso/graphql/mutation.rb +4 -2
  11. data/lib/osso/graphql/mutations.rb +3 -1
  12. data/lib/osso/graphql/mutations/base_mutation.rb +8 -2
  13. data/lib/osso/graphql/mutations/configure_identity_provider.rb +10 -1
  14. data/lib/osso/graphql/mutations/create_oauth_client.rb +30 -0
  15. data/lib/osso/graphql/mutations/delete_enterprise_account.rb +34 -0
  16. data/lib/osso/graphql/mutations/delete_oauth_client.rb +30 -0
  17. data/lib/osso/graphql/query.rb +4 -1
  18. data/lib/osso/graphql/resolvers/enterprise_accounts.rb +12 -4
  19. data/lib/osso/graphql/resolvers/oauth_clients.rb +1 -1
  20. data/lib/osso/graphql/schema.rb +4 -0
  21. data/lib/osso/graphql/types.rb +2 -0
  22. data/lib/osso/graphql/types/base_connection.rb +15 -0
  23. data/lib/osso/graphql/types/base_object.rb +4 -0
  24. data/lib/osso/graphql/types/enterprise_account.rb +4 -0
  25. data/lib/osso/graphql/types/identity_provider.rb +8 -3
  26. data/lib/osso/graphql/types/identity_provider_status.rb +14 -0
  27. data/lib/osso/graphql/types/oauth_client.rb +13 -1
  28. data/lib/osso/helpers/auth.rb +11 -12
  29. data/lib/osso/models/access_token.rb +18 -0
  30. data/lib/osso/models/authorization_code.rb +20 -0
  31. data/lib/osso/models/enterprise_account.rb +20 -0
  32. data/lib/osso/models/identity_provider.rb +29 -0
  33. data/lib/osso/models/models.rb +2 -0
  34. data/lib/osso/models/oauth_client.rb +17 -1
  35. data/lib/osso/models/redirect_uri.rb +17 -0
  36. data/lib/osso/models/user.rb +22 -0
  37. data/lib/osso/version.rb +1 -1
  38. data/osso-rb.gemspec +1 -0
  39. data/spec/factories/identity_providers.rb +22 -0
  40. data/spec/graphql/mutations/configure_identity_provider_spec.rb +14 -4
  41. data/spec/graphql/mutations/create_oauth_client_spec.rb +55 -0
  42. data/spec/graphql/mutations/delete_enterprise_account_spec.rb +63 -0
  43. data/spec/graphql/mutations/delete_oauth_client_spec.rb +51 -0
  44. data/spec/graphql/query/enterprise_account_spec.rb +1 -1
  45. data/spec/graphql/query/enterprise_accounts_spec.rb +32 -18
  46. data/spec/graphql/query/identity_provider_spec.rb +9 -6
  47. data/spec/graphql/query/{oauth_clients_account_spec.rb → oauth_clients_spec.rb} +2 -0
  48. metadata +30 -8
  49. data/lib/osso/db/migrate/20200328143303_create_oauth_tables.rb +0 -57
  50. data/lib/osso/graphql/mutations/set_identity_provider.rb +0 -27
  51. data/lib/osso/models/saml_provider.rb +0 -49
  52. data/lib/osso/models/saml_providers/azure_saml_provider.rb +0 -22
  53. data/lib/osso/models/saml_providers/okta_saml_provider.rb +0 -23
@@ -37,6 +37,10 @@ module Osso
37
37
  raise("Unexpected object: #{obj}")
38
38
  end
39
39
  end
40
+
41
+ def self.unauthorized_object(error)
42
+ raise ::GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions"
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -5,10 +5,12 @@ module Osso
5
5
  end
6
6
  end
7
7
 
8
+ require_relative 'types/base_connection'
8
9
  require_relative 'types/base_object'
9
10
  require_relative 'types/base_enum'
10
11
  require_relative 'types/base_input_object'
11
12
  require_relative 'types/identity_provider_service'
13
+ require_relative 'types/identity_provider_status'
12
14
  require_relative 'types/identity_provider'
13
15
  require_relative 'types/enterprise_account'
14
16
  require_relative 'types/oauth_client'
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Types
6
+ class BaseConnection < ::GraphQL::Types::Relay::BaseConnection
7
+ field :total_count, Integer, null: false
8
+
9
+ def total_count
10
+ object.items&.count
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -6,6 +6,10 @@ module Osso
6
6
  module GraphQL
7
7
  module Types
8
8
  class BaseObject < ::GraphQL::Schema::Object
9
+ connection_type_class GraphQL::Types::BaseConnection
10
+
11
+ field :created_at, ::GraphQL::Types::ISO8601DateTime, null: false
12
+ field :updated_at, ::GraphQL::Types::ISO8601DateTime, null: false
9
13
  end
10
14
  end
11
15
  end
@@ -23,6 +23,10 @@ module Osso
23
23
  def identity_providers
24
24
  object.identity_providers
25
25
  end
26
+
27
+ def self.authorized?(object, context)
28
+ super && (context[:scope] == :admin || object.domain == context[:scope])
29
+ end
26
30
  end
27
31
  end
28
32
  end
@@ -17,10 +17,15 @@ module Osso
17
17
  field :acs_url, String, null: false
18
18
  field :sso_url, String, null: true
19
19
  field :sso_cert, String, null: true
20
- field :configured, Boolean, null: false
20
+ field :status, Types::IdentityProviderStatus, null: false
21
+ field :documentation_pdf_url, String, null: true
21
22
 
22
- def configured
23
- !!(@object.sso_url && @object.sso_cert)
23
+ def documentation_pdf_url
24
+ ENV['BASE_URL'] + '/identity_provider/documentation/' + @object.id
25
+ end
26
+
27
+ def self.authorized?(object, context)
28
+ super && (context[:scope] == :admin || object.domain == context[:scope])
24
29
  end
25
30
  end
26
31
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Types
6
+ class IdentityProviderStatus < BaseEnum
7
+ value('Pending', value: 'PENDING')
8
+ value('Configured', value: 'CONFIGURED')
9
+ value('Active', value: 'ACTIVE')
10
+ value('Error', value: 'ERROR')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -5,7 +5,7 @@ require 'graphql'
5
5
  module Osso
6
6
  module GraphQL
7
7
  module Types
8
- class OAuthClient < Types::BaseObject
8
+ class OauthClient < Types::BaseObject
9
9
  description 'An OAuth client used to consume Osso SAML users'
10
10
  implements ::GraphQL::Types::Relay::Node
11
11
 
@@ -14,6 +14,18 @@ module Osso
14
14
  field :name, String, null: false
15
15
  field :client_id, String, null: false
16
16
  field :client_secret, String, null: false
17
+
18
+ def client_id
19
+ object.identifier
20
+ end
21
+
22
+ def client_secret
23
+ object.secret
24
+ end
25
+
26
+ def self.authorized?(object, context)
27
+ super && context[:scope] == :admin
28
+ end
17
29
  end
18
30
  end
19
31
  end
@@ -15,12 +15,7 @@ module Osso
15
15
  end
16
16
 
17
17
  def enterprise_authorized?(_domain)
18
- payload, _args = JWT.decode(
19
- token,
20
- ENV['JWT_HMAC_SECRET'],
21
- true,
22
- { algorithm: 'HS256' },
23
- )
18
+ payload, _args = decode(token)
24
19
 
25
20
  @current_scope = payload['scope']
26
21
 
@@ -36,12 +31,7 @@ module Osso
36
31
  end
37
32
 
38
33
  def admin_authorized?
39
- payload, _args = JWT.decode(
40
- token,
41
- ENV['JWT_HMAC_SECRET'],
42
- true,
43
- { algorithm: 'HS256' },
44
- )
34
+ payload, _args = decode(token)
45
35
 
46
36
  if payload['scope'] == 'admin'
47
37
  @current_scope = :admin
@@ -66,6 +56,15 @@ module Osso
66
56
 
67
57
  redirect request.path
68
58
  end
59
+
60
+ def decode(token)
61
+ JWT.decode(
62
+ token,
63
+ ENV['JWT_HMAC_SECRET'],
64
+ true,
65
+ { algorithm: 'HS256' },
66
+ )
67
+ end
69
68
  end
70
69
  end
71
70
  end
@@ -27,3 +27,21 @@ module Osso
27
27
  end
28
28
  end
29
29
  end
30
+
31
+ # == Schema Information
32
+ #
33
+ # Table name: access_tokens
34
+ #
35
+ # id :uuid not null, primary key
36
+ # token :string
37
+ # expires_at :datetime
38
+ # created_at :datetime not null
39
+ # updated_at :datetime not null
40
+ # user_id :uuid
41
+ # oauth_client_id :uuid
42
+ #
43
+ # Indexes
44
+ #
45
+ # index_access_tokens_on_oauth_client_id (oauth_client_id)
46
+ # index_access_tokens_on_user_id (user_id)
47
+ #
@@ -12,3 +12,23 @@ module Osso
12
12
  end
13
13
  end
14
14
  end
15
+
16
+ # == Schema Information
17
+ #
18
+ # Table name: authorization_codes
19
+ #
20
+ # id :uuid not null, primary key
21
+ # token :string
22
+ # redirect_uri :string
23
+ # expires_at :datetime
24
+ # created_at :datetime not null
25
+ # updated_at :datetime not null
26
+ # user_id :uuid
27
+ # oauth_client_id :uuid
28
+ #
29
+ # Indexes
30
+ #
31
+ # index_authorization_codes_on_oauth_client_id (oauth_client_id)
32
+ # index_authorization_codes_on_token (token) UNIQUE
33
+ # index_authorization_codes_on_user_id (user_id)
34
+ #
@@ -26,3 +26,23 @@ module Osso
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ # == Schema Information
31
+ #
32
+ # Table name: enterprise_accounts
33
+ #
34
+ # id :uuid not null, primary key
35
+ # domain :string not null
36
+ # external_uuid :uuid
37
+ # external_int_id :integer
38
+ # external_id :string
39
+ # oauth_client_id :uuid
40
+ # name :string not null
41
+ # created_at :datetime not null
42
+ # updated_at :datetime not null
43
+ #
44
+ # Indexes
45
+ #
46
+ # index_enterprise_accounts_on_domain (domain) UNIQUE
47
+ # index_enterprise_accounts_on_oauth_client_id (oauth_client_id)
48
+ #
@@ -8,6 +8,7 @@ module Osso
8
8
  belongs_to :enterprise_account
9
9
  belongs_to :oauth_client
10
10
  has_many :users
11
+ before_save :set_status
11
12
 
12
13
  def name
13
14
  service.titlecase
@@ -43,6 +44,34 @@ module Osso
43
44
  end
44
45
 
45
46
  alias acs_url assertion_consumer_service_url
47
+
48
+ def set_status
49
+ return if status != 'PENDING'
50
+
51
+ self.status = 'CONFIGURED' if sso_url && sso_cert
52
+ end
46
53
  end
47
54
  end
48
55
  end
56
+
57
+ # == Schema Information
58
+ #
59
+ # Table name: identity_providers
60
+ #
61
+ # id :uuid not null, primary key
62
+ # service :string
63
+ # domain :string not null
64
+ # sso_url :string
65
+ # sso_cert :text
66
+ # enterprise_account_id :uuid
67
+ # oauth_client_id :uuid
68
+ # status :enum default("PENDING")
69
+ # created_at :datetime
70
+ # updated_at :datetime
71
+ #
72
+ # Indexes
73
+ #
74
+ # index_identity_providers_on_domain (domain)
75
+ # index_identity_providers_on_enterprise_account_id (enterprise_account_id)
76
+ # index_identity_providers_on_oauth_client_id (oauth_client_id)
77
+ #
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # -*- SkipSchemaAnnotations
4
+
3
5
  require 'sinatra/activerecord'
4
6
 
5
7
  module Osso
@@ -25,8 +25,24 @@ module Osso
25
25
 
26
26
  def setup
27
27
  self.identifier = SecureRandom.hex(16)
28
- self.secret = SecureRandom.hex(64)
28
+ self.secret = SecureRandom.hex(32)
29
29
  end
30
30
  end
31
31
  end
32
32
  end
33
+
34
+ # == Schema Information
35
+ #
36
+ # Table name: oauth_clients
37
+ #
38
+ # id :uuid not null, primary key
39
+ # name :string not null
40
+ # secret :string not null
41
+ # identifier :string not null
42
+ # created_at :datetime not null
43
+ # updated_at :datetime not null
44
+ #
45
+ # Indexes
46
+ #
47
+ # index_oauth_clients_on_identifier (identifier) UNIQUE
48
+ #
@@ -18,3 +18,20 @@ module Osso
18
18
  end
19
19
  end
20
20
  end
21
+
22
+ # == Schema Information
23
+ #
24
+ # Table name: redirect_uris
25
+ #
26
+ # id :uuid not null, primary key
27
+ # uri :string not null
28
+ # primary :boolean default(FALSE), not null
29
+ # oauth_client_id :uuid
30
+ # created_at :datetime not null
31
+ # updated_at :datetime not null
32
+ #
33
+ # Indexes
34
+ #
35
+ # index_redirect_uris_on_oauth_client_id (oauth_client_id)
36
+ # index_redirect_uris_on_uri_and_primary (uri,primary) UNIQUE
37
+ #
@@ -22,3 +22,25 @@ module Osso
22
22
  end
23
23
  end
24
24
  end
25
+
26
+ # == Schema Information
27
+ #
28
+ # Table name: users
29
+ #
30
+ # id :uuid not null, primary key
31
+ # email :string not null
32
+ # idp_id :string not null
33
+ # identity_provider_id :uuid
34
+ # enterprise_account_id :uuid
35
+ # created_at :datetime not null
36
+ # updated_at :datetime not null
37
+ #
38
+ # Indexes
39
+ #
40
+ # index_users_on_email_and_idp_id (email,idp_id) UNIQUE
41
+ # index_users_on_enterprise_account_id (enterprise_account_id)
42
+ #
43
+ # Foreign Keys
44
+ #
45
+ # fk_rails_... (identity_provider_id => identity_providers.id)
46
+ #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Osso
4
- VERSION = '0.0.3.6'
4
+ VERSION = '0.0.3.11'
5
5
  end
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_runtime_dependency 'sinatra-activerecord'
29
29
  spec.add_runtime_dependency 'sinatra-contrib'
30
30
 
31
+ spec.add_development_dependency 'annotate', '~> 3.1'
31
32
  spec.add_development_dependency 'bundler', '~> 2.1'
32
33
  spec.add_development_dependency 'pry'
33
34
 
@@ -47,3 +47,25 @@ FactoryBot.define do
47
47
  end
48
48
  end
49
49
  end
50
+
51
+ # == Schema Information
52
+ #
53
+ # Table name: identity_providers
54
+ #
55
+ # id :uuid not null, primary key
56
+ # service :string
57
+ # domain :string not null
58
+ # sso_url :string
59
+ # sso_cert :text
60
+ # enterprise_account_id :uuid
61
+ # oauth_client_id :uuid
62
+ # status :enum default("PENDING")
63
+ # created_at :datetime
64
+ # updated_at :datetime
65
+ #
66
+ # Indexes
67
+ #
68
+ # index_identity_providers_on_domain (domain)
69
+ # index_identity_providers_on_enterprise_account_id (enterprise_account_id)
70
+ # index_identity_providers_on_oauth_client_id (oauth_client_id)
71
+ #
@@ -23,7 +23,7 @@ describe Osso::GraphQL::Schema do
23
23
  identityProvider {
24
24
  id
25
25
  domain
26
- configured
26
+ status
27
27
  enterpriseAccountId
28
28
  service
29
29
  acsUrl
@@ -46,8 +46,8 @@ describe Osso::GraphQL::Schema do
46
46
  describe 'for an admin user' do
47
47
  let(:current_scope) { :admin }
48
48
  it 'configures an identity provider' do
49
- expect(subject.dig('data', 'configureIdentityProvider', 'identityProvider', 'configured')).
50
- to be true
49
+ expect(subject.dig('data', 'configureIdentityProvider', 'identityProvider', 'status')).
50
+ to eq('Configured')
51
51
  end
52
52
  end
53
53
 
@@ -55,11 +55,21 @@ describe Osso::GraphQL::Schema do
55
55
  let(:domain) { Faker::Internet.domain_name }
56
56
  let(:current_scope) { domain }
57
57
  let(:enterprise_account) { create(:enterprise_account, domain: domain) }
58
+ let(:identity_provider) { create(:identity_provider, enterprise_account: enterprise_account, domain: domain) }
58
59
 
59
- it 'creates an identity provider' do
60
+ it 'configures an identity provider' do
60
61
  expect(subject.dig('data', 'configureIdentityProvider', 'identityProvider', 'domain')).
61
62
  to eq(domain)
62
63
  end
63
64
  end
65
+
66
+ describe 'for the wrong email scoped user' do
67
+ let(:domain) { Faker::Internet.domain_name }
68
+ let(:current_scope) { domain }
69
+
70
+ it 'does not configure an identity provider' do
71
+ expect(subject.dig('errors')).to_not be_empty
72
+ end
73
+ end
64
74
  end
65
75
  end