osso 0.0.3.7

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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/.buildkite/hooks/environment +9 -0
  3. data/.buildkite/hooks/pre-command +7 -0
  4. data/.buildkite/pipeline.yml +6 -0
  5. data/.buildkite/template.yml +5 -0
  6. data/.gitignore +10 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +81 -0
  9. data/CODE_OF_CONDUCT.md +130 -0
  10. data/Gemfile +18 -0
  11. data/Gemfile.lock +176 -0
  12. data/LICENSE +111 -0
  13. data/README.md +2 -0
  14. data/Rakefile +14 -0
  15. data/bin/console +8 -0
  16. data/bin/setup +8 -0
  17. data/config/database.yml +14 -0
  18. data/db/schema.rb +133 -0
  19. data/lib/osso.rb +11 -0
  20. data/lib/osso/Rakefile +13 -0
  21. data/lib/osso/db/migrate/20190909230109_enable_uuid.rb +7 -0
  22. data/lib/osso/db/migrate/20200328135750_create_users.rb +12 -0
  23. data/lib/osso/db/migrate/20200328143303_create_oauth_tables.rb +57 -0
  24. data/lib/osso/db/migrate/20200328143305_create_identity_providers.rb +12 -0
  25. data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +7 -0
  26. data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +15 -0
  27. data/lib/osso/db/migrate/20200413132407_add_oauth_clients.rb +13 -0
  28. data/lib/osso/db/migrate/20200413142511_create_authorization_codes.rb +15 -0
  29. data/lib/osso/db/migrate/20200413163451_create_access_tokens.rb +13 -0
  30. data/lib/osso/db/migrate/20200502120616_create_redirect_uris_and_drop_from_oauth_clients.rb +13 -0
  31. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_accounts_and_identity_providers.rb +6 -0
  32. data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +17 -0
  33. data/lib/osso/db/migrate/20200715154211_rename_idp_fields_on_identity_provider_to_sso.rb +6 -0
  34. data/lib/osso/db/migrate/20200715205801_add_name_to_enterprise_account.rb +5 -0
  35. data/lib/osso/graphql/mutation.rb +16 -0
  36. data/lib/osso/graphql/mutations.rb +12 -0
  37. data/lib/osso/graphql/mutations/base_mutation.rb +41 -0
  38. data/lib/osso/graphql/mutations/configure_identity_provider.rb +36 -0
  39. data/lib/osso/graphql/mutations/create_enterprise_account.rb +25 -0
  40. data/lib/osso/graphql/mutations/create_identity_provider.rb +30 -0
  41. data/lib/osso/graphql/mutations/set_identity_provider.rb +27 -0
  42. data/lib/osso/graphql/query.rb +25 -0
  43. data/lib/osso/graphql/resolvers.rb +12 -0
  44. data/lib/osso/graphql/resolvers/enterprise_account.rb +25 -0
  45. data/lib/osso/graphql/resolvers/enterprise_accounts.rb +17 -0
  46. data/lib/osso/graphql/resolvers/oauth_clients.rb +15 -0
  47. data/lib/osso/graphql/schema.rb +46 -0
  48. data/lib/osso/graphql/types.rb +15 -0
  49. data/lib/osso/graphql/types/base_enum.rb +10 -0
  50. data/lib/osso/graphql/types/base_input_object.rb +10 -0
  51. data/lib/osso/graphql/types/base_object.rb +12 -0
  52. data/lib/osso/graphql/types/enterprise_account.rb +33 -0
  53. data/lib/osso/graphql/types/identity_provider.rb +37 -0
  54. data/lib/osso/graphql/types/identity_provider_service.rb +12 -0
  55. data/lib/osso/graphql/types/oauth_client.rb +20 -0
  56. data/lib/osso/graphql/types/user.rb +17 -0
  57. data/lib/osso/helpers/auth.rb +71 -0
  58. data/lib/osso/helpers/helpers.rb +8 -0
  59. data/lib/osso/lib/app_config.rb +20 -0
  60. data/lib/osso/lib/oauth2_token.rb +38 -0
  61. data/lib/osso/lib/route_map.rb +28 -0
  62. data/lib/osso/models/access_token.rb +29 -0
  63. data/lib/osso/models/authorization_code.rb +14 -0
  64. data/lib/osso/models/enterprise_account.rb +28 -0
  65. data/lib/osso/models/identity_provider.rb +48 -0
  66. data/lib/osso/models/models.rb +16 -0
  67. data/lib/osso/models/oauth_client.rb +32 -0
  68. data/lib/osso/models/redirect_uri.rb +20 -0
  69. data/lib/osso/models/saml_provider.rb +49 -0
  70. data/lib/osso/models/saml_providers/azure_saml_provider.rb +22 -0
  71. data/lib/osso/models/saml_providers/okta_saml_provider.rb +23 -0
  72. data/lib/osso/models/user.rb +24 -0
  73. data/lib/osso/rake.rb +4 -0
  74. data/lib/osso/routes/admin.rb +41 -0
  75. data/lib/osso/routes/auth.rb +67 -0
  76. data/lib/osso/routes/oauth.rb +63 -0
  77. data/lib/osso/routes/routes.rb +10 -0
  78. data/lib/osso/routes/views/error.erb +1 -0
  79. data/lib/osso/routes/views/multiple_providers.erb +1 -0
  80. data/lib/osso/version.rb +5 -0
  81. data/lib/tasks/bootstrap.rake +16 -0
  82. data/osso-rb.gemspec +40 -0
  83. data/spec/factories/authorization_code.rb +10 -0
  84. data/spec/factories/enterprise_account.rb +46 -0
  85. data/spec/factories/identity_providers.rb +49 -0
  86. data/spec/factories/oauth_client.rb +12 -0
  87. data/spec/factories/redirect_uri.rb +14 -0
  88. data/spec/factories/user.rb +18 -0
  89. data/spec/graphql/mutations/configure_identity_provider_spec.rb +75 -0
  90. data/spec/graphql/mutations/create_enterprise_account_spec.rb +68 -0
  91. data/spec/graphql/mutations/create_identity_provider_spec.rb +104 -0
  92. data/spec/graphql/query/enterprise_account_spec.rb +68 -0
  93. data/spec/graphql/query/enterprise_accounts_spec.rb +44 -0
  94. data/spec/graphql/query/identity_provider_spec.rb +65 -0
  95. data/spec/graphql/query/oauth_clients_account_spec.rb +48 -0
  96. data/spec/models/azure_saml_provider_spec.rb +19 -0
  97. data/spec/models/identity_provider_spec.rb +17 -0
  98. data/spec/models/okta_saml_provider_spec.rb +20 -0
  99. data/spec/routes/admin_spec.rb +60 -0
  100. data/spec/routes/app_spec.rb +6 -0
  101. data/spec/routes/auth_spec.rb +112 -0
  102. data/spec/routes/oauth_spec.rb +134 -0
  103. data/spec/spec_helper.rb +68 -0
  104. data/spec/support/spec_app.rb +9 -0
  105. data/spec/support/views/admin.erb +5 -0
  106. metadata +348 -0
