osso 0.0.3.24 → 0.0.5.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/Gemfile.lock +16 -18
  4. data/db/schema.rb +2 -2
  5. data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +10 -14
  6. data/lib/osso/db/migrate/20200913154919_add_one_login_to_identity_provider_service_enum.rb +28 -0
  7. data/lib/osso/db/migrate/20200916125543_add_google_to_identity_provider_service_enum.rb +28 -0
  8. data/lib/osso/graphql/mutations/base_mutation.rb +17 -2
  9. data/lib/osso/graphql/mutations/configure_identity_provider.rb +2 -3
  10. data/lib/osso/graphql/mutations/create_enterprise_account.rb +1 -1
  11. data/lib/osso/graphql/mutations/create_identity_provider.rb +1 -1
  12. data/lib/osso/graphql/mutations/create_oauth_client.rb +1 -1
  13. data/lib/osso/graphql/mutations/delete_enterprise_account.rb +1 -1
  14. data/lib/osso/graphql/mutations/delete_oauth_client.rb +1 -1
  15. data/lib/osso/graphql/mutations/regenerate_oauth_credentials.rb +2 -2
  16. data/lib/osso/graphql/mutations/set_redirect_uris.rb +4 -4
  17. data/lib/osso/graphql/mutations/update_app_config.rb +1 -1
  18. data/lib/osso/graphql/types.rb +1 -0
  19. data/lib/osso/graphql/types/error.rb +20 -0
  20. data/lib/osso/graphql/types/identity_provider.rb +0 -5
  21. data/lib/osso/graphql/types/identity_provider_service.rb +4 -2
  22. data/lib/osso/models/identity_provider.rb +27 -1
  23. data/lib/osso/models/oauth_client.rb +5 -0
  24. data/lib/osso/routes/auth.rb +2 -2
  25. data/lib/osso/version.rb +1 -1
  26. data/spec/factories/identity_providers.rb +2 -0
  27. data/spec/graphql/mutations/configure_identity_provider_spec.rb +1 -1
  28. data/spec/models/identity_provider_spec.rb +23 -1
  29. data/spec/routes/auth_spec.rb +26 -0
  30. data/spec/spec_helper.rb +13 -0
  31. data/spec/support/fixtures/test.pem +30 -0
  32. metadata +9 -7
  33. data/spec/models/azure_saml_provider_spec.rb +0 -19
  34. data/spec/models/okta_saml_provider_spec.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d48075518d12201e52ee12e25f7db5de43ef13e3fc04e8902ba27787aabbd4a
4
- data.tar.gz: f511a13be8a898cf863e00966fc551b3d5a3f4bb5999f534ccb3bf0d1de7004e
3
+ metadata.gz: f0350490feb43457e4c6ed0a230f62c802892309fab6d5b5f720e93930653443
4
+ data.tar.gz: 1e3b77e49d750bb436324f49eeac8c2e02e958f52206e9705b8ce8ca937f5dba
5
5
  SHA512:
6
- metadata.gz: ee6f360d04918e40109a8349a5f8230d79069cd8399731ab98be4cf11d52a1979ca6cdcb5d2f18d2b20f9af1e0bb8d7b1310d30a43ef8dbe9e7835d7e3663b4f
7
- data.tar.gz: d23ba69bfa85ea6174df1789aadad1edc53fcaaffe93cd7f1773d923687bd492d65abe6aba0cd680813c66d84f8410d3b985d1d9453ac0bd2406d416c8e01a1a
6
+ metadata.gz: 9e9326d61c7ba8dbfca73d41c6d49dae57aa2dbee791fa2149dca21b60c3bca87025bcde10cec65e7b167bd14b0ed40ae9dc6a8ab41e76577569e21d5458ed40
7
+ data.tar.gz: 2a8f8bae8ae5c58258f9be18ecbe1b573d6a3a4b420d681ad7c15e658a456088bf9884b21925235ad1ce2ef815a63059a137a72206c995b51038deb3f63dc0bd
@@ -0,0 +1 @@
1
+ 2.6.6
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- osso (0.0.3.24)
4
+ osso (0.0.5.pre.alpha)
5
5
  activesupport (>= 6.0.3.2)
6
6
  graphql
7
7
  jwt
@@ -31,14 +31,13 @@ GEM
31
31
  zeitwerk (~> 2.2, >= 2.2.2)
32
32
  addressable (2.7.0)
33
33
  public_suffix (>= 2.0.2, < 5.0)
