1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package no.feide.moria.authorization;
23
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Stack;
28
29 import no.feide.moria.log.MessageLogger;
30
31 /***
32 * Represents a web service. A web service has a name, id, url and attributes.
33 * The attributes are flattened (for optimization) from a set of profiles,
34 * allowed and denied attributes.
35 */
36 final class AuthorizationClient {
37
38 /*** Used for logging. */
39 private final MessageLogger log = new MessageLogger(AuthorizationClient.class);
40
41 /***
42 * Cached hash code.
43 */
44 private volatile int hashCode = 0;
45
46 /***
47 * Unique identifier (principal) for the client.
48 */
49 private final String name;
50
51 /***
52 * Common name of the service.
53 */
54 private final String displayName;
55
56 /***
57 * Home page URL for web service. Used for creating hyperlinks (together
58 * with the name of the web service).
59 */
60 private final String url;
61
62 /***
63 * Language preferred by the web service.
64 */
65 private final String language;
66
67 /***
68 * The organization the webservice sets as default. Typically this is set to
69 * the organization that the web service belongs to.
70 */
71 private final String home;
72
73 /***
74 * The organizations that the service belongs to.
75 */
76 private final HashSet affiliation;
77
78 /***
79 * The organizations that can use the service.
80 */
81 private final HashSet orgsAllowed;
82
83 /***
84 * The operations the client can perform.
85 */
86 private final HashSet operations;
87
88 /***
89 * The subsystems the client can use proxy authentication for.
90 */
91 private final HashSet subsystems;
92
93 /***
94 * Attributes the client can query.
95 */
96 private final HashMap attributes;
97
98 /***
99 * The properties of this object. Used to transport internal data outside of
100 * the package.
101 */
102 private final HashMap properties = new HashMap();
103
104
105 /***
106 * Constructor. Creates a new object describing a Moria service client, used
107 * for authorization purposes.
108 * @param name
109 * serviceID The unique client ID assigned to this service.
110 * Cannot be <code>null</code> or an empty string.
111 * @param displayName
112 * Full name of the service, for display purposes. Cannot be
113 * <code>null</code> or an empty string.
114 * @param url
115 * URL to the service main page, where information on the service
116 * should be found. Cannot be <code>null</code> or an empty
117 * string.
118 * @param language
119 * Default language for the service. Must match one of the
120 * configured languages. Cannot be <code>null</code> or an
121 * empty string.
122 * @param home
123 * Service home organization. Must match one of the configured
124 * organizations. Cannot be <code>null</code> or an empty
125 * string.
126 * @param affiliation
127 * The organizations affiliated to the service. Cannot be
128 * <code>null</code>.
129 * @param orgsAllowed
130 * The organizations that are allowed to use the service. Cannot
131 * be null.
132 * @param operations
133 * Operations that the service can perform. Cannot be
134 * <code>null</code>.
135 * @param subsystems
136 * Subsystems the service can create proxy tickets for. May be
137 * <code>null</code>.
138 * @param attributes
139 * Attributes the service can access. Cannot be <code>null</code>.
140 * @throws IllegalArgumentException
141 * If any of <code>name</code>,<code>displayName</code>,
142 * <code>url</code>,<code>language</code>,
143 * <code>home</code>,<code>affiliation</code>,
144 * <code>allowedOrg</code>, <code>operations</code>, or
145 * <code>attributes</code> are <code>null</code> or an empty
146 * string (where applicable).
147 */
148 AuthorizationClient(final String name, final String displayName,
149 final String url, final String language,
150 final String home, final HashSet affiliation,
151 final HashSet orgsAllowed, final HashSet operations,
152 final HashSet subsystems, final HashMap attributes) {
153
154 if (name == null || name.equals("")) { throw new IllegalArgumentException("Name must be a non empty string."); }
155
156 if (displayName == null || displayName.equals("")) { throw new IllegalArgumentException("displayName must be a non empty string."); }
157
158 if (url == null || url.equals("")) { throw new IllegalArgumentException("URL must be a non empty string."); }
159
160 if (language == null || language.equals("")) { throw new IllegalArgumentException("Language must be a non empty string."); }
161
162 if (home == null || home.equals("")) { throw new IllegalArgumentException("Home must be a non empty string."); }
163
164 if (affiliation == null) { throw new IllegalArgumentException("Affiliation cannot be null."); }
165
166 if (orgsAllowed == null) { throw new IllegalArgumentException("OrgsAllowed cannot be null."); }
167
168 if (operations == null) { throw new IllegalArgumentException("Operations cannot be null."); }
169
170 if (attributes == null) { throw new IllegalArgumentException("Attributes cannot be null."); }
171
172
173 this.name = name;
174 this.displayName = displayName;
175 this.url = url;
176 this.language = language;
177 this.home = home;
178 this.affiliation = affiliation;
179 this.orgsAllowed = orgsAllowed;
180 this.operations = operations;
181 this.subsystems = subsystems;
182 this.attributes = attributes;
183
184
185
186
187 properties.put("displayName", new String(displayName));
188 properties.put("url", new String(url));
189 properties.put("language", new String(language));
190 properties.put("home", new String(home));
191 properties.put("name", new String(name));
192
193 }
194
195
196 /***
197 * Checks if all the requested attributes are legal for this web service.
198 * @param requestedAttributes
199 * Names of all requested attributes.
200 * @return true if access to the attributes is granted, else false.
201 * @throws IllegalArgumentException
202 * If <code>requestedAttributes</code> is <code>null</code>.
203 */
204 boolean allowAccessTo(final String[] requestedAttributes) {
205
206 boolean allow = true;
207
208 if (requestedAttributes == null) { throw new IllegalArgumentException("RequestedAttributes cannot be null"); }
209
210 if (requestedAttributes.length == 0) { return true; }
211
212 for (int i = 0; i < requestedAttributes.length; i++) {
213 if (!attributes.containsKey(requestedAttributes[i])) {
214 allow = false;
215 break;
216 }
217 }
218 return allow;
219 }
220
221
222 /***
223 * Checks attributes for use with single sign-on (SSO). If all attributes
224 * are registered in the web service's attributes list and all attributes
225 * are allowed to use with SSO, then so be it.
226 * @param requestedAttributes
227 * The names of all requested attributes.
228 * @return true if the attributes can be used with SSO, else false.
229 * @throws IllegalArgumentException
230 * If <code>requestedAttributes</code> is <code>null</code>.
231 */
232 boolean allowSSOForAttributes(final String[] requestedAttributes) {
233
234
235 if (requestedAttributes == null)
236 throw new IllegalArgumentException("Requested attributes cannot be NULL");
237
238
239 for (int i = 0; i < requestedAttributes.length; i++) {
240 final String attrName = requestedAttributes[i];
241 if (!attributes.containsKey(attrName) || !((AuthorizationAttribute) attributes.get(attrName)).getAllowSSO())
242
243 return false;
244 }
245
246
247 return true;
248 }
249
250
251 /***
252 * Get the attributes not allowed for use in an SSO context for this client.
253 * @return An array of attribute names. May be an empty array, but never
254 * <code>null</code>.
255 */
256 protected String[] getNonSSOAttributeNames() {
257
258 Stack buffer = new Stack();
259 Iterator i = attributes.keySet().iterator();
260 AuthorizationAttribute attribute;
261 while (i.hasNext()) {
262 attribute = (AuthorizationAttribute) attributes.get(i.next());
263 if (!attribute.getAllowSSO())
264 buffer.push(attribute.getName());
265 }
266 return (String[]) buffer.toArray(new String[] {});
267
268 }
269
270
271 /***
272 * Returns true if the supplied organization name is affiliated with the
273 * client.
274 * @param organization
275 * Name of the organization to match.
276 * @return true if the supplied organization name is affiliated with the
277 * client.
278 * @throws IllegalArgumentException
279 * If <code>organization</code> is <code>null</code> or an
280 * empty string.
281 */
282 boolean hasAffiliation(final String organization) {
283
284 if (organization == null || organization.equals("")) { throw new IllegalArgumentException("Organization must be a non empty string"); }
285
286 return affiliation.contains(organization);
287 }
288
289
290 /***
291 * Returns true if all elements in the requestedOperations array are
292 * represented in the objects operations set.
293 * @param requestedOperations
294 * A string array of operation names
295 * @return true if all operations are allowed, else false.
296 * @throws IllegalArgumentException
297 * If <code>requestedOperations</code> is <code>null</code>.
298 */
299 boolean allowOperations(final String[] requestedOperations) {
300
301 if (requestedOperations == null) { throw new IllegalArgumentException("RequestedOperations cannot be null"); }
302
303 if (requestedOperations.length == 0) { return true; }
304
305 for (int i = 0; i < requestedOperations.length; i++) {
306 if (!operations.contains(requestedOperations[i])) { return false; }
307 }
308
309 return true;
310 }
311
312
313 /***
314 * Returns true for the organizations that are allowed to use this service.
315 * @param organization
316 * The organization requesting authorization.
317 * @return true if the organization can use this service.
318 * @throws IllegalArgumentException
319 * If <code>organization</code> is <code>null</code>.
320 */
321 boolean allowUserorg(final String organization) {
322
323
324 if (organization == null) {
325 log.logInfo("organization = " + organization);
326 throw new IllegalArgumentException("Organization cannot be null");
327 }
328
329 if (orgsAllowed == null) {
330 log.logInfo("orgsAllowed = " + orgsAllowed);
331 return false;
332 }
333 return orgsAllowed.contains(organization);
334 }
335
336
337 /***
338 * Used to decide whether subsystems are allowed for this particular client,
339 * based on its configuration.
340 * @param requestedSubsystems
341 * A string array of subsystem names. Cannot be <code>null</code>.
342 * @return <code>true</code> if subsystems are allowed, otherwise
343 * <code>false</code>.
344 * @throws IllegalArgumentException
345 * If <code>requestedSubsystems</code> is <code>null</code>.
346 */
347 boolean allowSubsystems(final String[] requestedSubsystems) {
348
349
350 if (requestedSubsystems == null) {
351 log.logInfo("requestedSubsystems = " + requestedSubsystems);
352 throw new IllegalArgumentException("RequestedSubsystems cannot be null");
353 }
354
355
356 if ((requestedSubsystems.length == 0) || (subsystems == null)) {
357 log.logInfo("requestedSubsystems.length = " + requestedSubsystems.length);
358 log.logInfo("subsystems = " + subsystems);
359 return false;
360 }
361
362
363
364 for (int i = 0; i < requestedSubsystems.length; i++) {
365 if (!subsystems.contains(requestedSubsystems[i]))
366 return false;
367 }
368 return true;
369 }
370
371
372 /***
373 * Compares object with another, returnes true if all fields are equal.
374 * @param object
375 * The object to compare with.
376 * @return true if objects are equal.
377 */
378 public boolean equals(final Object object) {
379
380 if (object == this) { return true; }
381 if (object instanceof AuthorizationClient) {
382 final AuthorizationClient client = (AuthorizationClient) object;
383 if (client.getName().equals(name) && client.getDisplayName().equals(displayName) && client.getURL().equals(url) && client.getLanguage().equals(language) && client.getHome().equals(home) && client.getAffiliation().equals(affiliation) && client.getOrgsAllowed().equals(orgsAllowed) && client.getOperations().equals(operations) && client.getSubsystems().equals(subsystems) && client.getAttributes().equals(attributes)) { return true; }
384 }
385 return false;
386 }
387
388
389 /***
390 * Generate a hash code for the object. The hash code is computed from all
391 * fields.
392 * @return The hash code.
393 */
394 public int hashCode() {
395
396 if (hashCode == 0) {
397 int result = 17;
398 result = 37 * result + name.hashCode();
399 result = 37 * result + displayName.hashCode();
400 result = 37 * result + url.hashCode();
401 result = 37 * result + language.hashCode();
402 result = 37 * result + home.hashCode();
403 result = 37 * result + affiliation.hashCode();
404 result = 37 * result + orgsAllowed.hashCode();
405 result = 37 * result + operations.hashCode();
406 result = 37 * result + subsystems.hashCode();
407 result = 37 * result + attributes.hashCode();
408 hashCode = result;
409 }
410 return hashCode;
411
412 }
413
414
415 /***
416 * Returns a string representation of this object.
417 * @return A string representation of this object: Name: NAME DisplayName:
418 * DISPLAYNAME URL: URL Language: LANGUAGE Home: HOME Affiliations:
419 * AFFILIATION Operations: OPERATIONS Attributes: ATTRIBUTES
420 */
421 public String toString() {
422
423 return "Name: " + name + " DisplayName: " + displayName + " URL: " + url + " Language: " + language + " Home: " + home + " Affiliation: " + affiliation + " Operations: " + operations + "Attributes: " + attributes;
424 }
425
426
427 /***
428 * Returns the URL for this client.
429 * @return The URL for the main page of the client service.
430 */
431 public String getURL() {
432
433 return new String(url);
434 }
435
436
437 /***
438 * Returns the principal of this client.
439 * @return Client's principal.
440 */
441 public String getName() {
442
443 return new String(name);
444 }
445
446
447 /***
448 * Returns the display name for this client.
449 * @return Name of the client, to be displayed to the user.
450 */
451 public String getDisplayName() {
452
453 return new String(displayName);
454 }
455
456
457 /***
458 * Returns the language for this client.
459 * @return Language of the client service.
460 */
461 public String getLanguage() {
462
463 return new String(language);
464 }
465
466
467 /***
468 * Returns the home organization for this client.
469 * @return The home organization of the client service.
470 */
471 public String getHome() {
472
473 return new String(home);
474 }
475
476
477 /***
478 * Returns the affiliation for this client.
479 * @return Returns the affiliation.
480 */
481 HashSet getAffiliation() {
482
483 return new HashSet(affiliation);
484 }
485
486
487 /***
488 * Returns the organizations that are allowed to use the client.
489 * @return The organizations.
490 */
491 HashSet getOrgsAllowed() {
492
493 return new HashSet(orgsAllowed);
494 }
495
496
497 /***
498 * Returns the operations for this client.
499 * @return Returns the operations.
500 */
501 HashSet getOperations() {
502
503 return new HashSet(operations);
504 }
505
506
507 /***
508 * Returns the subsystems for this client, if any are defined.
509 * @return A new <code>HashSet</code> object containing the defined
510 * subsystems, or <code>null</code> if no subsystems are defined
511 * for this client.
512 */
513 HashSet getSubsystems() {
514
515 if (subsystems == null) { return null; }
516 return new HashSet(subsystems);
517 }
518
519
520 /***
521 * Returns the attributes for this client.
522 * @return Returns the attributes.
523 */
524 HashMap getAttributes() {
525
526 return new HashMap(attributes);
527 }
528
529
530 /***
531 * Gets the properties for this client. The properties object contains the
532 * data that should be transferred to other packages.
533 * @return The properties for this object.
534 */
535 public HashMap getProperties() {
536
537 return properties;
538 }
539
540
541 /***
542 * Returns the highest secLevel of the requested attributes.
543 * @param requestedAttributes
544 * The requested attributes.
545 * @return The highest of the attributes seclevel, 0 if no attributes are
546 * requested.
547 * @throws UnknownAttributeException
548 * if one (or more) of the requested attributes are not present
549 * in the authorization client.
550 * @throws IllegalArgumentException
551 * If <code>requestedAttributes</code> is <code>null</code>.
552 */
553 int getSecLevel(final String[] requestedAttributes)
554 throws UnknownAttributeException {
555
556 if (requestedAttributes == null) { throw new IllegalArgumentException("requestedAttributes cannot be null"); }
557
558 if (requestedAttributes.length == 0) { return 0; }
559
560 int res = 0;
561 for (int i = 0; i < requestedAttributes.length; i++) {
562 final AuthorizationAttribute authzAttribute = (AuthorizationAttribute) attributes.get(requestedAttributes[i]);
563 if (authzAttribute == null) { throw new UnknownAttributeException("Attribute '" + authzAttribute + "' does not exist."); }
564 if (authzAttribute.getSecLevel() > res) {
565 res = authzAttribute.getSecLevel();
566 }
567 }
568
569 return res;
570 }
571 }