osso 0.0.3.1 → 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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +4 -1
  3. data/.rubocop.yml +1 -2
  4. data/Gemfile.lock +3 -1
  5. data/bin/console +4 -3
  6. data/config/database.yml +2 -2
  7. data/db/schema.rb +133 -1
  8. data/lib/osso.rb +2 -0
  9. data/lib/osso/db/migrate/20200328143305_create_identity_providers.rb +12 -0
  10. data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +2 -2
  11. data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +1 -1
  12. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_accounts_and_identity_providers.rb +6 -0
  13. data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +17 -0
  14. data/lib/osso/db/migrate/20200715154211_rename_idp_fields_on_identity_provider_to_sso.rb +6 -0
  15. data/lib/osso/db/migrate/20200715205801_add_name_to_enterprise_account.rb +5 -0
  16. data/lib/osso/graphql/mutation.rb +10 -5
  17. data/lib/osso/graphql/mutations.rb +5 -2
  18. data/lib/osso/graphql/mutations/base_mutation.rb +29 -14
  19. data/lib/osso/graphql/mutations/configure_identity_provider.rb +19 -18
  20. data/lib/osso/graphql/mutations/create_enterprise_account.rb +25 -0
  21. data/lib/osso/graphql/mutations/create_identity_provider.rb +22 -16
  22. data/lib/osso/graphql/mutations/set_identity_provider.rb +27 -0
  23. data/lib/osso/graphql/query.rb +19 -22
  24. data/lib/osso/graphql/resolvers.rb +5 -1
  25. data/lib/osso/graphql/resolvers/enterprise_account.rb +16 -12
  26. data/lib/osso/graphql/resolvers/enterprise_accounts.rb +10 -6
  27. data/lib/osso/graphql/resolvers/oauth_clients.rb +9 -5
  28. data/lib/osso/graphql/schema.rb +23 -19
  29. data/lib/osso/graphql/types.rb +4 -1
  30. data/lib/osso/graphql/types/base_enum.rb +6 -2
  31. data/lib/osso/graphql/types/base_input_object.rb +10 -0
  32. data/lib/osso/graphql/types/base_object.rb +6 -2
  33. data/lib/osso/graphql/types/enterprise_account.rb +19 -19
  34. data/lib/osso/graphql/types/identity_provider.rb +19 -27
  35. data/lib/osso/graphql/types/identity_provider_service.rb +8 -4
  36. data/lib/osso/graphql/types/oauth_client.rb +13 -9
  37. data/lib/osso/graphql/types/user.rb +10 -5
  38. data/lib/osso/helpers/auth.rb +53 -49
  39. data/lib/osso/helpers/helpers.rb +3 -1
  40. data/lib/osso/lib/app_config.rb +1 -1
  41. data/lib/osso/lib/route_map.rb +28 -0
  42. data/lib/osso/models/enterprise_account.rb +4 -4
  43. data/lib/osso/models/identity_provider.rb +48 -0
  44. data/lib/osso/models/models.rb +1 -1
  45. data/lib/osso/models/oauth_client.rb +2 -2
  46. data/lib/osso/models/saml_provider.rb +13 -16
  47. data/lib/osso/models/saml_providers/azure_saml_provider.rb +2 -2
  48. data/lib/osso/models/saml_providers/okta_saml_provider.rb +1 -1
  49. data/lib/osso/models/user.rb +3 -3
  50. data/lib/osso/routes/admin.rb +18 -15
  51. data/lib/osso/routes/auth.rb +30 -27
  52. data/lib/osso/routes/oauth.rb +50 -45
  53. data/lib/osso/version.rb +1 -1
  54. data/osso-rb.gemspec +3 -3
  55. data/spec/factories/enterprise_account.rb +5 -4
  56. data/spec/factories/identity_providers.rb +49 -0
  57. data/spec/factories/user.rb +1 -1
  58. data/spec/graphql/mutations/configure_identity_provider_spec.rb +65 -0
  59. data/spec/graphql/mutations/create_enterprise_account_spec.rb +68 -0
  60. data/spec/graphql/mutations/create_identity_provider_spec.rb +104 -0
  61. data/spec/graphql/query/enterprise_account_spec.rb +68 -0
  62. data/spec/graphql/query/enterprise_accounts_spec.rb +44 -0
  63. data/spec/graphql/query/identity_provider_spec.rb +62 -0
  64. data/spec/graphql/query/oauth_clients_account_spec.rb +48 -0
  65. data/spec/models/azure_saml_provider_spec.rb +14 -14
  66. data/spec/models/identity_provider_spec.rb +17 -0
  67. data/spec/models/okta_saml_provider_spec.rb +15 -15
  68. data/spec/routes/admin_spec.rb +2 -0
  69. data/spec/routes/auth_spec.rb +9 -9
  70. data/spec/routes/oauth_spec.rb +1 -1
  71. data/spec/spec_helper.rb +4 -5
  72. data/spec/support/spec_app.rb +9 -0
  73. data/spec/support/views/{public/index.erb → admin.erb} +0 -0
  74. metadata +37 -13
  75. data/lib/osso/db/migrate/20200411144528_create_saml_providers.rb +0 -13
  76. data/lib/osso/db/migrate/20200413153029_add_oauth_client_reference_to_saml_providers.rb +0 -5
  77. data/lib/osso/db/migrate/20200501203026_drop_null_constraints_from_saml_provider.rb +0 -7
  78. data/lib/osso/db/migrate/20200501204047_drop_acs_url.rb +0 -5
  79. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_account.rb +0 -5
  80. data/lib/osso/db/migrate/20200601131227_drop_null_constraint_from_saml_providers_provider.rb +0 -7
  81. data/lib/osso/db/schema.rb +0 -132
  82. data/lib/osso/graphql/mutations/set_saml_provider.rb +0 -23
  83. data/spec/factories/saml_providers.rb +0 -46
  84. data/spec/models/saml_provider_spec.rb +0 -31