34
- aes_key_wrap (1.0.1)
34
+ aes_key_wrap (1.1.0)
35
35
  annotate (3.1.1)
36
36
  activerecord (>= 3.2, < 7.0)
37
37
  rake (>= 10.4, < 14.0)
38
38
  ast (2.4.1)
39
39
  attr_required (1.0.1)
40
- backports (3.18.1)
41
- bindata (2.4.7)
40
+ bindata (2.4.8)
42
41
  coderay (1.1.3)
43
42
  concurrent-ruby (1.1.6)
44
43
  crack (0.4.3)
@@ -53,7 +52,7 @@ GEM
53
52
  activesupport (>= 5.0.0)
54
53
  faker (2.13.0)
55
54
  i18n (>= 1.6, < 2)
56
- graphql (1.11.1)
55
+ graphql (1.11.4)
57
56
  hashdiff (1.0.1)
58
57
  hashie (4.1.0)
59
58
  httpclient (2.8.3)
@@ -64,23 +63,23 @@ GEM
64
63
  activesupport (>= 4.2)
65
64
  aes_key_wrap
66
65
  bindata
67
- jwt (2.2.1)
66
+ jwt (2.2.2)
68
67
  method_source (1.0.0)
69
68
  mini_portile2 (2.4.0)
70
69
  minitest (5.14.1)
71
70
  multi_json (1.15.0)
72
71
  mustermann (1.1.1)
73
72
  ruby2_keywords (~> 0.0.1)
74
- nokogiri (1.10.9)
73
+ nokogiri (1.10.10)
75
74
  mini_portile2 (~> 2.4.0)
76
75
  omniauth (1.9.1)
77
76
  hashie (>= 3.4.6)
78
77
  rack (>= 1.6.2, < 3)
79
78
  omniauth-multi-provider (0.2.1)
80
79
  omniauth
81
- omniauth-saml (1.10.1)
80
+ omniauth-saml (1.10.2)
82
81
  omniauth (~> 1.3, >= 1.3.2)
83
- ruby-saml (~> 1.7)
82
+ ruby-saml (~> 1.9)
84
83
  parallel (1.19.2)
85
84
  parser (2.7.1.4)
86
85
  ast (~> 2.4.1)
@@ -92,13 +91,13 @@ GEM
92
91
  rack (2.2.3)
93
92
  rack-contrib (2.2.0)
94
93
  rack (~> 2.0)
95
- rack-oauth2 (1.14.0)
94
+ rack-oauth2 (1.16.0)
96
95
  activesupport
97
96
  attr_required
98
97
  httpclient
99
98
  json-jwt (>= 1.11.0)
100
99
  rack (>= 2.1.0)
101
- rack-protection (2.0.8.1)
100
+ rack-protection (2.1.0)
102
101
  rack
103
102
  rack-test (1.1.0)
104
103
  rack (>= 1.0, < 3)
@@ -140,20 +139,19 @@ GEM
140
139
  json (>= 1.8, < 3)
141
140
  simplecov-html (~> 0.10.0)
142
141
  simplecov-html (0.10.2)
143
- sinatra (2.0.8.1)
142
+ sinatra (2.1.0)
144
143
  mustermann (~> 1.0)
145
- rack (~> 2.0)
146
- rack-protection (= 2.0.8.1)
144
+ rack (~> 2.2)
145
+ rack-protection (= 2.1.0)
147
146
  tilt (~> 2.0)
148
147
  sinatra-activerecord (2.0.18)
149
148
  activerecord (>= 4.1)
150
149
  sinatra (>= 1.0)
151
- sinatra-contrib (2.0.8.1)
152
- backports (>= 2.8.2)
150
+ sinatra-contrib (2.1.0)
153
151
  multi_json
154
152
  mustermann (~> 1.0)
155
- rack-protection (= 2.0.8.1)
156
- sinatra (= 2.0.8.1)
153
+ rack-protection (= 2.1.0)
154
+ sinatra (= 2.1.0)
157
155
  tilt (~> 2.0)
158
156
  thread_safe (0.3.6)
159
157
  tilt (2.0.10)
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2020_08_26_201852) do
13
+ ActiveRecord::Schema.define(version: 2020_09_13_154919) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "pgcrypto"
@@ -62,7 +62,7 @@ ActiveRecord::Schema.define(version: 2020_08_26_201852) do
62
62
  end
63
63
 
64
64
  # Could not dump table "identity_providers" because of following StandardError
