-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathscim_users_controller.rb
More file actions
152 lines (129 loc) · 4.41 KB
/
Copy pathscim_users_controller.rb
File metadata and controls
152 lines (129 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
module ScimRails
class ScimUsersController < ScimRails::ApplicationController
def index
if params[:filter].present?
query = ScimRails::ScimQueryParser.new(params[:filter])
users = @company
.public_send(ScimRails.config.scim_users_scope)
.where(
"#{ScimRails.config.scim_users_model.connection.quote_column_name(query.attribute)} #{query.operator} ?",
query.parameter
)
.order(ScimRails.config.scim_users_list_order)
else
users = @company
.public_send(ScimRails.config.scim_users_scope)
.order(ScimRails.config.scim_users_list_order)
end
counts = ScimCount.new(
start_index: params[:startIndex],
limit: params[:count],
total: users.count
)
json_scim_response(object: users, counts: counts)
end
def create
if ScimRails.config.scim_user_prevent_update_on_create
user = @company.public_send(ScimRails.config.scim_users_scope).create!(permitted_user_params)
else
username_key = ScimRails.config.queryable_user_attributes[:userName]
find_by_username = Hash.new
find_by_username[username_key] = permitted_user_params[username_key]
user = @company
.public_send(ScimRails.config.scim_users_scope)
.find_or_create_by(find_by_username)
user.update!(permitted_user_params)
end
update_status(user) unless put_active_param.nil?
json_scim_response(object: user, status: :created)
end
def show
user = find_user
json_scim_response(object: user)
end
def put_update
user = find_user
update_status(user) unless put_active_param.nil?
user.update!(permitted_user_params)
json_scim_response(object: user)
end
# TODO: PATCH will only deprovision or reprovision users.
# This will work just fine for Okta but is not SCIM compliant.
def patch_update
user = find_user
update_status(user)
json_scim_response(object: user)
end
private
def find_user
@company.public_send(ScimRails.config.scim_users_scope).find(params[:id])
end
def permitted_user_params
ScimRails.config.mutable_user_attributes.each.with_object({}) do |attribute, hash|
hash[attribute] = find_value_for(attribute)
end
end
def find_value_for(attribute)
params.dig(*path_for(attribute))
end
# `path_for` is a recursive method used to find the "path" for
# `.dig` to take when looking for a given attribute in the
# params.
#
# Example: `path_for(:name)` should return an array that looks
# like [:names, 0, :givenName]. `.dig` can then use that path
# against the params to translate the :name attribute to "John".
def path_for(attribute, object = ScimRails.config.mutable_user_attributes_schema, path = [])
at_path = path.empty? ? object : object.dig(*path)
return path if at_path == attribute
case at_path
when Hash
at_path.each do |key, value|
found_path = path_for(attribute, object, [*path, key])
return found_path if found_path
end
nil
when Array
at_path.each_with_index do |value, index|
found_path = path_for(attribute, object, [*path, index])
return found_path if found_path
end
nil
end
end
def update_status(user)
user.public_send(ScimRails.config.user_reprovision_method) if active?
user.public_send(ScimRails.config.user_deprovision_method) unless active?
end
def active?
active = put_active_param
active = patch_active_param if active.nil?
case active
when true, "true", 1
true
when false, "false", 0
false
else
raise ActiveRecord::RecordInvalid
end
end
def put_active_param
params[:active]
end
def patch_active_param
handle_invalid = lambda do
raise ScimRails::ExceptionHandler::UnsupportedPatchRequest
end
operations = params["Operations"] || {}
valid_operation = operations.find(handle_invalid) do |operation|
valid_patch_operation?(operation)
end
valid_operation.dig("value", "active")
end
def valid_patch_operation?(operation)
operation["op"].casecmp("replace") &&
operation["value"] &&
[true, false].include?(operation["value"]["active"])
end
end
end