socialcast 1.3.8 → 1.3.9
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.
- checksums.yaml +4 -4
- data/lib/socialcast/command_line/ldap_connector.rb +95 -42
- data/lib/socialcast/command_line/provision_photo.rb +8 -8
- data/lib/socialcast/command_line/provision_user.rb +4 -4
- data/lib/socialcast/command_line/provisioner.rb +3 -11
- data/lib/socialcast/command_line/version.rb +1 -1
- data/spec/fixtures/ldap_with_multiple_connection_mappings.yml +2 -0
- data/spec/fixtures/ldap_with_profile_photo.yml +12 -0
- data/spec/fixtures/ldap_without_options.yml +34 -0
- data/spec/socialcast/command_line/cli_spec.rb +37 -41
- data/spec/socialcast/command_line/ldap_connector_spec.rb +354 -84
- data/spec/socialcast/command_line/provision_photo_spec.rb +147 -72
- data/spec/socialcast/command_line/provision_user_spec.rb +100 -35
- data/spec/spec_helper.rb +2 -2
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e51c9793ebf4ee2583d3ed81fa89daff0b434030
|
|
4
|
+
data.tar.gz: e2e52ed618072b8aba3d3b8d66f530220b2bbc27
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 91ed1ae61a7c01ce7e3d62758873e65588d2a65dced1b6c5745e55fb155d5aa00ca6be823cefd925417351a4b4f4535bc5863f141866d92e695ae285f8fd5243
|
|
7
|
+
data.tar.gz: bafba8c661f3f7ff5e5878b15167b6362ac3d558614b7d4fdea7de044847864da7086e76785b1f36f5204a96d587a88eeaeb7ec36a7d16d16dcbc7e40322a549
|
|
@@ -5,35 +5,55 @@ require 'active_support/core_ext/array/wrap'
|
|
|
5
5
|
module Socialcast
|
|
6
6
|
module CommandLine
|
|
7
7
|
class LDAPConnector
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
UNIQUE_IDENTIFIER_ATTRIBUTE = "unique_identifier"
|
|
9
|
+
EMAIL_ATTRIBUTE = "email"
|
|
10
|
+
MANAGER_ATTRIBUTE = "manager"
|
|
11
|
+
PRIMARY_ATTRIBUTES = [UNIQUE_IDENTIFIER_ATTRIBUTE, 'first_name', 'last_name', 'employee_number']
|
|
12
|
+
CONTACT_ATTRIBUTES = [EMAIL_ATTRIBUTE, 'location', 'cell_phone', 'office_phone']
|
|
13
|
+
PROFILE_PHOTO_ATTRIBUTE = 'profile_photo'
|
|
12
14
|
|
|
13
15
|
attr_reader :attribute_mappings, :connection_name
|
|
14
16
|
|
|
15
|
-
def
|
|
17
|
+
def self.with_connector(connection_name, config)
|
|
18
|
+
connection_config = config["connections"][connection_name]
|
|
19
|
+
ldap = Net::LDAP.new(:host => connection_config["host"], :port => connection_config["port"], :base => connection_config["basedn"]).tap do |ldap_instance|
|
|
20
|
+
ldap_instance.encryption connection_config['encryption'].to_sym if connection_config['encryption']
|
|
21
|
+
ldap_instance.auth connection_config["username"], connection_config["password"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ldap.open do |connected_ldap_instance|
|
|
25
|
+
yield new(connection_name, config, connected_ldap_instance)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.attribute_mappings_for(connection_name, config)
|
|
30
|
+
config['connections'][connection_name]['mappings'] || config.fetch('mappings', {})
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def initialize(connection_name, config, ldap)
|
|
16
34
|
@connection_name = connection_name
|
|
17
35
|
@config = config
|
|
36
|
+
@ldap = ldap
|
|
37
|
+
@group_unique_identifiers = fetch_group_unique_identifiers
|
|
38
|
+
@dn_to_email_hash = fetch_dn_to_email_hash
|
|
18
39
|
end
|
|
19
40
|
|
|
20
41
|
def each_user_hash
|
|
21
|
-
each_ldap_entry do |entry|
|
|
42
|
+
each_ldap_entry(ldap_user_search_attributes) do |entry|
|
|
22
43
|
yield build_user_hash_from_mappings(entry)
|
|
23
44
|
end
|
|
24
45
|
end
|
|
25
46
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
47
|
+
def each_photo_hash
|
|
48
|
+
each_ldap_entry(ldap_photo_search_attributes) do |entry|
|
|
49
|
+
photo_hash = build_photo_hash_from_mappings(entry)
|
|
50
|
+
yield photo_hash if photo_hash.present?
|
|
31
51
|
end
|
|
32
52
|
end
|
|
33
53
|
|
|
34
54
|
def fetch_user_hash(identifier, options)
|
|
35
55
|
options = options.dup
|
|
36
|
-
identifying_field = options.delete(:identifying_field) ||
|
|
56
|
+
identifying_field = options.delete(:identifying_field) || UNIQUE_IDENTIFIER_ATTRIBUTE
|
|
37
57
|
|
|
38
58
|
filter = if connection_config['filter'].present?
|
|
39
59
|
Net::LDAP::Filter.construct(connection_config['filter'])
|
|
@@ -43,7 +63,7 @@ module Socialcast
|
|
|
43
63
|
|
|
44
64
|
filter = filter & Net::LDAP::Filter.construct("#{attribute_mappings[identifying_field]}=#{identifier}")
|
|
45
65
|
|
|
46
|
-
search(:base => connection_config['basedn'], :filter => filter, :attributes =>
|
|
66
|
+
search(:base => connection_config['basedn'], :filter => filter, :attributes => ldap_user_search_attributes, :size => 1) do |entry|
|
|
47
67
|
return build_user_hash_from_mappings(entry)
|
|
48
68
|
end
|
|
49
69
|
|
|
@@ -51,8 +71,7 @@ module Socialcast
|
|
|
51
71
|
end
|
|
52
72
|
|
|
53
73
|
def attribute_mappings
|
|
54
|
-
@attribute_mappings ||=
|
|
55
|
-
@attribute_mappings ||= @config.fetch 'mappings', {}
|
|
74
|
+
@attribute_mappings ||= LDAPConnector.attribute_mappings_for(@connection_name, @config)
|
|
56
75
|
end
|
|
57
76
|
|
|
58
77
|
# grab a *single* value of an attribute
|
|
@@ -82,13 +101,37 @@ module Socialcast
|
|
|
82
101
|
|
|
83
102
|
private
|
|
84
103
|
|
|
104
|
+
def each_ldap_entry(attributes)
|
|
105
|
+
search(:return_result => false, :filter => connection_config["filter"], :base => connection_config["basedn"], :attributes => attributes) do |entry|
|
|
106
|
+
if grab(entry, attribute_mappings[EMAIL_ATTRIBUTE]).present? || (attribute_mappings.has_key?(UNIQUE_IDENTIFIER_ATTRIBUTE) && grab(entry, attribute_mappings[UNIQUE_IDENTIFIER_ATTRIBUTE]).present?)
|
|
107
|
+
yield entry
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
85
112
|
def connection_config
|
|
86
113
|
@config["connections"][connection_name]
|
|
87
114
|
end
|
|
88
115
|
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
def ldap_mail_search_attributes
|
|
117
|
+
search_attributes [attribute_mappings[LDAPConnector::EMAIL_ATTRIBUTE]]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def ldap_user_search_attributes
|
|
121
|
+
mappings = attribute_mappings.map do |mapping_key, mapping_value|
|
|
122
|
+
mapping_value unless mapping_key == PROFILE_PHOTO_ATTRIBUTE
|
|
123
|
+
end.compact
|
|
124
|
+
attributes = search_attributes(mappings)
|
|
125
|
+
attributes << permission_mappings.fetch('attribute_name', 'memberof')
|
|
126
|
+
attributes.flatten
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def ldap_photo_search_attributes
|
|
130
|
+
search_attributes [attribute_mappings[LDAPConnector::EMAIL_ATTRIBUTE], attribute_mappings[LDAPConnector::PROFILE_PHOTO_ATTRIBUTE]]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def search_attributes(mappings)
|
|
134
|
+
mappings.map do |mapping_value|
|
|
92
135
|
value = begin
|
|
93
136
|
mapping_value.camelize.constantize
|
|
94
137
|
rescue NameError
|
|
@@ -109,15 +152,6 @@ module Socialcast
|
|
|
109
152
|
mapping_value
|
|
110
153
|
end
|
|
111
154
|
end
|
|
112
|
-
end.flatten
|
|
113
|
-
attributes << membership_attribute
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def ldap
|
|
118
|
-
@ldap ||= Net::LDAP.new(:host => connection_config["host"], :port => connection_config["port"], :base => connection_config["basedn"]).tap do |ldap_instance|
|
|
119
|
-
ldap_instance.encryption connection_config['encryption'].to_sym if connection_config['encryption']
|
|
120
|
-
ldap_instance.auth connection_config["username"], connection_config["password"]
|
|
121
155
|
end
|
|
122
156
|
end
|
|
123
157
|
|
|
@@ -125,12 +159,12 @@ module Socialcast
|
|
|
125
159
|
options_for_search = if search_options[:base].present?
|
|
126
160
|
Array.wrap(search_options)
|
|
127
161
|
else
|
|
128
|
-
distinguished_names = Array.wrap(ldap.search_root_dse.namingcontexts)
|
|
162
|
+
distinguished_names = Array.wrap(@ldap.search_root_dse.namingcontexts)
|
|
129
163
|
options_for_search = distinguished_names.map { |dn| search_options.merge(:base => dn ) }
|
|
130
164
|
end
|
|
131
165
|
|
|
132
166
|
options_for_search.each do |options|
|
|
133
|
-
ldap.search(options) do |entry|
|
|
167
|
+
@ldap.search(options) do |entry|
|
|
134
168
|
yield(entry)
|
|
135
169
|
end
|
|
136
170
|
end
|
|
@@ -149,24 +183,35 @@ module Socialcast
|
|
|
149
183
|
permission_mappings['group_memberships']
|
|
150
184
|
end
|
|
151
185
|
|
|
152
|
-
def dereference_mail(entry, dn_field
|
|
186
|
+
def dereference_mail(entry, dn_field)
|
|
153
187
|
dn = grab(entry, dn_field)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
end
|
|
188
|
+
|
|
189
|
+
@dn_to_email_hash[dn]
|
|
157
190
|
end
|
|
158
191
|
|
|
159
|
-
def
|
|
160
|
-
|
|
192
|
+
def fetch_group_unique_identifiers
|
|
193
|
+
return nil unless group_membership_mappings.present?
|
|
194
|
+
|
|
195
|
+
{}.tap do |groups|
|
|
161
196
|
search_options = {
|
|
162
197
|
:return_result => false,
|
|
163
198
|
:filter => group_membership_mappings["filter"],
|
|
164
199
|
:base => connection_config["basedn"],
|
|
165
|
-
:attributes => [group_membership_mappings[
|
|
200
|
+
:attributes => [group_membership_mappings[UNIQUE_IDENTIFIER_ATTRIBUTE]]
|
|
166
201
|
}
|
|
167
202
|
|
|
168
203
|
search(search_options) do |entry|
|
|
169
|
-
groups[grab(entry, "dn")] = grab(entry, group_membership_mappings[
|
|
204
|
+
groups[grab(entry, "dn")] = grab(entry, group_membership_mappings[UNIQUE_IDENTIFIER_ATTRIBUTE])
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def fetch_dn_to_email_hash
|
|
210
|
+
return nil unless attribute_mappings[MANAGER_ATTRIBUTE].present?
|
|
211
|
+
|
|
212
|
+
{}.tap do |dn_to_email_hash|
|
|
213
|
+
each_ldap_entry(ldap_mail_search_attributes) do |entry|
|
|
214
|
+
dn_to_email_hash[entry.dn] = grab(entry, attribute_mappings[EMAIL_ATTRIBUTE])
|
|
170
215
|
end
|
|
171
216
|
end
|
|
172
217
|
end
|
|
@@ -187,12 +232,12 @@ module Socialcast
|
|
|
187
232
|
end
|
|
188
233
|
|
|
189
234
|
def add_custom_attributes(entry, user_hash)
|
|
190
|
-
custom_attributes = attribute_mappings.keys - (PRIMARY_ATTRIBUTES + CONTACT_ATTRIBUTES)
|
|
235
|
+
custom_attributes = attribute_mappings.keys - (PRIMARY_ATTRIBUTES + CONTACT_ATTRIBUTES + [PROFILE_PHOTO_ATTRIBUTE])
|
|
191
236
|
|
|
192
237
|
user_hash['custom_fields'] = []
|
|
193
238
|
custom_attributes.each do |attribute|
|
|
194
|
-
if attribute ==
|
|
195
|
-
user_hash['custom_fields'] << { 'id' => 'manager_email', 'label' => 'manager_email', 'value' => dereference_mail(entry, attribute_mappings[attribute]
|
|
239
|
+
if attribute == MANAGER_ATTRIBUTE
|
|
240
|
+
user_hash['custom_fields'] << { 'id' => 'manager_email', 'label' => 'manager_email', 'value' => dereference_mail(entry, attribute_mappings[attribute]) }
|
|
196
241
|
else
|
|
197
242
|
user_hash['custom_fields'] << { 'id' => attribute, 'label' => attribute, 'value' => grab(entry, attribute_mappings[attribute]) }
|
|
198
243
|
end
|
|
@@ -227,10 +272,10 @@ module Socialcast
|
|
|
227
272
|
membership_attribute = permission_mappings.fetch 'attribute_name', 'memberof'
|
|
228
273
|
memberships = entry[membership_attribute]
|
|
229
274
|
|
|
230
|
-
mapped_group_dns = (group_unique_identifiers.keys & memberships)
|
|
275
|
+
mapped_group_dns = (@group_unique_identifiers.keys & memberships)
|
|
231
276
|
|
|
232
277
|
user_hash['groups'] = mapped_group_dns.each_with_object([]) do |ldap_group_dn, socialcast_groups|
|
|
233
|
-
socialcast_groups << group_unique_identifiers[ldap_group_dn]
|
|
278
|
+
socialcast_groups << @group_unique_identifiers[ldap_group_dn]
|
|
234
279
|
end
|
|
235
280
|
end
|
|
236
281
|
|
|
@@ -246,6 +291,14 @@ module Socialcast
|
|
|
246
291
|
|
|
247
292
|
user_hash
|
|
248
293
|
end
|
|
294
|
+
|
|
295
|
+
def build_photo_hash_from_mappings(entry)
|
|
296
|
+
photo_hash = HashWithIndifferentAccess.new
|
|
297
|
+
photo_hash[EMAIL_ATTRIBUTE] = grab(entry, attribute_mappings[EMAIL_ATTRIBUTE])
|
|
298
|
+
photo_hash[PROFILE_PHOTO_ATTRIBUTE] = grab(entry, attribute_mappings[PROFILE_PHOTO_ATTRIBUTE])
|
|
299
|
+
|
|
300
|
+
return photo_hash if photo_hash[EMAIL_ATTRIBUTE].present? && photo_hash[PROFILE_PHOTO_ATTRIBUTE] && !photo_hash[PROFILE_PHOTO_ATTRIBUTE].empty?
|
|
301
|
+
end
|
|
249
302
|
end
|
|
250
303
|
end
|
|
251
304
|
end
|
|
@@ -5,13 +5,13 @@ module Socialcast
|
|
|
5
5
|
class ProvisionPhoto
|
|
6
6
|
include Socialcast::CommandLine::Provisioner
|
|
7
7
|
def sync
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
@ldap_config['connections'].keys.each do |connection_name|
|
|
9
|
+
LDAPConnector.attribute_mappings_for(connection_name, @ldap_config).fetch(LDAPConnector::PROFILE_PHOTO_ATTRIBUTE)
|
|
10
|
+
end
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
email =
|
|
12
|
+
each_ldap_connector do |connector|
|
|
13
|
+
connector.each_photo_hash do |photo_hash|
|
|
14
|
+
email = photo_hash[LDAPConnector::EMAIL_ATTRIBUTE]
|
|
15
15
|
|
|
16
16
|
## GET USER INFO
|
|
17
17
|
search_users_resource = Socialcast::CommandLine.resource_for_path '/api/users/search', http_config
|
|
@@ -19,10 +19,10 @@ module Socialcast
|
|
|
19
19
|
user_info = JSON.parse(user_search_response)['users'].first
|
|
20
20
|
|
|
21
21
|
is_community_default = user_info && user_info['avatars'] && user_info['avatars']['is_community_default']
|
|
22
|
-
|
|
22
|
+
next unless is_community_default || @options[:force_sync]
|
|
23
23
|
|
|
24
24
|
## PHOTO URL TO BINARY
|
|
25
|
-
if profile_photo_data =
|
|
25
|
+
if profile_photo_data = photo_hash[LDAPConnector::PROFILE_PHOTO_ATTRIBUTE]
|
|
26
26
|
if profile_photo_data.start_with?('http')
|
|
27
27
|
begin
|
|
28
28
|
profile_photo_data = RestClient.get(profile_photo_data)
|
|
@@ -36,7 +36,7 @@ module Socialcast
|
|
|
36
36
|
export.users(:type => "array") do |users|
|
|
37
37
|
each_user_hash do |user_hash|
|
|
38
38
|
users << user_hash.to_xml(:skip_instruct => true, :root => 'user')
|
|
39
|
-
user_whitelist << [user_hash['contact_info'][
|
|
39
|
+
user_whitelist << [user_hash['contact_info'][LDAPConnector::EMAIL_ATTRIBUTE], user_hash[LDAPConnector::UNIQUE_IDENTIFIER_ATTRIBUTE], user_hash['employee_number']]
|
|
40
40
|
end
|
|
41
41
|
end # users
|
|
42
42
|
end # export
|
|
@@ -50,8 +50,8 @@ module Socialcast
|
|
|
50
50
|
begin
|
|
51
51
|
File.open(output_file, 'r') do |file|
|
|
52
52
|
request_params = {:file => file}
|
|
53
|
-
request_params[:skip_emails] = 'true' if (@ldap_config
|
|
54
|
-
request_params[:test] = 'true' if (@ldap_config
|
|
53
|
+
request_params[:skip_emails] = 'true' if (@ldap_config.fetch('options', {})["skip_emails"] || @options[:skip_emails])
|
|
54
|
+
request_params[:test] = 'true' if (@ldap_config.fetch('options', {})["test"] || @options[:test])
|
|
55
55
|
resource.post request_params, :accept => :json
|
|
56
56
|
end
|
|
57
57
|
rescue RestClient::Unauthorized => e
|
|
@@ -59,7 +59,7 @@ module Socialcast
|
|
|
59
59
|
end
|
|
60
60
|
puts "Finished"
|
|
61
61
|
end
|
|
62
|
-
File.delete(output_file) if (@ldap_config
|
|
62
|
+
File.delete(output_file) if (@ldap_config.fetch('options', {})['delete_users_file'] || @options[:delete_users_file])
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
end
|
|
@@ -18,19 +18,11 @@ module Socialcast
|
|
|
18
18
|
@http_config ||= @ldap_config.fetch 'http', {}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def ldap_connector(connection_name)
|
|
22
|
-
@connectors ||= {}
|
|
23
|
-
|
|
24
|
-
unless @connectors[connection_name]
|
|
25
|
-
@connectors[connection_name] = Socialcast::CommandLine::LDAPConnector.new(connection_name, @ldap_config)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
@connectors[connection_name]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
21
|
def each_ldap_connector
|
|
32
22
|
@ldap_config['connections'].keys.each do |connection_name|
|
|
33
|
-
|
|
23
|
+
LDAPConnector.with_connector(connection_name, @ldap_config) do |ldap_connector|
|
|
24
|
+
yield ldap_connector
|
|
25
|
+
end
|
|
34
26
|
end
|
|
35
27
|
end
|
|
36
28
|
|
|
@@ -10,6 +10,7 @@ connections:
|
|
|
10
10
|
filter: "(mail=*)"
|
|
11
11
|
mappings:
|
|
12
12
|
email: mailCon
|
|
13
|
+
profile_photo: photoCon
|
|
13
14
|
|
|
14
15
|
example_connection_2:
|
|
15
16
|
username: "cn=Directory Manager"
|
|
@@ -21,6 +22,7 @@ connections:
|
|
|
21
22
|
mappings:
|
|
22
23
|
email: mailCon2
|
|
23
24
|
first_name: firstName
|
|
25
|
+
profile_photo: photoCon2
|
|
24
26
|
|
|
25
27
|
# Map LDAP Group Memberships to Socialcast Permissions
|
|
26
28
|
permission_mappings:
|
|
@@ -14,3 +14,15 @@ mappings:
|
|
|
14
14
|
last_name: sn
|
|
15
15
|
email: mail
|
|
16
16
|
profile_photo: jpegPhoto
|
|
17
|
+
|
|
18
|
+
# Map LDAP Group Memberships to Socialcast Permissions
|
|
19
|
+
permission_mappings:
|
|
20
|
+
# configure LDAP field for group memberships (ex: memberof, isMemberOf, etc)
|
|
21
|
+
attribute_name: memberof
|
|
22
|
+
account_types:
|
|
23
|
+
external: "cn=External,dc=example,dc=com"
|
|
24
|
+
roles:
|
|
25
|
+
tenant_admin: "cn=Admins,dc=example,dc=com"
|
|
26
|
+
sbi_admin: "cn=SbiAdmins,dc=example,dc=com"
|
|
27
|
+
reach_admin: "cn=ReachAdmins,dc=example,dc=com"
|
|
28
|
+
town_hall_admin: "cn=TownHallAdmins,dc=example,dc=com"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
# LDAP connections
|
|
3
|
+
connections:
|
|
4
|
+
example_connection_1:
|
|
5
|
+
username: "cn=Directory Manager"
|
|
6
|
+
password: "test"
|
|
7
|
+
host: localhost
|
|
8
|
+
port: 1389
|
|
9
|
+
basedn: "dc=example,dc=com"
|
|
10
|
+
filter: "(mail=*)"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# LDAP attribute mappings
|
|
14
|
+
mappings:
|
|
15
|
+
first_name: givenName
|
|
16
|
+
last_name: sn
|
|
17
|
+
email: mail
|
|
18
|
+
# only use employee_number if the email is unknown
|
|
19
|
+
# employee_number: emp_id
|
|
20
|
+
# only use unique_identifier if you do not wish to use email as the main user identification method
|
|
21
|
+
# unique_identifier: samaccountname
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Map LDAP Group Memberships to Socialcast Permissions
|
|
25
|
+
permission_mappings:
|
|
26
|
+
# configure LDAP field for group memberships (ex: memberof, isMemberOf, etc)
|
|
27
|
+
attribute_name: isMemberOf
|
|
28
|
+
account_types:
|
|
29
|
+
external: "cn=External,dc=example,dc=com"
|
|
30
|
+
roles:
|
|
31
|
+
tenant_admin: "cn=Admins,dc=example,dc=com"
|
|
32
|
+
sbi_admin: "cn=SbiAdmins,dc=example,dc=com"
|
|
33
|
+
reach_admin: "cn=ReachAdmins,dc=example,dc=com"
|
|
34
|
+
town_hall_admin: "cn=TownHallAdmins,dc=example,dc=com"
|
|
@@ -16,6 +16,13 @@ describe Socialcast::CommandLine::CLI do
|
|
|
16
16
|
Socialcast::CommandLine.stub(:credentials).and_return(credentials)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
let(:ldap) do
|
|
20
|
+
ldap_instance = double(Net::LDAP, :auth => nil, :encryption => nil)
|
|
21
|
+
ldap_instance.should_receive(:open).and_yield(ldap_instance)
|
|
22
|
+
Net::LDAP.should_receive(:new).and_return(ldap_instance)
|
|
23
|
+
ldap_instance
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
describe '#info' do
|
|
20
27
|
before do
|
|
21
28
|
Socialcast::CommandLine::CLI.any_instance.should_receive(:say).with("Socialcast Command Line #{Socialcast::CommandLine::VERSION}")
|
|
@@ -149,12 +156,12 @@ describe Socialcast::CommandLine::CLI do
|
|
|
149
156
|
context "user does not have a profile photo" do
|
|
150
157
|
let(:config_file) { ldap_with_profile_photo_config_file }
|
|
151
158
|
let(:system_default_photo) { true }
|
|
152
|
-
let(:photo_data) { "\x89PNGabc" }
|
|
159
|
+
let(:photo_data) { "\x89PNGabc".force_encoding('binary') }
|
|
153
160
|
before do
|
|
154
161
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
155
162
|
@entry[:mail] = 'ryan@example.com'
|
|
156
163
|
@entry[:jpegPhoto] = photo_data
|
|
157
|
-
|
|
164
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
158
165
|
|
|
159
166
|
user_search_resource = double(:user_search_resource)
|
|
160
167
|
search_api_response = {
|
|
@@ -191,7 +198,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
191
198
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
192
199
|
@entry[:mail] = 'ryan@example.com'
|
|
193
200
|
@entry[:jpegPhoto] = photo_data
|
|
194
|
-
|
|
201
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
195
202
|
|
|
196
203
|
user_search_resource = double(:user_search_resource)
|
|
197
204
|
search_api_response = {
|
|
@@ -219,12 +226,12 @@ describe Socialcast::CommandLine::CLI do
|
|
|
219
226
|
context "user already has a profile photo" do
|
|
220
227
|
let(:config_file) { ldap_with_profile_photo_config_file }
|
|
221
228
|
let(:system_default_photo) { false }
|
|
222
|
-
let(:photo_data) { "\x89PNGabc" }
|
|
229
|
+
let(:photo_data) { "\x89PNGabc".force_encoding('binary') }
|
|
223
230
|
before do
|
|
224
231
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
225
232
|
@entry[:mail] = 'ryan@example.com'
|
|
226
|
-
@entry[:jpegPhoto] =
|
|
227
|
-
|
|
233
|
+
@entry[:jpegPhoto] = photo_data
|
|
234
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
228
235
|
|
|
229
236
|
user_search_resource = double(:user_search_resource)
|
|
230
237
|
search_api_response = {
|
|
@@ -258,7 +265,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
258
265
|
end
|
|
259
266
|
context 'with 0 users found in ldap' do
|
|
260
267
|
before do
|
|
261
|
-
|
|
268
|
+
ldap.should_receive(:search).and_return(nil)
|
|
262
269
|
|
|
263
270
|
@result = ''
|
|
264
271
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -273,7 +280,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
273
280
|
end
|
|
274
281
|
context 'with 0 users found in ldap and force option passed' do
|
|
275
282
|
before do
|
|
276
|
-
|
|
283
|
+
ldap.should_receive(:search).and_return(nil)
|
|
277
284
|
|
|
278
285
|
@result = ''
|
|
279
286
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -289,7 +296,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
289
296
|
end
|
|
290
297
|
context 'with socialcast returning 401' do
|
|
291
298
|
before do
|
|
292
|
-
|
|
299
|
+
ldap.should_receive(:search).and_return(nil)
|
|
293
300
|
|
|
294
301
|
@result = ''
|
|
295
302
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -309,7 +316,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
309
316
|
before do
|
|
310
317
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
311
318
|
@entry[:mail] = 'ryan@example.com'
|
|
312
|
-
|
|
319
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
313
320
|
|
|
314
321
|
@result = ''
|
|
315
322
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -322,19 +329,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
322
329
|
it 'resolves absolute path without using current process directory' do end # see expectations
|
|
323
330
|
end
|
|
324
331
|
context 'with plugins option used with non-existent ruby files' do
|
|
325
|
-
|
|
326
|
-
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
327
|
-
@entry[:mail] = 'ryan@example.com'
|
|
328
|
-
Net::LDAP.any_instance.stub(:search).and_yield(@entry)
|
|
329
|
-
|
|
330
|
-
@result = ''
|
|
331
|
-
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
332
|
-
Socialcast::CommandLine::CLI.any_instance.should_receive(:ldap_config).and_return(ldap_without_permission_mappings_config)
|
|
333
|
-
File.stub(:open).with(/users.xml.gz/, anything).and_yield(@result)
|
|
334
|
-
RestClient::Resource.any_instance.stub(:post)
|
|
335
|
-
|
|
336
|
-
end
|
|
337
|
-
it 'does not post to Socialcast and throws Kernel.abort' do
|
|
332
|
+
it 'does not post to Socialcast and raises an error' do
|
|
338
333
|
lambda { Socialcast::CommandLine::CLI.start ['provision', '-c', '/my/path/to/ldap.yml', '--plugins', ['does_not_exist.rb', 'also_does_not_exist.rb']] }.should raise_error
|
|
339
334
|
end
|
|
340
335
|
end
|
|
@@ -343,7 +338,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
343
338
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
344
339
|
@entry[:mail] = 'ryan@example.com'
|
|
345
340
|
@entry[:plugin_attr] = 'some value'
|
|
346
|
-
|
|
341
|
+
ldap.should_receive(:search).with(hash_including(:attributes => ['plugin_attr', 'sn', 'mail', 'memberof'])).and_yield(@entry)
|
|
347
342
|
|
|
348
343
|
@result = ''
|
|
349
344
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -362,7 +357,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
362
357
|
@entry = Net::LDAP::Entry.new("dc=example,dc=com")
|
|
363
358
|
@entry[:mail] = 'ryan@example.com'
|
|
364
359
|
|
|
365
|
-
|
|
360
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
366
361
|
|
|
367
362
|
@result = ''
|
|
368
363
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -383,7 +378,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
383
378
|
@entry[:mail] = 'ryan@example.com'
|
|
384
379
|
@entry[:isMemberOf] = 'cn=External,dc=example,dc=com'
|
|
385
380
|
|
|
386
|
-
|
|
381
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
387
382
|
|
|
388
383
|
@result = ''
|
|
389
384
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -404,7 +399,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
404
399
|
@entry[:mail] = 'ryan@example.com'
|
|
405
400
|
@entry[:isMemberOf] = 'cn=Contractor,dc=example,dc=com'
|
|
406
401
|
|
|
407
|
-
|
|
402
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
408
403
|
|
|
409
404
|
@result = ''
|
|
410
405
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -426,7 +421,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
426
421
|
@entry[:mail] = 'ryan@example.com'
|
|
427
422
|
@entry[:isMemberOf] = 'cn=Admins,dc=example,dc=com'
|
|
428
423
|
|
|
429
|
-
|
|
424
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
430
425
|
|
|
431
426
|
@result = ''
|
|
432
427
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -450,7 +445,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
450
445
|
@entry[:mail] = 'ryan@example.com'
|
|
451
446
|
@entry[:isMemberOf] = 'cn=Marketing,dc=example,dc=com'
|
|
452
447
|
|
|
453
|
-
|
|
448
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
454
449
|
|
|
455
450
|
@result = ''
|
|
456
451
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -474,7 +469,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
474
469
|
@entry[:mail] = 'ryan@example.com'
|
|
475
470
|
@entry[:isMemberOf] = 'cn=Engineering,dc=example,dc=com'
|
|
476
471
|
|
|
477
|
-
|
|
472
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
478
473
|
|
|
479
474
|
@result = ''
|
|
480
475
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -500,7 +495,7 @@ describe Socialcast::CommandLine::CLI do
|
|
|
500
495
|
@entry[:l] = 'San Francisco'
|
|
501
496
|
@entry[:co] = 'USA'
|
|
502
497
|
|
|
503
|
-
|
|
498
|
+
ldap.should_receive(:search).and_yield(@entry)
|
|
504
499
|
|
|
505
500
|
@result = ''
|
|
506
501
|
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
@@ -518,17 +513,18 @@ describe Socialcast::CommandLine::CLI do
|
|
|
518
513
|
end
|
|
519
514
|
|
|
520
515
|
context 'with ldap.yml configuration including manager attribute mapping' do
|
|
516
|
+
let(:result) { '' }
|
|
521
517
|
before do
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
518
|
+
employee_entry = Net::LDAP::Entry.new("cn=employee,dc=example,dc=com")
|
|
519
|
+
employee_entry[:mail] = 'employee@example.com'
|
|
520
|
+
employee_entry[:ldap_manager] = 'cn=manager,dc=example,dc=com'
|
|
521
|
+
manager_entry = Net::LDAP::Entry.new("cn=manager,dc=example,dc=com")
|
|
522
|
+
manager_entry[:mail] = 'manager@example.com'
|
|
526
523
|
|
|
527
|
-
|
|
528
|
-
|
|
524
|
+
ldap.should_receive(:search).once.ordered.and_yield(manager_entry).and_yield(employee_entry)
|
|
525
|
+
ldap.should_receive(:search).once.ordered.and_yield(manager_entry).and_yield(employee_entry)
|
|
529
526
|
|
|
530
|
-
|
|
531
|
-
Zlib::GzipWriter.stub(:open).and_yield(@result)
|
|
527
|
+
Zlib::GzipWriter.stub(:open).and_yield(result)
|
|
532
528
|
Socialcast::CommandLine::CLI.any_instance.should_receive(:ldap_config).and_return(ldap_with_manager_attribute_config)
|
|
533
529
|
File.stub(:open).with(/users.xml.gz/, anything).and_yield(@result)
|
|
534
530
|
|
|
@@ -538,8 +534,8 @@ describe Socialcast::CommandLine::CLI do
|
|
|
538
534
|
end
|
|
539
535
|
|
|
540
536
|
it 'adds a manager_email entry of bossman@example.com' do
|
|
541
|
-
|
|
542
|
-
|
|
537
|
+
result.should =~ /<email>employee@example.com<\/email>/
|
|
538
|
+
result.should =~ /<label>manager_email<\/label>\s*<value>manager@example.com<\/value>/
|
|
543
539
|
end
|
|
544
540
|
end
|
|
545
541
|
end
|