65
- # Unknown type 'identity_provider_status' for column 'status'
65
+ # Unknown type 'identity_provider_service' for column 'service'
66
66
 
67
67
  create_table "oauth_clients", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
68
68
  t.string "name", null: false
@@ -1,17 +1,13 @@
1
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
- change_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
2
+ def up
3
+ execute "CREATE TYPE identity_provider_service AS ENUM ('OKTA', 'AZURE');"
4
+ change_column :identity_providers, :service, 'identity_provider_service USING CAST(service as identity_provider_service)'
5
+ end
6
+
7
+ def down
8
+ chnage_column :identity_providers, :service, :text
9
+ execute <<-SQL
10
+ DROP TYPE identity_provider_service;
11
+ SQL
16
12
  end
17
13
  end
@@ -0,0 +1,28 @@
1
+ class AddOneLoginToIdentityProviderServiceEnum < ActiveRecord::Migration[6.0]
2
+ disable_ddl_transaction!
3
+
4
+ def up
5
+ execute <<-SQL
6
+ ALTER TYPE identity_provider_service ADD VALUE 'ONELOGIN';
7
+ SQL
8
+ end
9
+
10
+ def down
11
+ execute <<~SQL
12
+ CREATE TYPE identity_provider_service_new AS ENUM ('AZURE', 'OKTA');
13
+
14
+ -- Remove values that won't be compatible with new definition
15
+ DELETE FROM identity_providers WHERE service = 'ONELOGIN';
16
+
17
+ -- Convert to new type, casting via text representation
18
+ ALTER TABLE identity_providers
19
+ ALTER COLUMN service TYPE identity_provider_service_new
20
+ USING (service::text::identity_provider_service_new);
21
+
22
+ -- and swap the types
23
+ DROP TYPE identity_provider_service;
24
+
25
+ ALTER TYPE identity_provider_service_new RENAME TO identity_provider_service;
26
+ SQL
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ class AddGoogleToIdentityProviderServiceEnum < ActiveRecord::Migration[6.0]
2
+ disable_ddl_transaction!
3
+
4
+ def up
5
+ execute <<-SQL
6
+ ALTER TYPE identity_provider_service ADD VALUE 'GOOGLE';
7
+ SQL
8
+ end
9
+
10
+ def down
11
+ execute <<~SQL
12
+ CREATE TYPE identity_provider_service_new AS ENUM ('AZURE', 'OKTA', 'ONELOGIN');
13
+
14
+ -- Remove values that won't be compatible with new definition
15
+ DELETE FROM identity_providers WHERE service = 'GOOGLE';
16
+
17
+ -- Convert to new type, casting via text representation
18
+ ALTER TABLE identity_providers
19
+ ALTER COLUMN service TYPE identity_provider_service_new
20
+ USING (service::text::identity_provider_service_new);
21
+
22
+ -- and swap the types
23
+ DROP TYPE identity_provider_service;
24
+
25
+ ALTER TYPE identity_provider_service_new RENAME TO identity_provider_service;
26
+ SQL
27
+ end
28
+ end
@@ -11,8 +11,23 @@ module Osso
11
11
  data.merge(errors: [])
12
12
  end
13
13
 
14
- def response_error(error)
15
- error.merge(data: nil)
14
+ def response_error(errors)
15
+ raise ::GraphQL::ExecutionError.new(
16
+ 'Mutation error',
17
+ extensions: {
18
+ 'errors' => field_errors(errors),
19
+ },
20
+ )
21
+ end
22
+
23
+ def field_errors(errors)
24
+ errors.map do |attribute, messages|
25
+ attribute = attribute.to_s.camelize(:lower)
26
+ {
27
+ attribute: attribute,
28
+ message: messages,
29
+ }
30
+ end
16
31
  end
17
32
 
18
33
  def ready?(**args)
@@ -10,15 +10,14 @@ module Osso
10
10
  argument :sso_url, String, required: false
11
11
  argument :sso_cert, String, required: false
12
12
 
13
- field :identity_provider, Types::IdentityProvider, null: false
14
- field :errors, [String], null: false
13
+ field :identity_provider, Types::IdentityProvider, null: true
15
14
 
16
15
  def resolve(**args)
17
16
  provider = identity_provider(**args)
18
17
 
19
18
  return response_data(identity_provider: provider) if provider.update(args)
20
19
 
21
- response_error(errors: provider.errors.messages)
20
+ response_error(provider.errors)
22
21
  end
23
22
 
24
23
  def domain(**args)
@@ -19,7 +19,7 @@ module Osso
19
19
 
