/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: ServiceConfigManager.java,v 1.11 2009/07/25 05:11:55 qcheng Exp $ * */ /* * Portions Copyrighted [2011] [ForgeRock AS] */ package com.sun.identity.sm; import com.iplanet.services.util.AMEncryption; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.iplanet.sso.SSOTokenManager; import com.iplanet.ums.IUMSConstants; import com.sun.identity.authentication.util.ISAuthConstants; import com.sun.identity.idm.IdConstants; import com.sun.identity.shared.xml.XMLUtils; import java.io.InputStream; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * The class ServiceConfigurationManager provides interfaces to * manage the service's configuration data. It provides access to * ServiceConfig which represents a single "configuration" in the * service. It manages configuration data only for GLOBAL and ORGANIZATION * types. * * @supported.api */ public class ServiceConfigManager { // Instance variables private SSOToken token; private String serviceName; private String version; // Pointer to ServiceSchemaManangerImpl private ServiceSchemaManagerImpl ssm; private ServiceConfigManagerImpl scm; /** * Constrctor to obtain an instance ServiceConfigManager * for * a service by providing an authenticated identity of the user. * This constructor assumes the server version to be 1.0. * * @param serviceName * name of the service * @param token * single sign on token of authenticated user identity * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired */ public ServiceConfigManager(String serviceName, SSOToken token) throws SMSException, SSOException { // Use of the service versions this(token, serviceName, ServiceManager.isCoexistenceMode() ? ServiceManager.serviceDefaultVersion(token, serviceName) : ServiceManager.getVersion(serviceName)); } /** * Creates an instance of * ServiceConfigManager for the given service and version. It * requires an user identity, that will used to perform operations with. It * is assumed that the application calling this constructor should * authenticate the user. * * @param token * single sign on token of the user identity on whose behalf the * operations are performed. * @param serviceName * the name of the service * @param version * the version of the service * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public ServiceConfigManager(SSOToken token, String serviceName, String version) throws SMSException, SSOException { if (token == null || serviceName == null || version == null) { throw new IllegalArgumentException(SMSEntry.bundle .getString(IUMSConstants.SMS_INVALID_PARAMETERS)); } SSOTokenManager.getInstance().validateToken(token); // Copy instance variables this.token = token; this.serviceName = serviceName; this.version = version; // Get the ServiceSchemaManagerImpl validateSCM(); } /** * Returns the name of the service. * * @return the name of the service * * @supported.api */ public String getName() { return (serviceName); } /** * Returns the service version. * * @return the version of the service * * @supported.api */ public String getVersion() { return (version); } /** * Returns the service instance names * * @return the service instance names * @throws SMSException * if an error has occurred while performing the operation * * @supported.api */ public Set getInstanceNames() throws SMSException { try { validateSCM(); return (scm.getInstanceNames(token)); } catch (SSOException s) { SMSEntry.debug.error("ServiceConfigManager: Unable to " + "get Instance Names", s); } return (Collections.EMPTY_SET); } /** * Returns the configuration group names * * @return the service configuration group names * @throws SMSException * if an error has occurred while performing the operation * * @supported.api */ public Set getGroupNames() throws SMSException { try { validateSCM(); return (scm.getGroupNames(token)); } catch (SSOException s) { SMSEntry.debug.error("ServiceConfigManager: Unable to " + "get Group Names", s); } return (Collections.EMPTY_SET); } /** * Returns the service instance given the instance * name * * @param instanceName * the name of the service instance * @return service instance for the given instance name * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * * @supported.api * if the user's single sign on token is invalid or expired */ public ServiceInstance getInstance(String instanceName) throws SMSException, SSOException { validateSCM(); return (new ServiceInstance(this, scm.getInstance(token, instanceName))); } /** * Removes the instance form the service * * @param instanceName * the service instance name * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public void removeInstance(String instanceName) throws SMSException, SSOException { getInstance(instanceName).delete(); } /** * Returns the global configuration for the given * service instance. * * @param instanceName * the service instance name * @return the global configuration for the given service instance * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public ServiceConfig getGlobalConfig(String instanceName) throws SMSException, SSOException { validateSCM(); ServiceConfigImpl sci = scm.getGlobalConfig(token, instanceName); return ((sci == null) ? null : new ServiceConfig(this, sci)); } /** * Returns the organization configuration for the * given organization and instance name. * * @param orgName * the name of the organization * @param instanceName * the service configuration instance name * @return the organization configuration for the given organization * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public ServiceConfig getOrganizationConfig(String orgName, String instanceName) throws SMSException, SSOException { // Get ServiceConfigImpl validateSCM(); ServiceConfigImpl sci = scm.getOrganizationConfig(token, orgName, instanceName); return ((sci == null) ? null : new ServiceConfig(this, sci)); } /** * Creates global configuration for the default * instance of the service given the configuration attributes. * * @param attrs * map of attribute values. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public ServiceConfig createGlobalConfig(Map attrs) throws SMSException, SSOException { validateSSM(); ServiceSchemaImpl ss = ssm.getSchema(SchemaType.GLOBAL); if (ss == null) { String[] args = { serviceName }; throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, "sms-service-does-not-have-global-schema", args)); } // Check base nodes for global attributes String orgDN = scm.constructServiceConfigDN(SMSUtils.DEFAULT, CreateServiceConfig.GLOBAL_CONFIG_NODE, null); // Create the sub config entry try { CreateServiceConfig.createSubConfigEntry(token, orgDN, ss, null, null, attrs, SMSEntry.baseDN); } catch (ServiceAlreadyExistsException slee) { // Ignore the exception } return (getGlobalConfig(null)); } /** * Creates organization configuration for the default * instance of the service given configuration attributes. * * @param orgName * name of organization. * @param attrs * map of attribute values. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public ServiceConfig createOrganizationConfig(String orgName, Map attrs) throws SMSException, SSOException { validateSSM(); ServiceSchemaImpl ss = ssm.getSchema(SchemaType.ORGANIZATION); if (ss == null) { String[] args = { serviceName }; throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, "sms-service-does-not-have-org-schema", args)); } // Check base nodes for org String orgdn = DNMapper.orgNameToDN(orgName); CreateServiceConfig.checkBaseNodesForOrg(token, orgdn, serviceName, version); String orgDN = scm.constructServiceConfigDN(SMSUtils.DEFAULT, CreateServiceConfig.ORG_CONFIG_NODE, orgdn); // Create the sub config entry try { CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, orgDN); if (cEntry.isDirty()) { cEntry.refresh(); } if (cEntry.isNewEntry()) { CreateServiceConfig.createSubConfigEntry(token, orgDN, ss, null, null, attrs, orgName); // if in co-existence mode, need to register the service // for AMOrganization if (ServiceManager.isCoexistenceMode()) { String smsDN = DNMapper.orgNameToDN(orgName); OrgConfigViaAMSDK amsdk = new OrgConfigViaAMSDK(token, DNMapper.realmNameToAMSDKName(smsDN), smsDN); amsdk.assignService(serviceName); } } else if (attrs != null && !attrs.isEmpty()) { // Set the attributes for the service config ServiceConfig sc = getOrganizationConfig(orgName, null); sc.setAttributes(attrs); } } catch (ServiceAlreadyExistsException slee) { // Ignore the exception } return (getOrganizationConfig(orgName, null)); } /** * Adds instances, global and organization * configurations * * @param in * input stream of configuration data. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public void addConfiguration(InputStream in) throws SMSException, SSOException { ServiceManager sm = new ServiceManager(token); // Get the document and search for service name and version Document doc = SMSSchema.getXMLDocument(in); NodeList nodes = doc.getElementsByTagName(SMSUtils.SERVICE); for (int i = 0; (nodes != null) && (i < nodes.getLength()); i++) { Node serviceNode = nodes.item(i); String sName = XMLUtils.getNodeAttributeValue(serviceNode, SMSUtils.NAME); String sVersion = XMLUtils.getNodeAttributeValue(serviceNode, SMSUtils.VERSION); Node configNode; if (sName.equals(serviceName) && (sVersion.equals(version)) && ((configNode = XMLUtils.getChildNode(serviceNode, SMSUtils.CONFIGURATION)) != null)) { CreateServiceConfig.createService(sm, sName, sVersion, configNode, null); } } } /** * Deletes the global configuration data for the given * group name. If group name is null, it used the default * group name. * * @param groupName * name of group. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public void removeGlobalConfiguration(String groupName) throws SMSException, SSOException { if (serviceName.equalsIgnoreCase(IdConstants.REPO_SERVICE) || serviceName.equalsIgnoreCase(ISAuthConstants.AUTH_SERVICE_NAME)) { String[] args = { serviceName }; throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, "sms-SERVICE_CORE_CANNOT_DELETE", args)); } if ((groupName == null) || groupName.length() == 0) { groupName = SMSUtils.DEFAULT; } // Construct the sub-config dn validateSCM(); String gdn = scm.constructServiceConfigDN(groupName, CreateServiceConfig.GLOBAL_CONFIG_NODE, null); // Delete the entry CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, gdn); if (cEntry.isDirty()) { cEntry.refresh(); } SMSEntry entry = cEntry.getClonedSMSEntry(); entry.delete(token); cEntry.refresh(entry); } /** * Deletes the organization configuration data for the * given organization. It removes all the groups within the organization. * * @param orgName * name of organization. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public void deleteOrganizationConfig(String orgName) throws SMSException, SSOException { removeOrganizationConfiguration(orgName, SMSUtils.DEFAULT); } /** * Deletes the organization's group configuration * data. * * @param orgName * name of organization. * @param groupName * name of group. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired * * @supported.api */ public void removeOrganizationConfiguration(String orgName, String groupName) throws SMSException, SSOException { removeOrganizationConfiguration(orgName, groupName, true); } /** * Deletes the organization's group configuration data. * * @param orgName * name of organization. * @param groupName * name of group. * @param checkLegacyMode * boolean to check if legacy or realm passed by amsdk as false. * @throws SMSException * if an error has occurred while performing the operation * @throws SSOException * if the user's single sign on token is invalid or expired */ public void removeOrganizationConfiguration(String orgName, String groupName, boolean checkLegacyMode) throws SMSException, SSOException { if ((groupName == null) || groupName.length() == 0) { groupName = SMSUtils.DEFAULT; } // Construct the sub-config dn String orgdn = DNMapper.orgNameToDN(orgName); validateSCM(); String odn = scm.constructServiceConfigDN(groupName, CreateServiceConfig.ORG_CONFIG_NODE, orgdn); // Delete the entry from the REALM DIT CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, odn); if (cEntry.isNewEntry()) { return; } // if in legacy/co-existence mode, need to unregister the service // from AMOrganization if (checkLegacyMode && ServiceManager.isCoexistenceMode() && groupName.equalsIgnoreCase(SMSUtils.DEFAULT)) { OrgConfigViaAMSDK amsdk = new OrgConfigViaAMSDK(token, DNMapper .realmNameToAMSDKName(orgdn), orgdn); amsdk.unassignService(serviceName); } // Now delete the entry. if (!cEntry.isNewEntry()) { SMSEntry entry = cEntry.getClonedSMSEntry(); entry.delete(token); cEntry.refresh(entry); } } /** * Returns a set of plugins configured for the given plugin interface and * plugin schema in a organization */ public Set getPluginConfigNames(String pluginSchemaName, String interfaceName, String orgName) throws SMSException, SSOException { StringBuilder sb = new StringBuilder(100); sb.append("ou=").append(pluginSchemaName).append(",ou=").append( interfaceName).append(",").append( CreateServiceConfig.PLUGIN_CONFIG_NODE).append("ou=").append( version).append(",").append("ou=").append(serviceName).append( ",").append(SMSEntry.SERVICES_RDN).append(",").append( DNMapper.orgNameToDN(orgName)); // Need to check if the user permission to read plugin names CachedSMSEntry.getInstance(token, sb.toString()); // Get the CachedSubEntries and return sub-entries CachedSubEntries cse = CachedSubEntries.getInstance(token, sb .toString()); return (cse.getSubEntries(token)); } /** * Returns the plugin configuration parameters for the service */ public PluginConfig getPluginConfig(String name, String pluginSchemaName, String interfaceName, String orgName) throws SMSException, SSOException { validateSCM(); PluginConfigImpl pci = scm.getPluginConfig(token, name, pluginSchemaName, interfaceName, orgName); return (new PluginConfig(name, this, pci)); } /** * Removes the plugin configuration for the service */ public void removePluginConfig(String name, String pluginSchemaName, String interfaceName, String orgName) throws SMSException, SSOException { PluginConfig pci = getPluginConfig(name, pluginSchemaName, interfaceName, orgName); if (pci != null) { pci.delete(); } } /** * Registers for changes to service's configuration. * The object will be called when configuration for this service and version * is changed. * * @param listener * callback object that will be invoked when schema changes. * @return an ID of the registered listener. * * @supported.api */ public String addListener(ServiceListener listener) { try { validateSCM(); return (scm.addListener(token, listener)); } catch (Exception e) { SMSEntry.debug.error("ServiceConfigManager:addListener exception" + " Service Name: " + serviceName, e); } return (null); } /** * Removes the listener from the service for the given * listener ID. The ID was issued when the listener was registered. * * @param listenerID * the listener ID issued when the listener was registered * * @supported.api */ public void removeListener(String listenerID) { if (scm != null) { scm.removeListener(listenerID); } } private void validateSCM() throws SSOException, SMSException { if ((scm == null) || !scm.isValid()) { scm = ServiceConfigManagerImpl.getInstance( token, serviceName, version); } } private void validateSSM() throws SSOException, SMSException { if ((ssm == null) || !ssm.isValid()) { validateSCM(); ssm = scm.getServiceSchemaManagerImpl(token); } } // @Override public int hashCode() { int hash = 3; hash = 29 * hash + (this.serviceName != null ? this.serviceName.hashCode() : 0); hash = 29 * hash + (this.version != null ? this.version.hashCode() : 0); return hash; } /** * Compares this object with the given object. * * @param o * object for comparison. * @return true if objects are equals. * * @supported.api */ public boolean equals(Object o) { if (o instanceof ServiceConfigManager) { ServiceConfigManager oscm = (ServiceConfigManager) o; if (serviceName.equals(oscm.serviceName) && version.equals(oscm.version)) { return (true); } } return (false); } /** * Returns String representation of the service's * configuration data, along with instances and groups. * * @return String representation of the service's configuration data, along * with instances and groups. * * @supported.api */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("\nService Config Manager: ").append(serviceName).append( "\n\tVersion: ").append(version); // Print Instances with global and base DN's org attributes try { Iterator instances = getInstanceNames().iterator(); while (instances.hasNext()) { String instanceName = (String) instances.next(); sb.append(getInstance(instanceName)); ServiceConfig config = null; try { config = getGlobalConfig(instanceName); if (config != null) { sb.append("\nGlobal Configuation:\n").append(config); } } catch (SMSException e) { // Ignore the exception } try { config = getOrganizationConfig(null, instanceName); if (config != null) { sb.append("Org Configuation:\n").append(config); } } catch (SMSException e) { // Ignore the exception } } sb.append("\n"); } catch (SMSException smse) { sb.append(smse.getMessage()); } catch (SSOException ssoe) { sb.append(ssoe.getMessage()); } return (sb.toString()); } public String toXML(AMEncryption encryptObj) throws SMSException, SSOException { StringBuilder buff = new StringBuilder(); buff.append("<" + SMSUtils.CONFIGURATION + ">"); Set instances = getInstanceNames(); for (Iterator i = instances.iterator(); i.hasNext(); ) { String instanceName = (String)i.next(); ServiceInstance instance = getInstance(instanceName); buff.append(instance.toXML()); } /* * Before calling the Global configuration we need to add "default" to * the set of instances as getInstances method does not return this. */ instances.add(SMSUtils.DEFAULT); for (Iterator i = instances.iterator(); i.hasNext(); ) { String instanceName = (String)i.next(); try { ServiceConfig sc = getGlobalConfig(instanceName); if (sc != null) { buff.append(sc.toXML(SMSUtils.GLOBAL_CONFIG, encryptObj)); } } catch (SMSException e) { //ignored } } OrganizationConfigManager orgMgr = new OrganizationConfigManager( token, "/"); Set orgNames = new HashSet(); Set oNames = orgMgr.getSubOrganizationNames("*", true); for (Iterator i = oNames.iterator(); i.hasNext(); ) { String name = (String)i.next(); if (!name.startsWith("/")) { name = "/" + name; } orgNames.add(name); } orgNames.add("/"); /* * we hide the hidden realm that is used for storing the configuration * data. Add it accordingly. */ orgNames.add(com.sun.identity.policy.PolicyManager.DELEGATION_REALM); for (Iterator i = orgNames.iterator(); i.hasNext(); ) { String orgName = (String)i.next(); for (Iterator j = instances.iterator(); j.hasNext(); ) { String instanceName = (String)j.next(); try { ServiceConfig sc = getOrganizationConfig( orgName, instanceName); if (sc != null) { buff.append(sc.toXML( SMSUtils.ORG_CONFIG, encryptObj, orgName)); } } catch (SMSException e) { //ignored } } } buff.append(""); return buff.toString(); } // --------------------------------------------------------- // Protected method // --------------------------------------------------------- SSOToken getSSOToken() { return (token); } boolean containsGroup(String groupName) throws SMSException, SSOException { return (scm.containsGroup(token, groupName)); } }