scimitar 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +16 -0
  3. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +180 -0
  4. data/app/controllers/scimitar/application_controller.rb +129 -0
  5. data/app/controllers/scimitar/resource_types_controller.rb +28 -0
  6. data/app/controllers/scimitar/resources_controller.rb +203 -0
  7. data/app/controllers/scimitar/schemas_controller.rb +16 -0
  8. data/app/controllers/scimitar/service_provider_configurations_controller.rb +8 -0
  9. data/app/models/scimitar/authentication_error.rb +9 -0
  10. data/app/models/scimitar/authentication_scheme.rb +18 -0
  11. data/app/models/scimitar/bulk.rb +8 -0
  12. data/app/models/scimitar/complex_types/address.rb +18 -0
  13. data/app/models/scimitar/complex_types/base.rb +41 -0
  14. data/app/models/scimitar/complex_types/email.rb +12 -0
  15. data/app/models/scimitar/complex_types/entitlement.rb +12 -0
  16. data/app/models/scimitar/complex_types/ims.rb +12 -0
  17. data/app/models/scimitar/complex_types/name.rb +12 -0
  18. data/app/models/scimitar/complex_types/phone_number.rb +12 -0
  19. data/app/models/scimitar/complex_types/photo.rb +12 -0
  20. data/app/models/scimitar/complex_types/reference_group.rb +12 -0
  21. data/app/models/scimitar/complex_types/reference_member.rb +12 -0
  22. data/app/models/scimitar/complex_types/role.rb +12 -0
  23. data/app/models/scimitar/complex_types/x509_certificate.rb +12 -0
  24. data/app/models/scimitar/engine_configuration.rb +24 -0
  25. data/app/models/scimitar/error_response.rb +20 -0
  26. data/app/models/scimitar/errors.rb +14 -0
  27. data/app/models/scimitar/filter.rb +11 -0
  28. data/app/models/scimitar/filter_error.rb +22 -0
  29. data/app/models/scimitar/invalid_syntax_error.rb +9 -0
  30. data/app/models/scimitar/lists/count.rb +64 -0
  31. data/app/models/scimitar/lists/query_parser.rb +730 -0
  32. data/app/models/scimitar/meta.rb +7 -0
  33. data/app/models/scimitar/not_found_error.rb +10 -0
  34. data/app/models/scimitar/resource_invalid_error.rb +9 -0
  35. data/app/models/scimitar/resource_type.rb +29 -0
  36. data/app/models/scimitar/resources/base.rb +159 -0
  37. data/app/models/scimitar/resources/group.rb +13 -0
  38. data/app/models/scimitar/resources/mixin.rb +964 -0
  39. data/app/models/scimitar/resources/user.rb +13 -0
  40. data/app/models/scimitar/schema/address.rb +24 -0
  41. data/app/models/scimitar/schema/attribute.rb +123 -0
  42. data/app/models/scimitar/schema/base.rb +86 -0
  43. data/app/models/scimitar/schema/derived_attributes.rb +24 -0
  44. data/app/models/scimitar/schema/email.rb +10 -0
  45. data/app/models/scimitar/schema/entitlement.rb +10 -0
  46. data/app/models/scimitar/schema/group.rb +27 -0
  47. data/app/models/scimitar/schema/ims.rb +10 -0
  48. data/app/models/scimitar/schema/name.rb +20 -0
  49. data/app/models/scimitar/schema/phone_number.rb +10 -0
  50. data/app/models/scimitar/schema/photo.rb +10 -0
  51. data/app/models/scimitar/schema/reference_group.rb +23 -0
  52. data/app/models/scimitar/schema/reference_member.rb +21 -0
  53. data/app/models/scimitar/schema/role.rb +10 -0
  54. data/app/models/scimitar/schema/user.rb +52 -0
  55. data/app/models/scimitar/schema/vdtp.rb +18 -0
  56. data/app/models/scimitar/schema/x509_certificate.rb +22 -0
  57. data/app/models/scimitar/service_provider_configuration.rb +49 -0
  58. data/app/models/scimitar/supportable.rb +14 -0
  59. data/app/views/layouts/scimitar/application.html.erb +14 -0
  60. data/config/initializers/scimitar.rb +82 -0
  61. data/config/routes.rb +6 -0
  62. data/lib/scimitar.rb +23 -0
  63. data/lib/scimitar/engine.rb +63 -0
  64. data/lib/scimitar/version.rb +13 -0
  65. data/spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb +24 -0
  66. data/spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb +30 -0
  67. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +13 -0
  68. data/spec/apps/dummy/app/controllers/mock_users_controller.rb +13 -0
  69. data/spec/apps/dummy/app/models/mock_group.rb +83 -0
  70. data/spec/apps/dummy/app/models/mock_user.rb +104 -0
  71. data/spec/apps/dummy/config/application.rb +17 -0
  72. data/spec/apps/dummy/config/boot.rb +2 -0
  73. data/spec/apps/dummy/config/environment.rb +2 -0
  74. data/spec/apps/dummy/config/environments/test.rb +15 -0
  75. data/spec/apps/dummy/config/initializers/cookies_serializer.rb +3 -0
  76. data/spec/apps/dummy/config/initializers/scimitar.rb +14 -0
  77. data/spec/apps/dummy/config/initializers/session_store.rb +3 -0
  78. data/spec/apps/dummy/config/routes.rb +24 -0
  79. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +15 -0
  80. data/spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb +10 -0
  81. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +8 -0
  82. data/spec/apps/dummy/db/schema.rb +42 -0
  83. data/spec/controllers/scimitar/application_controller_spec.rb +173 -0
  84. data/spec/controllers/scimitar/resource_types_controller_spec.rb +94 -0
  85. data/spec/controllers/scimitar/resources_controller_spec.rb +247 -0
  86. data/spec/controllers/scimitar/schemas_controller_spec.rb +75 -0
  87. data/spec/controllers/scimitar/service_provider_configurations_controller_spec.rb +22 -0
  88. data/spec/models/scimitar/complex_types/address_spec.rb +19 -0
  89. data/spec/models/scimitar/complex_types/email_spec.rb +23 -0
  90. data/spec/models/scimitar/lists/count_spec.rb +147 -0
  91. data/spec/models/scimitar/lists/query_parser_spec.rb +763 -0
  92. data/spec/models/scimitar/resource_type_spec.rb +21 -0
  93. data/spec/models/scimitar/resources/base_spec.rb +289 -0
  94. data/spec/models/scimitar/resources/base_validation_spec.rb +61 -0
  95. data/spec/models/scimitar/resources/mixin_spec.rb +2127 -0
  96. data/spec/models/scimitar/resources/user_spec.rb +55 -0
  97. data/spec/models/scimitar/schema/attribute_spec.rb +80 -0
  98. data/spec/models/scimitar/schema/base_spec.rb +64 -0
  99. data/spec/models/scimitar/schema/group_spec.rb +87 -0
  100. data/spec/models/scimitar/schema/user_spec.rb +710 -0
  101. data/spec/requests/active_record_backed_resources_controller_spec.rb +569 -0
  102. data/spec/requests/application_controller_spec.rb +49 -0
  103. data/spec/requests/controller_configuration_spec.rb +17 -0
  104. data/spec/requests/engine_spec.rb +20 -0
  105. data/spec/spec_helper.rb +66 -0
  106. metadata +315 -0