20
20
  return response_data(enterprise_account: enterprise_account) if enterprise_account.save
21
21
 
22
- response_error(errors: enterprise_account.errors.full_messages)
22
+ response_error(enterprise_account.errors)
23
23
  end
24
24
 
25
25
  def find_client_db_id(oauth_client_identifier)
@@ -23,7 +23,7 @@ module Osso
23
23
 
24
24
  return response_data(identity_provider: identity_provider) if identity_provider.save
25
25
 
26
- response_error(errors: identity_provider.errors.full_messages)
26
+ response_error(identity_provider.errors)
27
27
  end
28
28
 
29
29
  def domain(**args)
@@ -16,7 +16,7 @@ module Osso
16
16
 
17
17
  return response_data(oauth_client: oauth_client) if oauth_client.save
18
18
 
19
- response_error(errors: oauth_client.errors.full_messages)
19
+ response_error(oauth_client.errors)
20
20
  end
21
21
 
22
22
  def ready?(*)
@@ -20,7 +20,7 @@ module Osso
20
20
 
21
21
  return response_data(enterprise_account: nil) if customer.destroy
22
22
 
23
- response_error(errors: customer.errors.full_messages)
23
+ response_error(customer.errors)
24
24
  end
25
25
 
26
26
  def domain(**args)
@@ -16,7 +16,7 @@ module Osso
16
16
 
17
17
  return response_data(oauth_client: nil) if oauth_client.destroy
18
18
 
19
- response_error(errors: oauth_client.errors.full_messages)
19
+ response_error(oauth_client.errors)
20
20
  end
21
21
 
22
22
  def ready?(*)
@@ -13,11 +13,11 @@ module Osso
13
13
 
14
14
  def resolve(id:)
15
15
  oauth_client = Osso::Models::OauthClient.find(id)
16
- oauth_client.generate_secrets
16
+ oauth_client.regenerate_secrets!
17
17
 
18
18
  return response_data(oauth_client: oauth_client) if oauth_client.save
19
19
 
20
- response_error(errors: oauth_client.errors.full_messages)
20
+ response_error(oauth_client.errors)
21
21
  end
22
22
 
23
23
  def ready?(*)
@@ -20,7 +20,7 @@ module Osso
20
20
 
21
21
  response_data(oauth_client: oauth_client.reload)
22
22
  rescue StandardError => e
23
- response_error(errors: e)
23
+ response_error(e)
24
24
  end
25
25
 
26
26
  def ready?(*)
@@ -33,17 +33,17 @@ module Osso
33
33
 
34
34
  if updating_index
35
35
  updating = redirect_uris.delete_at(updating_index)
36
- redirect.update(updating.to_h)
36
+ redirect.update!(updating.to_h)
37
37
  next
38
38
  end
39
39
 
40
- redirect.destroy
40
+ redirect.destroy!
41
41
  end
42
42
  end
43
43
 
44
44
  def create_new(oauth_client, redirect_uris)
45
45
  redirect_uris.map do |uri|
46
- oauth_client.redirect_uris.create(uri.to_h.without(:id))
46
+ oauth_client.redirect_uris.create!(uri.to_h.without(:id))
47
47
  end
48
48
  end
49
49
  end
@@ -17,7 +17,7 @@ module Osso
17
17
  app_config = Osso::Models::AppConfig.find
18
18
  return response_data(app_config: app_config) if app_config.update(**args)
19
19
 
20
- response_error(errors: e)
20
+ response_error(app_config.errors)
21
21
  end
22
22
 
23
23
  def ready?(*)
@@ -11,6 +11,7 @@ require_relative 'types/base_enum'
11
11
  require_relative 'types/base_input_object'
12
12
  require_relative 'types/admin_user'
13
13
  require_relative 'types/app_config'
14
+ require_relative 'types/error'
14
15
  require_relative 'types/identity_provider_service'
15
16
  require_relative 'types/identity_provider_status'
16
17
  require_relative 'types/identity_provider'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+
5
+ module Osso
6
+ module GraphQL
7
+ module Types
8
+ class Error < Types::BaseObject
9
+ description 'A mutation error'
10
+
11
+ field :attribute, String, null: false
12
+ field :message, String, null: false
13
+
14
+ def self.authorized?(_object, _context)
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -16,11 +16,6 @@ module Osso
16
16
  field :sso_url, String, null: true
17
17
  field :sso_cert, String, null: true
18
18
  field :status, Types::IdentityProviderStatus, null: false
