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,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateOauthTables < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :oauth_applications, id: :uuid do |t|
6
+ t.string :name, null: false
7
+ t.string :secret, null: false
8
+ t.text :redirect_uri, null: false
9
+ t.string :scopes, null: false, default: ''
10
+ t.boolean :confidential, null: false, default: true
11
+ t.timestamps null: false
12
+ end
13
+
14
+ create_table :oauth_access_grants, id: :uuid do |t|
15
+ t.uuid :resource_owner_id, null: false
16
+ t.references :application, type: :uuid, null: false
17
+ t.string :token, null: false
18
+ t.integer :expires_in, null: false
19
+ t.text :redirect_uri, null: false
20
+ t.datetime :created_at, null: false
21
+ t.datetime :revoked_at
22
+ t.string :scopes, null: false, default: ''
23
+ end
24
+
25
+ add_index :oauth_access_grants, :token, unique: true
26
+ add_foreign_key(
27
+ :oauth_access_grants,
28
+ :oauth_applications,
29
+ column: :application_id
30
+ )
31
+
32
+ create_table :oauth_access_tokens, id: :uuid do |t|
33
+ t.uuid :resource_owner_id
34
+ t.references :application, type: :uuid
35
+ t.string :token, null: false
36
+
37
+ t.string :refresh_token
38
+ t.integer :expires_in
39
+ t.datetime :revoked_at
40
+ t.datetime :created_at, null: false
41
+ t.string :scopes
42
+
43
+ t.string :previous_refresh_token, null: false, default: ''
44
+ end
45
+
46
+ add_index :oauth_access_tokens, :token, unique: true
47
+ add_index :oauth_access_tokens, :refresh_token, unique: true
48
+ add_foreign_key(
49
+ :oauth_access_tokens,
50
+ :oauth_applications,
51
+ column: :application_id
52
+ )
53
+
54
+ add_foreign_key :oauth_access_grants, :users, column: :resource_owner_id
55
+ add_foreign_key :oauth_access_tokens, :users, column: :resource_owner_id
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ class CreateSamlProviders < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :saml_providers, id: :uuid do |t|
4
+ t.string :provider, null: false
5
+ t.string :domain, null: false
6
+ t.string :idp_sso_target_url, null: false
7
+ t.text :idp_cert, null: false
8
+ t.string :assertion_consumer_service_url
9
+ end
10
+
11
+ add_index :saml_providers, [:domain, :provider], unique: true
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class AddProviderIdToUsers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :users, :saml_provider_id, :uuid
4
+
5
+ add_foreign_key :users, :saml_providers
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ class CreateEnterpriseAccounts < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :enterprise_accounts, id: :uuid do |t|
4
+ t.string :domain, null: false
5
+ t.uuid :external_uuid
6
+ t.integer :external_int_id
7
+ t.string :external_id
8
+ end
9
+
10
+ add_index :enterprise_accounts, :domain, unique: true
11
+
12
+ add_reference :saml_providers, :enterprise_account, type: :uuid, index: true
13
+ add_reference :users, :enterprise_account, type: :uuid, index: true
14
+ end
15
+ end
@@ -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,5 @@
1
+ class AddOauthClientReferenceToSamlProviders < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_reference :saml_providers, :oauth_client, type: :uuid, index: true
4
+ end
5
+ 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,7 @@
1
+ class DropNullConstraintsFromSamlProvider < ActiveRecord::Migration[6.0]
2
+ def change
3
+ change_column :saml_providers, :idp_sso_target_url, :string, null: true
4
+ change_column :saml_providers, :idp_cert, :text, null: true
5
+ change_column :saml_providers, :assertion_consumer_service_url, :string, null: false
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class DropAcsUrl < ActiveRecord::Migration[6.0]
2
+ def change
3
+ remove_column :saml_providers, :assertion_consumer_service_url
4
+ end
5
+ 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,5 @@
1
+ class AddOauthClientIdToEnterpriseAccount < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_reference :enterprise_accounts, :oauth_client, type: :uuid, index: true
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DropNullConstraintFromSamlProvidersProvider < ActiveRecord::Migration[6.0]
4
+ def change
5
+ change_column :saml_providers, :provider, :string, null: true
6
+ end
7
+ end
@@ -0,0 +1,132 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # This file is the source Rails uses to define your schema when running `rails
6
+ # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(version: 2020_05_02_135008) do
14
+
15
+ # These are extensions that must be enabled in order to support this database
16
+ enable_extension "pgcrypto"
17
+ enable_extension "plpgsql"
18
+
19
+ create_table "access_tokens", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
20
+ t.string "token"
21
+ t.datetime "expires_at"
22
+ t.datetime "created_at", precision: 6, null: false
23
+ t.datetime "updated_at", precision: 6, null: false
24
+ t.uuid "user_id"
25
+ t.uuid "oauth_client_id"
26
+ t.index ["oauth_client_id"], name: "index_access_tokens_on_oauth_client_id"
27
+ t.index ["user_id"], name: "index_access_tokens_on_user_id"
28
+ end
29
+
30
+ create_table "authorization_codes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
31
+ t.string "token"
32
+ t.string "redirect_uri"
33
+ t.datetime "expires_at"
34
+ t.datetime "created_at", precision: 6, null: false
35
+ t.datetime "updated_at", precision: 6, null: false
36
+ t.uuid "user_id"
37
+ t.uuid "oauth_client_id"
38
+ t.index ["oauth_client_id"], name: "index_authorization_codes_on_oauth_client_id"
39
+ t.index ["token"], name: "index_authorization_codes_on_token", unique: true
40
+ t.index ["user_id"], name: "index_authorization_codes_on_user_id"
41
+ end
42
+
43
+ create_table "enterprise_accounts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
44
+ t.string "domain", null: false
45
+ t.uuid "external_uuid"
46
+ t.integer "external_int_id"
47
+ t.string "external_id"
48
+ t.uuid "oauth_client_id"
49
+ t.index ["domain"], name: "index_enterprise_accounts_on_domain", unique: true
50
+ t.index ["oauth_client_id"], name: "index_enterprise_accounts_on_oauth_client_id"
51
+ end
52
+
53
+ create_table "oauth_access_grants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
54
+ t.uuid "resource_owner_id", null: false
55
+ t.uuid "application_id", null: false
56
+ t.string "token", null: false
57
+ t.integer "expires_in", null: false
58
+ t.text "redirect_uri", null: false
59
+ t.datetime "created_at", null: false
60
+ t.datetime "revoked_at"
61
+ t.string "scopes", default: "", null: false
62
+ t.index ["application_id"], name: "index_oauth_access_grants_on_application_id"
63
+ t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true
64
+ end
65
+
66
+ create_table "oauth_access_tokens", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
67
+ t.uuid "resource_owner_id"
68
+ t.uuid "application_id"
69
+ t.string "token", null: false
70
+ t.string "refresh_token"
71
+ t.integer "expires_in"
72
+ t.datetime "revoked_at"
73
+ t.datetime "created_at", null: false
74
+ t.string "scopes"
75
+ t.string "previous_refresh_token", default: "", null: false
76
+ t.index ["application_id"], name: "index_oauth_access_tokens_on_application_id"
77
+ t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true
78
+ t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true
79
+ end
80
+
81
+ create_table "oauth_applications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
82
+ t.string "name", null: false
83
+ t.string "secret", null: false
84
+ t.text "redirect_uri", null: false
85
+ t.string "scopes", default: "", null: false
86
+ t.boolean "confidential", default: true, null: false
87
+ t.datetime "created_at", precision: 6, null: false
88
+ t.datetime "updated_at", precision: 6, null: false
89
+ end
90
+
91
+ create_table "oauth_clients", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
92
+ t.string "name", null: false
93
+ t.string "secret", null: false
94
+ t.string "identifier", null: false
95
+ t.index ["identifier"], name: "index_oauth_clients_on_identifier", unique: true
96
+ end
97
+
98
+ create_table "redirect_uris", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
99
+ t.string "uri", null: false
100
+ t.boolean "primary", default: false, null: false
101
+ t.uuid "oauth_client_id"
102
+ t.index ["oauth_client_id"], name: "index_redirect_uris_on_oauth_client_id"
103
+ t.index ["uri", "primary"], name: "index_redirect_uris_on_uri_and_primary", unique: true
104
+ end
105
+
106
+ create_table "saml_providers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
107
+ t.string "provider", null: false
108
+ t.string "domain", null: false
109
+ t.string "idp_sso_target_url"
110
+ t.text "idp_cert"
111
+ t.uuid "enterprise_account_id"
112
+ t.uuid "oauth_client_id"
113
+ t.index ["domain", "provider"], name: "index_saml_providers_on_domain_and_provider", unique: true
114
+ t.index ["enterprise_account_id"], name: "index_saml_providers_on_enterprise_account_id"
115
+ t.index ["oauth_client_id"], name: "index_saml_providers_on_oauth_client_id"
116
+ end
117
+
118
+ create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
119
+ t.string "email", null: false
120
+ t.string "idp_id", null: false
121
+ t.uuid "saml_provider_id"
122
+ t.uuid "enterprise_account_id"
123
+ t.index ["email", "idp_id"], name: "index_users_on_email_and_idp_id", unique: true
124
+ t.index ["enterprise_account_id"], name: "index_users_on_enterprise_account_id"
125
+ end
126
+
127
+ add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id"
128
+ add_foreign_key "oauth_access_grants", "users", column: "resource_owner_id"
129
+ add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id"
130
+ add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id"
131
+ add_foreign_key "users", "saml_providers"
132
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
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
13
+
14
+ def enterprise_authorized?(domain)
15
+ payload, _args = JWT.decode(
16
+ token,
17
+ ENV['JWT_HMAC_SECRET'],
18
+ true,
19
+ { algorithm: 'HS256' },
20
+ )
21
+
22
+ @current_scope = payload['scope']
23
+
24
+ true
25
+ rescue JWT::DecodeError
26
+ false
27
+ end
28
+
29
+ def admin_protected!
30
+ return if admin_authorized?
31
+
32
+ redirect ENV['JWT_URL']
33
+ end
34
+
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
46
+ end
47
+
48
+ false
49
+ rescue JWT::DecodeError
50
+ false
51
+ end
52
+
53
+ def token
54
+ request.env['admin_token'] || session['admin_token'] || request['admin_token']
55
+ end
56
+
57
+ def chomp_token
58
+ return unless request['admin_token'].present?
59
+
60
+ session['admin_token'] = request['admin_token']
61
+
62
+ return if request.post?
63
+
64
+ redirect request.path
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Helpers
4
+ end
5
+
6
+ require_relative 'auth'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/contrib'
4
+
5
+ module Osso
6
+ module AppConfig
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ use Rack::JSONBodyParser
10
+ use Rack::Session::Cookie, secret: ENV.fetch('SESSION_SECRET')
11
+
12
+ error ActiveRecord::RecordNotFound do
13
+ status 404
14
+ end
15
+
16
+ set :root, Dir.pwd
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Osso
6
+ module OAuth2Token
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ cattr_accessor :default_lifetime
10
+ self.default_lifetime = 1.minute
11
+ belongs_to :user
12
+ belongs_to :oauth_client
13
+
14
+ before_validation :setup, on: :create
15
+ validates :oauth_client, :expires_at, presence: true
16
+ validates :token, presence: true, uniqueness: true
17
+
18
+ scope :valid, -> { where('expires_at > ?', Time.now.utc) }
19
+ end
20
+ end
21
+
22
+ def expires_in
23
+ (expires_at - Time.now.utc).to_i
24
+ end
25
+
26
+ def expired!
27
+ self.expires_at = Time.now.utc
28
+ save!
29
+ end
30
+
31
+ private
32
+
33
+ def setup
34
+ self.token = SecureRandom.hex(32)
35
+ self.expires_at ||= default_lifetime.from_now
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ class AccessToken < ::ActiveRecord::Base
6
+ include OAuth2Token
7
+ self.default_lifetime = 10.minutes
8
+ belongs_to :refresh_token
9
+
10
+ def to_bearer_token
11
+ Rack::OAuth2::AccessToken::Bearer.new(
12
+ access_token: token,
13
+ expires_in: expires_in,
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def setup
20
+ super
21
+ return unless refresh_token
22
+
23
+ self.user = refresh_token.user
24
+ self.client = refresh_token.client
25
+ self.expires_at = [expires_at, refresh_token.expires_at].min
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ class AuthorizationCode < ActiveRecord::Base
6
+ include OAuth2Token
7
+
8
+ def access_token
9
+ @access_token ||= expired! &&
10
+ user.access_tokens.create(oauth_client: oauth_client)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ # Base class for Enterprises. This should map one-to-one with
6
+ # your own Account model. Persisting the EnterpriseAccount id
7
+ # in your application's database is recommended. The table also
8
+ # includes fields for external IDs such that you can persist
9
+ # your ID for an account in your Osso instance.
10
+ class EnterpriseAccount < ActiveRecord::Base
11
+ belongs_to :oauth_client
12
+ has_many :users
13
+ has_many :saml_providers
14
+
15
+ def single_provider?
16
+ saml_providers.one?
17
+ end
18
+
19
+ def provider
20
+ return nil unless single_provider?
21
+
22
+ saml_providers.first
23
+ end
24
+
25
+ alias saml_provider provider
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinatra/activerecord'
4
+
5
+ module Osso
6
+ module Models
7
+ end
8
+ end
9
+
10
+ require_relative 'access_token'
11
+ require_relative 'authorization_code'
12
+ require_relative 'enterprise_account'
13
+ require_relative 'oauth_client'
14
+ require_relative 'redirect_uri'
15
+ require_relative 'saml_provider'
16
+ require_relative 'user'
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ module Osso
5
+ module Models
6
+ class OauthClient < ActiveRecord::Base
7
+ has_many :access_tokens
8
+ has_many :refresh_tokens
9
+ has_many :saml_providers
10
+ has_many :redirect_uris
11
+
12
+ before_validation :setup, on: :create
13
+ validates :name, :secret, presence: true
14
+ validates :identifier, presence: true, uniqueness: true
15
+
16
+ def default_redirect_uri
17
+ redirect_uris.find(&:primary)
18
+ end
19
+
20
+ def redirect_uri_values
21
+ redirect_uris.map(&:uri)
22
+ end
23
+
24
+ private
25
+
26
+ def setup
27
+ self.identifier = SecureRandom.hex(16)
28
+ self.secret = SecureRandom.hex(64)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ class RedirectUri < ActiveRecord::Base
6
+ belongs_to :oauth_client
7
+
8
+ # TODO
9
+ # before_validation :set_primary, on: :creaet, :update
10
+
11
+ private
12
+
13
+ def set_primary
14
+ if primary_was.true? && primary.false?
15
+
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module Models
5
+ # Base class for SAML Providers
6
+ class SamlProvider < ActiveRecord::Base
7
+ NAME_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
8
+ self.inheritance_column = :provider
9
+ belongs_to :enterprise_account
10
+ belongs_to :oauth_client
11
+ has_many :users
12
+
13
+ before_create :create_enterprise_account
14
+
15
+ def name
16
+ raise(
17
+ NoMethodError,
18
+ '#name must be defined on each provider specific subclass',
19
+ )
20
+ end
21
+
22
+ def saml_options
23
+ raise(
24
+ NoMethodError,
25
+ '#saml_options must be defined on each provider specific subclass',
26
+ )
27
+ end
28
+
29
+ def assertion_consumer_service_url
30
+ [
31
+ ENV.fetch('BASE_URL'),
32
+ 'auth',
33
+ 'saml',
34
+ id,
35
+ 'callback',
36
+ ].join('/')
37
+ end
38
+
39
+ alias acs_url assertion_consumer_service_url
40
+
41
+ def create_enterprise_account
42
+ return if enterprise_account_id
43
+
44
+ self.enterprise_account = Models::EnterpriseAccount.create(
45
+ domain: domain,
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
51
+ require_relative 'saml_providers/azure_saml_provider'
52
+ require_relative 'saml_providers/okta_saml_provider'