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.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.yml +4 -1
- data/Gemfile.lock +1 -1
- data/config/database.yml +2 -2
- data/db/schema.rb +133 -1
- data/lib/osso/db/migrate/20200328143305_create_identity_providers.rb +12 -0
- data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +2 -2
- data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +1 -1
- data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_accounts_and_identity_providers.rb +6 -0
- data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +17 -0
- data/lib/osso/db/migrate/20200715154211_rename_idp_fields_on_identity_provider_to_sso.rb +6 -0
- data/lib/osso/db/migrate/20200715205801_add_name_to_enterprise_account.rb +5 -0
- data/lib/osso/graphql/mutation.rb +2 -1
- data/lib/osso/graphql/mutations.rb +2 -1
- data/lib/osso/graphql/mutations/base_mutation.rb +18 -7
- data/lib/osso/graphql/mutations/configure_identity_provider.rb +10 -13
- data/lib/osso/graphql/mutations/create_enterprise_account.rb +25 -0
- data/lib/osso/graphql/mutations/create_identity_provider.rb +9 -7
- data/lib/osso/graphql/mutations/{set_saml_provider.rb → set_identity_provider.rb} +4 -4
- data/lib/osso/graphql/query.rb +2 -2
- data/lib/osso/graphql/resolvers/oauth_clients.rb +1 -1
- data/lib/osso/graphql/schema.rb +1 -1
- data/lib/osso/graphql/types.rb +1 -0
- data/lib/osso/graphql/types/base_input_object.rb +10 -0
- data/lib/osso/graphql/types/enterprise_account.rb +1 -5
- data/lib/osso/graphql/types/identity_provider.rb +1 -13
- data/lib/osso/lib/app_config.rb +1 -1
- data/lib/osso/models/enterprise_account.rb +4 -4
- data/lib/osso/models/identity_provider.rb +48 -0
- data/lib/osso/models/models.rb +1 -1
- data/lib/osso/models/oauth_client.rb +1 -1
- data/lib/osso/models/saml_provider.rb +13 -16
- data/lib/osso/models/saml_providers/azure_saml_provider.rb +1 -1
- data/lib/osso/models/saml_providers/okta_saml_provider.rb +1 -1
- data/lib/osso/models/user.rb +3 -3
- data/lib/osso/routes/auth.rb +4 -4
- data/lib/osso/routes/oauth.rb +1 -1
- data/lib/osso/version.rb +1 -1
- data/spec/factories/enterprise_account.rb +5 -4
- data/spec/factories/identity_providers.rb +49 -0
- data/spec/factories/user.rb +1 -1
- data/spec/graphql/mutations/configure_identity_provider_spec.rb +65 -0
- data/spec/graphql/mutations/create_enterprise_account_spec.rb +68 -0
- data/spec/graphql/mutations/create_identity_provider_spec.rb +104 -0
- data/spec/graphql/query/enterprise_account_spec.rb +68 -0
- data/spec/graphql/query/enterprise_accounts_spec.rb +44 -0
- data/spec/graphql/query/identity_provider_spec.rb +62 -0
- data/spec/graphql/query/oauth_clients_account_spec.rb +48 -0
- data/spec/models/azure_saml_provider_spec.rb +14 -14
- data/spec/models/identity_provider_spec.rb +17 -0
- data/spec/models/okta_saml_provider_spec.rb +15 -15
- data/spec/routes/auth_spec.rb +9 -9
- data/spec/routes/oauth_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +20 -12
- data/lib/osso/db/migrate/20200411144528_create_saml_providers.rb +0 -13
- data/lib/osso/db/migrate/20200413153029_add_oauth_client_reference_to_saml_providers.rb +0 -5
- data/lib/osso/db/migrate/20200501203026_drop_null_constraints_from_saml_provider.rb +0 -7
- data/lib/osso/db/migrate/20200501204047_drop_acs_url.rb +0 -5
- data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_account.rb +0 -5
- data/lib/osso/db/migrate/20200601131227_drop_null_constraint_from_saml_providers_provider.rb +0 -7
- data/lib/osso/db/schema.rb +0 -132
- data/spec/factories/saml_providers.rb +0 -46
- data/spec/models/saml_provider_spec.rb +0 -31
data/lib/osso/graphql/schema.rb
CHANGED
data/lib/osso/graphql/types.rb
CHANGED
@@ -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'
|
@@ -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.
|
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.
|
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
|
data/lib/osso/lib/app_config.rb
CHANGED
@@ -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
|
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 :
|
13
|
+
has_many :identity_providers
|
14
14
|
|
15
15
|
def single_provider?
|
16
|
-
|
16
|
+
identity_providers.one?
|
17
17
|
end
|
18
18
|
|
19
19
|
def provider
|
20
20
|
return nil unless single_provider?
|
21
21
|
|
22
|
-
|
22
|
+
identity_providers.first
|
23
23
|
end
|
24
24
|
|
25
|
-
alias
|
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
|
data/lib/osso/models/models.rb
CHANGED
@@ -3,28 +3,27 @@
|
|
3
3
|
module Osso
|
4
4
|
module Models
|
5
5
|
# Base class for SAML Providers
|
6
|
-
class
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
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'
|
data/lib/osso/models/user.rb
CHANGED
@@ -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 :
|
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
|
-
|
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:
|
19
|
+
idp: identity_provider.name,
|
20
20
|
}
|
21
21
|
end
|
22
22
|
end
|
data/lib/osso/routes/auth.rb
CHANGED
@@ -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 |
|
29
|
-
provider = Models::
|
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::
|
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.
|
55
|
+
new_user.identity_provider_id = provider.id
|
56
56
|
end
|
57
57
|
|
58
58
|
authorization_code = user.authorization_codes.create!(
|
data/lib/osso/routes/oauth.rb
CHANGED
@@ -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(:
|
17
|
+
includes(:identity_providers).
|
18
18
|
find_by!(domain: params[:domain])
|
19
19
|
|
20
20
|
Rack::OAuth2::Server::Authorize.new do |req, _res|
|
data/lib/osso/version.rb
CHANGED
@@ -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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
34
|
+
:okta_identity_provider,
|
34
35
|
domain: enterprise.domain,
|
35
36
|
enterprise_account_id: enterprise.id,
|
36
37
|
)
|
37
38
|
|
38
39
|
create(
|
39
|
-
:
|
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
|
data/spec/factories/user.rb
CHANGED
@@ -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
|
-
|
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
|