19
- field :documentation_pdf_url, String, null: true
20
-
21
- def documentation_pdf_url
22
- ENV['BASE_URL'] + '/identity_provider/documentation/' + @object.id
23
- end
24
19
  end
25
20
  end
26
21
  end
@@ -4,8 +4,10 @@ module Osso
4
4
  module GraphQL
5
5
  module Types
6
6
  class IdentityProviderService < BaseEnum
7
- value('AZURE', 'Microsoft Azure Identity Provider', value: 'Osso::Models::AzureSamlProvider')
8
- value('OKTA', 'Okta Identity Provider', value: 'Osso::Models::OktaSamlProvider')
7
+ value('AZURE', 'Microsoft Azure Identity Provider', value: 'AZURE')
8
+ value('OKTA', 'Okta Identity Provider', value: 'OKTA')
9
+ value('ONELOGIN', 'OneLogin Identity Provider', value: 'ONELOGIN')
10
+ value('GOOGLE', 'Google SAML Identity Provider', value: 'GOOGLE')
9
11
  end
10
12
  end
11
13
  end
@@ -4,11 +4,14 @@ module Osso
4
4
  module Models
5
5
  # Base class for SAML Providers
6
6
  class IdentityProvider < ActiveRecord::Base
7
- NAME_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
8
7
  belongs_to :enterprise_account
9
8
  belongs_to :oauth_client
10
9
  has_many :users
11
10
  before_save :set_status
11
+ validate :sso_cert_valid
12
+
13
+ PEM_HEADER = "-----BEGIN CERTIFICATE-----\n"
14
+ PEM_FOOTER = "\n-----END CERTIFICATE-----"
12
15
 
13
16
  def name
14
17
  service.titlecase
@@ -41,11 +44,34 @@ module Osso
41
44
  self.status = 'CONFIGURED' if sso_url && sso_cert
42
45
  end
43
46
 
47
+ def active!
48
+ update(status: 'ACTIVE')
49
+ end
50
+
51
+ def error!
52
+ update(status: 'ERROR')
53
+ end
54
+
44
55
  def root_url
45
56
  return "https://#{ENV['HEROKU_APP_NAME']}.herokuapp.com" if ENV['HEROKU_APP_NAME']
46
57
 
47
58
  ENV.fetch('BASE_URL')
48
59
  end
60
+
61
+ def sso_cert_valid
62
+ return if sso_cert.blank?
63
+
64
+ has_header_and_footer = sso_cert.match(/#{PEM_HEADER}(?<cert>.*)#{PEM_FOOTER}/m)
65
+
66
+ if has_header_and_footer
67
+ OpenSSL::X509::Certificate.new(sso_cert)
68
+ self.sso_cert = has_header_and_footer[:cert]
69
+ else
70
+ OpenSSL::X509::Certificate.new([PEM_HEADER, sso_cert, PEM_FOOTER].join)
71
+ end
72
+ rescue OpenSSL::X509::CertificateError
73
+ errors.add(:sso_cert, 'x509 Certificate is malformed')
74
+ end
49
75
  end
50
76
  end
51
77
  end
@@ -26,6 +26,11 @@ module Osso
26
26
  self.identifier ||= SecureRandom.hex(16)
27
27
  self.secret ||= SecureRandom.hex(32)
28
28
  end
29
+
30
+ def regenerate_secrets!
31
+ self.identifier = SecureRandom.hex(16)
32
+ self.secret = SecureRandom.hex(32)
33
+ end
29
34
  end
30
35
  end
31
36
  end
@@ -41,6 +41,7 @@ module Osso
41
41
  provider = Models::IdentityProvider.find(params[:id])
42
42
  @oauth_client = provider.oauth_client
43
43
 
44
+ # TODO: PORC for validating attributes
44
45
  attributes = env['omniauth.auth']&.
45
46
  extra&.
46
47
  response_object&.
@@ -58,8 +59,7 @@ module Osso
58
59
  oauth_client: @oauth_client,
59
60
  redirect_uri: redirect_uri,
60
61
  )
61
-
62
- # Mark IDP as active
62
+ provider.active!
63
63
 
64
64
  redirect(redirect_uri + "?code=#{CGI.escape(authorization_code.token)}&state=#{provider_state}")
65
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Osso
4
- VERSION = '0.0.3.24'
4
+ VERSION = '0.0.5-alpha'
5
5
  end
@@ -5,6 +5,7 @@ FactoryBot.define do
5
5
  id { SecureRandom.uuid }
