scim_engine 2.1.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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +25 -0
  4. data/app/controllers/scim_engine/application_controller.rb +36 -0
  5. data/app/controllers/scim_engine/resource_types_controller.rb +22 -0
  6. data/app/controllers/scim_engine/resources_controller.rb +71 -0
  7. data/app/controllers/scim_engine/schemas_controller.rb +16 -0
  8. data/app/controllers/scim_engine/service_provider_configurations_controller.rb +8 -0
  9. data/app/models/scim_engine/authentication_error.rb +9 -0
  10. data/app/models/scim_engine/authentication_scheme.rb +12 -0
  11. data/app/models/scim_engine/bulk.rb +5 -0
  12. data/app/models/scim_engine/complex_types/base.rb +37 -0
  13. data/app/models/scim_engine/complex_types/email.rb +14 -0
  14. data/app/models/scim_engine/complex_types/name.rb +9 -0
  15. data/app/models/scim_engine/complex_types/reference.rb +9 -0
  16. data/app/models/scim_engine/error_response.rb +13 -0
  17. data/app/models/scim_engine/errors.rb +14 -0
  18. data/app/models/scim_engine/filter.rb +5 -0
  19. data/app/models/scim_engine/meta.rb +7 -0
  20. data/app/models/scim_engine/not_found_error.rb +10 -0
  21. data/app/models/scim_engine/resource_invalid_error.rb +9 -0
  22. data/app/models/scim_engine/resource_type.rb +29 -0
  23. data/app/models/scim_engine/resources/base.rb +139 -0
  24. data/app/models/scim_engine/resources/group.rb +13 -0
  25. data/app/models/scim_engine/resources/user.rb +13 -0
  26. data/app/models/scim_engine/schema/attribute.rb +91 -0
  27. data/app/models/scim_engine/schema/base.rb +35 -0
  28. data/app/models/scim_engine/schema/derived_attributes.rb +24 -0
  29. data/app/models/scim_engine/schema/email.rb +15 -0
  30. data/app/models/scim_engine/schema/group.rb +27 -0
  31. data/app/models/scim_engine/schema/name.rb +17 -0
  32. data/app/models/scim_engine/schema/reference.rb +14 -0
  33. data/app/models/scim_engine/schema/user.rb +30 -0
  34. data/app/models/scim_engine/service_provider_configuration.rb +31 -0
  35. data/app/models/scim_engine/supportable.rb +10 -0
  36. data/app/views/layouts/scim_engine/application.html.erb +14 -0
  37. data/config/routes.rb +6 -0
  38. data/lib/scim_engine.rb +13 -0
  39. data/lib/scim_engine/engine.rb +51 -0
  40. data/lib/scim_engine/version.rb +3 -0
  41. data/lib/tasks/scim_engine_tasks.rake +4 -0
  42. data/spec/controllers/scim_engine/application_controller_spec.rb +104 -0
  43. data/spec/controllers/scim_engine/resource_types_controller_spec.rb +78 -0
  44. data/spec/controllers/scim_engine/resources_controller_spec.rb +132 -0
  45. data/spec/controllers/scim_engine/schemas_controller_spec.rb +66 -0
  46. data/spec/controllers/scim_engine/service_provider_configurations_controller_spec.rb +21 -0
  47. data/spec/dummy/README.rdoc +28 -0
  48. data/spec/dummy/Rakefile +6 -0
  49. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  50. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  51. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  52. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  53. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  54. data/spec/dummy/bin/bundle +3 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/bin/setup +29 -0
  58. data/spec/dummy/config.ru +4 -0
  59. data/spec/dummy/config/application.rb +16 -0
  60. data/spec/dummy/config/boot.rb +5 -0
  61. data/spec/dummy/config/environment.rb +5 -0
  62. data/spec/dummy/config/environments/development.rb +41 -0
  63. data/spec/dummy/config/environments/production.rb +79 -0
  64. data/spec/dummy/config/environments/test.rb +42 -0
  65. data/spec/dummy/config/initializers/assets.rb +11 -0
  66. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  67. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  68. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  69. data/spec/dummy/config/initializers/inflections.rb +16 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  71. data/spec/dummy/config/initializers/session_store.rb +3 -0
  72. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +23 -0
  75. data/spec/dummy/config/routes.rb +4 -0
  76. data/spec/dummy/config/secrets.yml +22 -0
  77. data/spec/dummy/log/test.log +175 -0
  78. data/spec/dummy/public/404.html +67 -0
  79. data/spec/dummy/public/422.html +67 -0
  80. data/spec/dummy/public/500.html +66 -0
  81. data/spec/dummy/public/favicon.ico +0 -0
  82. data/spec/models/scim_engine/complex_types/email_spec.rb +23 -0
  83. data/spec/models/scim_engine/resource_type_spec.rb +21 -0
  84. data/spec/models/scim_engine/resources/base_spec.rb +246 -0
  85. data/spec/models/scim_engine/resources/base_validation_spec.rb +61 -0
  86. data/spec/models/scim_engine/resources/user_spec.rb +55 -0
  87. data/spec/models/scim_engine/schema/attribute_spec.rb +80 -0
  88. data/spec/models/scim_engine/schema/base_spec.rb +19 -0
  89. data/spec/models/scim_engine/schema/group_spec.rb +66 -0
  90. data/spec/models/scim_engine/schema/user_spec.rb +140 -0
  91. data/spec/rails_helper.rb +57 -0
  92. data/spec/spec_helper.rb +99 -0
  93. metadata +246 -0
