cnfs-iam 0.0.1.alpha

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 (98) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +75 -0
  4. data/Rakefile +24 -0
  5. data/app/controllers/concerns/is_tenant_scoped.rb +21 -0
  6. data/app/controllers/credentials_controller.rb +23 -0
  7. data/app/controllers/groups_controller.rb +4 -0
  8. data/app/controllers/iam/application_controller.rb +6 -0
  9. data/app/controllers/iam/confirmations_controller.rb +51 -0
  10. data/app/controllers/iam/passwords_controller.rb +56 -0
  11. data/app/controllers/iam/sessions_controller.rb +21 -0
  12. data/app/controllers/policies_controller.rb +4 -0
  13. data/app/controllers/public_keys_controller.rb +4 -0
  14. data/app/controllers/roots/sessions_controller.rb +16 -0
  15. data/app/controllers/roots_controller.rb +4 -0
  16. data/app/controllers/users/confirmations_controller.rb +21 -0
  17. data/app/controllers/users/passwords_controller.rb +25 -0
  18. data/app/controllers/users/sessions_controller.rb +19 -0
  19. data/app/controllers/users_controller.rb +17 -0
  20. data/app/mailers/account_mailer.rb +74 -0
  21. data/app/models/action.rb +6 -0
  22. data/app/models/credential.rb +47 -0
  23. data/app/models/group.rb +15 -0
  24. data/app/models/group_policy_join.rb +25 -0
  25. data/app/models/iam/application_record.rb +7 -0
  26. data/app/models/policy.rb +10 -0
  27. data/app/models/policy_action.rb +6 -0
  28. data/app/models/public_key.rb +17 -0
  29. data/app/models/role.rb +11 -0
  30. data/app/models/role_policy_join.rb +6 -0
  31. data/app/models/root.rb +26 -0
  32. data/app/models/root_credential.rb +7 -0
  33. data/app/models/tenant.rb +68 -0
  34. data/app/models/user.rb +69 -0
  35. data/app/models/user_credential.rb +8 -0
  36. data/app/models/user_group.rb +25 -0
  37. data/app/models/user_policy_join.rb +21 -0
  38. data/app/models/user_role.rb +6 -0
  39. data/app/operations/blackcomb_user_create.rb +49 -0
  40. data/app/operations/user_create.rb +53 -0
  41. data/app/policies/action_policy.rb +3 -0
  42. data/app/policies/credential_policy.rb +3 -0
  43. data/app/policies/group_policy.rb +3 -0
  44. data/app/policies/iam/application_policy.rb +6 -0
  45. data/app/policies/policy_policy.rb +3 -0
  46. data/app/policies/public_key_policy.rb +4 -0
  47. data/app/policies/root_policy.rb +3 -0
  48. data/app/policies/tenant_policy.rb +5 -0
  49. data/app/policies/user_policy.rb +33 -0
  50. data/app/resources/action_resource.rb +16 -0
  51. data/app/resources/credential_resource.rb +13 -0
  52. data/app/resources/group_resource.rb +8 -0
  53. data/app/resources/iam/application_resource.rb +7 -0
  54. data/app/resources/policy_resource.rb +9 -0
  55. data/app/resources/public_key_resource.rb +6 -0
  56. data/app/resources/root_resource.rb +14 -0
  57. data/app/resources/tenant_resource.rb +21 -0
  58. data/app/resources/user_resource.rb +25 -0
  59. data/app/views/layouts/mailer.html.erb +4 -0
  60. data/app/views/user_mailer/confirmation_instructions.html.erb +5 -0
  61. data/app/views/user_mailer/email_changed.html.erb +7 -0
  62. data/app/views/user_mailer/password_change.html.erb +3 -0
  63. data/app/views/user_mailer/reset_password_instructions.html.erb +106 -0
  64. data/app/views/user_mailer/team_welcome.html.erb +107 -0
  65. data/app/views/user_mailer/unlock_instructions.html.erb +7 -0
  66. data/config/environment.rb +0 -0
  67. data/config/initializers/devise.rb +311 -0
  68. data/config/locales/devise.en.yml +65 -0
  69. data/config/routes.rb +17 -0
  70. data/config/sidekiq.yml +5 -0
  71. data/config/spring.rb +3 -0
  72. data/db/migrate/20190101000001_create_policies.rb +11 -0
  73. data/db/migrate/20190101000002_create_actions.rb +13 -0
  74. data/db/migrate/20190101000003_create_policy_actions.rb +13 -0
  75. data/db/migrate/20190215214352_create_roots.rb +43 -0
  76. data/db/migrate/20190215214353_update_tenants.rb +10 -0
  77. data/db/migrate/20190215214355_create_credentials.rb +14 -0
  78. data/db/migrate/20190215214407_create_users.rb +50 -0
  79. data/db/migrate/20190215214409_create_user_credentials.rb +12 -0
  80. data/db/migrate/20190215214410_create_user_policy_joins.rb +12 -0
  81. data/db/migrate/20190215214411_create_groups.rb +11 -0
  82. data/db/migrate/20190215214412_create_user_groups.rb +12 -0
  83. data/db/migrate/20190215214413_create_group_policy_joins.rb +12 -0
  84. data/db/migrate/20190215214415_create_roles.rb +11 -0
  85. data/db/migrate/20190215214416_create_user_roles.rb +12 -0
  86. data/db/migrate/20190215214421_create_role_policy_joins.rb +12 -0
  87. data/db/migrate/20190924091536_add_display_properties_to_tenants.rb +5 -0
  88. data/db/migrate/20191021220135_create_public_keys.rb +10 -0
  89. data/db/migrate/20191120083154_add_confirmable_email_to_user.rb +9 -0
  90. data/db/seeds/development/tenants.seeds.rb +41 -0
  91. data/db/seeds/development/users.seeds.rb +67 -0
  92. data/lib/ros/api_token_strategy.rb +24 -0
  93. data/lib/ros/iam.rb +18 -0
  94. data/lib/ros/iam/console.rb +13 -0
  95. data/lib/ros/iam/engine.rb +51 -0
  96. data/lib/ros/iam/version.rb +7 -0
  97. data/lib/tasks/ros/iam_tasks.rake +51 -0
  98. metadata +209 -0
@@ -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
@@ -0,0 +1,5 @@
1
+ ---
2
+ :queues:
3
+ - iam_default
4
+ - mailers
5
+
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Spring.application_root = './spec/dummy'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreatePolicies < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :policies do |t|
6
+ t.string :name, null: false, index: { unique: true }
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateGroups < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :groups do |t|
6
+ t.string :name
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateUserGroups < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :user_groups do |t|
6
+ t.references :user, foreign_key: true
7
+ t.references :group, 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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateRoles < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :roles do |t|
6
+ t.string :name
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateUserRoles < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :user_roles do |t|
6
+ t.references :user, foreign_key: true
7
+ t.references :role, 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,5 @@
1
+ class AddDisplayPropertiesToTenants < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :tenants, :display_properties, :jsonb, default: {}
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ class CreatePublicKeys < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :public_keys do |t|
4
+ t.references :user
5
+ t.string :content
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ 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