scimitar 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"