cnfs-iam 0.0.1.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +75 -0
- data/Rakefile +24 -0
- data/app/controllers/concerns/is_tenant_scoped.rb +21 -0
- data/app/controllers/credentials_controller.rb +23 -0
- data/app/controllers/groups_controller.rb +4 -0
- data/app/controllers/iam/application_controller.rb +6 -0
- data/app/controllers/iam/confirmations_controller.rb +51 -0
- data/app/controllers/iam/passwords_controller.rb +56 -0
- data/app/controllers/iam/sessions_controller.rb +21 -0
- data/app/controllers/policies_controller.rb +4 -0
- data/app/controllers/public_keys_controller.rb +4 -0
- data/app/controllers/roots/sessions_controller.rb +16 -0
- data/app/controllers/roots_controller.rb +4 -0
- data/app/controllers/users/confirmations_controller.rb +21 -0
- data/app/controllers/users/passwords_controller.rb +25 -0
- data/app/controllers/users/sessions_controller.rb +19 -0
- data/app/controllers/users_controller.rb +17 -0
- data/app/mailers/account_mailer.rb +74 -0
- data/app/models/action.rb +6 -0
- data/app/models/credential.rb +47 -0
- data/app/models/group.rb +15 -0
- data/app/models/group_policy_join.rb +25 -0
- data/app/models/iam/application_record.rb +7 -0
- data/app/models/policy.rb +10 -0
- data/app/models/policy_action.rb +6 -0
- data/app/models/public_key.rb +17 -0
- data/app/models/role.rb +11 -0
- data/app/models/role_policy_join.rb +6 -0
- data/app/models/root.rb +26 -0
- data/app/models/root_credential.rb +7 -0
- data/app/models/tenant.rb +68 -0
- data/app/models/user.rb +69 -0
- data/app/models/user_credential.rb +8 -0
- data/app/models/user_group.rb +25 -0
- data/app/models/user_policy_join.rb +21 -0
- data/app/models/user_role.rb +6 -0
- data/app/operations/blackcomb_user_create.rb +49 -0
- data/app/operations/user_create.rb +53 -0
- data/app/policies/action_policy.rb +3 -0
- data/app/policies/credential_policy.rb +3 -0
- data/app/policies/group_policy.rb +3 -0
- data/app/policies/iam/application_policy.rb +6 -0
- data/app/policies/policy_policy.rb +3 -0
- data/app/policies/public_key_policy.rb +4 -0
- data/app/policies/root_policy.rb +3 -0
- data/app/policies/tenant_policy.rb +5 -0
- data/app/policies/user_policy.rb +33 -0
- data/app/resources/action_resource.rb +16 -0
- data/app/resources/credential_resource.rb +13 -0
- data/app/resources/group_resource.rb +8 -0
- data/app/resources/iam/application_resource.rb +7 -0
- data/app/resources/policy_resource.rb +9 -0
- data/app/resources/public_key_resource.rb +6 -0
- data/app/resources/root_resource.rb +14 -0
- data/app/resources/tenant_resource.rb +21 -0
- data/app/resources/user_resource.rb +25 -0
- data/app/views/layouts/mailer.html.erb +4 -0
- data/app/views/user_mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/user_mailer/email_changed.html.erb +7 -0
- data/app/views/user_mailer/password_change.html.erb +3 -0
- data/app/views/user_mailer/reset_password_instructions.html.erb +106 -0
- data/app/views/user_mailer/team_welcome.html.erb +107 -0
- data/app/views/user_mailer/unlock_instructions.html.erb +7 -0
- data/config/environment.rb +0 -0
- data/config/initializers/devise.rb +311 -0
- data/config/locales/devise.en.yml +65 -0
- data/config/routes.rb +17 -0
- data/config/sidekiq.yml +5 -0
- data/config/spring.rb +3 -0
- data/db/migrate/20190101000001_create_policies.rb +11 -0
- data/db/migrate/20190101000002_create_actions.rb +13 -0
- data/db/migrate/20190101000003_create_policy_actions.rb +13 -0
- data/db/migrate/20190215214352_create_roots.rb +43 -0
- data/db/migrate/20190215214353_update_tenants.rb +10 -0
- data/db/migrate/20190215214355_create_credentials.rb +14 -0
- data/db/migrate/20190215214407_create_users.rb +50 -0
- data/db/migrate/20190215214409_create_user_credentials.rb +12 -0
- data/db/migrate/20190215214410_create_user_policy_joins.rb +12 -0
- data/db/migrate/20190215214411_create_groups.rb +11 -0
- data/db/migrate/20190215214412_create_user_groups.rb +12 -0
- data/db/migrate/20190215214413_create_group_policy_joins.rb +12 -0
- data/db/migrate/20190215214415_create_roles.rb +11 -0
- data/db/migrate/20190215214416_create_user_roles.rb +12 -0
- data/db/migrate/20190215214421_create_role_policy_joins.rb +12 -0
- data/db/migrate/20190924091536_add_display_properties_to_tenants.rb +5 -0
- data/db/migrate/20191021220135_create_public_keys.rb +10 -0
- data/db/migrate/20191120083154_add_confirmable_email_to_user.rb +9 -0
- data/db/seeds/development/tenants.seeds.rb +41 -0
- data/db/seeds/development/users.seeds.rb +67 -0
- data/lib/ros/api_token_strategy.rb +24 -0
- data/lib/ros/iam.rb +18 -0
- data/lib/ros/iam/console.rb +13 -0
- data/lib/ros/iam/engine.rb +51 -0
- data/lib/ros/iam/version.rb +7 -0
- data/lib/tasks/ros/iam_tasks.rake +51 -0
- metadata +209 -0
data/config/routes.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Ros::Iam::Engine.routes.draw do
|
4
|
+
jsonapi_resources :public_keys
|
5
|
+
devise_for :users, module: 'users', defaults: { format: :json }
|
6
|
+
devise_for :roots, module: 'roots', defaults: { format: :json }
|
7
|
+
|
8
|
+
jsonapi_resources :credentials
|
9
|
+
jsonapi_resources :groups
|
10
|
+
jsonapi_resources :policies
|
11
|
+
jsonapi_resources :roots
|
12
|
+
jsonapi_resources :users
|
13
|
+
|
14
|
+
# TODO: temporary route until we support registering callbacks to allow
|
15
|
+
# a root owner account to create a tenant
|
16
|
+
post '/blackcomb_credentials', to: 'credentials#blackcomb'
|
17
|
+
end
|
data/config/sidekiq.yml
ADDED
data/config/spring.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateActions < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :actions do |t|
|
6
|
+
t.string :name, null: false, index: { unique: true }
|
7
|
+
t.string :type, null: false
|
8
|
+
t.string :resource
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreatePolicyActions < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :policy_actions do |t|
|
6
|
+
t.references :policy, foreign_key: true
|
7
|
+
t.references :action, foreign_key: true
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
add_index :policy_actions, %i[policy_id action_id], unique: true
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateRoots < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :roots do |t|
|
6
|
+
t.boolean :api, null: false, default: false
|
7
|
+
t.string :time_zone, null: false, default: 'UTC'
|
8
|
+
|
9
|
+
## Database authenticatable
|
10
|
+
t.string :email, null: false, default: '', index: { unique: true }
|
11
|
+
t.string :encrypted_password, null: false, default: ''
|
12
|
+
|
13
|
+
## Recoverable
|
14
|
+
t.string :reset_password_token, index: { unique: true }
|
15
|
+
t.datetime :reset_password_sent_at
|
16
|
+
|
17
|
+
## Rememberable
|
18
|
+
t.datetime :remember_created_at
|
19
|
+
|
20
|
+
## Trackable
|
21
|
+
# t.integer :sign_in_count, default: 0, null: false
|
22
|
+
# t.datetime :current_sign_in_at
|
23
|
+
# t.datetime :last_sign_in_at
|
24
|
+
# t.string :current_sign_in_ip
|
25
|
+
# t.string :last_sign_in_ip
|
26
|
+
|
27
|
+
## Confirmable
|
28
|
+
# t.string :confirmation_token
|
29
|
+
# t.datetime :confirmed_at
|
30
|
+
# t.datetime :confirmation_sent_at
|
31
|
+
# t.string :unconfirmed_email # Only if using reconfirmable
|
32
|
+
|
33
|
+
## Lockable
|
34
|
+
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
|
35
|
+
# t.string :unlock_token # Only if unlock strategy is :email or :both
|
36
|
+
# t.datetime :locked_at
|
37
|
+
|
38
|
+
t.timestamps null: false
|
39
|
+
end
|
40
|
+
# add_index :users, :confirmation_token, unique: true
|
41
|
+
# add_index :users, :unlock_token, unique: true
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UpdateTenants < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
add_reference :tenants, :root, null: false, foreign_key: true, index: { unique: true }
|
6
|
+
add_column :tenants, :alias, :string, null: true, index: { unique: true }
|
7
|
+
add_column :tenants, :name, :string
|
8
|
+
add_column :tenants, :state, :string
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateCredentials < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :credentials do |t|
|
6
|
+
t.references :owner, polymorphic: true
|
7
|
+
t.string :access_key_id, length: 20, index: { unique: true }
|
8
|
+
t.string :secret_access_key_digest
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
# add_index :credentials, :access_key_id, unique: true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateUsers < ActiveRecord::Migration[6.0]
|
4
|
+
# rubocop:disable Metrics/MethodLength
|
5
|
+
def change
|
6
|
+
create_table :users do |t|
|
7
|
+
t.boolean :console, null: false, default: false, comment: 'Allow console access when true'
|
8
|
+
t.boolean :api, null: false, default: false, comment: 'Allow API access when true'
|
9
|
+
t.string :time_zone, null: false, default: 'UTC', comment: 'Adjust timestamps to this time zone'
|
10
|
+
t.jsonb :attached_policies, null: false, default: {}
|
11
|
+
t.jsonb :attached_actions, null: false, default: {}
|
12
|
+
t.jsonb :properties, null: false, default: {}, comment: 'Custom properties of the user'
|
13
|
+
t.jsonb :display_properties, null: false, default: {}, comment: 'Custom display properties of the user'
|
14
|
+
|
15
|
+
## Database authenticatable
|
16
|
+
t.string :username, null: false, index: { unique: true }
|
17
|
+
t.string :encrypted_password, null: false, default: '', comment: 'Required if console is true'
|
18
|
+
|
19
|
+
## Recoverable
|
20
|
+
t.string :reset_password_token, index: { unique: true }
|
21
|
+
t.datetime :reset_password_sent_at
|
22
|
+
|
23
|
+
## Rememberable
|
24
|
+
t.datetime :remember_created_at
|
25
|
+
|
26
|
+
## Trackable
|
27
|
+
# t.integer :sign_in_count, default: 0, null: false
|
28
|
+
# t.datetime :current_sign_in_at
|
29
|
+
# t.datetime :last_sign_in_at
|
30
|
+
# t.string :current_sign_in_ip
|
31
|
+
# t.string :last_sign_in_ip
|
32
|
+
|
33
|
+
## Confirmable
|
34
|
+
# t.string :confirmation_token
|
35
|
+
# t.datetime :confirmed_at
|
36
|
+
# t.datetime :confirmation_sent_at
|
37
|
+
# t.string :unconfirmed_email # Only if using reconfirmable
|
38
|
+
|
39
|
+
## Lockable
|
40
|
+
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
|
41
|
+
# t.string :unlock_token # Only if unlock strategy is :email or :both
|
42
|
+
# t.datetime :locked_at
|
43
|
+
|
44
|
+
t.timestamps null: false
|
45
|
+
end
|
46
|
+
# add_index :users, :confirmation_token, unique: true
|
47
|
+
# add_index :users, :unlock_token, unique: true
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/MethodLength
|
50
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateUserCredentials < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :user_credentials do |t|
|
6
|
+
t.references :user, foreign_key: true
|
7
|
+
t.integer :credential_id, foreign_key: true, index: { unique: true }
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateUserPolicyJoins < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :user_policy_joins do |t|
|
6
|
+
t.references :user, foreign_key: true
|
7
|
+
t.references :policy, foreign_key: true
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateGroupPolicyJoins < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :group_policy_joins do |t|
|
6
|
+
t.references :group, foreign_key: true
|
7
|
+
t.references :policy, foreign_key: true
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateRolePolicyJoins < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :role_policy_joins do |t|
|
6
|
+
t.references :role, foreign_key: true
|
7
|
+
t.references :policy, foreign_key: true
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class AddConfirmableEmailToUser < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
add_column :users, :email, :string
|
4
|
+
add_column :users, :confirmation_token, :string
|
5
|
+
add_column :users, :confirmed_at, :datetime
|
6
|
+
add_column :users, :confirmation_sent_at, :datetime
|
7
|
+
add_column :users, :unconfirmed_email, :string
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# NOTE: Disabling event logging
|
4
|
+
logging_mem = Settings.event_logging.enabled
|
5
|
+
Settings.event_logging.enabled = false
|
6
|
+
# if 'platform owner' account does not exist then create it and initialize credentials file
|
7
|
+
initialize = Root.find_by(email: 'root@platform.com').nil?
|
8
|
+
|
9
|
+
create_list = if initialize
|
10
|
+
[
|
11
|
+
{ email: 'root@platform.com', password: 'asdfjkl;', api: true, alias: 'owner' },
|
12
|
+
{ email: 'root@generic.com', password: 'asdfjkl;', alias: 'generic' },
|
13
|
+
{ email: 'root@banking.com', password: 'asdfjkl;', alias: 'banking' },
|
14
|
+
{ email: 'root@telco.com', password: 'asdfjkl;', alias: 'telco' },
|
15
|
+
{ email: 'root@insurance.com', password: 'asdfjkl;', alias: 'insurance' },
|
16
|
+
{ email: 'root@retail.com', password: 'asdfjkl;', alias: 'retail' }
|
17
|
+
]
|
18
|
+
else
|
19
|
+
# TODO: We don't need it anymore
|
20
|
+
# id = Root.last.id
|
21
|
+
# create_list = [
|
22
|
+
# { email: "root@client#{id + 1}.com", password: 'asdfjkl;' },
|
23
|
+
# { email: "root@client#{id + 2}.com", password: 'asdfjkl;' }
|
24
|
+
# ]
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
owner_root = Root.create!(email: 'root@owner.com', password: 'asdfjkl;')
|
28
|
+
Tenant.create(schema_name: 'public', name: 'Account 1', alias: 'root', root: owner_root)
|
29
|
+
|
30
|
+
@created_list = []
|
31
|
+
create_list.each do |account|
|
32
|
+
tenant_alias = account.delete(:alias)
|
33
|
+
Root.create!(account).tap do |root|
|
34
|
+
root.create_tenant(schema_name: Tenant.account_id_to_schema(root.id.to_s * 9)[0..10],
|
35
|
+
name: "Account #{root.id}", state: :active, alias: tenant_alias)
|
36
|
+
credential = Credential.create(owner: root)
|
37
|
+
@created_list.append(type: 'root', owner: root, tenant: root.tenant, credential: credential,
|
38
|
+
secret: credential.secret_access_key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
Settings.event_logging.enabled = logging_mem
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# ubocop:disable Metrics/BlockLength
|
4
|
+
after 'development:tenants' do
|
5
|
+
Tenant.all.each do |tenant|
|
6
|
+
next if tenant.id.eql? 1
|
7
|
+
|
8
|
+
tenant.switch do
|
9
|
+
if Policy.count.zero?
|
10
|
+
# Add IAM Policies
|
11
|
+
Policy.create(name: 'AdministratorAccess')
|
12
|
+
Policy.create(name: 'IamUserFullAccess')
|
13
|
+
Policy.create(name: 'IamUserReadOnlyAccess')
|
14
|
+
end
|
15
|
+
next if User.count.positive?
|
16
|
+
|
17
|
+
user = User.create(username: 'Admin',
|
18
|
+
console: true,
|
19
|
+
api: true,
|
20
|
+
time_zone: 'Asia/Singapore',
|
21
|
+
email: 'admin@example.com',
|
22
|
+
confirmed_at: DateTime.now,
|
23
|
+
password: 'asdfjkl;')
|
24
|
+
User.create(username: 'Microsite',
|
25
|
+
console: false,
|
26
|
+
api: true,
|
27
|
+
time_zone: 'Asia/Singapore',
|
28
|
+
email: 'microsite@example.com',
|
29
|
+
confirmed_at: DateTime.now)
|
30
|
+
# user.locale: 'en-US'
|
31
|
+
credential = user.credentials.create
|
32
|
+
@created_list.append(type: 'user',
|
33
|
+
owner: user,
|
34
|
+
tenant: tenant,
|
35
|
+
credential: credential,
|
36
|
+
secret: credential.secret_access_key)
|
37
|
+
|
38
|
+
# Create a Group
|
39
|
+
group_admin = Group.create(name: 'Admin')
|
40
|
+
|
41
|
+
# Attach the Admin Policy to the Group
|
42
|
+
group_admin.policies << Policy.first
|
43
|
+
|
44
|
+
# Assign the first User to the Admin Group
|
45
|
+
group_admin.users << User.first
|
46
|
+
|
47
|
+
# NOTE: create remainign groups
|
48
|
+
Group.create(name: 'Creator')
|
49
|
+
Group.create(name: 'Customer Support')
|
50
|
+
Group.create(name: 'Manager')
|
51
|
+
Group.create(name: 'Viewer')
|
52
|
+
|
53
|
+
# Role.create(name: 'PerxServiceRoleForIAM')
|
54
|
+
# Role.create(name: 'PerxUserReadOnlyAccess')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Append newly created credentials to credentials.json in the tmp directory
|
59
|
+
FileUtils.mkdir_p(Ros.host_tmp_dir)
|
60
|
+
File.open("#{Ros.host_tmp_dir}/credentials.json", 'w') do |f|
|
61
|
+
f.puts(@created_list.to_json)
|
62
|
+
end
|
63
|
+
# Output the contents so that it can be captured by the helm log file when deployed into kubernetes
|
64
|
+
STDOUT.puts 'Credentials are next:'
|
65
|
+
STDOUT.puts File.read("#{Ros.host_tmp_dir}/credentials.json")
|
66
|
+
end
|
67
|
+
# ubocop:enable Metrics/BlockLength
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ros
|
4
|
+
# NOTE: Overrides methods in ros-core gem
|
5
|
+
class ApiTokenStrategy
|
6
|
+
def authenticate_basic
|
7
|
+
credential = if access_key[:owner_type].eql?('Root')
|
8
|
+
Apartment::Tenant.switch('public') { Credential.find_by(access_key_id: access_key_id) }
|
9
|
+
else
|
10
|
+
Credential.find_by(access_key_id: access_key_id)
|
11
|
+
end
|
12
|
+
return unless credential
|
13
|
+
|
14
|
+
credential.authenticate_secret_access_key(secret_access_key).try(:owner)
|
15
|
+
end
|
16
|
+
|
17
|
+
def authenticate_bearer
|
18
|
+
return unless (urn = Urn.from_jwt(token))
|
19
|
+
return unless urn.model_name.in? %w[Root User]
|
20
|
+
|
21
|
+
urn.instance
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|