scimitar 2.8.0 → 2.9.0

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.
@@ -15,8 +15,24 @@ module Scimitar
15
15
  JSON.parse(body)
16
16
  end
17
17
 
18
+ # Return an Array of all supported default and custom resource classes.
19
+ # See also :add_custom_resource and :set_default_resources.
20
+ #
18
21
  def self.resources
19
- default_resources + custom_resources
22
+ self.default_resources() + self.custom_resources()
23
+ end
24
+
25
+ # Returns a flat array of instances of all resource schema included in the
26
+ # resource classes returned by ::resources.
27
+ #
28
+ def self.schemas
29
+ self.resources().map(&:schemas).flatten.uniq.map(&:new)
30
+ end
31
+
32
+ # Returns the list of custom resources, if any.
33
+ #
34
+ def self.custom_resources
35
+ @custom_resources ||= []
20
36
  end
21
37
 
22
38
  # Can be used to add a new resource type which is not provided by the gem.
@@ -37,7 +53,7 @@ module Scimitar
37
53
  # Scimitar::Engine.add_custom_resource Scim::Resources::ShinyResource
38
54
  #
39
55
  def self.add_custom_resource(resource)
40
- custom_resources << resource
56
+ self.custom_resources() << resource
41
57
  end
42
58
 
43
59
  # Resets the resource list to default. This is really only intended for use
@@ -47,23 +63,45 @@ module Scimitar
47
63
  @custom_resources = []
48
64
  end
49
65
 
50
- # Returns the list of custom resources, if any.
51
- #
52
- def self.custom_resources
53
- @custom_resources ||= []
54
- end
55
-
56
- # Returns the default resources added in this gem:
66
+ # Returns the default resources added in this gem - by default, these are:
57
67
  #
58
68
  # * Scimitar::Resources::User
59
69
  # * Scimitar::Resources::Group
60
70
  #
71
+ # ...but if an implementation does not e.g. support Group, it can
72
+ # be overridden via ::set_default_resources to help with service
73
+ # auto-discovery.
74
+ #
61
75
  def self.default_resources
62
- [ Resources::User, Resources::Group ]
76
+ @standard_default_resources = [ Resources::User, Resources::Group ]
77
+ @default_resources ||= @standard_default_resources.dup()
63
78
  end
64
79
 
65
- def self.schemas
66
- resources.map(&:schemas).flatten.uniq.map(&:new)
80
+ # Override the resources returned by ::default_resources.
81
+ #
82
+ # +resource_array+:: An Array containing one or both of
83
+ # Scimitar::Resources::User and/or
84
+ # Scimitar::Resources::Group, and nothing else.
85
+ #
86
+ def self.set_default_resources(resource_array)
87
+ self.default_resources()
88
+ unrecognised_resources = resource_array - @standard_default_resources
89
+
90
+ if unrecognised_resources.any?
91
+ raise "Scimitar::Engine::set_default_resources: Only #{@standard_default_resources.map(&:name).join(', ')} are supported"
92
+ elsif resource_array.empty?
93
+ raise 'Scimitar::Engine::set_default_resources: At least one resource must be given'
94
+ end
95
+
96
+ @default_resources = resource_array
97
+ end
98
+
99
+ # Resets the default resource list. This is really only intended for use
100
+ # during testing, to avoid one test polluting another.
101
+ #
102
+ def self.reset_default_resources
103
+ self.default_resources()
104
+ @default_resources = @standard_default_resources
67
105
  end
68
106
 
69
107
  end
@@ -57,9 +57,10 @@ module Scimitar
57
57
  # <tt>scim_resource_type.extended_schemas</tt> value. The
58
58
  # Array should be empty if there are no extensions.
59
59
  #
60
- # +path_str+:: Path string, e.g. <tt>"password"</tt>, <tt>"name.givenName"</tt>,
60
+ # +path_str+:: Path String, e.g. <tt>"password"</tt>, <tt>"name.givenName"</tt>,
61
61
  # <tt>"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"</tt> (special case),
62
62
  # <tt>"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization"</tt>
63
+ # (if given a Symbol, it'll be converted to a String).
63
64
  #
64
65
  # Returns an array of components, e.g. <tt>["password"]</tt>, <tt>["name",
65
66
  # "givenName"]</tt>,
@@ -74,6 +75,7 @@ module Scimitar
74
75
  # path-free payload.
75
76
  #
76
77
  def self.path_str_to_array(schemas, path_str)
78
+ path_str = path_str.to_s
77
79
  components = []
78
80
 
79
81
  # Note the ":" separating the schema ID (URN) from the attribute.
@@ -84,11 +86,14 @@ module Scimitar
84
86
  # particular, https://tools.ietf.org/html/rfc7644#page-35.
85
87
  #
86
88
  if path_str.include?(':')
89
+ lower_case_path_str = path_str.downcase()
90
+
87
91
  schemas.each do |schema|
88
- attributes_after_schema_id = path_str.downcase.split(schema.id.downcase + ':').drop(1)
92
+ lower_case_schema_id = schema.id.downcase()
93
+ attributes_after_schema_id = lower_case_path_str.split(lower_case_schema_id + ':').drop(1)
89
94
 
90
95
  if attributes_after_schema_id.empty?