6
6
  domain { Faker::Internet.domain_name }
7
7
  oauth_client
8
+ status { 'PENDING' }
8
9
 
9
10
  factory :okta_identity_provider, parent: :identity_provider do
10
11
  service { 'OKTA' }
@@ -21,6 +22,7 @@ FactoryBot.define do
21
22
  end
22
23
 
23
24
  factory :configured_identity_provider, parent: :identity_provider do
25
+ status { 'CONFIGURED' }
24
26
  sso_cert do
25
27
  <<~CERT
26
28
  -----BEGIN CERTIFICATE-----
@@ -12,7 +12,7 @@ describe Osso::GraphQL::Schema do
12
12
  id: identity_provider.id,
13
13
  service: 'OKTA',
14
14
  ssoUrl: 'https://example.com',
15
- ssoCert: 'BEGIN_CERTIFICATE',
15
+ ssoCert: valid_x509_pem,
16
16
  },
17
17
  }
18
18
  end
@@ -7,10 +7,11 @@ describe Osso::Models::IdentityProvider do
7
7
 
8
8
  describe '#assertion_consumer_service_url' do
9
9
  it 'returns the expected URI for BASE_URL' do
10
+ ENV['HEROKU_APP_NAME'] = nil
10
11
  ENV['BASE_URL'] = 'https://example.com'
11
12
 
12
13
  expect(subject.assertion_consumer_service_url).to eq(
13
- "https://example.com/auth/saml/#{subject.id}/callback",
14
+ "#{ENV['BASE_URL']}/auth/saml/#{subject.id}/callback",
14
15
  )
15
16
  end
16
17
 
@@ -34,4 +35,25 @@ describe Osso::Models::IdentityProvider do
34
35
  )
35
36
  end
36
37
  end
38
+
39
+ describe '#validate_sso_cert' do
40
+ it 'rejects an invalid cert' do
41
+ subject.update(sso_cert: 'bad-cert')
42
+
43
+ expect(subject.errors.full_messages.first).to include('x509 Certificate is malformed')
44
+ end
45
+
46
+ it 'massages a cert with header and footer' do
47
+ subject.update(sso_cert: valid_x509_pem)
48
+
49
+ expect(subject.errors).to be_empty
50
+ expect(subject.sso_cert).to_not include('BEGIN CERTIFICATE')
51
+ end
52
+
53
+ it 'accepts a cert without header and footer' do
54
+ subject.update(sso_cert: raw_x509_string)
55
+
56
+ expect(subject.errors).to be_empty
57
+ end
58
+ end
37
59
  end
@@ -104,6 +104,17 @@ describe Osso::Auth do
104
104
  )
105
105
  end.to_not(change { Osso::Models::User.count })
106
106
  end
107
+ it 'marks the provider as ACTIVE' do
108
+ post(
109
+ "/auth/saml/#{okta_provider.id}/callback",
110
+ nil,
111
+ {
112
+ 'omniauth.auth' => OmniAuth.config.mock_auth[:saml],
113
+ 'identity_provider' => okta_provider,
114
+ },
115
+ )
116
+ expect(okta_provider.reload.status).to eq('ACTIVE')
117
+ end
107
118
  end
108
119
  end
109
120
 
@@ -126,6 +137,21 @@ describe Osso::Auth do
126
137
  )
127
138
  end.to change { Osso::Models::User.count }.by(1)
128
139
  end
140
+
141
+ it 'marks the provider ACTIVE' do
142
+ mock_saml_omniauth
143
+
144
+ post(
145
+ "/auth/saml/#{azure_provider.id}/callback",
146
+ nil,
147
+ {
148
+ 'omniauth.auth' => OmniAuth.config.mock_auth[:saml],
149
+ 'identity_provider' => azure_provider,
150
+ },
151
+ )
152
+
153
+ expect(azure_provider.reload.status).to eq('ACTIVE')
154
+ end
129
155
  end
130
156
 
131
157
  describe 'on subsequent authentications' do
@@ -21,6 +21,9 @@ require File.expand_path '../lib/osso.rb', __dir__
21
21
  require File.expand_path 'support/spec_app', __dir__
22
22
 
23
23
  module RSpecMixin
24
+ PEM_HEADER = "-----BEGIN CERTIFICATE-----\n"
25
+ PEM_FOOTER = "\n-----END CERTIFICATE-----"
26
+
24
27
  include Rack::Test::Methods
25
28
 
26
29
  def app
@@ -46,6 +49,16 @@ module RSpecMixin
46
49
  def spec_views
