crowd 0.5.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.
- data/History.txt +22 -0
- data/Manifest.txt +12 -0
- data/README.txt +68 -0
- data/Rakefile +20 -0
- data/lib/SecurityServerClient.rb +626 -0
- data/lib/crowd-1.1.0.wsdl +2203 -0
- data/lib/crowd.rb +508 -0
- data/lib/crowd/version.rb +9 -0
- data/lib/default.rb +1047 -0
- data/lib/defaultDriver.rb +328 -0
- data/lib/defaultMappingRegistry.rb +1553 -0
- data/test/test_crowd.rb +159 -0
- metadata +77 -0
data/lib/crowd.rb
ADDED
@@ -0,0 +1,508 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Created by Jason Rimmer, jrimmer@irth.net on 2007-10-16.
|
5
|
+
# I hereby place this work that I have authored into the public domain
|
6
|
+
# and in the process abandon all copyright protection.
|
7
|
+
#
|
8
|
+
require 'rubygems'
|
9
|
+
gem 'soap4r'
|
10
|
+
|
11
|
+
require File.join(File.dirname(__FILE__), 'defaultDriver.rb')
|
12
|
+
require 'crowd/version'
|
13
|
+
|
14
|
+
#
|
15
|
+
# Place 'obj.wiredump_dev = STDERR' after any SecurityServerPortType
|
16
|
+
# instantiation to see the raw SOAP calls and responses in a test
|
17
|
+
# console
|
18
|
+
#
|
19
|
+
|
20
|
+
class Crowd
|
21
|
+
#
|
22
|
+
# Class variables
|
23
|
+
#
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
@@application_token = nil
|
28
|
+
|
29
|
+
public
|
30
|
+
|
31
|
+
@@crowd_url = nil
|
32
|
+
@@crowd_app_name = nil
|
33
|
+
@@crowd_app_pword = nil
|
34
|
+
|
35
|
+
def self.crowd_url=(value); @@crowd_url = value; end
|
36
|
+
def self.crowd_app_name=(value); @@crowd_app_name = value; end
|
37
|
+
def self.crowd_app_pword=(value); @@crowd_app_pword = value; end
|
38
|
+
|
39
|
+
public
|
40
|
+
|
41
|
+
#
|
42
|
+
# Exceptions
|
43
|
+
#
|
44
|
+
class AuthenticationException < Exception; end
|
45
|
+
class AuthenticationConnectionException < AuthenticationException; end
|
46
|
+
class AuthenticationInvalidCredentialException < AuthenticationException; end
|
47
|
+
class AuthenticationInvalidException < AuthenticationException; end
|
48
|
+
class AuthenticationObjectNotFoundException < AuthenticationException; end
|
49
|
+
class AuthenticationInvalidObject < AuthenticationException; end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Public methods
|
53
|
+
#
|
54
|
+
|
55
|
+
##
|
56
|
+
# Authenticate application
|
57
|
+
def self.authenticate_application()
|
58
|
+
@@application_token = nil
|
59
|
+
|
60
|
+
if @@crowd_app_name.nil?
|
61
|
+
@@crowd_app_name = CROWD_APPLICATION_NAME
|
62
|
+
end
|
63
|
+
if @@crowd_app_pword.nil?
|
64
|
+
@@crowd_app_pword = CROWD_APPLICATION_PASSWORD
|
65
|
+
end
|
66
|
+
|
67
|
+
pword = PasswordCredential.new(@@crowd_app_pword, false)
|
68
|
+
ctx = ApplicationAuthenticationContext.new(pword, @@crowd_app_name, nil)
|
69
|
+
arg = AuthenticateApplication.new(ctx)
|
70
|
+
|
71
|
+
begin
|
72
|
+
response = server.authenticateApplication(arg)
|
73
|
+
rescue Errno::ECONNREFUSED
|
74
|
+
raise AuthenticationConnectionException
|
75
|
+
rescue Exception
|
76
|
+
raise AuthenticationException, response
|
77
|
+
end
|
78
|
+
|
79
|
+
if !response.is_a?(AuthenticateApplicationResponse)
|
80
|
+
raise AuthenticationException, response
|
81
|
+
end
|
82
|
+
|
83
|
+
@@application_token = AuthenticatedToken.new(@@crowd_app_name, response.out.token)
|
84
|
+
|
85
|
+
response.out.token
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Authenticate principal
|
90
|
+
def self.authenticate_principal(username, password)
|
91
|
+
response = authenticated_connection do
|
92
|
+
pword = PasswordCredential.new(password, false)
|
93
|
+
ctx = PrincipalAuthenticationContext.new(@@application_token.name, pword, username, nil)
|
94
|
+
arg = AuthenticatePrincipal.new(@@application_token, ctx)
|
95
|
+
|
96
|
+
server.authenticatePrincipal(arg)
|
97
|
+
end
|
98
|
+
|
99
|
+
#evaluate the response. ideally, the authenticatePrincipal call should
|
100
|
+
#return an AuthenticationInvalidCredentialException and we can handle it more
|
101
|
+
#nicely below.
|
102
|
+
case response
|
103
|
+
when AuthenticatePrincipalResponse
|
104
|
+
return response.out
|
105
|
+
when InvalidAuthenticationException
|
106
|
+
return nil
|
107
|
+
when nil #no reponse
|
108
|
+
raise AuthenticationInvalidCredentialException, response
|
109
|
+
else
|
110
|
+
raise AuthenticationException, response
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Add Principal
|
116
|
+
def self.add_principal(username, password, description, is_active, attributes)
|
117
|
+
response = authenticated_connection do
|
118
|
+
attrs = ArrayOfSOAPAttribute.new()
|
119
|
+
|
120
|
+
attributes.each do |key, val|
|
121
|
+
if (val.class == Array)
|
122
|
+
attrVal = ArrayOfString.new(val)
|
123
|
+
else
|
124
|
+
attrVal = ArrayOfString.new
|
125
|
+
attrVal << val
|
126
|
+
end
|
127
|
+
attrs << SOAPAttribute.new(key, attrVal)
|
128
|
+
end
|
129
|
+
|
130
|
+
principal = SOAPPrincipal.new(nil, is_active, attrs, nil, description, nil, nil, username)
|
131
|
+
pword = PasswordCredential.new(password, false)
|
132
|
+
arg = AddPrincipal.new(@@application_token, principal, pword)
|
133
|
+
|
134
|
+
server.addPrincipal(arg)
|
135
|
+
end
|
136
|
+
|
137
|
+
case response
|
138
|
+
when AddPrincipalResponse
|
139
|
+
return true
|
140
|
+
when InvalidCredentialException
|
141
|
+
raise AuthenticationInvalidCredentalException
|
142
|
+
when InvalidPrincipalException
|
143
|
+
raise AuthenticationInvalidException, response
|
144
|
+
else
|
145
|
+
raise AuthenticationException, response
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Find Principal via username
|
151
|
+
def self.find_principal_by_username(username)
|
152
|
+
response = authenticated_connection do
|
153
|
+
arg = FindPrincipalByName.new(@@application_token, username)
|
154
|
+
server.findPrincipalByName(arg)
|
155
|
+
end
|
156
|
+
|
157
|
+
case response
|
158
|
+
when FindPrincipalByNameResponse
|
159
|
+
return parse_principal(response.out)
|
160
|
+
when ObjectNotFoundException
|
161
|
+
return {}
|
162
|
+
else
|
163
|
+
raise AuthenticationException, response
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Find Principal via token
|
169
|
+
def self.find_principal_by_token(token)
|
170
|
+
response = authenticated_connection do
|
171
|
+
arg = FindPrincipalByToken.new(@@application_token, token)
|
172
|
+
server.findPrincipalByToken(arg)
|
173
|
+
end
|
174
|
+
|
175
|
+
case response
|
176
|
+
when FindPrincipalByTokenResponse
|
177
|
+
return parse_principal(response.out)
|
178
|
+
when ObjectNotFoundException
|
179
|
+
return {}
|
180
|
+
else
|
181
|
+
raise AuthenticationException, response
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Remove principal attribute
|
187
|
+
def self.remove_attribute_principal(username, attributes)
|
188
|
+
if(attributes.class != Array)
|
189
|
+
attributes = [attributes]
|
190
|
+
end
|
191
|
+
|
192
|
+
attributes.each do |attr|
|
193
|
+
response = authenticated_connection do
|
194
|
+
arg = RemoveAttributeFromPrincipal.new(@@application_token, username, attr)
|
195
|
+
server.removeAttributeFromPrincipal(arg)
|
196
|
+
end
|
197
|
+
|
198
|
+
case response
|
199
|
+
when RemoveAttributeFromPrincipalResponse
|
200
|
+
# Burying as this means it succeeded
|
201
|
+
when ObjectNotFoundException
|
202
|
+
raise AuthenticationObjectNotFoundException
|
203
|
+
else
|
204
|
+
raise AuthenticationException, response
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Add attribute to principal
|
211
|
+
def self.add_attribute_principal(username, attributes)
|
212
|
+
attributes.each do |key, val|
|
213
|
+
response = authenticated_connection do
|
214
|
+
if(val.class == Array)
|
215
|
+
valArray = ArrayOfString.new(val)
|
216
|
+
else
|
217
|
+
valArray = ArrayOfString.new
|
218
|
+
valArray << val
|
219
|
+
end
|
220
|
+
|
221
|
+
tuple = SOAPAttribute.new(key, valArray)
|
222
|
+
arg = AddAttributeToPrincipal.new(@@application_token, username, tuple)
|
223
|
+
|
224
|
+
server.addAttributeToPrincipal(arg)
|
225
|
+
end
|
226
|
+
|
227
|
+
case response
|
228
|
+
when AddAttributeToPrincipalResponse
|
229
|
+
# Burying it because this means it was successful
|
230
|
+
when ObjectNotFoundException
|
231
|
+
raise AuthenticationObjectNotFoundException
|
232
|
+
else
|
233
|
+
raise AuthenticationException, response
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Update attribute on principal
|
242
|
+
def self.update_attribute_principal(username, attributes)
|
243
|
+
attributes.each do |key, val|
|
244
|
+
response = authenticated_connection do
|
245
|
+
if val.is_a?(Array)
|
246
|
+
valArray = ArrayOfString.new(val)
|
247
|
+
else
|
248
|
+
valArray = ArrayOfString.new
|
249
|
+
valArray << val
|
250
|
+
end
|
251
|
+
|
252
|
+
tuple = SOAPAttribute.new(key, valArray)
|
253
|
+
arg = UpdatePrincipalAttribute.new(@@application_token, username, tuple)
|
254
|
+
|
255
|
+
server.updatePrincipalAttribute(arg)
|
256
|
+
end
|
257
|
+
|
258
|
+
case response
|
259
|
+
when UpdatePrincipalAttributeResponse
|
260
|
+
# Burying as it worked
|
261
|
+
when ObjectNotFoundException
|
262
|
+
raise AuthenticationObjectNotFoundException
|
263
|
+
else
|
264
|
+
raise AuthenticationException, response
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
true
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Remove principal
|
273
|
+
def self.remove_principal(username)
|
274
|
+
response = authenticated_connection do
|
275
|
+
arg = RemovePrincipal.new(@@application_token, username)
|
276
|
+
server.removePrincipal(arg)
|
277
|
+
end
|
278
|
+
|
279
|
+
case response
|
280
|
+
when RemovePrincipalResponse
|
281
|
+
return true
|
282
|
+
when ObjectNotFoundException
|
283
|
+
raise AuthenticationObjectNotFoundException
|
284
|
+
else
|
285
|
+
raise AuthenticationException, response
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
##
|
290
|
+
# Find all principal names
|
291
|
+
def self.find_all_principal_names
|
292
|
+
response = authenticated_connection do
|
293
|
+
arg = FindAllPrincipalNames.new(@@application_token)
|
294
|
+
server.findAllPrincipalNames(arg)
|
295
|
+
end
|
296
|
+
|
297
|
+
case response
|
298
|
+
when FindAllPrincipalNamesResponse
|
299
|
+
return response.out
|
300
|
+
when ObjectNotFoundException
|
301
|
+
return {}
|
302
|
+
else
|
303
|
+
raise AuthenticationException, response
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
##
|
308
|
+
# Find all role names
|
309
|
+
def self.find_all_role_names
|
310
|
+
response = authenticated_connection do
|
311
|
+
arg = FindAllRoleNames.new(@@application_token)
|
312
|
+
server.findAllRoleNames(arg)
|
313
|
+
end
|
314
|
+
|
315
|
+
case response
|
316
|
+
when FindAllRoleNamesResponse
|
317
|
+
return response.out
|
318
|
+
when ObjectNotFoundException
|
319
|
+
return {}
|
320
|
+
else
|
321
|
+
raise AuthenticationException, response
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
##
|
326
|
+
# Add Role
|
327
|
+
def self.add_role(name, description, is_active)
|
328
|
+
response = authenticated_connection do
|
329
|
+
role = SOAPRole.new(nil, is_active, nil, nil, description, nil, nil, nil, name)
|
330
|
+
arg = AddRole.new(@@application_token, role)
|
331
|
+
server.addRole(arg)
|
332
|
+
end
|
333
|
+
|
334
|
+
case response
|
335
|
+
when AddRoleResponse
|
336
|
+
return true
|
337
|
+
when ObjectNotFoundException
|
338
|
+
return AuthenticationObjectNotFoundException
|
339
|
+
else
|
340
|
+
raise AuthenticationException, response
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
##
|
345
|
+
# Add Principal to Role
|
346
|
+
def self.add_principal_to_role(username, role)
|
347
|
+
response = authenticated_connection do
|
348
|
+
arg = AddPrincipalToRole.new(@@application_token, username, role)
|
349
|
+
#raise arg.to_yaml
|
350
|
+
server.addPrincipalToRole(arg)
|
351
|
+
end
|
352
|
+
|
353
|
+
case response
|
354
|
+
when AddPrincipalToRoleResponse
|
355
|
+
return true
|
356
|
+
when ObjectNotFoundException
|
357
|
+
return AuthenticationObjectNotFoundException
|
358
|
+
else
|
359
|
+
raise AuthenticationException, response
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
##
|
364
|
+
# Remove Principal form Role
|
365
|
+
def self.remove_principal_from_role(username, role)
|
366
|
+
response = authenticated_connection do
|
367
|
+
arg = RemovePrincipalFromRole.new(@@application_token, username, role)
|
368
|
+
server.removePrincipalFromRole(arg)
|
369
|
+
end
|
370
|
+
|
371
|
+
case response
|
372
|
+
when RemovePrincipalFromRoleResponse
|
373
|
+
return true
|
374
|
+
when ObjectNotFoundException
|
375
|
+
return AuthenticationObjectNotFoundException
|
376
|
+
else
|
377
|
+
raise AuthenticationException, response
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
##
|
382
|
+
# Is Role Member
|
383
|
+
def self.is_role_member(username, role)
|
384
|
+
response = authenticated_connection do
|
385
|
+
arg = IsRoleMember.new(@@application_token, username, role )
|
386
|
+
server.isRoleMember(arg)
|
387
|
+
end
|
388
|
+
|
389
|
+
case response
|
390
|
+
when IsRoleMemberResponse
|
391
|
+
return response.out
|
392
|
+
when ObjectNotFoundException
|
393
|
+
return AuthenticationObjectNotFoundException
|
394
|
+
else
|
395
|
+
raise AuthenticationException, response
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
|
401
|
+
##
|
402
|
+
# Remove Role
|
403
|
+
def self.remove_role(role)
|
404
|
+
response = authenticated_connection do
|
405
|
+
arg = RemoveRole.new(@@application_token, role)
|
406
|
+
server.removeRole(arg)
|
407
|
+
end
|
408
|
+
|
409
|
+
case response
|
410
|
+
when RemoveRoleResponse
|
411
|
+
return true
|
412
|
+
when ObjectNotFoundException
|
413
|
+
return AuthenticationObjectNotFoundException
|
414
|
+
else
|
415
|
+
raise AuthenticationException, response
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
##
|
420
|
+
# Is Group Member
|
421
|
+
def self.is_group_member(username, group)
|
422
|
+
response = authenticated_connection do
|
423
|
+
arg = IsGroupMember.new(@@application_token, group, username )
|
424
|
+
server.isGroupMember(arg)
|
425
|
+
end
|
426
|
+
|
427
|
+
case response
|
428
|
+
when IsGroupMemberResponse
|
429
|
+
return response.out
|
430
|
+
when ObjectNotFoundException
|
431
|
+
return AuthenticationObjectNotFoundException
|
432
|
+
else
|
433
|
+
raise AuthenticationException, response
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
private
|
438
|
+
|
439
|
+
# Parse the user
|
440
|
+
def self.parse_principal(rp)
|
441
|
+
p = {}
|
442
|
+
|
443
|
+
p[:id] = rp.iD
|
444
|
+
p[:active] = rp.active
|
445
|
+
p[:conception] = rp.conception
|
446
|
+
p[:description] = rp.description
|
447
|
+
p[:directoryID] = rp.directoryID
|
448
|
+
p[:lastModified] = rp.lastModified
|
449
|
+
p[:name] = rp.name
|
450
|
+
|
451
|
+
p[:attributes] = {}
|
452
|
+
|
453
|
+
rp.attributes.each do |attr|
|
454
|
+
case attr.values.size
|
455
|
+
when 0
|
456
|
+
p[:attributes][attr.name.to_sym] = nil
|
457
|
+
when 1
|
458
|
+
p[:attributes][attr.name.to_sym] = attr.values[0]
|
459
|
+
else
|
460
|
+
p[:attributes][attr.name.to_sym] = attr.values.to_a
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
return p
|
465
|
+
end
|
466
|
+
|
467
|
+
# Has the application been authenticated?
|
468
|
+
def self.application_auth_check
|
469
|
+
authenticate_application if @@application_token.nil?
|
470
|
+
end
|
471
|
+
|
472
|
+
# Shorthand for getting the security server object
|
473
|
+
def self.server
|
474
|
+
SecurityServerPortType.new(@@crowd_url)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Wrapper for catching common exceptions. Also allows the application a chance
|
478
|
+
# to re-authenticate if the token is invalid.
|
479
|
+
def self.authenticated_connection
|
480
|
+
raise ArgumentError unless block_given?
|
481
|
+
|
482
|
+
application_auth_check
|
483
|
+
response = yield
|
484
|
+
rescue AuthenticationException
|
485
|
+
# Push the response into the exception message
|
486
|
+
raise AuthenticationException, response
|
487
|
+
rescue Errno::ECONNREFUSED
|
488
|
+
raise AuthenticationConnectionException
|
489
|
+
rescue SOAP::FaultError => e
|
490
|
+
# If the application token is invalid/expired, we'll give it one more shot.
|
491
|
+
if e.message =~ /Invalid application client/
|
492
|
+
authenticate_application
|
493
|
+
response = yield
|
494
|
+
else
|
495
|
+
# It may not always be a not found case but until the type of
|
496
|
+
# FaultError is known, which has not been able to be determined
|
497
|
+
raise AuthenticationObjectNotFoundException, e.message
|
498
|
+
end
|
499
|
+
rescue Exception
|
500
|
+
raise AuthenticationException, response
|
501
|
+
|
502
|
+
if response.is_a?(InvalidAuthorizationTokenException)
|
503
|
+
authenticate_application
|
504
|
+
response = yield
|
505
|
+
end
|
506
|
+
response
|
507
|
+
end
|
508
|
+
end
|