osso 0.0.2.8

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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.buildkite/hooks/environment +9 -0
  4. data/.buildkite/hooks/pre-command +7 -0
  5. data/.buildkite/pipeline.yml +3 -0
  6. data/.buildkite/template.yml +5 -0
  7. data/.gitignore +9 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +82 -0
  10. data/CODE_OF_CONDUCT.md +130 -0
  11. data/Gemfile +18 -0
  12. data/Gemfile.lock +174 -0
  13. data/LICENSE +111 -0
  14. data/README.md +2 -0
  15. data/Rakefile +14 -0
  16. data/bin/console +7 -0
  17. data/bin/setup +8 -0
  18. data/config/database.yml +14 -0
  19. data/lib/.DS_Store +0 -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/20200411144528_create_saml_providers.rb +13 -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/20200413153029_add_oauth_client_reference_to_saml_providers.rb +5 -0
  30. data/lib/osso/db/migrate/20200413163451_create_access_tokens.rb +13 -0
  31. data/lib/osso/db/migrate/20200501203026_drop_null_constraints_from_saml_provider.rb +7 -0
  32. data/lib/osso/db/migrate/20200501204047_drop_acs_url.rb +5 -0
  33. data/lib/osso/db/migrate/20200502120616_create_redirect_uris_and_drop_from_oauth_clients.rb +13 -0
  34. data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_account.rb +5 -0
  35. data/lib/osso/db/migrate/20200601131227_drop_null_constraint_from_saml_providers_provider.rb +7 -0
  36. data/lib/osso/db/schema.rb +132 -0
  37. data/lib/osso/helpers/auth.rb +67 -0
  38. data/lib/osso/helpers/helpers.rb +6 -0
  39. data/lib/osso/lib/app_config.rb +20 -0
  40. data/lib/osso/lib/oauth2_token.rb +38 -0
  41. data/lib/osso/models/access_token.rb +29 -0
  42. data/lib/osso/models/authorization_code.rb +14 -0
  43. data/lib/osso/models/enterprise_account.rb +28 -0
  44. data/lib/osso/models/models.rb +16 -0
  45. data/lib/osso/models/oauth_client.rb +32 -0
  46. data/lib/osso/models/redirect_uri.rb +20 -0
  47. data/lib/osso/models/saml_provider.rb +52 -0
  48. data/lib/osso/models/saml_providers/azure_saml_provider.rb +22 -0
  49. data/lib/osso/models/saml_providers/okta_saml_provider.rb +23 -0
  50. data/lib/osso/models/user.rb +24 -0
  51. data/lib/osso/rake.rb +4 -0
  52. data/lib/osso/routes/admin.rb +42 -0
  53. data/lib/osso/routes/auth.rb +64 -0
  54. data/lib/osso/routes/oauth.rb +57 -0
  55. data/lib/osso/routes/routes.rb +10 -0
  56. data/lib/osso/routes/views/error.erb +1 -0
  57. data/lib/osso/routes/views/multiple_providers.erb +1 -0
  58. data/lib/osso/version.rb +5 -0
  59. data/lib/osso.rb +9 -0
  60. data/lib/tasks/bootstrap.rake +17 -0
  61. data/osso-rb.gemspec +40 -0
  62. data/spec/factories/authorization_code.rb +10 -0
  63. data/spec/factories/enterprise_account.rb +45 -0
  64. data/spec/factories/oauth_client.rb +12 -0
  65. data/spec/factories/redirect_uri.rb +14 -0
  66. data/spec/factories/saml_providers.rb +46 -0
  67. data/spec/factories/user.rb +18 -0
  68. data/spec/models/azure_saml_provider_spec.rb +19 -0
  69. data/spec/models/okta_saml_provider_spec.rb +20 -0
  70. data/spec/models/saml_provider_spec.rb +31 -0
  71. data/spec/routes/admin_spec.rb +57 -0
  72. data/spec/routes/app_spec.rb +6 -0
  73. data/spec/routes/auth_spec.rb +112 -0
  74. data/spec/routes/oauth_spec.rb +134 -0
  75. data/spec/spec_helper.rb +65 -0
  76. data/spec/support/vcr_cassettes/okta_saml_callback.yml +59 -0
  77. metadata +302 -0
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ # Subclass for Azure / ADFS IDP instances
6
+ class AzureSamlProvider < Models::SamlProvider
7
+ def name
8
+ 'Azure'
9
+ end
10
+
11
+ def saml_options
12
+ attributes.slice(
13
+ 'domain',
14
+ 'idp_cert',
15
+ 'idp_sso_target_url',
16
+ ).merge(
17
+ issuer: "id:#{id}",
18
+ ).symbolize_keys
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ # Subclass for Okta IDP instances
6
+ class OktaSamlProvider < Models::SamlProvider
7
+ def name
8
+ 'Okta'
9
+ end
10
+
11
+ def saml_options
12
+ attributes.slice(
13
+ 'domain',
14
+ 'idp_cert',
15
+ 'idp_sso_target_url',
16
+ ).merge(
17
+ issuer: id,
18
+ name_identifier_format: NAME_FORMAT,
19
+ ).symbolize_keys
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ class User < ActiveRecord::Base
6
+ belongs_to :enterprise_account
7
+ belongs_to :saml_provider
8
+ has_many :authorization_codes, dependent: :delete_all
9
+ has_many :access_tokens, dependent: :delete_all
10
+
11
+ def oauth_client
12
+ saml_provider.oauth_client
13
+ end
14
+
15
+ def as_json(*)
16
+ {
17
+ email: email,
18
+ id: id,
19
+ idp: saml_provider.name,
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
data/lib/osso/rake.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ load 'active_record/railties/databases.rake'
4
+ require "sinatra/activerecord/rake/activerecord_#{ActiveRecord::VERSION::MAJOR}"
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jwt'
4
+
5
+ module Osso
6
+ class Admin < Sinatra::Base
7
+ include AppConfig
8
+ helpers Helpers::Auth
9
+
10
+ before do
11
+ chomp_token
12
+ end
13
+
14
+ get '/' do
15
+ admin_protected!
16
+
17
+ erb :'public/index'
18
+ end
19
+
20
+ get '/enterprise' do
21
+ admin_protected!
22
+
23
+ erb :admin
24
+ end
25
+
26
+ get '/enterprise/:domain' do
27
+ enterprise_protected!(params[:domain])
28
+
29
+ @enterprise = Models::EnterpriseAccount.where(
30
+ domain: params[:domain],
31
+ ).first_or_create
32
+
33
+ erb :admin
34
+ end
35
+
36
+ get '/config' do
37
+ admin_protected!
38
+
39
+ erb :admin
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+ require 'omniauth'
5
+ require 'omniauth-multi-provider'
6
+ require 'omniauth-saml'
7
+
8
+ module Osso
9
+ class Auth < Sinatra::Base
10
+ include AppConfig
11
+
12
+ UUID_REGEXP =
13
+ /[0-9a-f]{8}-[0-9a-f]{3,4}-[0-9a-f]{4}-[0-9a-f]{3,4}-[0-9a-f]{12}/.
14
+ freeze
15
+
16
+ def self.internal_redirect?(env)
17
+ env['HTTP_REFERER']&.match(env['SERVER_NAME'])
18
+ end
19
+
20
+ use OmniAuth::Builder do
21
+ OmniAuth::MultiProvider.register(
22
+ self,
23
+ provider_name: 'saml',
24
+ identity_provider_id_regex: UUID_REGEXP,
25
+ path_prefix: '/saml',
26
+ callback_suffix: 'callback',
27
+ ) do |saml_provider_id, _env|
28
+ provider = Models::SamlProvider.find(saml_provider_id)
29
+ provider.saml_options
30
+ end
31
+ end
32
+
33
+ # Enterprise users are sent here after authenticating against
34
+ # their Identity Provider. We find or create a user record,
35
+ # and then create an authorization code for that user. The user
36
+ # is redirected back to your application with this code
37
+ # as a URL query param, which you then exhange for an access token
38
+ post '/saml/:id/callback' do
39
+ provider = Models::SamlProvider.find(params[:id])
40
+ oauth_client = provider.oauth_client
41
+ redirect_uri = env['redirect_uri'] || oauth_client.default_redirect_uri.uri
42
+
43
+ attributes = env['omniauth.auth']&.
44
+ extra&.
45
+ response_object&.
46
+ attributes
47
+
48
+ user = Models::User.where(
49
+ email: attributes[:email],
50
+ idp_id: attributes[:id],
51
+ ).first_or_create! do |new_user|
52
+ new_user.enterprise_account_id = provider.enterprise_account_id
53
+ new_user.saml_provider_id = provider.id
54
+ end
55
+
56
+ authorization_code = user.authorization_codes.create!(
57
+ oauth_client: oauth_client,
58
+ redirect_uri: redirect_uri,
59
+ )
60
+
61
+ redirect(redirect_uri + "?code=#{CGI.escape(authorization_code.token)}&state=#{session[:oauth_state]}")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/oauth2'
4
+
5
+ module Osso
6
+ class Oauth < Sinatra::Base
7
+ include AppConfig
8
+ # Send your users here in order to being an authentication
9
+ # flow. This flow follows the authorization grant oauth
10
+ # spec with one exception - you must also pass the domain
11
+ # of the user who wants to sign in.
12
+ get '/authorize' do
13
+ @enterprise = Models::EnterpriseAccount.
14
+ includes(:saml_providers).
15
+ find_by!(domain: params[:domain])
16
+
17
+ Rack::OAuth2::Server::Authorize.new do |req, _res|
18
+ client = Models::OauthClient.find_by!(identifier: req.client_id)
19
+ req.verify_redirect_uri!(client.redirect_uri_values)
20
+ end.call(env)
21
+
22
+ if @enterprise.single_provider?
23
+ session[:oauth_state] = params[:state]
24
+ redirect "/auth/saml/#{@enterprise.provider.id}"
25
+ end
26
+
27
+ erb :multiple_providers
28
+
29
+ rescue Rack::OAuth2::Server::Authorize::BadRequest => e
30
+ @error = e
31
+ return erb :error
32
+ end
33
+
34
+ # Exchange an authorization code token for an access token.
35
+ # In addition to the token, you must include all paramaters
36
+ # required by Oauth spec: redirect_uri, client ID, and client secret
37
+ post '/token' do
38
+ Rack::OAuth2::Server::Token.new do |req, res|
39
+ code = Models::AuthorizationCode.
40
+ find_by_token!(params[:code])
41
+ client = Models::OauthClient.find_by!(identifier: req.client_id)
42
+ req.invalid_client! if client.secret != req.client_secret
43
+ req.invalid_grant! if code.redirect_uri != req.redirect_uri
44
+ res.access_token = code.access_token.to_bearer_token
45
+ end.call(env)
46
+ end
47
+
48
+ # Use the access token to request a user profile
49
+ get '/me' do
50
+ json Models::AccessToken.
51
+ includes(:user).
52
+ valid.
53
+ find_by_token!(params[:access_token]).
54
+ user
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/contrib'
4
+ require 'sinatra/base'
5
+ require 'sinatra/contrib'
6
+ require 'sinatra/json'
7
+
8
+ require_relative 'admin'
9
+ require_relative 'auth'
10
+ require_relative 'oauth'
@@ -0,0 +1 @@
1
+ <%= @error %>
@@ -0,0 +1 @@
1
+ multiple providers
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ VERSION = '0.0.2.8'
5
+ end
data/lib/osso.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ require_relative 'osso/helpers/helpers'
5
+ require_relative 'osso/lib/app_config'
6
+ require_relative 'osso/lib/oauth2_token'
7
+ require_relative 'osso/models/models'
8
+ require_relative 'osso/routes/routes'
9
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinatra/activerecord'
4
+ require 'sinatra/activerecord/rake'
5
+ require 'osso'
6
+ require 'dotenv/tasks'
7
+
8
+ namespace :osso do
9
+ desc 'Bootstrap Osso data for a deployment'
10
+ task bootstrap: :dotenv do
11
+ %w[Production Staging Development].each do |environement|
12
+ Osso::Models::OauthClient.create!(
13
+ name: environement,
14
+ )
15
+ end
16
+ end
17
+ end
data/osso-rb.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/osso/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'osso'
7
+ spec.version = Osso::VERSION
8
+ spec.authors = ['Sam Bauch']
9
+ spec.email = ['sbauch@gmail.com']
10
+
11
+ spec.summary = 'Main functionality for Osso'
12
+ spec.description = 'This gem includes the main functionality for Osso apps,'
13
+ spec.homepage = 'https://github.com/enterprise-oss/osso-rb'
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
+ spec.license = 'MIT'
16
+
17
+ spec.add_runtime_dependency 'activesupport', '>= 6.0.3.2'
18
+ spec.add_runtime_dependency 'jwt'
19
+ spec.add_runtime_dependency 'omniauth-multi-provider'
20
+ spec.add_runtime_dependency 'omniauth-saml'
21
+ spec.add_runtime_dependency 'rack', '>= 2.1.4'
22
+ spec.add_runtime_dependency 'rack-contrib'
23
+ spec.add_runtime_dependency 'rack-oauth2'
24
+ spec.add_runtime_dependency 'rake'
25
+ spec.add_runtime_dependency 'sinatra'
26
+ spec.add_runtime_dependency 'sinatra-activerecord'
27
+ spec.add_runtime_dependency 'sinatra-contrib'
28
+
29
+ spec.add_development_dependency 'bundler', '~> 2.1'
30
+ spec.add_development_dependency 'pry'
31
+
32
+ # Specify which files should be added to the gem when it is released.
33
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
34
+ spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
35
+ spec.files = `git ls-files`.split("\n")
36
+ spec.test_files = `git ls-files -- {spec}/*`.split("\n")
37
+ spec.bindir = 'bin'
38
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
39
+ spec.require_paths = ['lib']
40
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :authorization_code, class: Osso::Models::AuthorizationCode do
5
+ id { SecureRandom.uuid }
6
+ redirect_uri { Faker::Internet.url(path: '/saml-box/callback') }
7
+ user
8
+ oauth_client
9
+ end
10
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :enterprise_account, class: Osso::Models::EnterpriseAccount do
5
+ id { SecureRandom.uuid }
6
+ domain { Faker::Internet.domain_name }
7
+ oauth_client
8
+ end
9
+
10
+ factory :enterprise_with_okta, parent: :enterprise_account do
11
+ after :create do |enterprise|
12
+ create(
13
+ :okta_saml_provider,
14
+ domain: enterprise.domain,
15
+ enterprise_account_id: enterprise.id,
16
+ )
17
+ end
18
+ end
19
+
20
+ factory :enterprise_with_azure, parent: :enterprise_account do
21
+ after :create do |enterprise|
22
+ create(
23
+ :azure_saml_provider,
24
+ domain: enterprise.domain,
25
+ enterprise_account_id: enterprise.id,
26
+ )
27
+ end
28
+ end
29
+
30
+ factory :enterprise_with_multiple_providers, parent: :enterprise_account do
31
+ after :create do |enterprise|
32
+ create(
33
+ :okta_saml_provider,
34
+ domain: enterprise.domain,
35
+ enterprise_account_id: enterprise.id,
36
+ )
37
+
38
+ create(
39
+ :azure_saml_provider,
40
+ domain: enterprise.domain,
41
+ enterprise_account_id: enterprise.id,
42
+ )
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :oauth_client, class: Osso::Models::OauthClient do
5
+ id { SecureRandom.uuid }
6
+ name { Faker::Internet.domain_name }
7
+ after(:create) do |client|
8
+ create(:primary_redirect_uri, oauth_client: client)
9
+ create(:redirect_uri, oauth_client: client)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :redirect_uri, class: Osso::Models::RedirectUri do
5
+ id { SecureRandom.uuid }
6
+ uri { Faker::Internet.url }
7
+ primary { false }
8
+ oauth_client
9
+ end
10
+
11
+ factory :primary_redirect_uri, parent: :redirect_uri do
12
+ primary { true }
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :saml_provider, class: Osso::Models::SamlProvider do
5
+ id { SecureRandom.uuid }
6
+ domain { Faker::Internet.domain_name }
7
+ oauth_client
8
+ idp_cert do
9
+ <<~CERT
10
+ -----BEGIN CERTIFICATE-----
11
+ MIIDpDCCAoygAwIBAgIGAXEiD4LlMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
12
+ A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
13
+ MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi0xNjIwMjQxHDAaBgkqhkiG9w0BCQEW
14
+ DWluZm9Ab2t0YS5jb20wHhcNMjAwMzI4MTY1MTU0WhcNMzAwMzI4MTY1MjU0WjCBkjELMAkGA1UE
15
+ BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
16
+ BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtMTYyMDI0MRwwGgYJ
17
+ KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
18
+ wsnP4UTfv3bxR5Jh0at51Dqjj+fKxFznzFW3XA5NbF2SlRLjeYcvj3+47TC0eP6xOsLWfnvdnx4v
19
+ dd9Ufn7jDCo5pL3JykMVEh2I0szF3RLC+a532ArcwgU9Px48+rWVwPkASS7l4NHAM4+gOBHJMQt2
20
+ AMohPT0kU41P8BEPzfwhNyiEXR66JNZIJUE8fM3Vpgnxm/VSwYzJf0NfOyfxv8JczF0zkDbpE7Tk
21
+ 3Ww/PFFLoMxWzanWGJQ+blnhv6UV6H4fcfAbcwAplOdIVHjS2ghYBvYNGahuFxjia0+6csyZGrt8
22
+ H4XmR5Dr+jXY5K1b1VOA0k19/FCnHHN/smn25wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBgD9NE
23
+ 4OCuR1+vucV8S1T6XXIL2hB7bXBAZEVHZ1aErRzktgXAMgVwG267vIkD5VOXBiTy9yNU5LK6G3k2
24
+ zewU190sL1dMfyPnoVZyn94nvwe9A+on0tmZdmk00xirKk3FJdacnZNE9Dl/afIrcNf6xAm0WsU9
25
+ kbMiRwwvjO4TAiygDQzbrRC8ZfmT3hpBa3aTUzAccrvEQcgarLk4r7UjXP7a2mCN3UIIh+snN2Ms
26
+ vXHL0r6fM3xbniz+5lleWtPFw73yySBc8znkWZ4Tn8Lh0r6o5nCRYbr2REUB7ZIfiIyBbZxIp4kv
27
+ a+habbnQDFiNVzEd8OPXHh4EqLxOPDRW
28
+ -----END CERTIFICATE-----
29
+ CERT
30
+ end
31
+
32
+ factory :okta_saml_provider, parent: :saml_provider, class: Osso::Models::OktaSamlProvider do
33
+ provider { 'Osso::Models::OktaSamlProvider' }
34
+ idp_sso_target_url do
35
+ 'https://dev-162024.okta.com/app/vcardmedev162024_rubydemo2_1/exk51326b3U1941Hf4x6/sso/saml'
36
+ end
37
+ end
38
+
39
+ factory :azure_saml_provider, parent: :saml_provider, class: Osso::Models::AzureSamlProvider do
40
+ provider { 'Osso::Models::AzureSamlProvider' }
41
+ idp_sso_target_url do
42
+ 'https://login.microsoftonline.com/0af6c610-c40c-4683-9ea4-f25e509b8172/saml2'
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :user, class: Osso::Models::User do
5
+ id { SecureRandom.uuid }
6
+ email { Faker::Internet.email }
7
+ idp_id { SecureRandom.hex(32) }
8
+ saml_provider { create(:okta_saml_provider) }
9
+ enterprise_account
10
+ after(:create) do |user|
11
+ create(
12
+ :authorization_code,
13
+ user: user,
14
+ redirect_uri: user.oauth_client.redirect_uri_values.sample,
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Osso::Models::AzureSamlProvider do
6
+ subject { create(:azure_saml_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
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Osso::Models::OktaSamlProvider do
6
+ subject { create(:okta_saml_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
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Osso::Models::SamlProvider do
6
+ subject { create(:okta_saml_provider) }
7
+
8
+ describe '.create' do
9
+ it 'creates an enterprise account' do
10
+ domain = Faker::Internet.domain_name
11
+
12
+ provider = described_class.create(
13
+ domain: domain,
14
+ provider: 'Osso::Models::OktaSamlProvider',
15
+ )
16
+
17
+ expect(provider.enterprise_account).to be_a(Osso::Models::EnterpriseAccount)
18
+ expect(provider.enterprise_account.domain).to eq(domain)
19
+ end
20
+ end
21
+
22
+ describe '#assertion_consumer_service_url' do
23
+ it 'returns the expected URI' do
24
+ ENV['BASE_URL'] = 'https://example.com'
25
+
26
+ expect(subject.assertion_consumer_service_url).to eq(
27
+ "https://example.com/auth/saml/#{subject.id}/callback",
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Osso::Admin do
6
+ let(:jwt_url) { 'https://foo.com/jwt' }
7
+ let(:jwt_hmac_secret) { SecureRandom.hex(32) }
8
+
9
+ before do
10
+ ENV['JWT_URL'] = jwt_url
11
+ ENV['JWT_HMAC_SECRET'] = jwt_hmac_secret
12
+ end
13
+
14
+ describe 'get /admin' do
15
+ it 'redirects to JWT_URL without a session or token' do
16
+ get('/admin')
17
+
18
+ expect(last_response).to be_redirect
19
+ follow_redirect!
20
+ expect(last_request.url).to eq(jwt_url)
21
+ end
22
+
23
+ it 'redirects to JWT_URL with an invalid token' do
24
+ get('/admin', token: SecureRandom.hex(32))
25
+
26
+ expect(last_response).to be_redirect
27
+ follow_redirect!
28
+ expect(last_request.url).to eq(jwt_url)
29
+ end
30
+
31
+ it 'chomps the token and redirects to request path with valid token' do
32
+ token = JWT.encode(
33
+ { email: 'admin@saas.com', scope: 'admin' },
34
+ jwt_hmac_secret,
35
+ 'HS256',
36
+ )
37
+
38
+ get('/admin', { admin_token: token })
39
+
40
+ expect(last_response).to be_redirect
41
+ follow_redirect!
42
+ expect(last_request.url).to match('/admin')
43
+ end
44
+
45
+ it 'renders the admin page for a valid session token' do
46
+ token = JWT.encode(
47
+ { email: 'admin@saas.com', scope: 'admin' },
48
+ jwt_hmac_secret,
49
+ 'HS256',
50
+ )
51
+
52
+ get('/admin', {}, 'rack.session' => { admin_token: token })
53
+
54
+ expect(last_response).to be_ok
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'App' do
6
+ end