scimaenaga 0.7.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -7
  3. data/Rakefile +6 -8
  4. data/app/controllers/concerns/{scim_rails → scimaenaga}/exception_handler.rb +47 -37
  5. data/app/controllers/concerns/scimaenaga/response.rb +94 -0
  6. data/app/controllers/scimaenaga/application_controller.rb +72 -0
  7. data/app/controllers/{scim_rails → scimaenaga}/scim_groups_controller.rb +26 -26
  8. data/app/controllers/scimaenaga/scim_schemas_controller.rb +42 -0
  9. data/app/controllers/scimaenaga/scim_users_controller.rb +104 -0
  10. data/app/helpers/{scim_rails → scimaenaga}/application_helper.rb +1 -1
  11. data/app/libraries/scim_patch.rb +16 -9
  12. data/app/libraries/scim_patch_operation.rb +51 -141
  13. data/app/libraries/scim_patch_operation_converter.rb +90 -0
  14. data/app/libraries/scim_patch_operation_group.rb +100 -0
  15. data/app/libraries/scim_patch_operation_user.rb +53 -0
  16. data/app/models/{scim_rails → scimaenaga}/application_record.rb +1 -1
  17. data/app/models/scimaenaga/authorize_api_request.rb +39 -0
  18. data/app/models/{scim_rails → scimaenaga}/scim_count.rb +8 -4
  19. data/app/models/scimaenaga/scim_query_parser.rb +49 -0
  20. data/config/routes.rb +15 -13
  21. data/lib/generators/scimaenaga/USAGE +8 -0
  22. data/lib/generators/scimaenaga/scimaenaga_generator.rb +7 -0
  23. data/lib/generators/{scim_rails → scimaenaga}/templates/initializer.rb +128 -22
  24. data/lib/{scim_rails → scimaenaga}/config.rb +9 -7
  25. data/lib/scimaenaga/encoder.rb +27 -0
  26. data/lib/scimaenaga/engine.rb +12 -0
  27. data/lib/scimaenaga/version.rb +5 -0
  28. data/lib/scimaenaga.rb +6 -0
  29. data/lib/tasks/{scim_rails_tasks.rake → scimaenaga_tasks.rake} +1 -1
  30. data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_controller_spec.rb +8 -8
  31. data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_request_spec.rb +18 -18
  32. data/spec/controllers/scimaenaga/scim_schemas_controller_spec.rb +238 -0
  33. data/spec/controllers/scimaenaga/scim_schemas_request_spec.rb +39 -0
  34. data/spec/controllers/{scim_rails → scimaenaga}/scim_users_controller_spec.rb +14 -15
  35. data/spec/controllers/{scim_rails → scimaenaga}/scim_users_request_spec.rb +20 -20
  36. data/spec/dummy/app/assets/config/manifest.js +1 -1
  37. data/spec/dummy/config/application.rb +1 -2
  38. data/spec/dummy/config/initializers/{scim_rails_config.rb → scimaenaga_config.rb} +25 -25
  39. data/spec/dummy/config/routes.rb +1 -1
  40. data/spec/factories/company.rb +3 -3
  41. data/spec/lib/scimaenaga/encoder_spec.rb +64 -0
  42. data/spec/libraries/scim_patch_operation_group_spec.rb +165 -0
  43. data/spec/libraries/scim_patch_operation_user_spec.rb +101 -0
  44. data/spec/libraries/scim_patch_spec.rb +129 -45
  45. data/spec/models/scim_query_parser_spec.rb +5 -6
  46. metadata +107 -108
  47. data/app/controllers/concerns/scim_rails/response.rb +0 -94
  48. data/app/controllers/scim_rails/application_controller.rb +0 -72
  49. data/app/controllers/scim_rails/scim_users_controller.rb +0 -107
  50. data/app/models/scim_rails/authorize_api_request.rb +0 -40
  51. data/app/models/scim_rails/scim_query_parser.rb +0 -49
  52. data/lib/generators/scim_rails/USAGE +0 -8
  53. data/lib/generators/scim_rails/scim_rails_generator.rb +0 -7
  54. data/lib/scim_rails/encoder.rb +0 -25
  55. data/lib/scim_rails/engine.rb +0 -12
  56. data/lib/scim_rails/version.rb +0 -5
  57. data/lib/scim_rails.rb +0 -6
  58. data/spec/dummy/db/development.sqlite3 +0 -0
  59. data/spec/dummy/db/test.sqlite3 +0 -0
  60. data/spec/dummy/log/development.log +0 -0
  61. data/spec/dummy/log/test.log +0 -5770
  62. data/spec/dummy/put_group.http +0 -5
  63. data/spec/dummy/tmp/restart.txt +0 -0
  64. data/spec/lib/scim_rails/encoder_spec.rb +0 -62
  65. data/spec/libraries/scim_patch_operation_spec.rb +0 -116
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d2d55daa03a9b1e4771b1f2e1287a75075514d57faeb0075ea8784a7dd8cc9e
4
- data.tar.gz: b4a38c2c629cce871703a2a1874c3be93e34d55f0d5eacadae8da9b8c5e5c438
3
+ metadata.gz: 41335471b09b4e09028210f9c05586a1f171cf2e6cf3d12d03b07bddd0022dc3
4
+ data.tar.gz: 12c2072c1bc4a57274cb427a4507ed2b4a13a038b9e311bfdb7e29fabc94e524
5
5
  SHA512:
6
- metadata.gz: 43e2ec416e2f9bad5c185042aff3e6fd576437d3d9bff5ac6ad5d1f930246fa0b59b12e1940a5498e386c8c8f385a245d531907e7ab5850cc8ebc5a7c35df607
7
- data.tar.gz: 284bead26bc660ca0d4cc229dd5f13102501904b7658e3e780f5ea5657eb367c52cd5399d4a29dcd20af66eee19ce4592af7defa62c2f182bb7b23f76ebe6a31
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', require: 'scim_rails'
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 scim_rails config
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/scim_rails_config.rb
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 ScimRails::Engine => "/"
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 = ScimRails::Encoder.encode(company)
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 = ScimRails::Encoder.encode(company)
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,11 +245,26 @@ 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
- ScimRails.configure do |config|
248
+ Scimaenaga.configure do |config|
249
249
  config.on_error = ->(e) { Honeybadger.notify(e) }
250
250
  end
251
251
  ```
252
252
 
253
+ ### Schemas endpoint
254
+
255
+ If you need Schemas endpoint configure `schemas`.
256
+ (Azure AD requires Schemas endpoint when registering to Application Gallery.)
257
+
258
+ You have to configure `schemas` as
259
+ - corresponding with other configurations.
260
+ e.g.) When `userName` is defined in `mutable_user_attributes`, configure `userName` as `mutability: 'readWrite'`.
261
+
262
+ - corresponding with your model.
263
+ e.g.) When `userName` must be specified configure `userName` as `required: true`
264
+
265
+ Sample config (with comment) is written in lib/generators/scimaenaga/templates/initializer.rb.
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
+
253
268
  ## Contributing
254
269
 
255
270
  ### [Code of Conduct](https://github.com/StudistCorporation/scimaenaga/blob/master/CODE_OF_CONDUCT.md)
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 = 'ScimRails'
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("../spec/dummy/Rakefile", __FILE__)
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 "Run all specs in spec directory (excluding plugin specs)"
32
- RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
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 :default => :spec
32
+ task default: :spec
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ScimRails
3
+ module Scimaenaga
4
4
  module ExceptionHandler
5
5
  extend ActiveSupport::Concern
6
6
 
@@ -25,10 +25,19 @@ module ScimRails
25
25
  class UnexpectedError < StandardError
26
26
  end
27
27
 
28
+ class ResourceNotFound < StandardError
29
+ attr_reader :id
30
+
31
+ def initialize(id)
32
+ super
33
+ @id = id
34
+ end
35
+ end
36
+
28
37
  included do
29
38
  if Rails.env.production?
30
39
  rescue_from StandardError do |exception|
31
- on_error = ScimRails.config.on_error
40
+ on_error = Scimaenaga.config.on_error
32
41
  if on_error.respond_to?(:call)
33
42
  on_error.call(exception)
34
43
  else
@@ -37,98 +46,99 @@ module ScimRails
37
46
 
38
47
  json_response(
39
48
  {
40
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
41
- status: "500"
49
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
50
+ status: '500',
42
51
  },
43
52
  :internal_server_error
44
53
  )
45
54
  end
46
55
  end
47
56
 
48
- rescue_from ScimRails::ExceptionHandler::InvalidCredentials do
57
+ rescue_from Scimaenaga::ExceptionHandler::InvalidCredentials do
49
58
  json_response(
50
59
  {
51
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
52
- detail: "Authorization failure. The authorization header is invalid or missing.",
53
- status: "401"
60
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
61
+ detail: 'Authorization failure. The authorization header is invalid or missing.',
62
+ status: '401',
54
63
  },
55
64
  :unauthorized
56
65
  )
57
66
  end
58
67
 
59
- rescue_from ScimRails::ExceptionHandler::InvalidRequest do |e|
68
+ rescue_from Scimaenaga::ExceptionHandler::InvalidRequest do |e|
60
69
  json_response(
61
70
  {
62
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
71
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
63
72
  detail: "Invalid request. #{e.message}",
64
- status: "400"
73
+ status: '400',
65
74
  },
66
75
  :bad_request
67
76
  )
68
77
  end
69
78
 
70
- rescue_from ScimRails::ExceptionHandler::InvalidQuery do
79
+ rescue_from Scimaenaga::ExceptionHandler::InvalidQuery do
71
80
  json_response(
72
81
  {
73
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
74
- scimType: "invalidFilter",
75
- detail: "The specified filter syntax was invalid, or the specified attribute and filter comparison combination is not supported.",
76
- status: "400"
82
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
83
+ scimType: 'invalidFilter',
84
+ detail: 'The specified filter syntax was invalid, or the specified attribute and filter comparison combination is not supported.',
85
+ status: '400',
77
86
  },
78
87
  :bad_request
79
88
  )
80
89
  end
81
90
 
82
- rescue_from ScimRails::ExceptionHandler::UnsupportedPatchRequest do
91
+ rescue_from Scimaenaga::ExceptionHandler::UnsupportedPatchRequest do
83
92
  json_response(
84
93
  {
85
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
86
- detail: "Invalid PATCH request.",
87
- status: "422"
94
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
95
+ detail: 'Invalid PATCH request.',
96
+ status: '422',
88
97
  },
89
98
  :unprocessable_entity
90
99
  )
91
100
  end
92
101
 
93
- rescue_from ScimRails::ExceptionHandler::UnsupportedDeleteRequest do
102
+ rescue_from Scimaenaga::ExceptionHandler::UnsupportedDeleteRequest do
94
103
  json_response(
95
104
  {
96
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
97
- detail: "Delete operation is disabled for the requested resource.",
98
- status: "501"
105
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
106
+ detail: 'Delete operation is disabled for the requested resource.',
107
+ status: '501',
99
108
  },
100
109
  :not_implemented
101
110
  )
102
111
  end
103
112
 
104
- rescue_from ScimRails::ExceptionHandler::InvalidConfiguration do |e|
113
+ rescue_from Scimaenaga::ExceptionHandler::InvalidConfiguration do |e|
105
114
  json_response(
106
115
  {
107
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
116
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
108
117
  detail: "Invalid configuration. #{e.message}",
109
- status: "500"
118
+ status: '500',
110
119
  },
111
120
  :internal_server_error
112
121
  )
113
122
  end
114
123
 
115
- rescue_from ScimRails::ExceptionHandler::UnexpectedError do |e|
124
+ rescue_from Scimaenaga::ExceptionHandler::UnexpectedError do |e|
116
125
  json_response(
117
126
  {
118
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
127
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
119
128
  detail: "Unexpected Error. #{e.message}",
120
- status: "500"
129
+ status: '500',
121
130
  },
122
131
  :internal_server_error
123
132
  )
124
133
  end
125
134
 
126
- rescue_from ActiveRecord::RecordNotFound do |e|
135
+ rescue_from ActiveRecord::RecordNotFound,
136
+ Scimaenaga::ExceptionHandler::ResourceNotFound do |e|
127
137
  json_response(
128
138
  {
129
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
139
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
130
140
  detail: "Resource #{e.id} not found.",
131
- status: "404"
141
+ status: '404',
132
142
  },
133
143
  :not_found
134
144
  )
@@ -139,18 +149,18 @@ module ScimRails
139
149
  when /has already been taken/
140
150
  json_response(
141
151
  {
142
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
152
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
143
153
  detail: e.message,
144
- status: "409"
154
+ status: '409',
145
155
  },
146
156
  :conflict
147
157
  )
148
158
  else
149
159
  json_response(
150
160
  {
151
- schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
161
+ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'],
152
162
  detail: e.message,
153
- status: "422"
163
+ status: '422',
154
164
  },
155
165
  :unprocessable_entity
156
166
  )
@@ -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 ScimRails
4
- class ScimGroupsController < ScimRails::ApplicationController
3
+ module Scimaenaga
4
+ class ScimGroupsController < Scimaenaga::ApplicationController
5
5
  def index
6
6
  if params[:filter].present?
7
- query = ScimRails::ScimQueryParser.new(
8
- params[:filter], ScimRails.config.queryable_group_attributes
7
+ query = Scimaenaga::ScimQueryParser.new(
8
+ params[:filter], Scimaenaga.config.queryable_group_attributes
9
9
  )
10
10
 
11
11
  groups = @company
12
- .public_send(ScimRails.config.scim_groups_scope)
12
+ .public_send(Scimaenaga.config.scim_groups_scope)
13
13
  .where(
14
- "#{ScimRails.config.scim_groups_model
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(ScimRails.config.scim_groups_list_order)
19
+ .order(Scimaenaga.config.scim_groups_list_order)
20
20
  else
21
21
  groups = @company
22
- .public_send(ScimRails.config.scim_groups_scope)
22
+ .public_send(Scimaenaga.config.scim_groups_scope)
23
23
  .preload(:users)
24
- .order(ScimRails.config.scim_groups_list_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(ScimRails.config.scim_groups_scope)
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(ScimRails.config.scim_groups_scope)
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(ScimRails.config.scim_groups_scope)
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,32 +58,32 @@ module ScimRails
58
58
 
59
59
  def patch_update
60
60
  group = @company
61
- .public_send(ScimRails.config.scim_groups_scope)
61
+ .public_send(Scimaenaga.config.scim_groups_scope)
62
62
  .find(params[:id])
63
- patch = ScimPatch.new(params, ScimRails.config.mutable_group_attributes_schema)
63
+ patch = ScimPatch.new(params, :group)
64
64
  patch.save(group)
65
65
 
66
66
  json_scim_response(object: group)
67
67
  end
68
68
 
69
69
  def destroy
70
- unless ScimRails.config.group_destroy_method
71
- raise ScimRails::ExceptionHandler::InvalidConfiguration
70
+ unless Scimaenaga.config.group_destroy_method
71
+ raise Scimaenaga::ExceptionHandler::InvalidConfiguration
72
72
  end
73
73
 
74
74
  group = @company
75
- .public_send(ScimRails.config.scim_groups_scope)
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(ScimRails.config.group_destroy_method)
80
+ group.public_send(Scimaenaga.config.group_destroy_method)
81
81
  rescue NoMethodError => e
82
- raise ScimRails::ExceptionHandler::InvalidConfiguration, e.message
82
+ raise Scimaenaga::ExceptionHandler::InvalidConfiguration, e.message
83
83
  rescue ActiveRecord::RecordNotDestroyed => e
84
- raise ScimRails::ExceptionHandler::InvalidRequest, e.message
85
- rescue => e
86
- raise ScimRails::ExceptionHandler::UnexpectedError, e.message
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
- ScimRails.config.group_member_relation_attribute =>
105
+ Scimaenaga.config.group_member_relation_attribute =>
106
106
  params[:members].map do |member|
107
- member[ScimRails.config.group_member_relation_schema.keys.first]
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
- ScimRails.config.mutable_group_attributes
113
+ Scimaenaga.config.mutable_group_attributes
114
114
  end
115
115
 
116
116
  def controller_schema
117
- ScimRails.config.mutable_group_attributes_schema
117
+ Scimaenaga.config.mutable_group_attributes_schema
118
118
  end
119
119
  end
120
120
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scimaenaga
4
+ class ScimSchemasController < Scimaenaga::ApplicationController
5
+ def index
6
+ schemas = Scimaenaga.config.schemas
7
+
8
+ counts = ScimCount.new(
9
+ start_index: params[:startIndex],
10
+ limit: params[:count],
11
+ total: schemas.count
12
+ )
13
+
14
+ list_schemas_response(schemas, counts)
15
+ end
16
+
17
+ def show
18
+ schema = Scimaenaga.config.schemas.find do |s|
19
+ s[:id] == params[:id]
20
+ end
21
+
22
+ raise Scimaenaga::ExceptionHandler::ResourceNotFound, params[:id] if schema.nil?
23
+
24
+ json_response(schema)
25
+ end
26
+
27
+ private
28
+
29
+ def list_schemas_response(schemas, counts)
30
+ response = {
31
+ schemas: [
32
+ 'urn:ietf:params:scim:api:messages:2.0:ListResponse'
33
+ ],
34
+ totalResults: counts.total,
35
+ startIndex: counts.start_index,
36
+ itemsPerPage: counts.limit,
37
+ Resources: schemas[counts.offset...counts.offset + counts.limit],
38
+ }
39
+ json_response(response)
40
+ end
41
+ end
42
+ end