@@ -0,0 +1,16 @@
1
+ require_dependency "scimitar/application_controller"
2
+
3
+ module Scimitar
4
+ class SchemasController < ApplicationController
5
+ def index
6
+ schemas = Scimitar::Engine.schemas
7
+ schemas_by_id = schemas.reduce({}) do |hash, schema|
8
+ hash[schema.id] = schema
9
+ hash
10
+ end
11
+
12
+ render json: schemas_by_id[params[:name]] || schemas
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ require_dependency "scimitar/application_controller"
2
+ module Scimitar
3
+ class ServiceProviderConfigurationsController < ApplicationController
4
+ def show
5
+ render json: Scimitar.service_provider_configuration(location: request.url)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Scimitar
2
+
3
+ class AuthenticationError < ErrorResponse
4
+ def initialize
5
+ super(status: 401, detail: 'Requires authentication')
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Scimitar
2
+ class AuthenticationScheme
3
+ include ActiveModel::Model
4
+ attr_accessor :type, :name, :description
5
+
6
+ def self.basic
7
+ new type: 'httpbasic',
8
+ name: 'HTTP Basic',
9
+ description: 'Authentication scheme using the HTTP Basic Standard'
10
+ end
11
+
12
+ def self.bearer
13
+ new type: 'oauthbearertoken',
14
+ name: 'OAuth Bearer Token',
15
+ description: 'Authentication scheme using the OAuth Bearer Token Standard'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ module Scimitar
2
+
3
+ # This isn't supported yet; the class is a placeholder.
4
+ #
5
+ class Bulk < Supportable
6
+ attr_accessor :maxOperations, :maxPayloadSize
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Address type.
5
+ #
6
+ # See also Scimitar::Schema::Address
7
+ #
8
+ class Address < Base
9
+ set_schema Scimitar::Schema::Address
10
+
11
+ # Returns the JSON representation of an Address.
12
+ #
13
+ def as_json(options = {})
14
+ {'type' => 'work'}.merge(super(options))
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # This class represents complex types that could be used inside SCIM
5
+ # resources. Each complex type must inherit from this class. They also need
6
+ # to have their own schema defined. For example:
7
+ #
8
+ # module Scimitar
9
+ # module ComplexTypes
10
+ # class Email < Base
11
+ # set_schema Scimitar::Schema::Email
12
+ #
13
+ # def as_json(options = {})
14
+ # {'type' => 'work', 'primary' => true}.merge(super(options))
15
+ # end
16
+ # end
17
+ # end
18
+ # end
19
+ #
20
+ class Base
21
+ include ActiveModel::Model
22
+ include Scimitar::Schema::DerivedAttributes
23
+ include Scimitar::Errors
24
+
25
+ def initialize(options={})
26
+ super
27
+ @errors = ActiveModel::Errors.new(self)
28
+ end
29
+
30
+ # Converts the object to its SCIM representation, which is always JSON.
31
+ #
32
+ # +options+:: A hash that could provide default values for some of the
33
+ # attributes of this complex type object.
34
+ #
35
+ def as_json(options={})
36
+ options[:except] ||= ['errors']
37
+ super.except(options)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Email type.
5
+ #
6
+ # See also Scimitar::Schema::Email
7
+ #
8
+ class Email < Base
9
+ set_schema Scimitar::Schema::Email
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Entitlement type.
5
+ #
6
+ # See also Scimitar::Schema::Entitlement
7
+ #
8
+ class Entitlement < Base
9
+ set_schema Scimitar::Schema::Entitlement
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Instant Messaging type.
5
+ #
6
+ # See also Scimitar::Schema::Ims
7
+ #
8
+ class Ims < Base
9
+ set_schema Scimitar::Schema::Ims
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Name type.
5
+ #
6
+ # See also Scimitar::Schema::Name
7
+ #
8
+ class Name < Base
9
+ set_schema Scimitar::Schema::Name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex PhoneNumber type.
5
+ #
6
+ # See also Scimitar::Schema::PhoneNumber
7
+ #
8
+ class PhoneNumber < Base
9
+ set_schema Scimitar::Schema::PhoneNumber
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Photo type.
5
+ #
6
+ # See also Scimitar::Schema::Photo
7
+ #
8
+ class Photo < Base
9
+ set_schema Scimitar::Schema::Photo
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex reference-a-group type.
5
+ #
6
+ # See also Scimitar::Schema::ReferenceGroup
7
+ #
8
+ class ReferenceGroup < Base
9
+ set_schema Scimitar::Schema::ReferenceGroup
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex reference-a-member type.
5
+ #
6
+ # See also Scimitar::Schema::ReferenceMember
7
+ #
8
+ class ReferenceMember < Base
9
+ set_schema Scimitar::Schema::ReferenceMember
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex Role type.
5
+ #
6
+ # See also Scimitar::Schema::Role
7
+ #
8
+ class Role < Base
9
+ set_schema Scimitar::Schema::Role
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scimitar
2
+ module ComplexTypes
3
+
4
+ # Represents the complex X509Certificate type.
5
+ #
6
+ # See also Scimitar::Schema::X509Certificate
7
+ #
8
+ class X509Certificate < Base
9
+ set_schema Scimitar::Schema::X509Certificate
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module Scimitar
2
+
3
+ # Scimitar general configuration.
4
+ #
5
+ # See config/initializers/scimitar.rb for more information.
6
+ #
7
+ class EngineConfiguration
8
+ include ActiveModel::Model
9
+
10
+ attr_accessor :basic_authenticator,
11
+ :token_authenticator,
12
+ :application_controller_mixin
13
+
14
+ def initialize(attributes = {})
15
+
16
+ # No defaults yet - reserved for future use.
17
+ #
18
+ defaults = {}
19
+
20
+ super(defaults.merge(attributes))
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module Scimitar
2
+ class ErrorResponse < StandardError
3
+ include ActiveModel::Model
4
+
5
+ attr_accessor :status,
6
+ :detail,
7
+ :scimType
8
+
9
+ def as_json(options = {})
10
+ data = {
11
+ 'schemas': ['urn:ietf:params:scim:api:messages:2.0:Error'],
12
+ 'detail': detail,
13
+ 'status': "#{status}"
14
+ }
15
+
16
+ data['scimType'] = scimType if scimType
17
+ data
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Scimitar
2
+ module Errors
3
+ def add_errors_from_hash(errors_hash, prefix: nil)
4
+ errors_hash.each_pair do |key, value|
5
+ new_key = prefix.nil? ? key : "#{prefix}.#{key}".to_sym
6
+ if value.is_a?(Array)
7
+ value.each {|error| errors.add(new_key, error)}
8
+ else
9
+ errors.add(new_key, value)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Scimitar
2
+
3
+ # Used to configure filters via
4
+ # app/models/scimitar/service_provider_configuration.rb.
5
+ #
6
+ class Filter < Supportable
7
+ MAX_RESULTS_DEFAULT = 100
8
+
9
+ attr_accessor :maxResults
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Scimitar
2
+
3
+ # Raised when an invalid query is attempted, either by being malformed or by
4
+ # being unsupported in some way.
5
+ #
6
+ class FilterError < ErrorResponse
7
+ def initialize(message = nil)
8
+ detail = 'The specified filter syntax was invalid, or the specified attribute and filter comparison combination is not supported'
9
+
10
+ if message.present?
11
+ detail << ":\n#{message}"
12
+ end
13
+
14
+ super(
15
+ status: 400,
16
+ scimType: 'invalidFilter',
17
+ detail: detail
18
+ )
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,9 @@
1
+ module Scimitar
2
+ class InvalidSyntaxError < ErrorResponse
3
+
4
+ def initialize(error_message)
5
+ super(status: 400, scimType: 'invalidSyntax', detail: error_message)
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,64 @@
1
+ module Scimitar
2
+ module Lists
3
+ class Count
4
+ include ActiveModel::Model
5
+
6
+ attr_accessor :limit, :start_index, :total
7
+ attr_reader :offset
8
+
9
+ def initialize(*args)
10
+ @limit = 100
11
+ @start_index = 1
12
+
13
+ super(*args)
14
+ end
15
+
16
+ # Set a limit (page size) value.
17
+ #
18
+ # +value+:: Integer value held in a String. Must be >= 1.
19
+ #
20
+ # Raises exceptions if given non-numeric, zero or negative input.
21
+ #
22
+ def limit=(value)
23
+ value = value&.to_s
24
+ return if value.blank? # NOTE EARLY EXIT
25
+
26
+ validate_numericality(value)
27
+ input = value.to_i
28
+ raise if input < 1
29
+ @limit = input
30
+ end
31
+
32
+ # Set a start index (offset) value. Values start at 1. See also #offset.
33
+ #
34
+ # +value+:: Integer value held in a String. Must be >= 1.
35
+ #
36
+ # Raises exceptions if given non-numeric or negative input. Corrects an
37
+ # input value of zero to 1.
38
+ #
39
+ def start_index=(value)
40
+ value = value&.to_s
41
+ return if value.blank? # NOTE EARLY EXIT
42
+
43
+ validate_numericality(value)
44
+ input = value.to_i
45
+ input = 1 if input < 1
46
+ @start_index = input
47
+ end
48
+
49
+ # Read-only accessor that represents #start_index as a zero-based offset,
50
+ # rather than 1-based. This is useful for most storage engines.
51
+ #
52
+ def offset
53
+ start_index - 1
54
+ end
55
+
56
+ private
57
+
58
+ def validate_numericality(input)
59
+ raise unless input.match?(/\A\d+\z/)
60
+ end
61
+
62
+ end
63
+ end
64
+ end