91
- components += [schema.id]
96
+ components += [schema.id] if lower_case_path_str == lower_case_schema_id
92
97
  else
93
98
  attributes_after_schema_id.each do |component|
94
99
  components += [schema.id] + component.split('.')
@@ -3,11 +3,11 @@ module Scimitar
3
3
  # Gem version. If this changes, be sure to re-run "bundle install" or
4
4
  # "bundle update".
5
5
  #
6
- VERSION = '2.8.0'
6
+ VERSION = '2.9.0'
7
7
 
8
8
  # Date for VERSION. If this changes, be sure to re-run "bundle install"
9
9
  # or "bundle update".
10
10
  #
11
- DATE = '2024-06-13'
11
+ DATE = '2024-06-27'
12
12
 
13
13
  end
@@ -18,6 +18,7 @@ class MockUser < ActiveRecord::Base
18
18
  work_phone_number
19
19
  organization
20
20
  department
21
+ manager
21
22
  mock_groups
22
23
  }
23
24
 
@@ -48,6 +49,7 @@ class MockUser < ActiveRecord::Base
48
49
  externalId: :scim_uid,
49
50
  userName: :username,
50
51
  password: :password,
52
+ active: :is_active,
51
53
  name: {
52
54
  givenName: :first_name,
53
55
  familyName: :last_name
@@ -80,8 +82,11 @@ class MockUser < ActiveRecord::Base
80
82
  }
81
83
  },
82
84
  ],
83
- groups: [ # NB read-only, so no :find_with key
85
+ groups: [
84
86
  {
87
+ # Read-only, so no :find_with key. There's no 'class' specified here
88
+ # either, to help test the "/Schemas" endpoint's reflection code.
89
+ #
85
90
  list: :mock_groups,
86
91
  using: {
87
92
  value: :id,
@@ -89,7 +94,6 @@ class MockUser < ActiveRecord::Base
89
94
  }
90
95
  }
91
96
  ],
92
- active: :is_active,
93
97
 
94
98
  # Custom extension schema - see configuration in
95
99
  # "spec/apps/dummy/config/initializers/scimitar.rb".
@@ -97,6 +101,9 @@ class MockUser < ActiveRecord::Base
97
101
  organization: :organization,
98
102
  department: :department,
99
103
  primaryEmail: :scim_primary_email,
104
+
105
+ manager: :manager,
106
+
100
107
  userGroups: [
101
108
  {
102
109
  list: :mock_groups,
@@ -130,7 +137,8 @@ class MockUser < ActiveRecord::Base
130
137
  }
131
138
  end
132
139
 
133
- # reader
140
+ # Custom attribute reader
141
+ #
134
142
  def scim_primary_email
135
143
  work_email_address
136
144
  end
@@ -33,10 +33,13 @@ Rails.application.config.to_prepare do
33
33
 
34
34
  module ScimSchemaExtensions
35
35
  module User
36
+
37
+ # This "looks like" part of the standard Enterprise extension.
38
+ #
36
39
  class Enterprise < Scimitar::Schema::Base
37
40
  def initialize(options = {})
38
41
  super(
39
- name: 'ExtendedUser',
42
+ name: 'EnterpriseExtendedUser',
40
43
  description: 'Enterprise extension for a User',
41
44
  id: self.class.id,
42
45
  scim_attributes: self.class.scim_attributes
@@ -55,8 +58,33 @@ Rails.application.config.to_prepare do
55
58
  ]
56
59
  end
57
60
  end
61
+
62
+ # In https://github.com/RIPAGlobal/scimitar/issues/122 we learn that with
63
+ # more than one extension, things can go wrong - so now we test with two.
64
+ #
65
+ class Manager < Scimitar::Schema::Base
66
+ def initialize(options = {})
67
+ super(
68
+ name: 'ManagementExtendedUser',
69
+ description: 'Management extension for a User',
70
+ id: self.class.id,
71
+ scim_attributes: self.class.scim_attributes
72
+ )
73
+ end
74
+
75
+ def self.id
76
+ 'urn:ietf:params:scim:schemas:extension:manager:1.0:User'
77
+ end
78
+
79
+ def self.scim_attributes
80
+ [
81
+ Scimitar::Schema::Attribute.new(name: 'manager', type: 'string')
82
+ ]
83
+ end
84
+ end
58
85
  end
59
86
  end
60
87
 
61
88
  Scimitar::Resources::User.extend_schema ScimSchemaExtensions::User::Enterprise
89
+ Scimitar::Resources::User.extend_schema ScimSchemaExtensions::User::Manager
62
90
  end
@@ -19,6 +19,7 @@ class CreateMockUsers < ActiveRecord::Migration[6.1]
19
19
  #
20
20
  t.text :organization
21
21
  t.text :department
22
+ t.text :manager
22
23
  end
23
24
  end
24
25
  end
@@ -41,6 +41,7 @@ ActiveRecord::Schema[7.1].define(version: 2021_03_08_044214) do
41
41
  t.text "work_phone_number"
42
42
  t.text "organization"
43
43
  t.text "department"
44
+ t.text "manager"
44
45
  end
45
46
 
46
47
  add_foreign_key "mock_groups_users", "mock_groups"