@@ -0,0 +1,78 @@
1
+ require 'rails_helper'
2
+
3
+ describe ScimEngine::ResourceTypesController do
4
+ routes { ScimEngine::Engine.routes }
5
+
6
+ before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
7
+
8
+ describe 'GET index' do
9
+ it 'renders the resource type for user' do
10
+ get :index, format: :scim
11
+ response_hash = JSON.parse(response.body)
12
+ expected_response = [ ScimEngine::Resources::User.resource_type(scim_resource_type_url(name: 'User')),
13
+ ScimEngine::Resources::Group.resource_type(scim_resource_type_url(name: 'Group'))
14
+ ].to_json
15
+
16
+ response_hash = JSON.parse(response.body)
17
+ expect(response_hash).to eql(JSON.parse(expected_response))
18
+ end
19
+
20
+ it 'renders custom resource types' do
21
+ custom_resource = Class.new(ScimEngine::Resources::Base) do
22
+ set_schema ScimEngine::Schema::User
23
+
24
+ def self.endpoint
25
+ "/Gaga"
26
+ end
27
+
28
+ def self.resource_type_id
29
+ 'Gaga'
30
+ end
31
+ end
32
+
33
+ allow(ScimEngine::Engine).to receive(:custom_resources) {[ custom_resource ]}
34
+
35
+ get :index, params: { format: :scim }
36
+ response_hash = JSON.parse(response.body)
37
+ expect(response_hash.size).to eql(3)
38
+ end
39
+ end
40
+
41
+ describe 'GET show' do
42
+ it 'renders the resource type for user' do
43
+ get :show, params: { name: 'User', format: :scim }
44
+ response_hash = JSON.parse(response.body)
45
+ expected_response = ScimEngine::Resources::User.resource_type(scim_resource_type_url(name: 'User')).to_json
46
+ expect(response_hash).to eql(JSON.parse(expected_response))
47
+ end
48
+
49
+ it 'renders the resource type for group' do
50
+ get :show, params: { name: 'Group', format: :scim }
51
+ response_hash = JSON.parse(response.body)
52
+ expected_response = ScimEngine::Resources::Group.resource_type(scim_resource_type_url(name: 'Group')).to_json
53
+ expect(response_hash).to eql(JSON.parse(expected_response))
54
+ end
55
+
56
+ it 'renders custom resource type' do
57
+ custom_resource = Class.new(ScimEngine::Resources::Base) do
58
+ set_schema ScimEngine::Schema::User
59
+
60
+ def self.endpoint
61
+ "/Gaga"
62
+ end
63
+
64
+ def self.resource_type_id
65
+ 'Gaga'
66
+ end
67
+ end
68
+
69
+ allow(ScimEngine::Engine).to receive(:custom_resources) {[ custom_resource ]}
70
+
71
+
72
+ get :show, params: { name: 'Gaga', format: :scim }
73
+ response_hash = JSON.parse(response.body)
74
+ expected_response = custom_resource.resource_type(scim_resource_type_url(name: 'Gaga')).to_json
75
+ expect(response_hash).to eql(JSON.parse(expected_response))
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,132 @@
1
+ require 'rails_helper'
2
+
3
+ describe ScimEngine::ResourcesController do
4
+
5
+ before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
6
+ let(:response_body) { JSON.parse(response.body, symbolize_names: true) }
7
+
8
+ controller do
9
+ def show
10
+ super do |id|
11
+ ScimEngine::Resources::Group.new(id: id)
12
+ end
13
+ end
14
+
15
+ def create
16
+ super(ScimEngine::Resources::Group) do |resource|
17
+ resource
18
+ end
19
+ end
20
+
21
+ def update
22
+ super(ScimEngine::Resources::Group) do |resource|
23
+ resource
24
+ end
25
+ end
26
+
27
+ def destroy
28
+ super do |id|
29
+ successful_delete?
30
+ end
31
+ end
32
+
33
+ def successful_delete?
34
+ true
35
+ end
36
+ end
37
+
38
+ describe 'GET show' do
39
+ it 'renders the resource' do
40
+ get :show, params: { id: '10', format: :scim }
41
+
42
+ expect(response).to be_ok
43
+ expect(response_body).to include(id: '10')
44
+ end
45
+ end
46
+
47
+ describe 'POST create' do
48
+ it 'returns error if body is missing' do
49
+ post :create, params: { format: :scim }
50
+ expect(response.status).to eql(400)
51
+ expect(response_body[:detail]).to eql('must provide a request body')
52
+ end
53
+
54
+ it 'works if the request is valid' do
55
+ post :create, params: { displayName: 'Sauron biz', format: :scim }
56
+ expect(response).to have_http_status(:created)
57
+ expect(response_body[:displayName]).to eql('Sauron biz')
58
+ end
59
+
60
+ it 'renders error if resource object cannot be built from the params' do
61
+ put :update, params: { id: 'group-id', name: {email: 'a@b.com'}, format: :scim }
62
+ expect(response.status).to eql(400)
63
+ expect(response_body[:detail]).to match(/^Invalid/)
64
+ end
65
+
66
+ it 'renders application side error' do
67
+ allow_any_instance_of(ScimEngine::Resources::Group).to receive(:to_json).and_raise(ScimEngine::ErrorResponse.new(status: 400, detail: 'gaga'))
68
+ put :update, params: { id: 'group-id', displayName: 'invalid name', format: :scim }
69
+ expect(response.status).to eql(400)
70
+ expect(response_body[:detail]).to eql('gaga')
71
+ end
72
+
73
+ it 'renders error if id is provided' do
74
+ post :create, params: { id: 'some-id', displayName: 'sauron', format: :scim }
75
+
76
+ expect(response).to have_http_status(:bad_request)
77
+ expect(response_body[:detail]).to start_with('id is not a valid parameter for create')
78
+ end
79
+
80
+ it 'does not renders error if externalId is provided' do
81
+ post :create, params: { externalId: 'some-id', displayName: 'sauron', format: :scim }
82
+
83
+ expect(response).to have_http_status(:created)
84
+
85
+ expect(response_body[:displayName]).to eql('sauron')
86
+ expect(response_body[:externalId]).to eql('some-id')
87
+ end
88
+ end
89
+
90
+ describe 'PUT update' do
91
+ it 'returns error if body is missing' do
92
+ put :update, params: { id: 'group-id', format: :scim }
93
+ expect(response.status).to eql(400)
94
+ expect(response_body[:detail]).to eql('must provide a request body')
95
+ end
96
+
97
+ it 'works if the request is valid' do
98
+ put :update, params: { id: 'group-id', displayName: 'sauron', format: :scim }
99
+ expect(response.status).to eql(200)
100
+ expect(response_body[:displayName]).to eql('sauron')
101
+ end
102
+
103
+ it 'renders error if resource object cannot be built from the params' do
104
+ put :update, params: { id: 'group-id', name: {email: 'a@b.com'}, format: :scim }
105
+ expect(response.status).to eql(400)
106
+ expect(response_body[:detail]).to match(/^Invalid/)
107
+ end
108
+
109
+ it 'renders application side error' do
110
+ allow_any_instance_of(ScimEngine::Resources::Group).to receive(:to_json).and_raise(ScimEngine::ErrorResponse.new(status: 400, detail: 'gaga'))
111
+ put :update, params: { id: 'group-id', displayName: 'invalid name', format: :scim }
112
+ expect(response.status).to eql(400)
113
+ expect(response_body[:detail]).to eql('gaga')
114
+ end
115
+
116
+ end
117
+
118
+ describe 'DELETE destroy' do
119
+ it 'returns an empty response with no content status if deletion is successful' do
120
+ delete :destroy, params: { id: 'group-id', format: :scim }
121
+ expect(response).to have_http_status(:no_content)
122
+ expect(response.body).to be_empty
123
+ end
124
+
125
+ it 'renders error if deletion fails' do
126
+ allow(controller).to receive(:successful_delete?).and_return(false)
127
+ delete :destroy, params: { id: 'group-id', format: :scim }
128
+ expect(response).to have_http_status(:internal_server_error)
129
+ expect(response_body[:detail]).to eql("Failed to delete the resource with id 'group-id'. Please try again later")
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,66 @@
1
+ require 'rails_helper'
2
+
3
+ describe ScimEngine::SchemasController do
4
+
5
+ before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
6
+
7
+ controller do
8
+ def index
9
+ super
10
+ end
11
+ end
12
+ describe '#index' do
13
+ it 'returns a collection of supported schemas' do
14
+ get :index, params: { format: :scim }
15
+ expect(response).to be_ok
16
+ parsed_body = JSON.parse(response.body)
17
+ expect(parsed_body.length).to eql(2)
18
+ schema_names = parsed_body.map {|schema| schema['name']}
19
+ expect(schema_names).to match_array(['User', 'Group'])
20
+ end
21
+
22
+ it 'returns only the User schema when its id is provided' do
23
+ get :index, params: { name: ScimEngine::Schema::User.id, format: :scim }
24
+ expect(response).to be_ok
25
+ parsed_body = JSON.parse(response.body)
26
+ expect(parsed_body['name']).to eql('User')
27
+ end
28
+
29
+ it 'returns only the Group schema when its id is provided' do
30
+ get :index, params: { name: ScimEngine::Schema::Group.id, format: :scim }
31
+ expect(response).to be_ok
32
+ parsed_body = JSON.parse(response.body)
33
+ expect(parsed_body['name']).to eql('Group')
34
+ end
35
+
36
+ it 'returns only the License schemas when its id is provided' do
37
+ license_schema = Class.new(ScimEngine::Schema::Base) do
38
+ def initialize(options = {})
39
+ super(name: 'License',
40
+ id: self.class.id,
41
+ description: 'Represents a License')
42
+ end
43
+ def self.id
44
+ 'License'
45
+ end
46
+ def self.scim_attributes
47
+ []
48
+ end
49
+ end
50
+
51
+ license_resource = Class.new(ScimEngine::Resources::Base) do
52
+ set_schema license_schema
53
+ def self.endopint
54
+ '/Gaga'
55
+ end
56
+ end
57
+
58
+ allow(ScimEngine::Engine).to receive(:custom_resources) {[license_resource]}
59
+ get :index, params: { name: license_schema.id, format: :scim }
60
+ expect(response).to be_ok
61
+ parsed_body = JSON.parse(response.body)
62
+ expect(parsed_body['name']).to eql('License')
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,21 @@
1
+ require 'rails_helper'
2
+
3
+ describe ScimEngine::ServiceProviderConfigurationsController do
4
+
5
+ before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
6
+
7
+ controller do
8
+ def show
9
+ super
10
+ end
11
+ end
12
+ describe '#show' do
13
+ it 'renders the servive provider configurations' do
14
+ get :show, params: { id: 'fake', format: :scim }
15
+
16
+ expect(response).to be_ok
17
+ expect(JSON.parse(response.body)).to include('patch' => {'supported' => false})
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application