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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.buildkite/hooks/environment +9 -0
- data/.buildkite/hooks/pre-command +7 -0
- data/.buildkite/pipeline.yml +3 -0
- data/.buildkite/template.yml +5 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.rubocop.yml +82 -0
- data/CODE_OF_CONDUCT.md +130 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +174 -0
- data/LICENSE +111 -0
- data/README.md +2 -0
- data/Rakefile +14 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/config/database.yml +14 -0
- data/lib/.DS_Store +0 -0
- data/lib/osso/Rakefile +13 -0
- data/lib/osso/db/migrate/20190909230109_enable_uuid.rb +7 -0
- data/lib/osso/db/migrate/20200328135750_create_users.rb +12 -0
- data/lib/osso/db/migrate/20200328143303_create_oauth_tables.rb +57 -0
- data/lib/osso/db/migrate/20200411144528_create_saml_providers.rb +13 -0
- data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +7 -0
- data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +15 -0
- data/lib/osso/db/migrate/20200413132407_add_oauth_clients.rb +13 -0
- data/lib/osso/db/migrate/20200413142511_create_authorization_codes.rb +15 -0
- data/lib/osso/db/migrate/20200413153029_add_oauth_client_reference_to_saml_providers.rb +5 -0
- data/lib/osso/db/migrate/20200413163451_create_access_tokens.rb +13 -0
- data/lib/osso/db/migrate/20200501203026_drop_null_constraints_from_saml_provider.rb +7 -0
- data/lib/osso/db/migrate/20200501204047_drop_acs_url.rb +5 -0
- data/lib/osso/db/migrate/20200502120616_create_redirect_uris_and_drop_from_oauth_clients.rb +13 -0
- data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_account.rb +5 -0
- data/lib/osso/db/migrate/20200601131227_drop_null_constraint_from_saml_providers_provider.rb +7 -0
- data/lib/osso/db/schema.rb +132 -0
- data/lib/osso/helpers/auth.rb +67 -0
- data/lib/osso/helpers/helpers.rb +6 -0
- data/lib/osso/lib/app_config.rb +20 -0
- data/lib/osso/lib/oauth2_token.rb +38 -0
- data/lib/osso/models/access_token.rb +29 -0
- data/lib/osso/models/authorization_code.rb +14 -0
- data/lib/osso/models/enterprise_account.rb +28 -0
- data/lib/osso/models/models.rb +16 -0
- data/lib/osso/models/oauth_client.rb +32 -0
- data/lib/osso/models/redirect_uri.rb +20 -0
- data/lib/osso/models/saml_provider.rb +52 -0
- data/lib/osso/models/saml_providers/azure_saml_provider.rb +22 -0
- data/lib/osso/models/saml_providers/okta_saml_provider.rb +23 -0
- data/lib/osso/models/user.rb +24 -0
- data/lib/osso/rake.rb +4 -0
- data/lib/osso/routes/admin.rb +42 -0
- data/lib/osso/routes/auth.rb +64 -0
- data/lib/osso/routes/oauth.rb +57 -0
- data/lib/osso/routes/routes.rb +10 -0
- data/lib/osso/routes/views/error.erb +1 -0
- data/lib/osso/routes/views/multiple_providers.erb +1 -0
- data/lib/osso/version.rb +5 -0
- data/lib/osso.rb +9 -0
- data/lib/tasks/bootstrap.rake +17 -0
- data/osso-rb.gemspec +40 -0
- data/spec/factories/authorization_code.rb +10 -0
- data/spec/factories/enterprise_account.rb +45 -0
- data/spec/factories/oauth_client.rb +12 -0
- data/spec/factories/redirect_uri.rb +14 -0
- data/spec/factories/saml_providers.rb +46 -0
- data/spec/factories/user.rb +18 -0
- data/spec/models/azure_saml_provider_spec.rb +19 -0
- data/spec/models/okta_saml_provider_spec.rb +20 -0
- data/spec/models/saml_provider_spec.rb +31 -0
- data/spec/routes/admin_spec.rb +57 -0
- data/spec/routes/app_spec.rb +6 -0
- data/spec/routes/auth_spec.rb +112 -0
- data/spec/routes/oauth_spec.rb +134 -0
- data/spec/spec_helper.rb +65 -0
- data/spec/support/vcr_cassettes/okta_saml_callback.yml +59 -0
- 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,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,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,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,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,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'
|