entitlements-app 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/VERSION +1 -0
  3. data/bin/deploy-entitlements +18 -0
  4. data/lib/entitlements/auditor/base.rb +163 -0
  5. data/lib/entitlements/backend/base_controller.rb +171 -0
  6. data/lib/entitlements/backend/base_provider.rb +55 -0
  7. data/lib/entitlements/backend/dummy/controller.rb +89 -0
  8. data/lib/entitlements/backend/dummy.rb +3 -0
  9. data/lib/entitlements/backend/ldap/controller.rb +188 -0
  10. data/lib/entitlements/backend/ldap/provider.rb +128 -0
  11. data/lib/entitlements/backend/ldap.rb +4 -0
  12. data/lib/entitlements/backend/member_of/controller.rb +203 -0
  13. data/lib/entitlements/backend/member_of.rb +3 -0
  14. data/lib/entitlements/cli.rb +121 -0
  15. data/lib/entitlements/data/groups/cached.rb +120 -0
  16. data/lib/entitlements/data/groups/calculated/base.rb +478 -0
  17. data/lib/entitlements/data/groups/calculated/filters/base.rb +93 -0
  18. data/lib/entitlements/data/groups/calculated/filters/member_of_group.rb +32 -0
  19. data/lib/entitlements/data/groups/calculated/modifiers/base.rb +38 -0
  20. data/lib/entitlements/data/groups/calculated/modifiers/expiration.rb +56 -0
  21. data/lib/entitlements/data/groups/calculated/ruby.rb +137 -0
  22. data/lib/entitlements/data/groups/calculated/rules/base.rb +35 -0
  23. data/lib/entitlements/data/groups/calculated/rules/group.rb +129 -0
  24. data/lib/entitlements/data/groups/calculated/rules/username.rb +41 -0
  25. data/lib/entitlements/data/groups/calculated/text.rb +337 -0
  26. data/lib/entitlements/data/groups/calculated/yaml.rb +171 -0
  27. data/lib/entitlements/data/groups/calculated.rb +290 -0
  28. data/lib/entitlements/data/groups.rb +13 -0
  29. data/lib/entitlements/data/people/combined.rb +197 -0
  30. data/lib/entitlements/data/people/dummy.rb +71 -0
  31. data/lib/entitlements/data/people/ldap.rb +142 -0
  32. data/lib/entitlements/data/people/yaml.rb +102 -0
  33. data/lib/entitlements/data/people.rb +58 -0
  34. data/lib/entitlements/extras/base.rb +40 -0
  35. data/lib/entitlements/extras/ldap_group/base.rb +20 -0
  36. data/lib/entitlements/extras/ldap_group/filters/member_of_ldap_group.rb +50 -0
  37. data/lib/entitlements/extras/ldap_group/rules/ldap_group.rb +69 -0
  38. data/lib/entitlements/extras/orgchart/base.rb +32 -0
  39. data/lib/entitlements/extras/orgchart/logic.rb +171 -0
  40. data/lib/entitlements/extras/orgchart/person_methods.rb +55 -0
  41. data/lib/entitlements/extras/orgchart/rules/direct_report.rb +62 -0
  42. data/lib/entitlements/extras/orgchart/rules/management.rb +59 -0
  43. data/lib/entitlements/extras.rb +82 -0
  44. data/lib/entitlements/models/action.rb +82 -0
  45. data/lib/entitlements/models/group.rb +280 -0
  46. data/lib/entitlements/models/person.rb +149 -0
  47. data/lib/entitlements/plugins/dummy.rb +22 -0
  48. data/lib/entitlements/plugins/group_of_names.rb +28 -0
  49. data/lib/entitlements/plugins/posix_group.rb +46 -0
  50. data/lib/entitlements/plugins.rb +13 -0
  51. data/lib/entitlements/rule/base.rb +74 -0
  52. data/lib/entitlements/service/ldap.rb +405 -0
  53. data/lib/entitlements/util/mirror.rb +42 -0
  54. data/lib/entitlements/util/override.rb +64 -0
  55. data/lib/entitlements/util/util.rb +219 -0
  56. data/lib/entitlements.rb +606 -0
  57. metadata +343 -0
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entitlements
4
+ class Models
5
+ class Person
6
+ include ::Contracts::Core
7
+ C = ::Contracts
8
+
9
+ attr_reader :uid
10
+
11
+ # Constructor.
12
+ #
13
+ # uid - A String with user's ID (unique throughout Entitlements)
14
+ # attributes - Optionally a Hash of {String => String | Array<String>} with additional attributes
15
+ Contract C::KeywordArgs[
16
+ uid: String,
17
+ attributes: C::Maybe[C::HashOf[String => C::Or[String, C::ArrayOf[String], nil]]]
18
+ ] => C::Any
19
+ def initialize(uid:, attributes: {})
20
+ @uid = uid
21
+ setup_attributes(attributes)
22
+ end
23
+
24
+ # Grab any methods that have been defined by extras and dispatch them to the appropriate backend.
25
+ # The first argument sent to the method is a reference to this object (self). Any arguments passed
26
+ # by the caller are sent thereafter. For now this ignores blocks (maybe figure this out later?).
27
+ #
28
+ # Arguments and return varies.
29
+ def method_missing(m, *args, &block)
30
+ if method_class_ref = Entitlements.person_extra_methods[m]
31
+ return method_class_ref.send(m, self, *args)
32
+ end
33
+
34
+ # :nocov:
35
+ raise NoMethodError, "No method '#{m}' exists for Entitlements::Models::Person or any registered extras."
36
+ # :nocov:
37
+ end
38
+
39
+ # Hash method to get current value of an attribute. Raises if the attribute is undefined.
40
+ #
41
+ # attribute - A String with the attribute name to retrieve.
42
+ #
43
+ # Returns a String or Array<String> with the attribute's value. (nil deletes later)
44
+ Contract String => C::Or[String, C::ArrayOf[String], nil]
45
+ def [](attribute)
46
+ outward(@current_attributes.fetch(attribute))
47
+ end
48
+
49
+ # Get current value of the original attribute.
50
+ #
51
+ # attribute - A String with the attribute name to retrieve.
52
+ #
53
+ # Returns a String or Array<String> with the attribute's value. (nil if it did not exist)
54
+ Contract String => C::Or[String, C::ArrayOf[String], nil]
55
+ def original(attribute)
56
+ outward(@original_attributes[attribute])
57
+ end
58
+
59
+ # Hash method to set current value of an attribute.
60
+ #
61
+ # attribute - A String with the attribute name to set.
62
+ # val - A String, Array<String>, Set<String>, or nil with new value. (nil deletes later)
63
+ #
64
+ # Returns nothing interesting (this method is in void context).
65
+ Contract String, C::Or[String, C::ArrayOf[String], C::SetOf[String], nil] => C::Any
66
+ def []=(attribute, val)
67
+ @touched_attributes.add(attribute)
68
+
69
+ if val.nil? && @original_attributes[attribute].nil?
70
+ @original_attributes.delete(attribute)
71
+ @current_attributes.delete(attribute)
72
+ return
73
+ end
74
+
75
+ @original_attributes[attribute] ||= nil
76
+ if val.nil? || val.is_a?(String)
77
+ @current_attributes[attribute] = val
78
+ elsif val.is_a?(Set)
79
+ @current_attributes[attribute] = val.dup
80
+ else
81
+ @current_attributes[attribute] = Set.new(val)
82
+ end
83
+ end
84
+
85
+ # Get the changes between original attributes and any attributes updated in this session.
86
+ #
87
+ # Takes no arguments.
88
+ #
89
+ # Returns a Hash of { attribute name => new value }.
90
+ Contract C::None => C::HashOf[String => C::Or[String, C::ArrayOf[String], nil]]
91
+ def attribute_changes
92
+ @current_attributes
93
+ .select { |k, _| @touched_attributes.member?(k) }
94
+ .reject { |k, v| @original_attributes[k] == v }
95
+ .reject { |k, v| (@original_attributes[k].nil? || @original_attributes[k] == Set.new) && (v.nil? || v == Set.new) }
96
+ .map { |k, _| [k, self[k]] }
97
+ .to_h
98
+ end
99
+
100
+ # Update an attribute that is an array or a set by adding a new string item to it.
101
+ #
102
+ # attribute - A String with the attribute name to set.
103
+ # val - A String to add to the array/set.
104
+ #
105
+ # Returns nothing.
106
+ Contract String, String => nil
107
+ def add(attribute, val)
108
+ @touched_attributes.add(attribute)
109
+ ca = @current_attributes.fetch(attribute) # Raises if not found
110
+ raise ArgumentError, "Called add() on attribute that is a #{ca.class}" unless ca.is_a?(Set)
111
+ ca.add(val)
112
+ nil
113
+ end
114
+
115
+ private
116
+
117
+ # Convert the internal structure of an attribute to the displayed structure. Basically
118
+ # converts sets into sorted arrays and leaves everything else untouched.
119
+ #
120
+ # internal_obj - The internal structure.
121
+ #
122
+ # Returns the outward facing structure.
123
+ Contract C::Or[nil, String, C::SetOf[String]] => C::Or[nil, String, C::ArrayOf[String]]
124
+ def outward(internal_obj)
125
+ internal_obj.is_a?(Set) ? internal_obj.sort : internal_obj
126
+ end
127
+
128
+ # Construct a hash of attributes, keeping track of the original attributes as well
129
+ # as the current ones.
130
+ #
131
+ # attributes - Hash of {String => String | Array<String>} with additional attributes
132
+ #
133
+ # Returns nothing.
134
+ Contract C::HashOf[String => C::Or[String, C::ArrayOf[String], nil]] => nil
135
+ def setup_attributes(attributes)
136
+ @touched_attributes = Set.new
137
+ @original_attributes = {}
138
+ @current_attributes = {}
139
+ attributes.each do |k, v|
140
+ next if v.nil?
141
+ val = v.is_a?(Array) ? Set.new(v.sort) : v
142
+ @original_attributes[k] = val.dup
143
+ @current_attributes[k] = val.dup
144
+ end
145
+ nil
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entitlements
4
+ class Plugins
5
+ class Dummy < Entitlements::Plugins
6
+ include ::Contracts::Core
7
+ C = ::Contracts
8
+
9
+ # Dummy override hash.
10
+ #
11
+ # group - Entitlements::Models::Group object
12
+ # plugin_config - Additional configuration for the plugin
13
+ # ldap - Reference to the underlying Entitlements::Service::LDAP object
14
+ #
15
+ # Returns Hash with override settings.
16
+ Contract Entitlements::Models::Group, C::HashOf[String => C::Any], Entitlements::Service::LDAP => C::HashOf[String => C::Any]
17
+ def self.override_hash(_group, _plugin_config, _ldap)
18
+ {}
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entitlements
4
+ class Plugins
5
+ class GroupOfNames < Entitlements::Plugins
6
+ include ::Contracts::Core
7
+ C = ::Contracts
8
+
9
+ # Produce the override hash for an LDAP groupOfNames.
10
+ #
11
+ # group - Entitlements::Models::Group object
12
+ # plugin_config - Additional configuration for the plugin
13
+ # ldap - Reference to the underlying Entitlements::Service::LDAP object
14
+ #
15
+ # Returns Hash with override settings.
16
+ Contract Entitlements::Models::Group, C::HashOf[String => C::Any], Entitlements::Service::LDAP => C::HashOf[String => C::Any]
17
+ def self.override_hash(group, _plugin_config, ldap)
18
+ members = group.member_strings.map { |ms| ldap.person_dn_format.gsub("%KEY%", ms) }
19
+
20
+ {
21
+ "objectClass" => "GroupOfNames",
22
+ "member" => members,
23
+ "uniqueMember" => nil
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entitlements
4
+ class Plugins
5
+ class PosixGroup < Entitlements::Plugins
6
+ include ::Contracts::Core
7
+ C = ::Contracts
8
+
9
+ # Produce the override hash for an LDAP posixGroup.
10
+ #
11
+ # group - Entitlements::Models::Group object
12
+ # plugin_config - Additional configuration for the plugin
13
+ # ldap - Reference to the underlying Entitlements::Service::LDAP object
14
+ #
15
+ # Returns Hash with override settings.
16
+ Contract Entitlements::Models::Group, C::HashOf[String => C::Any], Entitlements::Service::LDAP => C::HashOf[String => C::Any]
17
+ def self.override_hash(group, _plugin_config, ldap)
18
+ members = group.member_strings.map { |ms| ldap.person_dn_format.gsub("%KEY%", ms) }
19
+
20
+ {
21
+ "objectClass" => "PosixGroup",
22
+ "memberUid" => members,
23
+ "gidNumber" => gid_number(group).to_s,
24
+ "uniqueMember" => nil,
25
+ "owner" => nil
26
+ }
27
+ end
28
+
29
+ # Get the gidNumber from the metadata in the group.
30
+ #
31
+ # group - Entitlements::Models::Group object
32
+ #
33
+ # Returns an Integer with the GID number of the group.
34
+ Contract Entitlements::Models::Group => Integer
35
+ def self.gid_number(group)
36
+ unless group.metadata.key?("gid_number")
37
+ raise ArgumentError, "POSIX Group #{group.dn} has no metadata setting for gid_number!"
38
+ end
39
+
40
+ result = group.metadata["gid_number"].to_i
41
+ return result if result >= 1 && result < 65536
42
+ raise ArgumentError, "POSIX Group #{group.dn} has GID #{result} out of 1-65535 range!"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entitlements
4
+ class Plugins
5
+ def self.loaded?
6
+ true
7
+ end
8
+
9
+ def self.override_hash(*args)
10
+ raise "Please define override_hash in the child class #{self}!"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rules written in ruby can (and should) inherit this class.
4
+
5
+ module Entitlements
6
+ class Rule
7
+ class Base
8
+ include ::Contracts::Core
9
+ C = ::Contracts
10
+
11
+ # This method must be re-implemented by the child class.
12
+ #
13
+ # Takes no Arguments.
14
+ #
15
+ # Returns a Set[String] of the DN's of all people who satisfy the filter.
16
+ Contract C::None => C::SetOf[String]
17
+ def members
18
+ # :nocov:
19
+ raise "Must be implemented by the child class"
20
+ # :nocov:
21
+ end
22
+
23
+ # This method allows the class to contain a line like:
24
+ # description "This is some text"
25
+ # and have that description be set as a class variable. When
26
+ # called without an argument, this returns the value of the
27
+ # description, so the instance can access it.
28
+ Contract C::Maybe[String] => String
29
+ def self.description(text = nil)
30
+ if text
31
+ @description = text
32
+ else
33
+ @description ||= ""
34
+ end
35
+ end
36
+
37
+ # Retrieve the description of the group from the class variable.
38
+ #
39
+ # Takes no arguments.
40
+ #
41
+ # Returns a String with the description.
42
+ Contract C::None => String
43
+ def description
44
+ self.class.description
45
+ end
46
+
47
+ # This method allows the class to contain a line like:
48
+ # filter "foo" => :all / :none / [list of Strings]
49
+ # and have that filter be set as a class variable. When
50
+ # called without an argument, this returns the value of the
51
+ # filter, so the instance can access it.
52
+ Contract C::Maybe[C::HashOf[String => C::Or[:all, :none, C::ArrayOf[String]]]] => C::HashOf[String => C::Or[:all, :none, C::ArrayOf[String]]]
53
+ def self.filter(filter_pair = nil)
54
+ @filters ||= Entitlements::Data::Groups::Calculated.filters_default
55
+ @filters.merge!(filter_pair) if filter_pair
56
+ @filters
57
+ end
58
+
59
+ # Retrieve the filters for the group from the class variable.
60
+ #
61
+ # Takes no arguments.
62
+ #
63
+ # Returns a Hash with the filters.
64
+ Contract C::None => C::HashOf[String => C::Or[:all, :none, C::ArrayOf[String]]]
65
+ def filters
66
+ self.class.filter
67
+ end
68
+
69
+ private
70
+
71
+ attr_reader :cache
72
+ end
73
+ end
74
+ end