001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: SubjectTypeManager.java,v 1.5 2009/01/28 05:35:01 ww203982 Exp $ 026 * 027 */ 028 029 030 031 032package com.sun.identity.policy; 033 034import java.util.*; 035 036import com.iplanet.sso.SSOToken; 037import com.iplanet.sso.SSOException; 038import com.sun.identity.sm.*; 039import com.sun.identity.policy.interfaces.Subject; 040import com.sun.identity.shared.locale.AMResourceBundleCache; 041import com.sun.identity.shared.debug.Debug; 042import com.sun.identity.shared.locale.Locale; 043 044import com.sun.identity.shared.ldap.util.DN; 045 046/** 047 * The class <code>SubjectTypeManager</code> provides 048 * methods to get a list of configured <code>Subject 049 * </code> objects, and to obtain a factory object for it. 050 * 051 * @supported.all.api 052 */ 053public class SubjectTypeManager { 054 055 private static String SUBJECT = "Subject"; 056 057 private SSOToken token; 058 private PolicyManager pm; 059 060 private ResourceBundle rb; 061 private Subjects realmSubjects = null; 062 private Map sharedSubjects = Collections.synchronizedMap(new HashMap()); 063 private static AMResourceBundleCache amCache = 064 AMResourceBundleCache.getInstance(); 065 private String pmRealmName; 066 067 static Debug debug = PolicyManager.debug; 068 069 /** 070 * Constructs a <code>SubjectTypeManager</code> object 071 */ 072 protected SubjectTypeManager() throws SSOException { 073 token = ServiceTypeManager.getSSOToken(); 074 String lstr = token.getProperty("Locale"); 075 java.util.Locale loc = com.sun.identity.shared.locale.Locale.getLocale( 076 lstr); 077 rb = amCache.getResBundle(ResBundleUtils.rbName, loc); 078 } 079 080 /** 081 * Constructs a <code>SubjectTypeManager</code> object 082 * @param pm <code>PolicyManager</code> to initialize 083 * <code>SubjectTypeManager</code> with 084 */ 085 protected SubjectTypeManager(PolicyManager pm) { 086 this.pm = pm; 087 pmRealmName = new DN(pm.getOrganizationDN()).toRFCString() 088 .toLowerCase(); 089 token = pm.token; 090 java.util.Locale loc; 091 try { 092 String lstr = token.getProperty("Locale"); 093 loc = com.sun.identity.shared.locale.Locale.getLocale(lstr); 094 } catch (SSOException ex) { 095 debug.error( 096 "SubjectTypeManager:Unable to retreive locale from SSOToken", 097 ex); 098 loc = Locale.getDefaultLocale(); 099 } 100 101 if (debug.messageEnabled()) { 102 debug.message("SubjectManager locale="+loc+"\tI18nFileName = "+ 103 ResBundleUtils.rbName); 104 } 105 rb = amCache.getResBundle(ResBundleUtils.rbName, loc); 106 } 107 108 /** 109 * Returns a set of all valid subject type names defined by the policy 110 * service. 111 * Examples are <code>LDAPRole</code>, <code>LDAPGroup</code>, etc. 112 * 113 * @return a set of all valid subject type names defined by the policy 114 * service. 115 * @throws SSOException if the <code>SSOToken</code> used to create 116 * the <code>PolicyManager</code> has become invalid 117 * @throws PolicyException for any other abnormal condition 118 */ 119 public Set getSubjectTypeNames() throws SSOException, 120 PolicyException { 121 return (PolicyManager.getPluginSchemaNames(SUBJECT)); 122 } 123 124 /** 125 * Returns a set of valid subject type names configured for the 126 * organization. 127 * Examples are <code>LDAPRole</code>, <code>LDAPGroup</code>, etc. 128 * 129 * @return a set of valid subject type names configured for the 130 * organization. 131 * @throws SSOException if the <code>SSOToken</code> used to create 132 * the <code>PolicyManager</code> has become invalid 133 * @throws PolicyException for any other abnormal condition 134 */ 135 public Set getSelectedSubjectTypeNames() throws SSOException, 136 PolicyException { 137 Map policyConfig = pm.getPolicyConfig(); 138 Set selectedSubjects = null; 139 if (policyConfig != null) { 140 selectedSubjects = 141 (Set)policyConfig.get(PolicyConfig.SELECTED_SUBJECTS); 142 } 143 if ( selectedSubjects == null) { 144 selectedSubjects = Collections.EMPTY_SET; 145 } 146 return selectedSubjects; 147 } 148 149 /** 150 * Returns the type of the <code>Subject</code> implementation. 151 * For example <code>LDAPRoles</code>, <code>LDAPGroups</code> etc. 152 * 153 * @param subject <code>Subject</code> for which this method will 154 * return its associated type 155 * 156 * @return type of the <code>Subject</code>, e.g., <code>LDAPRoles</code>, 157 * <code>LDAPGroups</code>, etc. Returns <code>null</code> if 158 * not present. 159 */ 160 public String getSubjectTypeName(Subject subject) { 161 return (subjectTypeName(subject)); 162 } 163 164 /** 165 * Returns the I18N properties file name that should be 166 * used to localize display names for the given 167 * subject type. 168 * 169 * @param subjectType subject type name 170 * 171 * @return i18n properties file name 172 */ 173 protected String getI18NPropertiesFileName(String subjectType) { 174 // %%% Need to get the file name from plugin schema 175 return (null); 176 } 177 178 /** 179 * Returns the I18N key to be used to localize the 180 * display name for the subject type name. 181 * 182 * @param subjectType subject type name 183 * 184 * @return i18n key to obtain the display name 185 */ 186 public String getI18NKey(String subjectType) { 187 PluginSchema ps = PolicyManager.getPluginSchema(SUBJECT, subjectType); 188 if (ps != null) { 189 return (ps.getI18NKey()); 190 } 191 return (null); 192 } 193 194 /** 195 * Returns the display name for the subject type 196 * @param subjectType subject type 197 * @return display name for the subject type 198 */ 199 public String getDisplayName(String subjectType) { 200 String displayName = null; 201 String i18nKey = getI18NKey(subjectType); 202 if (i18nKey == null || i18nKey.length() == 0) { 203 displayName = subjectType; 204 } else { 205 displayName = Locale.getString(rb,i18nKey,debug); 206 } 207 return displayName; 208 } 209 210 /** 211 * Returns an instance of the <code>Subject</code> given the subject type 212 * name. 213 * 214 * @param subjectType subject type. 215 * @return an instance of the <code>Subject</code> given the subject type 216 * name. 217 * @throws NameNotFoundException if the <code>Subject</code> for the 218 * <code>subjectType</code> name is not found 219 * @throws PolicyException for any other abnormal condition 220 */ 221 public Subject getSubject(String subjectType) 222 throws NameNotFoundException, PolicyException { 223 PluginSchema ps = PolicyManager.getPluginSchema(SUBJECT, subjectType); 224 if (ps == null) { 225 throw (new NameNotFoundException(ResBundleUtils.rbName, 226 "invalid_subject", null, 227 subjectType, PolicyException.USER_COLLECTION)); 228 } 229 230 // Construct the object 231 Subject answer = null; 232 try { 233 String className = ps.getClassName(); 234 answer = (Subject) Class.forName(className).newInstance(); 235 } catch (Exception e) { 236 throw (new PolicyException(e)); 237 } 238 239 //initialize with policy config 240 answer.initialize(pm.getPolicyConfig()); 241 return (answer); 242 } 243 244 /** 245 * Adds a policy subject at realm. 246 * 247 * @param subjectName name of the Subject instance 248 * @param subject Subject object to be added 249 * 250 * @throws NameAlreadyExistsException if a Subject with the given name 251 * already exists at the realm 252 * @throws InvalidNameException if the subject name is invalid 253 * 254 * @throws PolicyException if can not add the Subject 255 */ 256 public void addSubject(String subjectName, Subject subject) 257 throws NameAlreadyExistsException, InvalidNameException, 258 PolicyException, SSOException { 259 260 //we really do not use the exclusive flag at realm level 261 addSubject(subjectName, subject, false); 262 } 263 264 /** 265 * Adds a policy subject at realm. 266 * 267 * @param subjectName name of the Subject instance 268 * @param subject Subject object to be added 269 * 270 * @param exclusive boolean flag indicating whether the subject 271 * is to be exclusive subject. If subject is exclusive, 272 * policy applies to users who are not members of the 273 * subject. Otherwise, policy applies to members of the subject. 274 * 275 * @throws NameAlreadyExistsException if a Subject with the given name 276 * already exists at the realm 277 * @throws InvalidNameException if the subject name is invalid 278 * 279 * @throws PolicyException if can not add the Subject 280 * 281 * 282 */ 283 private void addSubject(String subjectName, Subject subject, 284 boolean exclusive) 285 throws NameAlreadyExistsException, InvalidNameException, 286 PolicyException, SSOException { 287 if (debug.messageEnabled()) { 288 debug.message("Adding realm subject : " + subjectName 289 + ", in realm:" + pmRealmName); 290 } 291 if (realmSubjects == null) { 292 initRealmSubjects(); 293 } 294 realmSubjects.addSubject(subjectName, subject, exclusive); 295 saveSubjects(); 296 if (debug.messageEnabled()) { 297 debug.message("Added realm subject : " + subjectName 298 + ", in realm:" + pmRealmName); 299 } 300 } 301 302 /** 303 * Removes the subject with the given name from the realm. 304 * This method would throw PolicyException if the subject 305 * is being used by any policy. 306 * 307 * @param subjectName name of the Subject 308 * 309 * @return returns the Subject object being removed, 310 * returns <code>null</code> if Subject with 311 * the given subjectName is not present 312 * 313 * @throws PolicyException if can not remove the Subject 314 */ 315 public Subject removeSubject(String subjectName) 316 throws ObjectInUseException, PolicyException, SSOException { 317 return removeSubject(subjectName, false); 318 } 319 320 /** 321 * Removes the subject with the given name from the realm. 322 * This method would throw PolicyException if the subject 323 * is being used by any policy unless <code>forcedRemove</code> 324 * argument is set to <code>true</code>. 325 * If the <code>forcedRemove</code> argument is set to 326 * <code>true</code> policies that are using the subject would 327 * be modified to remove the references to the subject 328 * 329 * @param subjectName name of the Subject 330 * @param forcedRemove if set to <code>true</code>, policies that 331 * use the subject would be modifed to remove the references 332 * to the subject. Otherwise, <code>ObjectInUseException</code> 333 * would be thrown if there is any policy using the subject 334 * 335 * @return returns the Subject object being removed, 336 * returns <code>null</code> if Subject with 337 * the given subjectName is not present 338 * 339 * @throws PolicyException if can not remove the Subject 340 */ 341 public Subject removeSubject(String subjectName, boolean forcedRemove) 342 throws ObjectInUseException, PolicyException, SSOException { 343 if (debug.messageEnabled()) { 344 debug.message("Removing realm subject : " + subjectName 345 + ", in realm:" + pmRealmName); 346 } 347 if (realmSubjects == null) { 348 initRealmSubjects(); 349 } 350 if (forcedRemove) { 351 Set userPolicies = pm.getPoliciesUsingRealmSubject(subjectName); 352 for (Iterator policyIter = userPolicies.iterator(); 353 policyIter.hasNext();) { 354 Policy policy = (Policy)policyIter.next(); 355 policy.removeSubject(subjectName); 356 } 357 } else { 358 Policy p = pm.getPolicyUsingRealmSubject(subjectName); 359 if ( p != null) { 360 //ObjectInUseException(String rbName, String errCode, 361 //Object[] args, String name, Object user) 362 throw new ObjectInUseException(null, null, null, null, null); 363 } 364 } 365 Subject subject = realmSubjects.removeSubject(subjectName); 366 saveSubjects(); 367 if (debug.messageEnabled()) { 368 debug.message("Removed realm subject : " + subjectName 369 + ", in realm:" + pmRealmName); 370 } 371 return subject; 372 } 373 374 /** 375 * Replaces an existing subject with the same name by the 376 * current one at the realm. If a subject with the same name does 377 * not exist, it will be added. 378 * 379 * @param subjectName name of the Subject instance 380 * @param subject Subject that will replace an existing Subject 381 * with the same name 382 * 383 * @throws NameNotFoundException if a Subject instance 384 * with the given name is not present 385 * 386 * @throws PolicyException if can not replace the Subject 387 */ 388 public void replaceSubject(String subjectName, Subject subject) 389 throws NameNotFoundException, PolicyException, SSOException { 390 391 //we really do not use the exclusive flag at realm level 392 replaceSubject(subjectName, subject, false); 393 } 394 395 /** 396 * Replaces an existing subject with the same name by the 397 * current one at the realm. If a subject with the same name does 398 * not exist, it will be added. 399 * 400 * @param subjectName name of the Subject instance 401 * @param subject Subject that will replace an existing Subject 402 * with the same name 403 * 404 * @param exclusive boolean flag indicating whether the subject 405 * is to be exclusive subject. If subject is exclusive, 406 * policy applies to users who are not members of the 407 * subject. Otherwise, policy applies to members of the subject. 408 * 409 * @throws NameNotFoundException if a Subject instance 410 * with the given name is not present 411 * 412 * @throws PolicyException if can not replace the Subject 413 * 414 * 415 */ 416 private void replaceSubject(String subjectName, Subject subject, 417 boolean exclusive) 418 throws NameNotFoundException, PolicyException, SSOException { 419 if (debug.messageEnabled()) { 420 debug.message("Replacing realm subject : " + subjectName 421 + ", in realm:" + pmRealmName); 422 } 423 if (realmSubjects == null) { 424 initRealmSubjects(); 425 } 426 realmSubjects.replaceSubject(subjectName, subject, exclusive); 427 saveSubjects(); 428 if (debug.messageEnabled()) { 429 debug.message("Replaced realm subject : " + subjectName 430 + ", in realm:" + pmRealmName); 431 } 432 } 433 434 /** 435 * Get the set of names of Subject(s) defined at the realm 436 * 437 * @return set of subject names 438 */ 439 public Set getSubjectNames() throws PolicyException, SSOException { 440 if (debug.messageEnabled()) { 441 debug.message("Getting subject names from realm: " 442 + pmRealmName); 443 } 444 if (realmSubjects == null) { 445 initRealmSubjects(); 446 } 447 Set subjectNames = realmSubjects.getSubjectNames(); 448 if (debug.messageEnabled()) { 449 debug.message("Returning subject names from realm: " 450 + pmRealmName + ",subjectNames=" + subjectNames); 451 } 452 return subjectNames; 453 } 454 455 /** 456 * Returns the Subject object identified by subjectName defined at 457 * the realm 458 * 459 * @param subjectName name of subject. 460 * 461 * @return Subject object 462 * 463 * @throws NameNotFoundException if a Subject with the given name 464 * does not exist 465 * 466 * @throws PolicyException if can not get the Subject 467 */ 468 public Subject getSubjectByName(String subjectName) 469 throws NameNotFoundException, PolicyException { 470 if (debug.messageEnabled()) { 471 debug.message("Getting subject by name from realm: " 472 + pmRealmName + ", subjectName=" + subjectName); 473 } 474 if (realmSubjects == null) { 475 initRealmSubjects(); 476 } 477 if (debug.messageEnabled()) { 478 debug.message("Returning subject by name from realm: " 479 + pmRealmName + ", subjectName=" + subjectName); 480 } 481 return (Subject)realmSubjects.getSubject(subjectName).clone(); 482 } 483 484 synchronized Subject getCachedSubjectByName(String subjectName) 485 throws PolicyException { 486 if (debug.messageEnabled()) { 487 debug.message("Getting cached subject by name from realm: " 488 + pmRealmName + ", subjectName=" + subjectName); 489 } 490 if (realmSubjects == null) { 491 initRealmSubjects(); 492 } 493 if (debug.messageEnabled()) { 494 debug.message("Returning cached subject by name from realm: " 495 + pmRealmName + ", subjectName=" + subjectName); 496 } 497 return (Subject)realmSubjects.fetchSubject(subjectName); 498 } 499 500 /** 501 * Returns a handle to the Subject object identified by subjectName 502 * defined at the realm, to add to a policy. 503 * Returned Subject is backed by 504 * the Subject at the realm. However, you can not change the values 505 * using the returned Subject. 506 * 507 * @param subjectName name of subject. 508 * 509 * @return Subject object 510 * 511 * @throws NameNotFoundException if a Subject with the given name 512 * does not exist 513 * 514 * @throws PolicyException if can not get the Subject 515 * 516 */ 517 Subject getSharedSubject(String subjectName) 518 throws PolicyException { 519 if (debug.messageEnabled()) { 520 debug.message("Getting shared subject from realm: " 521 + pmRealmName + ", subjectName=" + subjectName); 522 } 523 Subject subject = (Subject)sharedSubjects.get(subjectName); 524 if (subject == null) { 525 subject = new SharedSubject(subjectName, this); 526 sharedSubjects.put(subjectName, subject); 527 } 528 if (debug.messageEnabled()) { 529 debug.message("Returning shared subject from realm: " 530 + pmRealmName + ", subjectName=" + subjectName); 531 } 532 return subject; 533 } 534 535 /** 536 * Returns subject type name for the given <code>subject</code> 537 * @return subject type name for the given <code>subject</code> 538 */ 539 static String subjectTypeName(Subject subject) { 540 if (subject == null) { 541 return (null); 542 } 543 String answer = null; 544 String className = subject.getClass().getName(); 545 Iterator items = PolicyManager.getPluginSchemaNames(SUBJECT).iterator(); 546 while (items.hasNext()) { 547 String pluginName = (String) items.next(); 548 PluginSchema ps = PolicyManager.getPluginSchema(SUBJECT, 549 pluginName); 550 if (className.equals(ps.getClassName())) { 551 answer = pluginName; 552 break; 553 } 554 } 555 return (answer); 556 } 557 558 /** 559 * Returns the view bean URL given the Subject 560 * 561 * @param subject subject for which to get the view bean URL 562 * 563 * @return view bean URL defined for the subject plugin in the policy 564 * service <code>PluginSchema</code>. 565 */ 566 public String getViewBeanURL(Subject subject) { 567 return PolicyManager.getViewBeanURL(SUBJECT, 568 subject.getClass().getName()); 569 } 570 571 /** 572 * Returns <code>PolicyManager</code> used by this object 573 */ 574 PolicyManager getPolicyManager() { 575 return pm; 576 } 577 578 /** 579 * Saves the realm scoped <code>Subject</code> objects to persistent store 580 */ 581 private void saveSubjects() throws PolicyException, SSOException { 582 if (realmSubjects != null) { 583 pm.saveRealmSubjects(realmSubjects); 584 } 585 } 586 587 /** 588 * Initializes the realm scoped <code>Subject</code> objects reading from 589 * persistent store 590 */ 591 private void initRealmSubjects() throws PolicyException { 592 if (debug.messageEnabled()) { 593 debug.message("Initializing realm subjects in realm : " 594 + pmRealmName); 595 } 596 try { 597 realmSubjects = pm.readRealmSubjects(); 598 } catch (SSOException ssoe){ 599 throw new PolicyException(ResBundleUtils.rbName, 600 "could_not_initialize_realm_subjects", null, ssoe); 601 } 602 if (debug.messageEnabled()) { 603 debug.message("Initialized realm subjects in realm : " 604 + pmRealmName); 605 } 606 } 607 608 /** 609 * Resets the cached realm scoped <code>Subject</code> objects. 610 * Would read from persistent store on next access to realm scoped 611 * <code>Subject</code> object 612 */ 613 void resetRealmSubjects() { 614 if (debug.messageEnabled()) { 615 debug.message("Resetting realm subjects in realm : " 616 + pmRealmName); 617 } 618 synchronized(this) { 619 realmSubjects = null; 620 } 621 if (debug.messageEnabled()) { 622 debug.message("Reset realm subjects in realm : " 623 + pmRealmName); 624 } 625 } 626 627}