@@ -0,0 +1,13 @@
1
+ class AddOauthClients < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :oauth_clients, id: :uuid do |t|
4
+ t.string :name, null: false
5
+ t.string :secret, null: false
6
+ t.string :identifier, null: false
7
+ t.jsonb :redirect_uris, default: [], null: false
8
+ end
9
+
10
+ add_index :oauth_clients, :redirect_uris, using: :gin
11
+ add_index :oauth_clients, :identifier, unique: true
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ class CreateAuthorizationCodes < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :authorization_codes, id: :uuid do |t|
4
+ t.string :token
5
+ t.string :redirect_uri
6
+ t.datetime :expires_at
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :authorization_codes, :token, unique: true
12
+ add_reference :authorization_codes, :user, type: :uuid, index: true
13
+ add_reference :authorization_codes, :oauth_client, type: :uuid, index: true
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class CreateAccessTokens < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :access_tokens, id: :uuid do |t|
4
+ t.string :token
5
+ t.datetime :expires_at
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_reference :access_tokens, :user, type: :uuid, index: true
11
+ add_reference :access_tokens, :oauth_client, type: :uuid, index: true
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CreateRedirectUrisAndDropFromOauthClients < ActiveRecord::Migration[6.0]
2
+ def change
3
+ remove_column :oauth_clients, :redirect_uris
4
+
5
+ create_table :redirect_uris, id: :uuid do |t|
6
+ t.string :uri, null: false
7
+ t.boolean :primary, default: false, null: false
8
+ end
9
+
10
+ add_index :redirect_uris, [:uri, :primary], unique: true
11
+ add_reference :redirect_uris, :oauth_client, type: :uuid, index: true
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ class AddOauthClientIdToEnterpriseAccountsAndIdentityProviders < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_reference :enterprise_accounts, :oauth_client, type: :uuid, index: true
4
+ add_reference :identity_providers, :oauth_client, type: :uuid, index: true
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ class AddIdentityProviderServiceEnum < ActiveRecord::Migration[6.0]
2
+ def change
3
+ def up
4
+ execute <<-SQL
5
+ CREATE TYPE identity_provider_service AS ENUM ('OKTA', 'AZURE');
6
+ SQL
7
+ chnage_column :identity_providers, :service, :identity_provider_service
8
+ end
9
+
10
+ def down
11
+ chnage_column :identity_providers, :service, :text
12
+ execute <<-SQL
13
+ DROP TYPE identity_provider_service;
14
+ SQL
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ class RenameIdpFieldsOnIdentityProviderToSso < ActiveRecord::Migration[6.0]
2
+ def change
3
+ rename_column :identity_providers, :idp_cert, :sso_cert
4
+ rename_column :identity_providers, :idp_sso_target_url, :sso_url
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddNameToEnterpriseAccount < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :enterprise_accounts, :name, :string, null: false
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mutations'
4
+
5
+ module Osso
6
+ module GraphQL
7
+ module Types
8
+ class MutationType < BaseObject
9
+ field :configure_identity_provider, mutation: Mutations::ConfigureIdentityProvider, null: true
10
+ field :create_identity_provider, mutation: Mutations::CreateIdentityProvider
11
+ field :create_enterprise_account, mutation: Mutations::CreateEnterpriseAccount
12
+ field :set_identity_provider, mutation: Mutations::SetSamlProvider
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Mutations
5
+ end
6
+ end
7
+
8
+ require_relative 'mutations/base_mutation'
9
+ require_relative 'mutations/configure_identity_provider'
10
+ require_relative 'mutations/create_identity_provider'
11
+ require_relative 'mutations/create_enterprise_account'
12
+ require_relative 'mutations/set_identity_provider'
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class BaseMutation < ::GraphQL::Schema::RelayClassicMutation
7
+ object_class Types::BaseObject
8
+ input_object_class Types::BaseInputObject
9
+
10
+ def response_data(data)
11
+ data.merge(errors: [])
12
+ end
13
+
14
+ def response_error(error)
15
+ error.merge(data: nil)
16
+ end
17
+
18
+ def ready?(enterprise_account_id: nil, domain: nil, identity_provider_id: nil, **args)
19
+ return true if context[:scope] == :admin
20
+
21
+ domain ||= account_domain(enterprise_account_id) || provider_domain(identity_provider_id)
22
+ return true if domain == context[:scope]
23
+
24
+ raise ::GraphQL::ExecutionError, "This user lacks the scope to mutate records belonging to #{args[:domain]}"
25
+ end
26
+
27
+ def account_domain(id)
28
+ return false unless id
29
+
30
+ Osso::Models::EnterpriseAccount.find(id)&.domain
31
+ end
32
+
33
+ def provider_domain(id)
34
+ return false unless id
35
+
36
+ Osso::Models::IdentityProvider.find(id)&.domain
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class ConfigureIdentityProvider < BaseMutation
7
+ null false
8
+ argument :id, ID, required: true
9
+ argument :service, Types::IdentityProviderService, required: false
10
+ argument :sso_url, String, required: false
11
+ argument :sso_cert, String, required: false
12
+
13
+ field :identity_provider, Types::IdentityProvider, null: false
14
+ field :errors, [String], null: false
15
+
16
+ def resolve(id:, **args)
17
+ provider = Osso::Models::IdentityProvider.find(id)
18
+
19
+ return response_data(identity_provider: provider) if provider.update(args)
20
+
21
+ response_error(errors: provder.errors.messages)
22
+ end
23
+
24
+ def ready?(id:, **args)
25
+ return true if context[:scope] == :admin
26
+
27
+ domain = Osso::Models::IdentityProvider.find(id)&.domain
28
+
29
+ return true if domain == context[:scope]
30
+
31
+ raise ::GraphQL::ExecutionError, "This user lacks the scope to mutate records belonging to #{domain}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class CreateEnterpriseAccount < BaseMutation
7
+ null false
8
+
9
+ argument :domain, String, required: true
10
+ argument :name, String, required: true
11
+
12
+ field :enterprise_account, Types::EnterpriseAccount, null: false
13
+ field :errors, [String], null: false
14
+
15
+ def resolve(**args)
16
+ enterprise_account = Osso::Models::EnterpriseAccount.new(args)
17
+
18
+ return response_data(enterprise_account: enterprise_account) if enterprise_account.save
19
+
20
+ response_error(errors: enterprise_account.errors.full_messages)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class CreateIdentityProvider < BaseMutation
7
+ null false
8
+
9
+ argument :enterprise_account_id, ID, required: true
10
+ argument :service, Types::IdentityProviderService, required: false
11
+
12
+ field :identity_provider, Types::IdentityProvider, null: false
13
+ field :errors, [String], null: false
14
+
15
+ def resolve(enterprise_account_id:, service: nil)
16
+ enterprise_account = Osso::Models::EnterpriseAccount.find(enterprise_account_id)
17
+ identity_provider = enterprise_account.identity_providers.build(
18
+ enterprise_account_id: enterprise_account_id,
19
+ service: service,
20
+ domain: enterprise_account.domain,
21
+ )
22
+
23
+ return response_data(identity_provider: identity_provider) if identity_provider.save
24
+
25
+ response_error(errors: identity_provider.errors.full_messages)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class SetSamlProvider < BaseMutation
7
+ null false
8
+
9
+ argument :provider, Types::IdentityProviderService, required: true
10
+ argument :id, ID, required: true
11
+
12
+ field :identity_provider, Types::IdentityProvider, null: false
13
+ field :errors, [String], null: false
14
+
15
+ def resolve(provider:, id:)
16
+ identity_provider = Osso::Models::IdentityProvider.find(id)
17
+ identity_provider.service = provider
18
+ identity_provider.save!
19
+ {
20
+ identity_provider: identity_provider,
21
+ errors: [],
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Types
6
+ class QueryType < ::GraphQL::Schema::Object
7
+ field :enterprise_accounts, null: true, resolver: Resolvers::EnterpriseAccounts
8
+ field :oauth_clients, null: true, resolver: Resolvers::OAuthClients
9
+
10
+ field :enterprise_account, null: true, resolver: Resolvers::EnterpriseAccount do
11
+ argument :domain, String, required: true
12
+ end
13
+
14
+ field(
15
+ :identity_provider,
16
+ Types::IdentityProvider,
17
+ null: true,
18
+ resolve: ->(_obj, args, _context) { Osso::Models::IdentityProvider.find(args[:id]) },
19
+ ) do
20
+ argument :id, ID, required: true
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Resolvers
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative 'resolvers/enterprise_account'
11
+ require_relative 'resolvers/enterprise_accounts'
12
+ require_relative 'resolvers/oauth_clients'
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Resolvers
6
+ class EnterpriseAccount < ::GraphQL::Schema::Resolver
7
+ type Types::EnterpriseAccount, null: false
8
+
9
+ def resolve(args)
10
+ return unless admin? || enterprise_authorized?(args[:domain])
11
+
12
+ Osso::Models::EnterpriseAccount.find_by(domain: args[:domain])
13
+ end
14
+
15
+ def admin?
16
+ context[:scope] == :admin
17
+ end
18
+
19
+ def enterprise_authorized?(domain)
20
+ context[:scope] == domain
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Resolvers
6
+ class EnterpriseAccounts < ::GraphQL::Schema::Resolver
7
+ type [Types::EnterpriseAccount], null: true
8
+
9
+ def resolve
10
+ return Osso::Models::EnterpriseAccount.all if context[:scope] == :admin
11
+
12
+ Array(Osso::Models::EnterpriseAccount.find_by(domain: context[:scope]))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Resolvers
6
+ class OAuthClients < ::GraphQL::Schema::Resolver
7
+ type [Types::OAuthClient], null: true
8
+
9
+ def resolve
10
+ return Osso::Models::OauthClient.all if context[:scope] == :admin
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+ require_relative 'types'
5
+ require_relative 'resolvers'
6
+ require_relative 'mutation'
7
+ require_relative 'query'
8
+
9
+ GraphQL::Relay::BaseConnection.register_connection_implementation(
10
+ ActiveRecord::Relation,
11
+ GraphQL::Relay::RelationConnection,
12
+ )
13
+
14
+ module Osso
15
+ module GraphQL
16
+ class Schema < ::GraphQL::Schema
17
+ use ::GraphQL::Pagination::Connections
18
+ query Types::QueryType
19
+ mutation Types::MutationType
20
+
21
+ def self.id_from_object(object, _type_definition = nil, _query_ctx = nil)
22
+ GraphQL::Schema::UniqueWithinType.encode(object.class.name, object.id)
23
+ end
24
+
25
+ def self.object_from_id(id, _query_ctx = nil)
26
+ class_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
27
+ Object.const_get(class_name).find(item_id)
28
+ end
29
+
30
+ def self.resolve_type(_type, obj, _ctx)
31
+ case obj
32
+ when Osso::Models::EnterpriseAccount
33
+ Types::EnterpriseAccount
34
+ when Osso::Models::IdentityProvider
35
+ Types::IdentityProvider
36
+ else
37
+ raise("Unexpected object: #{obj}")
38
+ end
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
44
+ end
45
+ end
46
+ end