/**
  * Returns <code>true</code> if attribute value for the given user represented by
  * <class>Subject</class> object is present.
  *
  * @param subject identity of the user
  * @param attrName attribute name to check
  * @param attrValue attribute value to check
  * @return <code>true</code> if attribute value for the given user represented by
  *     <class>Subject</class> object is present.
  * @throws com.sun.identity.entitlement.EntitlementException if this operation failed.
  */
 public boolean hasAttribute(Subject subject, String attrName, String attrValue)
     throws EntitlementException {
   String uuid = SubjectUtils.getPrincipalId(subject);
   try {
     SSOToken adminToken =
         (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
     AMIdentity amid = new AMIdentity(adminToken, uuid);
     if (attrName.startsWith(NAMESPACE_ATTR)) {
       Set<String> values = amid.getAttribute(attrName.substring(NAMESPACE_ATTR.length()));
       return (values != null) ? values.contains(attrValue) : false;
     } else if (attrName.startsWith(NAMESPACE_MEMBERSHIP)) {
       IdType type = IdUtils.getType(attrName.substring(NAMESPACE_MEMBERSHIP.length()));
       if (type != null) {
         AMIdentity parent = new AMIdentity(adminToken, attrValue);
         if (parent.getType().equals(type)) {
           Set<String> members = parent.getMembers(IdType.USER);
           return members.contains(amid.getUniversalId());
         }
       }
     }
     return false;
   } catch (IdRepoException e) {
     Object[] params = {uuid};
     throw new EntitlementException(601, params, e);
   } catch (SSOException e) {
     Object[] params = {uuid};
     throw new EntitlementException(601, params, e);
   }
 }
 /**
  * Returns the attribute values of the given user represented by <class>Subject</class> object.
  *
  * @param subject identity of the user.
  * @param attrNames requested attribute names.
  * @return a map of attribute names and their values
  * @throws com.sun.identity.entitlement.EntitlementException if this operation failed.
  */
 public Map<String, Set<String>> getUserAttributes(Subject subject, Set<String> attrNames)
     throws EntitlementException {
   String uuid = SubjectUtils.getPrincipalId(subject);
   try {
     SSOToken adminToken =
         (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
     AMIdentity amid = new AMIdentity(adminToken, uuid);
     return amid.getAttributes(attrNames);
   } catch (IdRepoException e) {
     Object[] params = {uuid};
     throw new EntitlementException(601, params, e);
   } catch (SSOException e) {
     Object[] params = {uuid};
     throw new EntitlementException(601, params, e);
   }
 }
  private static void registerListener() {
    SSOToken adminToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());

    EntitlementConfiguration ec =
        EntitlementConfiguration.getInstance(SubjectUtils.createSubject(adminToken), "/");
    if (ec.migratedToEntitlementService()) {
      try {
        ServiceConfigManager scm = new ServiceConfigManager(IdConstants.REPO_SERVICE, adminToken);
        scm.addListener(new SubRealmObserver());
      } catch (SMSException e) {
        PrivilegeManager.debug.error("SubRealmObserver.registerListener", e);
      } catch (SSOException e) {
        PrivilegeManager.debug.error("SubRealmObserver.registerListener", e);
      }
    }
  }
  /**
   * Returns the attribute values of the given user represented by <class>Subject</class> object.
   *
   * @param subject identity of the user
   * @param attrNames requested attribute names
   * @return a map of attribute names and their values
   * @throws com.sun.identity.entitlement.EntitlementException if this operation failed.
   */
  public Map<String, Set<String>> getAttributes(Subject subject, Set<String> attrNames)
      throws EntitlementException {
    String uuid = SubjectUtils.getPrincipalId(subject);
    try {
      Map<String, Set<String>> results = new HashMap<String, Set<String>>();
      Map<String, Set<String>> pubCreds = new HashMap<String, Set<String>>();

      SSOToken adminToken =
          (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
      AMIdentity amid = new AMIdentity(adminToken, uuid);

      Set<String> set = new HashSet<String>(2);
      set.add(getIDWithoutOrgName(amid));
      results.put(NAMESPACE_IDENTITY, set);
      set = new HashSet<String>(2);
      set.add(uuid);
      pubCreds.put(NAMESPACE_IDENTITY, set);

      Set<String> primitiveAttrNames = getAttributeNames(attrNames, NAMESPACE_ATTR);
      if (!primitiveAttrNames.isEmpty()) {
        Map<String, Set<String>> primitiveAttrValues = amid.getAttributes(primitiveAttrNames);
        for (String name : primitiveAttrValues.keySet()) {
          Set<String> values = primitiveAttrValues.get(name);
          if (values != null) {
            results.put(NAMESPACE_ATTR + name, values);
            pubCreds.put(NAMESPACE_ATTR + name, values);
          }
        }
      }

      Set<String> membershipAttrNames = getAttributeNames(attrNames, NAMESPACE_MEMBERSHIP);
      if (!membershipAttrNames.isEmpty()) {
        for (String m : membershipAttrNames) {
          IdType type = IdUtils.getType(m);

          if (type != null) {
            Set<AMIdentity> memberships = amid.getMemberships(type);

            if (memberships != null) {
              Set<String> setMemberships = new HashSet<String>();
              Set<String> membershipsCred = new HashSet<String>();
              for (AMIdentity a : memberships) {
                setMemberships.add(getIDWithoutOrgName(a));
                membershipsCred.add(a.getUniversalId());
              }
              results.put(NAMESPACE_MEMBERSHIP + m, setMemberships);
              pubCreds.put(NAMESPACE_MEMBERSHIP + m, membershipsCred);
            }
          }
        }
      }

      Set<Object> publicCreds = subject.getPublicCredentials();
      publicCreds.add(pubCreds);
      return results;
    } catch (SSOException e) {
      Object[] params = {uuid};
      throw new EntitlementException(600, params, e);
    } catch (IdRepoException e) {
      Object[] params = {uuid};
      throw new EntitlementException(600, params, e);
    }
  }
/**
 * This observer will remove all referral and application privileges that have reference to a delete
 * sub realm.
 */
public class SubRealmObserver implements ServiceListener, SetupListener {
  private static Subject adminSubject = SubjectUtils.createSuperAdminSubject();

  public void addListener() {
    registerListener();
  }

  private static void registerListener() {
    SSOToken adminToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());

    EntitlementConfiguration ec =
        EntitlementConfiguration.getInstance(SubjectUtils.createSubject(adminToken), "/");
    if (ec.migratedToEntitlementService()) {
      try {
        ServiceConfigManager scm = new ServiceConfigManager(IdConstants.REPO_SERVICE, adminToken);
        scm.addListener(new SubRealmObserver());
      } catch (SMSException e) {
        PrivilegeManager.debug.error("SubRealmObserver.registerListener", e);
      } catch (SSOException e) {
        PrivilegeManager.debug.error("SubRealmObserver.registerListener", e);
      }
    }
  }

  public void schemaChanged(String serviceName, String version) {
    // do nothing
  }

  public void globalConfigChanged(
      String serviceName, String version, String groupName, String serviceComponent, int type) {
    // do nothing
  }

  public void organizationConfigChanged(
      String serviceName,
      String version,
      String orgName,
      String groupName,
      String serviceComponent,
      int type) {
    if (type == ServiceListener.REMOVED) {
      ApplicationManager.clearCache(DNMapper.orgNameToRealmName(orgName));
      try {
        OpenSSOApplicationPrivilegeManager.removeAllPrivileges(orgName);
      } catch (EntitlementException ex) {
        PrivilegeManager.debug.error(
            "SubRealmObserver.organizationConfigChanged: "
                + "Unable to remove application  privileges",
            ex);
      }

      String deletedRealm = DNMapper.orgNameToRealmName(orgName);
      try {
        EntitlementService es = new EntitlementService(deletedRealm);
        Set<String> parentAndPeerRealms = es.getParentAndPeerRealmNames();

        if ((parentAndPeerRealms != null) && !parentAndPeerRealms.isEmpty()) {
          for (String r : parentAndPeerRealms) {
            removeReferrals(r, deletedRealm);
          }
        }

      } catch (EntitlementException ex) {
        PrivilegeManager.debug.error(
            "SubRealmObserver.organizationConfigChanged: " + "Unable to remove referral privileges",
            ex);
      }
    } else if (type == ServiceListener.MODIFIED) {
      ApplicationManager.clearCache(DNMapper.orgNameToRealmName(orgName));
    }
  }

  private void removeReferrals(String realm, String deletedRealm) throws EntitlementException {
    Set<String> referralNames = DataStore.getReferralNames(realm, deletedRealm);
    if ((referralNames != null) && !referralNames.isEmpty()) {
      ReferralPrivilegeManager rfm = new ReferralPrivilegeManager(realm, adminSubject);

      for (String name : referralNames) {
        ReferralPrivilege referral = rfm.getReferral(name);
        Set<String> realms = referral.getRealms();

        for (Iterator<String> i = realms.iterator(); i.hasNext(); ) {
          String r = i.next();
          if (r.equalsIgnoreCase(deletedRealm)) {
            i.remove();
          }
        }

        if (realms.isEmpty()) {
          rfm.delete(name);
        } else {
          referral.setRealms(realms);
          rfm.modify(referral);
        }
      }
    }
  }
}