@@ -2,15 +2,19 @@
2
2
 
3
3
  require 'graphql'
4
4
 
5
- module Types
6
- class OAuthClient < Types::BaseObject
7
- description 'An OAuth client used to consume Osso SAML users'
8
- implements GraphQL::Types::Relay::Node
5
+ module Osso
6
+ module GraphQL
7
+ module Types
8
+ class OAuthClient < Types::BaseObject
9
+ description 'An OAuth client used to consume Osso SAML users'
10
+ implements ::GraphQL::Types::Relay::Node
9
11
 
10
- global_id_field :gid
11
- field :id, ID, null: false
12
- field :name, String, null: false
13
- field :client_id, String, null: false
14
- field :client_secret, String, null: false
12
+ global_id_field :gid
13
+ field :id, ID, null: false
14
+ field :name, String, null: false
15
+ field :client_id, String, null: false
16
+ field :client_secret, String, null: false
17
+ end
18
+ end
15
19
  end
16
20
  end
@@ -2,11 +2,16 @@
2
2
 
3
3
  require 'graphql'
4
4
  require_relative 'base_object'
5
- module Types
6
- class User < Types::BaseObject
7
- description 'A User of the application'
8
5
 
9
- field :id, ID, null: false
10
- field :name, String, null: true
6
+ module Osso
7
+ module GraphQL
8
+ module Types
9
+ class User < Types::BaseObject
10
+ description 'A User of the application'
11
+
12
+ field :id, ID, null: false
13
+ field :name, String, null: true
14
+ end
15
+ end
11
16
  end
12
17
  end
@@ -1,67 +1,71 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Helpers
4
- module Auth
5
- attr_accessor :current_scope
6
-
7
- def enterprise_protected!(domain = nil)
8
- return if admin_authorized?
9
- return if enterprise_authorized?(domain)
10
-
11
- redirect ENV['JWT_URL']
12
- end
3
+ module Osso
4
+ module Helpers
5
+ module Auth
6
+ attr_accessor :current_scope
13
7
 
14
- def enterprise_authorized?(domain)
15
- payload, _args = JWT.decode(
16
- token,
17
- ENV['JWT_HMAC_SECRET'],
18
- true,
19
- { algorithm: 'HS256' },
20
- )
8
+ def enterprise_protected!(domain = nil)
9
+ return if admin_authorized?
10
+ return if enterprise_authorized?(domain)
21
11
 
22
- @current_scope = payload['scope']
12
+ halt 401 if request.post?
23
13
 
24
- true
25
- rescue JWT::DecodeError
26
- false
27
- end
14
+ redirect ENV['JWT_URL']
15
+ end
28
16
 
