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.
- 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
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserPolicyJoin < ApplicationRecord
|
4
|
+
belongs_to :user
|
5
|
+
belongs_to :policy
|
6
|
+
|
7
|
+
after_create :add_policy_to_user
|
8
|
+
after_destroy :remove_policy_from_user
|
9
|
+
|
10
|
+
def add_policy_to_user
|
11
|
+
user.attached_policies[policy.name] ||= 0
|
12
|
+
user.attached_policies[policy.name] += 1
|
13
|
+
user.save
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_policy_from_user
|
17
|
+
user.attached_policies[policy.name] -= 1
|
18
|
+
user.attached_policies.delete(policy.name) if user.attached_policies[policy.name].zero?
|
19
|
+
user.save
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
class BlackcombUserCreate < Ros::ActivityBase
|
6
|
+
step :valdidate_root_owner
|
7
|
+
failed :invalid_user, Output(:success) => End(:failure)
|
8
|
+
step :switch_tenant
|
9
|
+
failed :invalid_schema, Output(:success) => End(:failure)
|
10
|
+
step :create_or_find_blackcomb_user
|
11
|
+
failed :failed_to_create_user
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def valdidate_root_owner(_ctx, params:, **)
|
16
|
+
Apartment::Tenant.current == 'public' && params[:current_user].root?
|
17
|
+
end
|
18
|
+
|
19
|
+
def invalid_user(_ctx, errors:, **)
|
20
|
+
errors.add(:user, 'Not a owner root')
|
21
|
+
end
|
22
|
+
|
23
|
+
def switch_tenant(_ctx, params:, **)
|
24
|
+
tenant = Tenant.find_by_schema_or_alias(params[:account_id])
|
25
|
+
return false unless tenant
|
26
|
+
|
27
|
+
tenant.switch!
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def invalid_schema(_ctx, errors:, **)
|
32
|
+
errors.add(:account_id, 'Invalid account id')
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_or_find_blackcomb_user(ctx, **)
|
36
|
+
ctx[:model] = User.find_or_initialize_by(username: 'blackcomb')
|
37
|
+
|
38
|
+
return true if ctx[:model].persisted?
|
39
|
+
|
40
|
+
password = SecureRandom.hex
|
41
|
+
ctx[:model].update(password: password, password_confirmation: password,
|
42
|
+
confirmed_at: Time.zone.today, attached_policies: { AdministratorAccess: 1 })
|
43
|
+
ctx[:model].save
|
44
|
+
end
|
45
|
+
|
46
|
+
def failed_to_create_user(ctx, model:, **)
|
47
|
+
ctx[:errors] = model.errors
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserCreate < Ros::ActivityBase
|
4
|
+
step :check_permission
|
5
|
+
failed :not_permitted, Output(:success) => End(:failure)
|
6
|
+
step :init
|
7
|
+
step :initialize_user
|
8
|
+
step :skip_confirmation_notification
|
9
|
+
step :generate_reset_passowrd_token
|
10
|
+
step :save__model, Output(:failure) => End(:failure)
|
11
|
+
step :create_relationships
|
12
|
+
step :send_welcome_email
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def check_permission(_ctx, user:, **)
|
17
|
+
UserPolicy.new(user, User.new).create?
|
18
|
+
end
|
19
|
+
|
20
|
+
def not_permitted(_ctx, errors:, **)
|
21
|
+
errors.add(:user, 'not permitted to create a user')
|
22
|
+
end
|
23
|
+
|
24
|
+
def init(ctx, params:, **)
|
25
|
+
ctx[:relationships] = params.delete(:relationships)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize_user(ctx, params:, **)
|
30
|
+
ctx[:model] = User.new(params)
|
31
|
+
end
|
32
|
+
|
33
|
+
def skip_confirmation_notification(_ctx, model:, **)
|
34
|
+
model.skip_confirmation_notification!
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_reset_passowrd_token(ctx, model:, **)
|
38
|
+
ctx[:reset_password_token], enc = Devise.token_generator.generate(model.class, :reset_password_token)
|
39
|
+
|
40
|
+
model.reset_password_token = enc
|
41
|
+
model.reset_password_sent_at = Time.now.utc
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_relationships(_ctx, model:, relationships:, **)
|
45
|
+
return true if relationships&.dig(:groups, :data).blank?
|
46
|
+
|
47
|
+
model.groups << Group.where(id: relationships[:groups][:data].pluck(:id)).all
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_welcome_email(_ctx, model:, reset_password_token:, **)
|
51
|
+
AccountMailer.team_welcome(model, reset_password_token).deliver_later
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserPolicy < Iam::ApplicationPolicy
|
4
|
+
# def index?
|
5
|
+
# user.action_permitted?(requested_action(__method__))
|
6
|
+
# # user.admin? || !record.published?
|
7
|
+
# end
|
8
|
+
|
9
|
+
# def self.zactions
|
10
|
+
# {
|
11
|
+
# Write: [
|
12
|
+
# 'AddUserToGroup'
|
13
|
+
# ]
|
14
|
+
# }
|
15
|
+
# end
|
16
|
+
|
17
|
+
# def update?
|
18
|
+
# super
|
19
|
+
# # does current_user have permission 'UpdateUser'
|
20
|
+
# end
|
21
|
+
|
22
|
+
# NOTE: Iam is a class in the api-client as are all namespaced models
|
23
|
+
# requested_action = Iam::Service.find_by(name: 'User').actions.find_by(name: 'DescribeUser')
|
24
|
+
# NOTE: The result should be cached as this value will not change frequently
|
25
|
+
# NOTE: There should be a way to break the cache in case the value does change
|
26
|
+
# def requested_action(method_name)
|
27
|
+
# Service.find_by(name: service_name).actions.find_by(name: action_name(method_name))
|
28
|
+
# end
|
29
|
+
|
30
|
+
# def action_name(method_name)
|
31
|
+
# method_map[method_name] + service_name
|
32
|
+
# end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActionResource < Iam::ApplicationResource
|
4
|
+
# caching
|
5
|
+
attributes :name, :resource, :action_type
|
6
|
+
|
7
|
+
def action_type
|
8
|
+
@model.type
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# class ListActionResource < ActionResource; end
|
13
|
+
|
14
|
+
# class ReadActionResource < ActionResource; end
|
15
|
+
|
16
|
+
# class WriteActionResource < ActionResource; end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CredentialResource < Iam::ApplicationResource
|
4
|
+
attributes :access_key_id, :owner_type, :owner_id, :secret_access_key
|
5
|
+
|
6
|
+
filter :access_key_id
|
7
|
+
|
8
|
+
def self.descriptions
|
9
|
+
{
|
10
|
+
access_key_id: 'The access key'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RootResource < Iam::ApplicationResource
|
4
|
+
attributes :email, :jwt_payload
|
5
|
+
attributes :attached_policies, :attached_actions
|
6
|
+
|
7
|
+
has_many :credentials
|
8
|
+
|
9
|
+
filter :email
|
10
|
+
|
11
|
+
def attached_policies; {} end
|
12
|
+
|
13
|
+
def attached_actions; {} end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TenantResource < Iam::ApplicationResource
|
4
|
+
attributes :account_id, :root_id, :alias, :name, :display_properties # :locale
|
5
|
+
|
6
|
+
filter :schema_name
|
7
|
+
|
8
|
+
def self.descriptions
|
9
|
+
{
|
10
|
+
schema_name: 'The name of the <h1>Schema</h1>'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.updatable_fields(context)
|
15
|
+
super - [:root_id]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.creatable_fields(context)
|
19
|
+
super - [:root_id]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserResource < Iam::ApplicationResource
|
4
|
+
attributes :username, :api, :console, :time_zone, :properties,
|
5
|
+
:display_properties, :jwt_payload, :attached_policies,
|
6
|
+
:attached_actions, :email, :password, :password_confirmation, :unconfirmed_email
|
7
|
+
|
8
|
+
has_many :groups
|
9
|
+
has_many :credentials
|
10
|
+
has_many :public_keys
|
11
|
+
|
12
|
+
filters :username, :groups
|
13
|
+
|
14
|
+
def fetchable_fields
|
15
|
+
super - %i[password password_confirmation]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.creatable_fields(context)
|
19
|
+
super - %i[attached_policies attached_actions jwt_payload]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.updatable_fields(context)
|
23
|
+
super - %i[attached_policies attached_actions jwt_payload]
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<p>Hello <%= @email %>!</p>
|
2
|
+
|
3
|
+
<% if @resource.try(:unconfirmed_email?) %>
|
4
|
+
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
5
|
+
<% else %>
|
6
|
+
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
7
|
+
<% end %>
|
@@ -0,0 +1,106 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
7
|
+
|
8
|
+
<title>PERX Reset Password</title>
|
9
|
+
|
10
|
+
<link href="https://fonts.googleapis.com/css?family=Roboto:400,500" rel="stylesheet" type="text/css">
|
11
|
+
<style type="text/css">
|
12
|
+
</style>
|
13
|
+
</head>
|
14
|
+
<body style="margin:0; padding:0; background-color:#F2F6FC;">
|
15
|
+
<center>
|
16
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#F2F6FC">
|
17
|
+
<tr>
|
18
|
+
<td align="center" height="100%" valign="top" width="100%">
|
19
|
+
<!--[if (gte mso 9)|(IE)]>
|
20
|
+
<table align="center" border="0" cellspacing="24" cellpadding="0" width="600">
|
21
|
+
<tr>
|
22
|
+
<td align="center" valign="top" width="600">
|
23
|
+
<![endif]-->
|
24
|
+
<table align="center" border="0" cellpadding="0" cellspacing="24" width="100%" style="max-width:600px;" bgcolor="#ffffff">
|
25
|
+
<tr>
|
26
|
+
<td align="left">
|
27
|
+
<img alt="Perx" src="https://cdn.uat.whistler.perxtech.io/dev1/global/assets/email/logo.png" width="96" height="34" style="width: 100%; max-width: 96px; font-family: 'Roboto', Helvetica, Arial, sans-serif; font-weight: 500; font-size: 24px; line-height: 24px; letter-spacing: 0.18px; color: #2664ed; text-transform: lowercase; display: block; border: 0px;" border="0">
|
28
|
+
</td>
|
29
|
+
</tr>
|
30
|
+
<tr>
|
31
|
+
<td align="center">
|
32
|
+
<img alt="Illustration of user unlocking account" src="https://cdn.uat.whistler.perxtech.io/dev1/global/assets/email/email-reset.png" width="268" style="width: 100%; max-width: 268px; font-family: 'Roboto', Helvetica, Arial, sans-serif; font-weight: 400; font-size: 12px; line-height: 16px; letter-spacing: 0.4px; color: #7b7b7b; display: block; border: 0px;" border="0">
|
33
|
+
</td>
|
34
|
+
</tr>
|
35
|
+
<tr>
|
36
|
+
<td align="left" valign="top" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-weight: 400; font-size: 24px; line-height: 24px; letter-spacing: 0.18px; color: #333333;">
|
37
|
+
Hi <%= @resource.username %>,
|
38
|
+
</td>
|
39
|
+
</tr>
|
40
|
+
<tr>
|
41
|
+
<td align="left" valign="top" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; letter-spacing: 0.15px; color: #7b7b7b;">
|
42
|
+
A request has been made to reset your password. Simply click on the button below to reset it.
|
43
|
+
<b style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; letter-spacing: 0.15px; color: #333333; font-weight: 500;">
|
44
|
+
This password reset is only valid for the next 24 hours.
|
45
|
+
</b>
|
46
|
+
</td>
|
47
|
+
</tr>
|
48
|
+
<tr>
|
49
|
+
<td align="center">
|
50
|
+
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
51
|
+
<tr>
|
52
|
+
<td align="center">
|
53
|
+
<table border="0" cellspacing="0" cellpadding="0" width="268" style="width: 100%; max-width: 268px;">
|
54
|
+
<tr>
|
55
|
+
<td align="center" width="100%" style="width: 100%; border-radius: 4px;" bgcolor="#2664ED"><a href="<%= @reset_url %>" target="_blank" style="font-size: 14px; letter-spacing: 0.75px; font-family: 'Roboto', Helvetica, Arial, sans-serif; color: #ffffff; font-weight: 500; text-decoration: none; border-radius: 4px; padding: 12px 24px; border: 1px solid #2664ED; display: block;"><!--[if mso]> <![endif]-->Reset Password<!--[if mso]> <![endif]--></a></td>
|
56
|
+
</tr>
|
57
|
+
</table>
|
58
|
+
</td>
|
59
|
+
</tr>
|
60
|
+
</table>
|
61
|
+
</td>
|
62
|
+
</tr>
|
63
|
+
<tr>
|
64
|
+
<td align="left" valign="top" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; letter-spacing: 0.15px; color: #7b7b7b;">
|
65
|
+
If you did not make this request, you can safely ignore this email or
|
66
|
+
<a href="#" target="_blank" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; letter-spacing: 0.15px; color: #2664ED; font-weight: 400; display: inline-block; text-decoration: none;">
|
67
|
+
contact support
|
68
|
+
</a>
|
69
|
+
if you have questions.
|
70
|
+
</td>
|
71
|
+
</tr>
|
72
|
+
<tr>
|
73
|
+
<td align="left" valign="top" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; letter-spacing: 0.15px; color: #7b7b7b;">
|
74
|
+
Thank you, <br />
|
75
|
+
Team Perx
|
76
|
+
</td>
|
77
|
+
</tr>
|
78
|
+
<tr>
|
79
|
+
<td height="1" style="font-size:1px; line-height:1px;"> </td>
|
80
|
+
</tr>
|
81
|
+
<tr>
|
82
|
+
<td height="1" style="font-size:1px; line-height:1px;" bgcolor="#e8e8e8"> </td>
|
83
|
+
</tr>
|
84
|
+
<tr>
|
85
|
+
<td height="1" style="font-size:1px; line-height:1px;"> </td>
|
86
|
+
</tr>
|
87
|
+
<tr>
|
88
|
+
<td align="left" valign="top" style="font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 16px; letter-spacing: 0.4px; color: #7b7b7b;">
|
89
|
+
© 2019 Perx Technologies. All rights reserved.<br /><br />
|
90
|
+
20 Maxwell Road #02-01 <br />
|
91
|
+
Maxwell House, 069113
|
92
|
+
</td>
|
93
|
+
</tr>
|
94
|
+
|
95
|
+
</table>
|
96
|
+
<!--[if (gte mso 9)|(IE)]>
|
97
|
+
</td>
|
98
|
+
</tr>
|
99
|
+
</table>
|
100
|
+
<![endif]-->
|
101
|
+
</td>
|
102
|
+
</tr>
|
103
|
+
</table>
|
104
|
+
</center>
|
105
|
+
</body>
|
106
|
+
</html>
|