-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Basic Groups support #1
Changes from all commits
50a4c5b
6c49351
dc237ed
8b56c30
96a7e44
0a9ad75
47cce8f
6496503
fa1578e
dabd49c
a42c69d
e0f1fa6
8d65ade
f3425e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
inherit_from: | ||
- https://raw.githubusercontent.com/lessonly/rubocop-default-configuration/master/.rubocop.yml | ||
|
||
Metrics/BlockLength: | ||
# don't warn about block length in block-centered DSLs | ||
Exclude: | ||
- 'config/routes.rb' | ||
- 'spec/**/*.rb' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
module ScimRails | ||
module Response | ||
CONTENT_TYPE = "application/scim+json".freeze | ||
CONTENT_TYPE = "application/scim+json" | ||
|
||
def json_response(object, status = :ok) | ||
render \ | ||
|
@@ -18,7 +20,7 @@ def json_scim_response(object:, status: :ok, counts: nil) | |
content_type: CONTENT_TYPE | ||
when "show", "create", "put_update", "patch_update" | ||
render \ | ||
json: user_response(object), | ||
json: object_response(object), | ||
status: status, | ||
content_type: CONTENT_TYPE | ||
end | ||
|
@@ -32,49 +34,60 @@ def list_response(object, counts) | |
.offset(counts.offset) | ||
.limit(counts.limit) | ||
{ | ||
"schemas": [ | ||
"urn:ietf:params:scim:api:messages:2.0:ListResponse" | ||
schemas: [ | ||
"urn:ietf:params:scim:api:messages:2.0:ListResponse" | ||
], | ||
"totalResults": counts.total, | ||
"startIndex": counts.start_index, | ||
"itemsPerPage": counts.limit, | ||
"Resources": list_users(object) | ||
totalResults: counts.total, | ||
startIndex: counts.start_index, | ||
itemsPerPage: counts.limit, | ||
Resources: list_objects(object) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. list_objects -> object_response -> find_value と関数が呼ばれていくが、 |
||
} | ||
end | ||
|
||
def list_users(users) | ||
users.map do |user| | ||
user_response(user) | ||
def list_objects(objects) | ||
objects.map do |object| | ||
object_response(object) | ||
end | ||
end | ||
|
||
def user_response(user) | ||
schema = ScimRails.config.user_schema | ||
find_value(user, schema) | ||
def object_response(object) | ||
schema = case object | ||
when ScimRails.config.scim_users_model | ||
ScimRails.config.user_schema | ||
when ScimRails.config.scim_groups_model | ||
ScimRails.config.group_schema | ||
else | ||
raise ScimRails::ExceptionHandler::InvalidQuery, | ||
"Unknown model: #{object}" | ||
end | ||
find_value(object, schema) | ||
end | ||
|
||
|
||
# `find_value` is a recursive method that takes a "user" and a | ||
# "user schema" and replaces any symbols in the schema with the | ||
# corresponding value from the user. Given a schema with symbols, | ||
# `find_value` will search through the object for the symbols, | ||
# send those symbols to the model, and replace the symbol with | ||
# the return value. | ||
|
||
def find_value(user, object) | ||
case object | ||
def find_value(object, schema) | ||
case schema | ||
when Hash | ||
object.each.with_object({}) do |(key, value), hash| | ||
hash[key] = find_value(user, value) | ||
schema.each.with_object({}) do |(key, value), hash| | ||
hash[key] = find_value(object, value) | ||
Comment on lines
75
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一番最初のfind_valueは絶対にここに入る |
||
end | ||
when Array | ||
object.map do |value| | ||
find_value(user, value) | ||
when Array, ActiveRecord::Associations::CollectionProxy | ||
schema.map do |value| | ||
find_value(object, value) | ||
end | ||
when ScimRails.config.scim_users_model | ||
find_value(schema, ScimRails.config.user_abbreviated_schema) | ||
Comment on lines
+83
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Group のレスポンスを返す時に、members としてユーザの情報を返す。
|
||
when ScimRails.config.scim_groups_model | ||
find_value(schema, ScimRails.config.group_abbreviated_schema) | ||
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 上述の Group に対する members のように、Userのレスポンスを返す時に groups として情報を返すパターンで利用。 |
||
when Symbol | ||
user.public_send(object) | ||
find_value(object, object.public_send(schema)) | ||
else | ||
object | ||
schema | ||
end | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
module ScimRails | ||
class ApplicationController < ActionController::API | ||
include ActionController::HttpAuthentication::Basic::ControllerMethods | ||
|
@@ -28,11 +30,43 @@ def authentication_strategy | |
end | ||
|
||
def authenticate_with_oauth_bearer | ||
authentication_attribute = request.headers["Authorization"].split(" ").last | ||
authentication_attribute = request.headers["Authorization"].split.last | ||
payload = ScimRails::Encoder.decode(authentication_attribute).with_indifferent_access | ||
searchable_attribute = payload[ScimRails.config.basic_auth_model_searchable_attribute] | ||
|
||
yield searchable_attribute, authentication_attribute | ||
end | ||
|
||
def find_value_for(attribute) | ||
params.dig(*path_for(attribute)) | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. find_value_for および、path_for は scim_users_controller.rb に存在したが、Groupでも使うので application_controller に移動。 |
||
|
||
# `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 = controller_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 | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# frozen_string_literal: true | ||
|
||
module ScimRails | ||
class ScimGroupsController < ScimRails::ApplicationController | ||
def index | ||
if params[:filter].present? | ||
query = ScimRails::ScimQueryParser.new( | ||
params[:filter], ScimRails.config.queryable_group_attributes | ||
) | ||
|
||
groups = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.where( | ||
"#{ScimRails.config.scim_groups_model.connection.quote_column_name(query.attribute)} #{query.operator} ?", | ||
query.parameter | ||
) | ||
.order(ScimRails.config.scim_groups_list_order) | ||
else | ||
groups = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.preload(:users) | ||
.order(ScimRails.config.scim_groups_list_order) | ||
end | ||
|
||
counts = ScimCount.new( | ||
start_index: params[:startIndex], | ||
limit: params[:count], | ||
total: groups.count | ||
) | ||
|
||
json_scim_response(object: groups, counts: counts) | ||
end | ||
|
||
def show | ||
group = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.find(params[:id]) | ||
json_scim_response(object: group) | ||
end | ||
|
||
def create | ||
group = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.create!(permitted_group_params) | ||
|
||
json_scim_response(object: group, status: :created) | ||
end | ||
|
||
def put_update | ||
group = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.find(params[:id]) | ||
group.update!(permitted_group_params) | ||
json_scim_response(object: group) | ||
end | ||
|
||
def destroy | ||
unless ScimRails.config.group_destroy_method | ||
raise ScimRails::ExceptionHandler::UnsupportedDeleteRequest | ||
end | ||
group = @company | ||
.public_send(ScimRails.config.scim_groups_scope) | ||
.find(params[:id]) | ||
group.public_send(ScimRails.config.group_destroy_method) | ||
head :no_content | ||
end | ||
|
||
private | ||
|
||
def permitted_group_params | ||
converted = mutable_attributes.each.with_object({}) do |attribute, hash| | ||
hash[attribute] = find_value_for(attribute) | ||
end | ||
return converted unless params[:members] | ||
|
||
converted.merge(member_params) | ||
end | ||
|
||
def member_params | ||
{ | ||
ScimRails.config.group_member_relation_attribute => | ||
params[:members].map do |member| | ||
member[ScimRails.config.group_member_relation_schema.keys.first] | ||
end | ||
} | ||
end | ||
|
||
def mutable_attributes | ||
ScimRails.config.mutable_group_attributes | ||
end | ||
|
||
def controller_schema | ||
ScimRails.config.mutable_group_attributes_schema | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response.rb の修正:userしか扱わない前提だったが、groupも共通で扱えるようにするために object に統一