scimaenaga 0.9.0 → 0.9.1
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 +4 -4
- data/README.md +8 -8
- data/Rakefile +6 -8
- data/app/controllers/concerns/{scim_rails → scimaenaga}/exception_handler.rb +10 -10
- data/app/controllers/concerns/scimaenaga/response.rb +94 -0
- data/app/controllers/scimaenaga/application_controller.rb +72 -0
- data/app/controllers/{scim_rails → scimaenaga}/scim_groups_controller.rb +25 -25
- data/app/controllers/{scim_rails → scimaenaga}/scim_schemas_controller.rb +5 -5
- data/app/controllers/scimaenaga/scim_users_controller.rb +104 -0
- data/app/helpers/{scim_rails → scimaenaga}/application_helper.rb +1 -1
- data/app/libraries/scim_patch.rb +2 -2
- data/app/libraries/scim_patch_operation.rb +1 -1
- data/app/libraries/scim_patch_operation_group.rb +3 -3
- data/app/libraries/scim_patch_operation_user.rb +2 -2
- data/app/models/{scim_rails → scimaenaga}/application_record.rb +1 -1
- data/app/models/scimaenaga/authorize_api_request.rb +39 -0
- data/app/models/{scim_rails → scimaenaga}/scim_count.rb +8 -4
- data/app/models/scimaenaga/scim_query_parser.rb +49 -0
- data/config/routes.rb +1 -1
- data/lib/generators/scimaenaga/USAGE +8 -0
- data/lib/generators/scimaenaga/scimaenaga_generator.rb +7 -0
- data/lib/generators/{scim_rails → scimaenaga}/templates/initializer.rb +22 -22
- data/lib/{scim_rails → scimaenaga}/config.rb +2 -2
- data/lib/scimaenaga/encoder.rb +27 -0
- data/lib/scimaenaga/engine.rb +12 -0
- data/lib/scimaenaga/version.rb +5 -0
- data/lib/scimaenaga.rb +6 -0
- data/lib/tasks/{scim_rails_tasks.rake → scimaenaga_tasks.rake} +1 -1
- data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_controller_spec.rb +8 -8
- data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_request_spec.rb +18 -18
- data/spec/controllers/{scim_rails → scimaenaga}/scim_schemas_controller_spec.rb +7 -7
- data/spec/controllers/{scim_rails → scimaenaga}/scim_schemas_request_spec.rb +1 -1
- data/spec/controllers/{scim_rails → scimaenaga}/scim_users_controller_spec.rb +14 -15
- data/spec/controllers/{scim_rails → scimaenaga}/scim_users_request_spec.rb +20 -20
- data/spec/dummy/app/assets/config/manifest.js +1 -1
- data/spec/dummy/config/application.rb +1 -2
- data/spec/dummy/config/initializers/{scim_rails_config.rb → scimaenaga_config.rb} +1 -1
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/factories/company.rb +3 -3
- data/spec/lib/scimaenaga/encoder_spec.rb +64 -0
- data/spec/libraries/scim_patch_operation_group_spec.rb +14 -14
- data/spec/libraries/scim_patch_operation_user_spec.rb +5 -5
- data/spec/libraries/scim_patch_spec.rb +2 -2
- data/spec/models/scim_query_parser_spec.rb +5 -6
- metadata +40 -39
- data/app/controllers/concerns/scim_rails/response.rb +0 -94
- data/app/controllers/scim_rails/application_controller.rb +0 -72
- data/app/controllers/scim_rails/scim_users_controller.rb +0 -104
- data/app/models/scim_rails/authorize_api_request.rb +0 -40
- data/app/models/scim_rails/scim_query_parser.rb +0 -49
- data/lib/generators/scim_rails/USAGE +0 -8
- data/lib/generators/scim_rails/scim_rails_generator.rb +0 -7
- data/lib/scim_rails/encoder.rb +0 -25
- data/lib/scim_rails/engine.rb +0 -12
- data/lib/scim_rails/version.rb +0 -5
- data/lib/scim_rails.rb +0 -6
- data/spec/lib/scim_rails/encoder_spec.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41335471b09b4e09028210f9c05586a1f171cf2e6cf3d12d03b07bddd0022dc3
|
4
|
+
data.tar.gz: 12c2072c1bc4a57274cb427a4507ed2b4a13a038b9e311bfdb7e29fabc94e524
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc91680912294a747970e1ede984f5bbe4ad555bfacace02cc844abd6d13b124cb07f62481a6e7a7aaf1258253ca5e3d9fc83d4606cebfc44e50041dbd0e881f
|
7
|
+
data.tar.gz: 87da8ec3d1a3295d1766f13dc8474e525dc0a0c96fc4a458e79279ff48b05d7e8d628311880b10aa15925f149a59a4f54991154eeea605304df4338779dc03d3
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ The goal of the Gem is to offer a relatively painless way of adding SCIM 2.0 to
|
|
17
17
|
Add this line to your application's Gemfile:
|
18
18
|
|
19
19
|
```ruby
|
20
|
-
gem 'scimaenaga'
|
20
|
+
gem 'scimaenaga'
|
21
21
|
```
|
22
22
|
|
23
23
|
And then execute:
|
@@ -35,13 +35,13 @@ $ gem install scimaenaga
|
|
35
35
|
Generate the config file with:
|
36
36
|
|
37
37
|
```bash
|
38
|
-
$ rails generate
|
38
|
+
$ rails generate scimaenaga config
|
39
39
|
```
|
40
40
|
|
41
41
|
The config file will be located at:
|
42
42
|
|
43
43
|
```
|
44
|
-
config/initializers/
|
44
|
+
config/initializers/scimaenaga_config.rb
|
45
45
|
```
|
46
46
|
|
47
47
|
Please update the config file with the models and attributes of your app.
|
@@ -50,7 +50,7 @@ Mount the gem in your routes file:
|
|
50
50
|
|
51
51
|
```ruby
|
52
52
|
Application.routes.draw do
|
53
|
-
mount
|
53
|
+
mount Scimaenaga::Engine => "/"
|
54
54
|
end
|
55
55
|
```
|
56
56
|
|
@@ -95,7 +95,7 @@ The config setting `basic_auth_model_authenticatable_attribute` is the model att
|
|
95
95
|
|
96
96
|
Assuming the attribute is `:api_token`, generate the password using:
|
97
97
|
```ruby
|
98
|
-
token =
|
98
|
+
token = Scimaenaga::Encoder.encode(company)
|
99
99
|
# use the token as password for requests
|
100
100
|
company.api_token = token # required
|
101
101
|
company.save! # don't forget to persist the company record
|
@@ -119,7 +119,7 @@ In the config settings, ensure you set `signing_secret` to a secret key that wil
|
|
119
119
|
|
120
120
|
If you have already generated the `api_token` in the "Basic Auth" section, then use that as your bearer token and ignore the steps below:
|
121
121
|
```ruby
|
122
|
-
token =
|
122
|
+
token = Scimaenaga::Encoder.encode(company)
|
123
123
|
# use the token as bearer token for requests
|
124
124
|
company.api_token = token #required
|
125
125
|
company.save! # don't forget to persist the company record
|
@@ -245,7 +245,7 @@ If you would like, you can supply a custom handler for exceptions in the initial
|
|
245
245
|
For example, you might want to notify Honeybadger:
|
246
246
|
|
247
247
|
```ruby
|
248
|
-
|
248
|
+
Scimaenaga.configure do |config|
|
249
249
|
config.on_error = ->(e) { Honeybadger.notify(e) }
|
250
250
|
end
|
251
251
|
```
|
@@ -262,7 +262,7 @@ e.g.) When `userName` is defined in `mutable_user_attributes`, configure `userNa
|
|
262
262
|
- corresponding with your model.
|
263
263
|
e.g.) When `userName` must be specified configure `userName` as `required: true`
|
264
264
|
|
265
|
-
Sample config (with comment) is written in lib/generators/
|
265
|
+
Sample config (with comment) is written in lib/generators/scimaenaga/templates/initializer.rb.
|
266
266
|
For more details, read [Schema Definition](https://datatracker.ietf.org/doc/html/rfc7643#section-7), and [Schema Representation](https://datatracker.ietf.org/doc/html/rfc7643#section-8.7)
|
267
267
|
|
268
268
|
## Contributing
|
data/Rakefile
CHANGED
@@ -8,27 +8,25 @@ require 'rdoc/task'
|
|
8
8
|
|
9
9
|
RDoc::Task.new(:rdoc) do |rdoc|
|
10
10
|
rdoc.rdoc_dir = 'rdoc'
|
11
|
-
rdoc.title = '
|
11
|
+
rdoc.title = 'Scimaenaga'
|
12
12
|
rdoc.options << '--line-numbers'
|
13
13
|
rdoc.rdoc_files.include('README.md')
|
14
14
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
15
|
end
|
16
16
|
|
17
|
-
APP_RAKEFILE = File.expand_path(
|
17
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
18
18
|
load 'rails/tasks/engine.rake'
|
19
19
|
|
20
|
-
|
21
20
|
load 'rails/tasks/statistics.rake'
|
22
21
|
|
23
|
-
|
24
22
|
Bundler::GemHelper.install_tasks
|
25
23
|
|
26
|
-
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
|
24
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each { |f| load f }
|
27
25
|
|
28
26
|
require 'rspec/core'
|
29
27
|
require 'rspec/core/rake_task'
|
30
28
|
|
31
|
-
desc
|
32
|
-
RSpec::Core::RakeTask.new(:
|
29
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
30
|
+
RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
|
33
31
|
|
34
|
-
task :
|
32
|
+
task default: :spec
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Scimaenaga
|
4
4
|
module ExceptionHandler
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
@@ -37,7 +37,7 @@ module ScimRails
|
|
37
37
|
included do
|
38
38
|
if Rails.env.production?
|
39
39
|
rescue_from StandardError do |exception|
|
40
|
-
on_error =
|
40
|
+
on_error = Scimaenaga.config.on_error
|
41
41
|
if on_error.respond_to?(:call)
|
42
42
|
on_error.call(exception)
|
43
43
|
else
|
@@ -54,7 +54,7 @@ module ScimRails
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
rescue_from
|
57
|
+
rescue_from Scimaenaga::ExceptionHandler::InvalidCredentials do
|
58
58
|
json_response(
|
59
59
|
{
|
60
60
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -65,7 +65,7 @@ module ScimRails
|
|
65
65
|
)
|
66
66
|
end
|
67
67
|
|
68
|
-
rescue_from
|
68
|
+
rescue_from Scimaenaga::ExceptionHandler::InvalidRequest do |e|
|
69
69
|
json_response(
|
70
70
|
{
|
71
71
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -76,7 +76,7 @@ module ScimRails
|
|
76
76
|
)
|
77
77
|
end
|
78
78
|
|
79
|
-
rescue_from
|
79
|
+
rescue_from Scimaenaga::ExceptionHandler::InvalidQuery do
|
80
80
|
json_response(
|
81
81
|
{
|
82
82
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -88,7 +88,7 @@ module ScimRails
|
|
88
88
|
)
|
89
89
|
end
|
90
90
|
|
91
|
-
rescue_from
|
91
|
+
rescue_from Scimaenaga::ExceptionHandler::UnsupportedPatchRequest do
|
92
92
|
json_response(
|
93
93
|
{
|
94
94
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -99,7 +99,7 @@ module ScimRails
|
|
99
99
|
)
|
100
100
|
end
|
101
101
|
|
102
|
-
rescue_from
|
102
|
+
rescue_from Scimaenaga::ExceptionHandler::UnsupportedDeleteRequest do
|
103
103
|
json_response(
|
104
104
|
{
|
105
105
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -110,7 +110,7 @@ module ScimRails
|
|
110
110
|
)
|
111
111
|
end
|
112
112
|
|
113
|
-
rescue_from
|
113
|
+
rescue_from Scimaenaga::ExceptionHandler::InvalidConfiguration do |e|
|
114
114
|
json_response(
|
115
115
|
{
|
116
116
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -121,7 +121,7 @@ module ScimRails
|
|
121
121
|
)
|
122
122
|
end
|
123
123
|
|
124
|
-
rescue_from
|
124
|
+
rescue_from Scimaenaga::ExceptionHandler::UnexpectedError do |e|
|
125
125
|
json_response(
|
126
126
|
{
|
127
127
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -133,7 +133,7 @@ module ScimRails
|
|
133
133
|
end
|
134
134
|
|
135
135
|
rescue_from ActiveRecord::RecordNotFound,
|
136
|
-
|
136
|
+
Scimaenaga::ExceptionHandler::ResourceNotFound do |e|
|
137
137
|
json_response(
|
138
138
|
{
|
139
139
|
schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Scimaenaga
|
4
|
+
module Response
|
5
|
+
CONTENT_TYPE = 'application/scim+json'
|
6
|
+
|
7
|
+
def json_response(object, status = :ok)
|
8
|
+
render \
|
9
|
+
json: object,
|
10
|
+
status: status,
|
11
|
+
content_type: CONTENT_TYPE
|
12
|
+
end
|
13
|
+
|
14
|
+
def json_scim_response(object:, status: :ok, counts: nil)
|
15
|
+
case params[:action]
|
16
|
+
when 'index'
|
17
|
+
render \
|
18
|
+
json: list_response(object, counts),
|
19
|
+
status: status,
|
20
|
+
content_type: CONTENT_TYPE
|
21
|
+
when 'show', 'create', 'put_update', 'patch_update'
|
22
|
+
render \
|
23
|
+
json: object_response(object),
|
24
|
+
status: status,
|
25
|
+
content_type: CONTENT_TYPE
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def list_response(object, counts)
|
32
|
+
object = object
|
33
|
+
.order(:id)
|
34
|
+
.offset(counts.offset)
|
35
|
+
.limit(counts.limit)
|
36
|
+
{
|
37
|
+
schemas: [
|
38
|
+
'urn:ietf:params:scim:api:messages:2.0:ListResponse'
|
39
|
+
],
|
40
|
+
totalResults: counts.total,
|
41
|
+
startIndex: counts.start_index,
|
42
|
+
itemsPerPage: counts.limit,
|
43
|
+
Resources: list_objects(object),
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def list_objects(objects)
|
48
|
+
objects.map do |object|
|
49
|
+
object_response(object)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def object_response(object)
|
54
|
+
schema = case object
|
55
|
+
when Scimaenaga.config.scim_users_model
|
56
|
+
Scimaenaga.config.user_schema
|
57
|
+
when Scimaenaga.config.scim_groups_model
|
58
|
+
Scimaenaga.config.group_schema
|
59
|
+
else
|
60
|
+
raise Scimaenaga::ExceptionHandler::InvalidQuery,
|
61
|
+
"Unknown model: #{object}"
|
62
|
+
end
|
63
|
+
find_value(object, schema)
|
64
|
+
end
|
65
|
+
|
66
|
+
# `find_value` is a recursive method that takes a "user" and a
|
67
|
+
# "user schema" and replaces any symbols in the schema with the
|
68
|
+
# corresponding value from the user. Given a schema with symbols,
|
69
|
+
# `find_value` will search through the object for the symbols,
|
70
|
+
# send those symbols to the model, and replace the symbol with
|
71
|
+
# the return value.
|
72
|
+
|
73
|
+
def find_value(object, schema)
|
74
|
+
case schema
|
75
|
+
when Hash
|
76
|
+
schema.each.with_object({}) do |(key, value), hash|
|
77
|
+
hash[key] = find_value(object, value)
|
78
|
+
end
|
79
|
+
when Array, ActiveRecord::Associations::CollectionProxy
|
80
|
+
schema.map do |value|
|
81
|
+
find_value(object, value)
|
82
|
+
end
|
83
|
+
when Scimaenaga.config.scim_users_model
|
84
|
+
find_value(schema, Scimaenaga.config.user_abbreviated_schema)
|
85
|
+
when Scimaenaga.config.scim_groups_model
|
86
|
+
find_value(schema, Scimaenaga.config.group_abbreviated_schema)
|
87
|
+
when Symbol
|
88
|
+
find_value(object, object.public_send(schema))
|
89
|
+
else
|
90
|
+
schema
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Scimaenaga
|
4
|
+
class ApplicationController < ActionController::API
|
5
|
+
include ActionController::HttpAuthentication::Basic::ControllerMethods
|
6
|
+
include ExceptionHandler
|
7
|
+
include Response
|
8
|
+
|
9
|
+
before_action :authorize_request
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def authorize_request
|
14
|
+
send(authentication_strategy) do |searchable_attribute, authentication_attribute|
|
15
|
+
authorization = AuthorizeApiRequest.new(
|
16
|
+
searchable_attribute: searchable_attribute,
|
17
|
+
authentication_attribute: authentication_attribute
|
18
|
+
)
|
19
|
+
@company = authorization.company
|
20
|
+
end
|
21
|
+
raise Scimaenaga::ExceptionHandler::InvalidCredentials if @company.blank?
|
22
|
+
end
|
23
|
+
|
24
|
+
def authentication_strategy
|
25
|
+
if request.headers['Authorization']&.include?('Bearer')
|
26
|
+
:authenticate_with_oauth_bearer
|
27
|
+
else
|
28
|
+
:authenticate_with_http_basic
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def authenticate_with_oauth_bearer
|
33
|
+
authentication_attribute = request.headers['Authorization'].split.last
|
34
|
+
payload = Scimaenaga::Encoder.decode(authentication_attribute).with_indifferent_access
|
35
|
+
searchable_attribute = payload[Scimaenaga.config.basic_auth_model_searchable_attribute]
|
36
|
+
|
37
|
+
yield searchable_attribute, authentication_attribute
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_value_for(attribute)
|
41
|
+
params.dig(*path_for(attribute))
|
42
|
+
end
|
43
|
+
|
44
|
+
# `path_for` is a recursive method used to find the "path" for
|
45
|
+
# `.dig` to take when looking for a given attribute in the
|
46
|
+
# params.
|
47
|
+
#
|
48
|
+
# Example: `path_for(:name)` should return an array that looks
|
49
|
+
# like [:names, 0, :givenName]. `.dig` can then use that path
|
50
|
+
# against the params to translate the :name attribute to "John".
|
51
|
+
|
52
|
+
def path_for(attribute, object = controller_schema, path = [])
|
53
|
+
at_path = path.empty? ? object : object.dig(*path)
|
54
|
+
return path if at_path == attribute
|
55
|
+
|
56
|
+
case at_path
|
57
|
+
when Hash
|
58
|
+
at_path.each do |key, _value|
|
59
|
+
found_path = path_for(attribute, object, [*path, key])
|
60
|
+
return found_path if found_path
|
61
|
+
end
|
62
|
+
nil
|
63
|
+
when Array
|
64
|
+
at_path.each_with_index do |_value, index|
|
65
|
+
found_path = path_for(attribute, object, [*path, index])
|
66
|
+
return found_path if found_path
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
class ScimGroupsController <
|
3
|
+
module Scimaenaga
|
4
|
+
class ScimGroupsController < Scimaenaga::ApplicationController
|
5
5
|
def index
|
6
6
|
if params[:filter].present?
|
7
|
-
query =
|
8
|
-
params[:filter],
|
7
|
+
query = Scimaenaga::ScimQueryParser.new(
|
8
|
+
params[:filter], Scimaenaga.config.queryable_group_attributes
|
9
9
|
)
|
10
10
|
|
11
11
|
groups = @company
|
12
|
-
.public_send(
|
12
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
13
13
|
.where(
|
14
|
-
"#{
|
14
|
+
"#{Scimaenaga.config.scim_groups_model
|
15
15
|
.connection.quote_column_name(query.attribute)}
|
16
16
|
#{query.operator} ?",
|
17
17
|
query.parameter
|
18
18
|
)
|
19
|
-
.order(
|
19
|
+
.order(Scimaenaga.config.scim_groups_list_order)
|
20
20
|
else
|
21
21
|
groups = @company
|
22
|
-
.public_send(
|
22
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
23
23
|
.preload(:users)
|
24
|
-
.order(
|
24
|
+
.order(Scimaenaga.config.scim_groups_list_order)
|
25
25
|
end
|
26
26
|
|
27
27
|
counts = ScimCount.new(
|
@@ -35,14 +35,14 @@ module ScimRails
|
|
35
35
|
|
36
36
|
def show
|
37
37
|
group = @company
|
38
|
-
.public_send(
|
38
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
39
39
|
.find(params[:id])
|
40
40
|
json_scim_response(object: group)
|
41
41
|
end
|
42
42
|
|
43
43
|
def create
|
44
44
|
group = @company
|
45
|
-
.public_send(
|
45
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
46
46
|
.create!(permitted_group_params)
|
47
47
|
|
48
48
|
json_scim_response(object: group, status: :created)
|
@@ -50,7 +50,7 @@ module ScimRails
|
|
50
50
|
|
51
51
|
def put_update
|
52
52
|
group = @company
|
53
|
-
.public_send(
|
53
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
54
54
|
.find(params[:id])
|
55
55
|
group.update!(permitted_group_params)
|
56
56
|
json_scim_response(object: group)
|
@@ -58,7 +58,7 @@ module ScimRails
|
|
58
58
|
|
59
59
|
def patch_update
|
60
60
|
group = @company
|
61
|
-
.public_send(
|
61
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
62
62
|
.find(params[:id])
|
63
63
|
patch = ScimPatch.new(params, :group)
|
64
64
|
patch.save(group)
|
@@ -67,23 +67,23 @@ module ScimRails
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def destroy
|
70
|
-
unless
|
71
|
-
raise
|
70
|
+
unless Scimaenaga.config.group_destroy_method
|
71
|
+
raise Scimaenaga::ExceptionHandler::InvalidConfiguration
|
72
72
|
end
|
73
73
|
|
74
74
|
group = @company
|
75
|
-
.public_send(
|
75
|
+
.public_send(Scimaenaga.config.scim_groups_scope)
|
76
76
|
.find(params[:id])
|
77
77
|
raise ActiveRecord::RecordNotFound unless group
|
78
78
|
|
79
79
|
begin
|
80
|
-
group.public_send(
|
80
|
+
group.public_send(Scimaenaga.config.group_destroy_method)
|
81
81
|
rescue NoMethodError => e
|
82
|
-
raise
|
82
|
+
raise Scimaenaga::ExceptionHandler::InvalidConfiguration, e.message
|
83
83
|
rescue ActiveRecord::RecordNotDestroyed => e
|
84
|
-
raise
|
85
|
-
rescue => e
|
86
|
-
raise
|
84
|
+
raise Scimaenaga::ExceptionHandler::InvalidRequest, e.message
|
85
|
+
rescue StandardError => e
|
86
|
+
raise Scimaenaga::ExceptionHandler::UnexpectedError, e.message
|
87
87
|
end
|
88
88
|
|
89
89
|
head :no_content
|
@@ -102,19 +102,19 @@ module ScimRails
|
|
102
102
|
|
103
103
|
def member_params
|
104
104
|
{
|
105
|
-
|
105
|
+
Scimaenaga.config.group_member_relation_attribute =>
|
106
106
|
params[:members].map do |member|
|
107
|
-
member[
|
107
|
+
member[Scimaenaga.config.group_member_relation_schema.keys.first]
|
108
108
|
end,
|
109
109
|
}
|
110
110
|
end
|
111
111
|
|
112
112
|
def mutable_attributes
|
113
|
-
|
113
|
+
Scimaenaga.config.mutable_group_attributes
|
114
114
|
end
|
115
115
|
|
116
116
|
def controller_schema
|
117
|
-
|
117
|
+
Scimaenaga.config.mutable_group_attributes_schema
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
class ScimSchemasController <
|
3
|
+
module Scimaenaga
|
4
|
+
class ScimSchemasController < Scimaenaga::ApplicationController
|
5
5
|
def index
|
6
|
-
schemas =
|
6
|
+
schemas = Scimaenaga.config.schemas
|
7
7
|
|
8
8
|
counts = ScimCount.new(
|
9
9
|
start_index: params[:startIndex],
|
@@ -15,11 +15,11 @@ module ScimRails
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def show
|
18
|
-
schema =
|
18
|
+
schema = Scimaenaga.config.schemas.find do |s|
|
19
19
|
s[:id] == params[:id]
|
20
20
|
end
|
21
21
|
|
22
|
-
raise
|
22
|
+
raise Scimaenaga::ExceptionHandler::ResourceNotFound, params[:id] if schema.nil?
|
23
23
|
|
24
24
|
json_response(schema)
|
25
25
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Scimaenaga
|
4
|
+
class ScimUsersController < Scimaenaga::ApplicationController
|
5
|
+
|
6
|
+
def index
|
7
|
+
if params[:filter].present?
|
8
|
+
query = Scimaenaga::ScimQueryParser.new(
|
9
|
+
params[:filter], Scimaenaga.config.queryable_user_attributes
|
10
|
+
)
|
11
|
+
|
12
|
+
users = @company
|
13
|
+
.public_send(Scimaenaga.config.scim_users_scope)
|
14
|
+
.where(
|
15
|
+
"#{Scimaenaga.config.scim_users_model
|
16
|
+
.connection.quote_column_name(query.attribute)} #{query.operator} ?",
|
17
|
+
query.parameter
|
18
|
+
)
|
19
|
+
.order(Scimaenaga.config.scim_users_list_order)
|
20
|
+
else
|
21
|
+
users = @company
|
22
|
+
.public_send(Scimaenaga.config.scim_users_scope)
|
23
|
+
.order(Scimaenaga.config.scim_users_list_order)
|
24
|
+
end
|
25
|
+
|
26
|
+
counts = ScimCount.new(
|
27
|
+
start_index: params[:startIndex],
|
28
|
+
limit: params[:count],
|
29
|
+
total: users.count
|
30
|
+
)
|
31
|
+
|
32
|
+
json_scim_response(object: users, counts: counts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def create
|
36
|
+
if Scimaenaga.config.scim_user_prevent_update_on_create
|
37
|
+
user = @company
|
38
|
+
.public_send(Scimaenaga.config.scim_users_scope)
|
39
|
+
.create!(permitted_user_params)
|
40
|
+
else
|
41
|
+
username_key = Scimaenaga.config.queryable_user_attributes[:userName]
|
42
|
+
find_by_username = {}
|
43
|
+
find_by_username[username_key] = permitted_user_params[username_key]
|
44
|
+
user = @company
|
45
|
+
.public_send(Scimaenaga.config.scim_users_scope)
|
46
|
+
.find_or_create_by(find_by_username)
|
47
|
+
user.update!(permitted_user_params)
|
48
|
+
end
|
49
|
+
json_scim_response(object: user, status: :created)
|
50
|
+
end
|
51
|
+
|
52
|
+
def show
|
53
|
+
user = @company.public_send(Scimaenaga.config.scim_users_scope).find(params[:id])
|
54
|
+
json_scim_response(object: user)
|
55
|
+
end
|
56
|
+
|
57
|
+
def put_update
|
58
|
+
user = @company.public_send(Scimaenaga.config.scim_users_scope).find(params[:id])
|
59
|
+
user.update!(permitted_user_params)
|
60
|
+
json_scim_response(object: user)
|
61
|
+
end
|
62
|
+
|
63
|
+
def patch_update
|
64
|
+
user = @company.public_send(Scimaenaga.config.scim_users_scope).find(params[:id])
|
65
|
+
patch = ScimPatch.new(params, :user)
|
66
|
+
patch.save(user)
|
67
|
+
|
68
|
+
json_scim_response(object: user)
|
69
|
+
end
|
70
|
+
|
71
|
+
def destroy
|
72
|
+
unless Scimaenaga.config.user_destroy_method
|
73
|
+
raise Scimaenaga::ExceptionHandler::InvalidConfiguration
|
74
|
+
end
|
75
|
+
|
76
|
+
user = @company.public_send(Scimaenaga.config.scim_users_scope).find(params[:id])
|
77
|
+
raise ActiveRecord::RecordNotFound unless user
|
78
|
+
|
79
|
+
begin
|
80
|
+
user.public_send(Scimaenaga.config.user_destroy_method)
|
81
|
+
rescue NoMethodError => e
|
82
|
+
raise Scimaenaga::ExceptionHandler::InvalidConfiguration, e.message
|
83
|
+
rescue ActiveRecord::RecordNotDestroyed => e
|
84
|
+
raise Scimaenaga::ExceptionHandler::InvalidRequest, e.message
|
85
|
+
rescue StandardError => e
|
86
|
+
raise Scimaenaga::ExceptionHandler::UnexpectedError, e.message
|
87
|
+
end
|
88
|
+
|
89
|
+
head :no_content
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def permitted_user_params
|
95
|
+
Scimaenaga.config.mutable_user_attributes.each.with_object({}) do |attribute, hash|
|
96
|
+
hash[attribute] = find_value_for(attribute)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def controller_schema
|
101
|
+
Scimaenaga.config.mutable_user_attributes_schema
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/app/libraries/scim_patch.rb
CHANGED
@@ -7,7 +7,7 @@ class ScimPatch
|
|
7
7
|
def initialize(params, resource_type)
|
8
8
|
if params['schemas'] != ['urn:ietf:params:scim:api:messages:2.0:PatchOp'] ||
|
9
9
|
params['Operations'].nil?
|
10
|
-
raise
|
10
|
+
raise Scimaenaga::ExceptionHandler::UnsupportedPatchRequest
|
11
11
|
end
|
12
12
|
|
13
13
|
# complex-value(Hash) operation is converted to multiple single-value operations
|
@@ -35,6 +35,6 @@ class ScimPatch
|
|
35
35
|
rescue ActiveRecord::RecordNotFound
|
36
36
|
raise
|
37
37
|
rescue StandardError
|
38
|
-
raise
|
38
|
+
raise Scimaenaga::ExceptionHandler::UnsupportedPatchRequest
|
39
39
|
end
|
40
40
|
end
|
@@ -10,7 +10,7 @@ class ScimPatchOperation
|
|
10
10
|
# complex-value(Hash) is converted to multiple single-value operations by ScimPatchOperationConverter
|
11
11
|
def initialize(op, path, value)
|
12
12
|
if !op.in?(%w[add replace remove]) || path.nil?
|
13
|
-
raise
|
13
|
+
raise Scimaenaga::ExceptionHandler::UnsupportedPatchRequest
|
14
14
|
end
|
15
15
|
|
16
16
|
# define validate method in the inherited class
|