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.
@@ -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