47
50
  File.dirname(__FILE__) + '/support/views'
48
51
  end
52
+
53
+ def valid_x509_pem
54
+ raw = File.read(File.dirname(__FILE__) + '/support/fixtures/test.pem')
55
+ OpenSSL::X509::Certificate.new(raw).to_pem
56
+ end
57
+
58
+ def raw_x509_string
59
+ raw = valid_x509_pem.match(/#{PEM_HEADER}(?<cert>.*)#{PEM_FOOTER}/m)
60
+ raw[:cert]
61
+ end
49
62
  end
50
63
 
51
64
  RSpec.configure do |config|
@@ -0,0 +1,30 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANDYf/XXreldztPH
3
+ 0IJSkvgeQVZCu1ie+D2Ij9nEzJAuM10bD4p2IjI8EQUKUTn1OBbX4ykhn5Ovw9SU
4
+ D8qEllQCzq7zuX54BEm8cHX3IXTpMLM90T2zJayS+3hQqXHzGXeX3fuP1KhNrrkL
5
+ HAlDEtVD/vwIci/TS2Mep7weytOjAgMBAAECgYA23kpwCmQUhaLLHRn4wzz9luVP
6
+ hmS2Gb3aXMB+VCfyUVEJSwzAMd02GXXXPyir83Ly/XEe40iLgogOl3+2kzLzEegI
7
+ 1wx9mydlar0kBIDKJkYdnikbvy0IKFNXRxqHl0Oecy9lArDKmBmadYsse8hsZLX2
8
+ eZUmB8G50TeDyz/4gQJBAO1OM4dT/Uo/zTaTDMs7A+td1C4gvjpI7aKPwHdwmvoc
9
+ dQN9BKoAV0EMoUcXvAeVreWEYGZrMwXQB6xT7aydyUMCQQDhTFffVlvsqOmQYhzf
10
+ lbKS8orI0SZZHz8F5dnj1zwb4Xp+hl6tIAkxcZ1DxP4emfc1htd4GswzNqSVfFJv
11
+ JXYhAkEAsmdWSekUxVtN9jd7KNbHTY2O1Nb87GijbtFPyvu3J015kxPMC9qRvm+2
12
+ V/I6BCG9SI3Kw3TYOQh6nE3Eoz9EbQJBAKvzm4F+pOwsQw8KguT2mPNkoB4C2xTc
13
+ LzquIi2t4VeaMOaOYYYa1EljYFcP66+pbS7yOlOViFJyGw1odHYWDmECQCBGi7f5
14
+ qT4Bs3DoaIyD0w9F3LY/ny7+Pa7WGUqQvQWygUDObBtwojXhg/A9BGckUrQ2jmu/
15
+ bhqnqQJs3f05ETA=
16
+ -----END PRIVATE KEY-----
17
+ -----BEGIN CERTIFICATE-----
18
+ MIICDTCCAXYCCQCm0tqsG7zO2TANBgkqhkiG9w0BAQsFADBLMQswCQYDVQQGEwJV
19
+ UzERMA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCEJyb29rbHluMRYwFAYDVQQK
20
+ DA1FbnRlcnByaXNlT1NTMB4XDTIwMDkwMjE0MTEyMVoXDTIxMDkwMjE0MTEyMVow
21
+ SzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhCcm9v
22
+ a2x5bjEWMBQGA1UECgwNRW50ZXJwcmlzZU9TUzCBnzANBgkqhkiG9w0BAQEFAAOB
23
+ jQAwgYkCgYEA0Nh/9det6V3O08fQglKS+B5BVkK7WJ74PYiP2cTMkC4zXRsPinYi
24
+ MjwRBQpROfU4FtfjKSGfk6/D1JQPyoSWVALOrvO5fngESbxwdfchdOkwsz3RPbMl
25
+ rJL7eFCpcfMZd5fd+4/UqE2uuQscCUMS1UP+/AhyL9NLYx6nvB7K06MCAwEAATAN
26
+ BgkqhkiG9w0BAQsFAAOBgQDGze/POq+GSwOIYftr83+YkNTIQAg+bl8hiFMtJ3OV
27
+ buFsI/oUGaKloXOrDLbygk+lvimFbj36k3IhwRI7iXJDCwZGxtVCC4+8VNqqT1Yj
28
+ uZT9xHGYVszzGc8nz4wcaQ8M/W4mCuXet1qDwAi0Zo9yLBnyEdc6pluDdJuz0cg6
29
+ xQ==
30
+ -----END CERTIFICATE-----
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.3.24
4
+ version: 0.0.5.pre.alpha
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-08-28 00:00:00.000000000 Z
11
+ date: 2020-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -231,7 +231,6 @@ executables:
231
231
  extensions: []
232
232
  extra_rdoc_files: []
233
233
  files:
234
- - ".DS_Store"
235
234
  - ".buildkite/hooks/environment"
236
235
  - ".buildkite/hooks/pre-command"
237
236
  - ".buildkite/pipeline.yml"
@@ -239,6 +238,7 @@ files:
239
238
  - ".gitignore"
240
239
  - ".rspec"
241
240
  - ".rubocop.yml"
241
+ - ".ruby-version"
242
242
  - CODE_OF_CONDUCT.md
243
243
  - Gemfile
244
244
  - Gemfile.lock
@@ -271,6 +271,8 @@ files:
271
271
  - lib/osso/db/migrate/20200723153750_add_missing_timestamps.rb
272
272
  - lib/osso/db/migrate/20200723162228_drop_unneeded_tables.rb
273
273
  - lib/osso/db/migrate/20200826201852_create_app_config.rb
274
+ - lib/osso/db/migrate/20200913154919_add_one_login_to_identity_provider_service_enum.rb
275
+ - lib/osso/db/migrate/20200916125543_add_google_to_identity_provider_service_enum.rb
274
276
  - lib/osso/graphql/.DS_Store
275
277
  - lib/osso/graphql/mutation.rb
276
278
  - lib/osso/graphql/mutations.rb
@@ -299,6 +301,7 @@ files:
299
301
  - lib/osso/graphql/types/base_input_object.rb
300
302
  - lib/osso/graphql/types/base_object.rb
301
303
  - lib/osso/graphql/types/enterprise_account.rb
304
+ - lib/osso/graphql/types/error.rb
302
305
  - lib/osso/graphql/types/identity_provider.rb
303
306
  - lib/osso/graphql/types/identity_provider_service.rb
304
307
  - lib/osso/graphql/types/identity_provider_status.rb
@@ -346,14 +349,13 @@ files:
346
349
  - spec/graphql/query/identity_provider_spec.rb
347
350
  - spec/graphql/query/oauth_clients_spec.rb
348
351
  - spec/helpers/auth_spec.rb
349
- - spec/models/azure_saml_provider_spec.rb
350
352
  - spec/models/identity_provider_spec.rb
351
- - spec/models/okta_saml_provider_spec.rb
352
353
  - spec/routes/admin_spec.rb
353
354
  - spec/routes/app_spec.rb
354
355
  - spec/routes/auth_spec.rb
355
356
  - spec/routes/oauth_spec.rb
356
357
  - spec/spec_helper.rb
358
+ - spec/support/fixtures/test.pem
357
359
  - spec/support/spec_app.rb
358
360
  - spec/support/views/admin.erb
359
361
  - spec/support/views/error.erb
@@ -372,9 +374,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
372
374
  version: 2.3.0
373
375
  required_rubygems_version: !ruby/object:Gem::Requirement
374
376
  requirements:
375
- - - ">="
377
+ - - ">"
376
378
  - !ruby/object:Gem::Version
377
- version: '0'
379
+ version: 1.3.1
378
380
  requirements: []
379
381
  rubygems_version: 3.0.3
380
382
  signing_key:
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- # describe Osso::Models::AzureSamlProvider do
6
- # subject { create(:azure_identity_provider) }
7
-
8
- # describe '#saml_options' do
9
- # it 'returns the required args' do
10
- # expect(subject.saml_options).
11
- # to match(
12
- # domain: subject.domain,
13
- # idp_cert: subject.idp_cert,
14
- # idp_sso_target_url: subject.idp_sso_target_url,
15
- # issuer: "id:#{subject.id}",
16
- # )
17
- # end
18
- # end
19
- # end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- # describe Osso::Models::OktaSamlProvider do
6
- # subject { create(:okta_identity_provider) }
7
-
8
- # describe '#saml_options' do
9
- # it 'returns the required args' do
10
- # expect(subject.saml_options).
11
- # to match(
12
- # domain: subject.domain,
13
- # idp_cert: subject.idp_cert,
14
- # idp_sso_target_url: subject.idp_sso_target_url,
15
- # issuer: subject.id,
16
- # name_identifier_format: described_class::NAME_FORMAT,
17
- # )
18
- # end
19
- # end
20
- # end