29
- def admin_protected!
30
- return if admin_authorized?
17
+ def enterprise_authorized?(_domain)
18
+ payload, _args = JWT.decode(
19
+ token,
20
+ ENV['JWT_HMAC_SECRET'],
21
+ true,
22
+ { algorithm: 'HS256' },
23
+ )
31
24
 
32
- redirect ENV['JWT_URL']
33
- end
25
+ @current_scope = payload['scope']
34
26
 
35
- def admin_authorized?
36
- payload, _args = JWT.decode(
37
- token,
38
- ENV['JWT_HMAC_SECRET'],
39
- true,
40
- { algorithm: 'HS256' },
41
- )
42
-
43
- if payload['scope'] == 'admin'
44
- @current_scope = :admin
45
- return true
27
+ true
28
+ rescue JWT::DecodeError
29
+ false
46
30
  end
47
31
 
48
- false
49
- rescue JWT::DecodeError
50
- false
51
- end
32
+ def admin_protected!
33
+ return if admin_authorized?
52
34
 
53
- def token
54
- request.env['admin_token'] || session['admin_token'] || request['admin_token']
55
- end
35
+ redirect ENV['JWT_URL']
36
+ end
56
37
 
57
- def chomp_token
58
- return unless request['admin_token'].present?
38
+ def admin_authorized?
39
+ payload, _args = JWT.decode(
40
+ token,
41
+ ENV['JWT_HMAC_SECRET'],
42
+ true,
43
+ { algorithm: 'HS256' },
44
+ )
59
45
 
60
- session['admin_token'] = request['admin_token']
46
+ if payload['scope'] == 'admin'
47
+ @current_scope = :admin
48
+ return true
49
+ end
61
50
 
62
- return if request.post?
51
+ false
52
+ rescue JWT::DecodeError
53
+ false
54
+ end
55
+
56
+ def token
57
+ request.env['admin_token'] || session['admin_token'] || request['admin_token']
58
+ end
59
+
60
+ def chomp_token
61
+ return unless request['admin_token'].present?
63
62
 
64
- redirect request.path
63
+ session['admin_token'] = request['admin_token']
64
+
65
+ return if request.post?
66
+
67
+ redirect request.path
68
+ end
65
69
  end
66
70
  end
67
71
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Helpers
3
+ module Osso
4
+ module Helpers
5
+ end
4
6
  end
5
7
 
6
8
  require_relative 'auth'
@@ -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
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+
5
+ module Osso
6
+ module RouteMap
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ use Osso::Admin
10
+ use Osso::Auth
11
+ use Osso::Oauth
12
+
13
+ post '/graphql' do
14
+ enterprise_protected!
15
+
16
+ result = Osso::GraphQL::Schema.execute(
17
+ params[:query],
18
+ variables: params[:variables],
19
+ context: { scope: current_scope },
20
+ )
21
+
22
+ json result
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ # rubocop:enable Metrics/MethodLength
@@ -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
@@ -29,4 +29,4 @@ module Osso
29
29
  end
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -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
@@ -19,4 +19,4 @@ module Osso
19
19
  end
20
20
  end
21
21
  end
22
- end
22
+ 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
@@ -6,33 +6,36 @@ module Osso
6
6
  class Admin < Sinatra::Base
7
7
  include AppConfig
8
8
  helpers Helpers::Auth
9
+ register Sinatra::Namespace
9
10
 
10
11
  before do
11
12
  chomp_token
12
13
  end
13
14
 
14
- get '/' do
15
- admin_protected!
15
+ namespace '/admin' do
16
+ get '' do
17
+ admin_protected!
16
18
 
17
- erb :admin
18
- end
19
+ erb :admin
20
+ end
19
21
 
20
- get '/enterprise' do
21
- admin_protected!
22
+ get '/enterprise' do
23
+ admin_protected!
22
24
 
23
- erb :admin
24
- end
25
+ erb :admin
26
+ end
25
27
 
26
- get '/enterprise/:domain' do
27
- enterprise_protected!(params[:domain])
28
+ get '/enterprise/:domain' do
29
+ enterprise_protected!(params[:domain])
28
30
 
29
- erb :admin
30
- end
31
+ erb :admin
32
+ end
31
33
 
32
- get '/config' do
33
- admin_protected!
34
+ get '/config' do
35
+ admin_protected!
34
36
 
35
- erb :admin
37
+ erb :admin
38
+ end
36
39
  end
37
40
  end
38
41
  end