class CF::UAA::StubScim
StubScim
is the in-memory database of the stubbed out UAA
server. Although called StubScim
it manages ALL of the objects of the server; users, groups, clients, zones, providers, etc
Constants
- ATTR_NAMES
- BOOLEANS
- COMMON_ATTRS
- CREATOR
- ENUMS
- EXPLICIT_MULTI
- EXPLICIT_SINGLE
represents the schema of the scimuser name and meta attributes
- GENERAL_MULTI
- GENERAL_SUBATTRS
- GROUPS
- HIDDEN_ATTRS
attribute types. Anything not listed is case-ignore string
- LEGAL_ATTRS
- MEMBERSHIP
- NAME_ATTR
resource class definitions: naming and legal attributes
- NUMBERS
- READ_ONLY_ATTRS
- REFERENCES
- SUBATTR_NAMES
- VISIBLE_ATTRS
Public Class Methods
new()
click to toggle source
# File lib/uaa/stub/scim.rb, line 197 def initialize @things_by_id, @things_by_name, @clients_metadata = {}, {}, {} end
Private Class Methods
searchable_attribute(attr)
click to toggle source
# File lib/uaa/stub/scim.rb, line 83 def self.searchable_attribute(attr) attr if ATTR_NAMES.include?(attr) && !HIDDEN_ATTRS.include?(attr = attr.to_sym) end
Public Instance Methods
add(rtype, stuff)
click to toggle source
# File lib/uaa/stub/scim.rb, line 207 def add(rtype, stuff) unless stuff.is_a?(Hash) && (name = stuff[NAME_ATTR[rtype].to_s]) raise SchemaViolation, "new #{rtype} has no name #{NAME_ATTR[rtype]}" end name = append_origin_to_username(name, rtype, stuff['origin']) raise AlreadyExists if @things_by_name.key?(name = rtype.to_s + name.downcase) enforce_schema(rtype, stuff) thing = input(stuff).merge!(rtype: rtype, id: (id = SecureRandom.uuid), meta: { created: Time.now.iso8601, last_modified: Time.now.iso8601, version: 1}) if rtype == :client @clients_metadata[stuff['client_id']] = {:createdby => CREATOR} end add_user_groups(id, thing[:members]) @things_by_id[id] = @things_by_name[name] = thing id end
add_group_mapping(external_group, group_id, group_name, origin)
click to toggle source
# File lib/uaa/stub/scim.rb, line 344 def add_group_mapping(external_group, group_id, group_name, origin) group = group_id ? ref_by_id(group_id, :group) : ref_by_name(group_name, :group) return unless group (group[:external_groups] ||= Hash.new) group[:external_groups][external_group] = origin group end
add_member(gid, member)
click to toggle source
# File lib/uaa/stub/scim.rb, line 281 def add_member(gid, member) return unless g = ref_by_id(gid, :group) (g[:members] ||= Set.new) << member add_user_groups(gid, Set[member]) end
append_origin_to_username(name, rtype, origin)
click to toggle source
# File lib/uaa/stub/scim.rb, line 324 def append_origin_to_username(name, rtype, origin) if rtype == :user origin = origin || 'uaa' name = "#{name}_#{origin}" end name end
delete(id, rtype = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 297 def delete(id, rtype = nil) return unless thing = ref_by_id(id, rtype) rtype = thing[:rtype] delete_user_groups(id, thing[:members]) origin = @things_by_id[id][:origin] @things_by_id.delete(id) name = append_origin_to_username(rtype.to_s + thing[NAME_ATTR[rtype]].downcase, rtype, origin) thing = @things_by_name.delete(name) delete_references(id) remove_attrs(output(thing)) end
delete_group_mapping(group_id, external_group, origin)
click to toggle source
# File lib/uaa/stub/scim.rb, line 352 def delete_group_mapping(group_id, external_group, origin) raise NotFound unless group = ref_by_id(group_id, :group) raise NotFound unless group[:external_groups] && group[:external_groups].include?(external_group) group[:external_groups][external_group].delete(origin) end
find(rtype, opts = {})
click to toggle source
# File lib/uaa/stub/scim.rb, line 332 def find(rtype, opts = {}) filter, total, start = ScimFilter.new(opts[:filter]), 0, (opts[:start] || 0) count, attrs, acl, acl_id = opts[:count], opts[:attrs], opts[:acl], opts[:acl_id] objs = @things_by_id.each_with_object([]) { |(k, v), o| next unless rtype == v[:rtype] && filter.match?(v) next if acl && acl_id && !is_member(v[:id], acl_id, acl) o << output(v, attrs) if total >= start && (count.nil? || o.length < count) total += 1 } [objs, total] end
get(id, rtype = nil, *attrs)
click to toggle source
# File lib/uaa/stub/scim.rb, line 309 def get(id, rtype = nil, *attrs) return unless thing = ref_by_id(id, rtype) output(thing, attrs) end
get_by_name(name, rtype, *attrs)
click to toggle source
# File lib/uaa/stub/scim.rb, line 318 def get_by_name(name, rtype, *attrs) name = append_origin_to_username(name, rtype, nil) return unless thing = ref_by_name(name, rtype) output(thing, attrs) end
get_client_meta(client_id)
click to toggle source
# File lib/uaa/stub/scim.rb, line 314 def get_client_meta(client_id) @clients_metadata[client_id] end
get_group_mappings()
click to toggle source
# File lib/uaa/stub/scim.rb, line 358 def get_group_mappings group_mappings = [] @things_by_id.each do |id, thing| if thing[:rtype] == :group thing[:external_groups].each do |key, value| group_mappings << { groupid: thing[:id], displayname: thing[:displayname], externalgroup: key, origin: value } end if thing[:external_groups] end end unless @things_by_id.empty? group_mappings end
id(name, rtype)
click to toggle source
# File lib/uaa/stub/scim.rb, line 202 def id(name, rtype) name = append_origin_to_username(name, rtype, nil) (t = ref_by_name(name, rtype))? t[:id] : nil end
is_member(gid, member, attr = :members)
click to toggle source
# File lib/uaa/stub/scim.rb, line 287 def is_member(gid, member, attr = :members) (g = ref_by_id(gid, :group)) && (a = g[attr]) && a.include?(member) end
name(id, rtype = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 201 def name(id, rtype = nil) (t = ref_by_id(id, rtype))? t[NAME_ATTR[t[:rtype]]]: nil end
patch(id, stuff, match_version = nil, match_type = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 252 def patch(id, stuff, match_version = nil, match_type = nil) raise NotFound unless thing = ref_by_id(id, match_type) raise BadVersion if match_version && match_version != thing[:meta][:version] enforce_schema(rtype = thing[:rtype], remove_attrs(stuff, READ_ONLY_ATTRS)) new_thing = input(stuff) if newname = new_thing[NAME_ATTR[rtype]] oldname = rtype.to_s + thing[NAME_ATTR[rtype]].downcase unless (newname = rtype.to_s + newname.downcase) == oldname raise AlreadyExists if @things_by_name.key?(newname) @things_by_name.delete(oldname) @things_by_name[newname] = thing end end if new_thing[:members] || thing[:members] old_members = thing[:members] || Set.new new_members = new_thing[:members] || Set.new delete_user_groups(id, old_members - new_members) add_user_groups(id, new_members - old_members) end READ_ONLY_ATTRS.each { |a| new_thing[a] = thing[a] if thing[a] } HIDDEN_ATTRS.each { |a| new_thing[a] = thing[a] if thing[a] } new_thing.each do |key, value| thing[key] = value end thing[:meta][:version] += 1 thing[:meta][:lastmodified] == Time.now.iso8601 id end
update(id, stuff, match_version = nil, match_type = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 224 def update(id, stuff, match_version = nil, match_type = nil) raise NotFound unless thing = ref_by_id(id, match_type) raise BadVersion if match_version && match_version != thing[:meta][:version] enforce_schema(rtype = thing[:rtype], remove_attrs(stuff, READ_ONLY_ATTRS)) new_thing = input(stuff) if newname = new_thing[NAME_ATTR[rtype]] oldname = rtype.to_s + thing[NAME_ATTR[rtype]].downcase unless (newname = rtype.to_s + newname.downcase) == oldname name = append_origin_to_username(newname, rtype, stuff['origin']) raise AlreadyExists if @things_by_name.key?(name) @things_by_name.delete(oldname) @things_by_name[name] = thing end end if new_thing[:members] || thing[:members] old_members = thing[:members] || Set.new new_members = new_thing[:members] || Set.new delete_user_groups(id, old_members - new_members) add_user_groups(id, new_members - old_members) end READ_ONLY_ATTRS.each { |a| new_thing[a] = thing[a] if thing[a] } HIDDEN_ATTRS.each { |a| new_thing[a] = thing[a] if thing[a] } thing.replace new_thing thing[:meta][:version] += 1 thing[:meta][:lastmodified] == Time.now.iso8601 id end
Private Instance Methods
add_user_groups(gid, members)
click to toggle source
# File lib/uaa/stub/scim.rb, line 181 def add_user_groups(gid, members) members.each {|m| (m[:groups] ||= Set.new) << gid if m = ref_by_id(m, :user)} if members end
delete_references(id)
click to toggle source
# File lib/uaa/stub/scim.rb, line 189 def delete_references(id) @things_by_id.each { |k, v| REFERENCES.each { |a| v.delete(a) if v[a] && v[a].delete(id) && v[a].empty? } } end
delete_user_groups(gid, members)
click to toggle source
# File lib/uaa/stub/scim.rb, line 185 def delete_user_groups(gid, members) members.each {|m| m[:groups].delete(gid) if m = ref_by_id(m, :user) } if members end
enforce_schema(rtype, stuff)
click to toggle source
# File lib/uaa/stub/scim.rb, line 121 def enforce_schema(rtype, stuff) stuff.each do |ks, v| unless ATTR_NAMES.include?(ks.to_s) && LEGAL_ATTRS[rtype].include?(k = ks.to_sym) raise SchemaViolation, "illegal #{ks} on #{rtype}" end if READ_ONLY_ATTRS.include?(k) raise SchemaViolation, "attempt to modify read-only attribute #{k} on #{rtype}" end valid_attr = case k when *BOOLEANS then v == !!v when *NUMBERS then v.is_a?(Integer) when *GENERAL_MULTI then valid_multi?(v, GENERAL_SUBATTRS, true) when *GROUPS then valid_ids?(v, :group) when *MEMBERSHIP then valid_ids?(v) when ENUMS[k] then ENUMS[k].include?(v) # not applicable to client objects (only scimuser objects have complex 'name' or 'meta' attributes) when *EXPLICIT_SINGLE.keys && rtype.equal?(:client) then valid_complex?(v, EXPLICIT_SINGLE[k]) when *EXPLICIT_MULTI.keys then valid_multi?(v, EXPLICIT_MULTI[k]) else k.is_a?(String) || k.is_a?(Symbol) end raise SchemaViolation, "#{v} is an invalid #{k}" unless valid_attr end end
input(stuff)
click to toggle source
# File lib/uaa/stub/scim.rb, line 145 def input(stuff) thing = Util.hash_keys(stuff.dup, :sym) REFERENCES.each {|a| next unless thing[a] thing[a] = thing[a].each_with_object(Set.new) { |r, s| s << (r.is_a?(Hash)? r[:value] : r ) } } GENERAL_MULTI.each {|a| next unless thing[a] thing[a] = thing[a].each_with_object({}) { |v, o| v = {value: v} unless v.is_a?(Hash) # enforce values are unique by type and value k = Util.encode_form(t: [v[:type], v: v[:value]]).downcase o[k] = v } } thing end
output(thing, attrs = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 165 def output(thing, attrs = nil) attrs = thing.keys if attrs.nil? || attrs.empty? attrs.each_with_object({}) {|a, o| next if thing[a].nil? case a when *MEMBERSHIP o[a] = thing[a].each_with_object([]) { |v, a| a << { value: v, type: ref_by_id(v)[:rtype] } } when *GROUPS then o[a] = thing[a].to_a when *GENERAL_MULTI then o[a] = thing[a].values else o[a] = thing[a] end } end
ref_by_id(id, rtype = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 98 def ref_by_id(id, rtype = nil) (t = @things_by_id[id]) && (rtype.nil? || t[:rtype] == rtype) ? t : nil end
ref_by_name(name, rtype)
click to toggle source
# File lib/uaa/stub/scim.rb, line 96 def ref_by_name(name, rtype) @things_by_name[rtype.to_s + name.downcase] end
remove_attrs(stuff, attrs = HIDDEN_ATTRS)
click to toggle source
# File lib/uaa/stub/scim.rb, line 87 def remove_attrs(stuff, attrs = HIDDEN_ATTRS) attrs.each { |a| stuff.delete(a.to_s) } stuff end
valid_complex?(value, subattrs, simple_ok = false)
click to toggle source
# File lib/uaa/stub/scim.rb, line 102 def valid_complex?(value, subattrs, simple_ok = false) return true if simple_ok && value.is_a?(String) return unless value.is_a?(Hash) && (!simple_ok || value.key?("value")) value.each { |k, v| return unless SUBATTR_NAMES.include?(k) && subattrs.include?(k.to_sym) } end
valid_id?(id, rtype)
click to toggle source
# File lib/uaa/stub/scim.rb, line 92 def valid_id?(id, rtype) id && (t = @things_by_id[id]) && (rtype.nil? || t[:rtype] == rtype) end
valid_ids?(value, rtype = nil)
click to toggle source
# File lib/uaa/stub/scim.rb, line 113 def valid_ids?(value, rtype = nil) return unless value.is_a?(Array) value.each do |ref| return unless ref.is_a?(String) && valid_id?(ref, rtype) || ref.is_a?(Hash) && valid_id?(ref["value"], rtype) end end
valid_multi?(values, subattrs, simple_ok = false)
click to toggle source
# File lib/uaa/stub/scim.rb, line 108 def valid_multi?(values, subattrs, simple_ok = false) return unless values.is_a?(Array) values.each { |value| return unless valid_complex?(value, subattrs, simple_ok) } end