/* * 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: CreateServiceConfig.java,v 1.14 2009/01/28 05:35:03 ww203982 Exp $ * * Portions Copyrighted 2011-2015 ForgeRock AS. */ package com.sun.identity.sm; import javax.naming.ldap.Rdn; import java.security.AccessController; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.iplanet.services.util.AMEncryption; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.iplanet.ums.IUMSConstants; import com.sun.identity.security.DecodeAction; import com.sun.identity.shared.xml.XMLUtils; import org.forgerock.openam.ldap.LDAPUtils; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.RDN; import org.w3c.dom.Node; public class CreateServiceConfig { static final String GLOBAL_CONFIG_NODE = "ou=GlobalConfig,"; static final String ORG_CONFIG_NODE = "ou=OrganizationConfig,"; static final String PLUGIN_CONFIG_NODE = "ou=PluginConfig,"; static final String INSTANCES_NODE = "ou=Instances,"; // ---------------------------------------------------------- // Protected methods // ---------------------------------------------------------- static void createService( ServiceManager sm, String sName, String version, Node configNode, AMEncryption decryptObj ) throws SMSException, SSOException { createService(sm, sName, version, configNode, false, decryptObj); } static void createService( ServiceManager sm, String sName, String version, Node configNode, boolean createRealms, AMEncryption decryptObj ) throws SMSException, SSOException { // Make sure schema exists for the given service & version SSOToken token = sm.getSSOToken(); ServiceSchemaManagerImpl ssm = ServiceSchemaManagerImpl.getInstance( token, sName, version); // Construct the base DN String baseDN = ServiceManager.getServiceNameDN(sName, version); checkBaseNodes(token, baseDN); // Check for instance nodes Iterator insNodes = XMLUtils.getChildNodes(configNode, SMSUtils.INSTANCE).iterator(); while (insNodes.hasNext()) { Node insNode = (Node) insNodes.next(); String insName = XMLUtils.getNodeAttributeValue(insNode, SMSUtils.NAME); if (insName == null) { insName = SMSUtils.DEFAULT; } String insGroup = XMLUtils.getNodeAttributeValue(insNode, SMSUtils.GROUP); if (insGroup == null) { insGroup = SMSUtils.DEFAULT; } String insUri = XMLUtils.getNodeAttributeValue(insNode, SMSUtils.URI); // Get Attribute Value Pairs, if any Map insAttrs = getAttributeValuePairs(insNode); StringBuilder sb = new StringBuilder(100); sb.append("ou=").append(insName).append(",").append(INSTANCES_NODE) .append(baseDN); CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, sb .toString()); if (cEntry.isDirty()) { cEntry.refresh(); } SMSEntry insEntry = cEntry.getSMSEntry(); if (insEntry.isNewEntry()) { // create the entry insEntry = cEntry.getClonedSMSEntry(); insEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); insEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE_COMP); insEntry.addAttribute(SMSEntry.ATTR_SERVICE_ID, insGroup); if (insUri != null) { insEntry.addAttribute(SMSEntry.ATTR_LABELED_URI, insUri); } if (insAttrs != null) { SMSUtils.setAttributeValuePairs(insEntry, insAttrs, Collections.EMPTY_SET); } insEntry.save(token); cEntry.refresh(insEntry); updateSubEntriesNode(token, insEntry.getDN()); } else { // throw instance already exists exception Object[] args = { sName, version }; throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, IUMSConstants.SMS_service_already_exists, args)); } } // Process global configuration Iterator globalNodes = XMLUtils.getChildNodes(configNode, SMSUtils.GLOBAL_CONFIG).iterator(); while (globalNodes.hasNext()) { Node globalNode = (Node) globalNodes.next(); ServiceSchemaImpl ss = ssm.getSchema(SchemaType.GLOBAL); String globalGroup = XMLUtils.getNodeAttributeValue(globalNode, SMSUtils.GROUP); if (globalGroup == null) { globalGroup = SMSUtils.DEFAULT; } StringBuilder sb = new StringBuilder(100); sb.append("ou=").append(globalGroup).append(",").append( GLOBAL_CONFIG_NODE).append(baseDN); createSubConfig(token, sb.toString(), globalNode, ss, baseDN, decryptObj); } // Process organization configuration Iterator orgNodes = XMLUtils.getChildNodes(configNode, SMSUtils.ORG_CONFIG).iterator(); while (orgNodes.hasNext()) { Node orgNode = (Node) orgNodes.next(); ServiceSchemaImpl ss = ssm.getSchema(SchemaType.ORGANIZATION); String orgGroup = XMLUtils.getNodeAttributeValue(orgNode, SMSUtils.GROUP); if (orgGroup == null) { orgGroup = SMSUtils.DEFAULT; } // Construct the org name String orgDN = SMSEntry.baseDN; String orgName = XMLUtils.getNodeAttributeValue(orgNode, SMSUtils.NAME); if (orgName != null) { if (LDAPUtils.isDN(orgName)) { orgDN = orgName; } else if (orgName.indexOf('/') != -1) { orgDN = DNMapper.orgNameToDN(orgName); } } // Check if config nodes exists checkBaseNodesForOrg(token, orgDN, sName, version, createRealms); // create sub-config node StringBuilder sb = new StringBuilder(100); sb.append("ou=").append(orgGroup).append(",").append( ORG_CONFIG_NODE).append("ou=").append(version).append( ",ou=").append(sName).append(",ou=services,").append(orgDN); createSubConfig(token, sb.toString(), orgNode, ss, orgDN, decryptObj); // Process OrganizationAttributeValuePairs Node orgAttrValuePairNode = XMLUtils.getChildNode(orgNode, SMSUtils.ORG_ATTRIBUTE_VALUE_PAIR); if (orgAttrValuePairNode != null) { // Get the attributes Map attrs = getAttributeValuePairs(orgAttrValuePairNode); OrganizationConfigManager ocm = new OrganizationConfigManager(token, orgDN); ocm.setAttributes(sName, attrs); } } // Process Plugin configuration Iterator pNodes = XMLUtils.getChildNodes(configNode, SMSUtils.PLUGIN_CONFIG).iterator(); while (pNodes.hasNext()) { Node pNode = (Node) pNodes.next(); String pName = XMLUtils.getNodeAttributeValue(pNode, SMSUtils.NAME); String schemaName = XMLUtils.getNodeAttributeValue(pNode, SMSUtils.PLUGIN_CONFIG_SCHEMA_NAME); String intName = XMLUtils.getNodeAttributeValue(pNode, SMSUtils.PLUGIN_CONFIG_INT_NAME); String orgName = DNMapper.orgNameToDN(XMLUtils .getNodeAttributeValue(pNode, SMSUtils.PLUGIN_CONFIG_ORG_NAME)); // Get the PluginSchema PluginSchemaImpl psi = PluginSchemaImpl.getInstance(token, sName, version, schemaName, intName, orgName); // Check if config nodes exists checkBaseNodesForOrg(token, orgName, sName, version); // Check and create interfaces node StringBuilder sb = new StringBuilder(100); sb.append("ou=").append(intName).append(",").append( PLUGIN_CONFIG_NODE).append("ou=").append(version).append( ",ou=").append(sName).append(",ou=services,").append( orgName); checkAndCreateServiceNode(token, sb.toString()); // Check and create schema node sb.insert(0, ",").insert(0, schemaName).insert(0, "ou="); checkAndCreateServiceNode(token, sb.toString()); // Create plugin config node sb.insert(0, ",").insert(0, pName).insert(0, "ou="); createSubConfig(token, sb.toString(), pNode, psi, orgName, decryptObj); } } static void createSubConfig( SSOToken token, String dn, Node node, ServiceSchemaImpl ss, String orgdn, AMEncryption decryptObj ) throws SMSException, SSOException { // Get service id and priority String id = XMLUtils.getNodeAttributeValue(node, SMSUtils.SERVICE_ID); String priority = XMLUtils.getNodeAttributeValue(node, SMSUtils.PRIORITY); // Get the attributes Map attrs = getAttributeValuePairs(node); if ((decryptObj != null) && (attrs != null) && !attrs.isEmpty()) { for (Iterator i = attrs.keySet().iterator(); i.hasNext(); ) { String attrName = (String)i.next(); AttributeSchemaImpl as = ss.getAttributeSchema(attrName); AttributeSchema.Syntax syntax = as.getSyntax(); if (syntax.equals(AttributeSchema.Syntax.ENCRYPTED_PASSWORD) || syntax.equals(AttributeSchema.Syntax.PASSWORD) ) { Set values = (Set) attrs.get(attrName); if ((values != null) && !values.isEmpty()) { Set decoded = new HashSet(values.size() * 2); for (Iterator j = values.iterator(); j.hasNext();) { decoded.add(AccessController.doPrivileged( new DecodeAction((String) j.next(), decryptObj))); } attrs.put(attrName, decoded); } } } } // Create the LDAP entry createSubConfigEntry(token, dn, ss, id, priority, attrs, orgdn); // Check for further sub-configuration Iterator subConfigs = XMLUtils.getChildNodes(node, SMSUtils.SUB_CONFIG) .iterator(); while (subConfigs.hasNext()) { Node subConfigNode = (Node) subConfigs.next(); String subConfigName = XMLUtils.getNodeAttributeValue( subConfigNode, SMSUtils.NAME); String subConfigID = XMLUtils.getNodeAttributeValue(subConfigNode, SMSUtils.SERVICE_ID); if (subConfigID == null) { subConfigID = subConfigName; } createSubConfig(token, ("ou=" + subConfigName + "," + dn), subConfigNode, ss.getSubSchema(subConfigID), orgdn, decryptObj); } } static void createSubConfigEntry(SSOToken token, String dn, ServiceSchemaImpl ss, String id, String priority, Map attrs, String orgDN) throws SMSException, SSOException { // Construct the SMSEntry for the node CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, dn); if (cEntry.isDirty()) { cEntry.refresh(); } SMSEntry entry = cEntry.getClonedSMSEntry(); if ((ss == null) || !entry.isNewEntry()) { SMSEntry.debug.error( "CreateServiceConfig.createSubConfigEntry: Entry already exists: " + dn); throw (new ServiceAlreadyExistsException( IUMSConstants.UMS_BUNDLE_NAME, IUMSConstants.SMS_service_already_exists_no_args, null)); } // Add LDAP objectclasses entry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); entry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE_COMP); if (attrs != null) { // Validate the attributes ss.validateAttributes(token, attrs, true, orgDN); SMSUtils.setAttributeValuePairs(entry, attrs, ss .getSearchableAttributeNames()); } if (id != null) { entry.addAttribute(SMSEntry.ATTR_SERVICE_ID, id); } if (priority != null) { entry.addAttribute(SMSEntry.ATTR_PRIORITY, priority); } // Save the entry, and add to cache entry.save(token); cEntry.refresh(entry); updateSubEntriesNode(token, entry.getDN()); } static void checkBaseNodesForOrg( SSOToken token, String orgDN, String sName, String version ) throws SMSException, SSOException { checkBaseNodesForOrg(token, orgDN, sName, version, false); } static void checkBaseNodesForOrg( SSOToken token, String orgDN, String sName, String version, boolean createRealms ) throws SMSException, SSOException { // Check if org exists SMSEntry entry = new SMSEntry(token, orgDN); if (entry.isNewEntry()) { // Organization does not exists, create if needed if (createRealms) { createOrganization(token, orgDN); } else { Object[] args = { orgDN }; throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, "sms-org-doesnot-exist", args)); } } // Check if services node exists String dn = "ou=services," + orgDN; checkAndCreateOrgUnitNode(token, dn); // Check if service node exists dn = "ou=" + sName + "," + dn; checkAndCreateServiceNode(token, dn); // Check if verion node exists dn = "ou=" + version + "," + dn; checkAndCreateServiceVersionNode(token, dn, sName); // Check orgUnit node if (orgDN.equalsIgnoreCase(SMSEntry.getRootSuffix())) { // Create all based nodes for root realm checkBaseNodes(token, dn); } else { // create only organization config checkAndCreateOrgUnitNode(token, ORG_CONFIG_NODE + dn); } } static void checkBaseNodes(SSOToken t, String baseDN) throws SMSException, SSOException { // Check global config node checkAndCreateOrgUnitNode(t, GLOBAL_CONFIG_NODE + baseDN); checkAndCreateOrgUnitNode(t, ORG_CONFIG_NODE + baseDN); checkAndCreateServiceNode(t, PLUGIN_CONFIG_NODE + baseDN); checkAndCreateOrgUnitNode(t, INSTANCES_NODE + baseDN); } static void checkAndCreateOrgUnitNode(SSOToken token, String dn) throws SMSException, SSOException { SMSEntry e = new SMSEntry(token, dn); if (SMSEntry.debug.messageEnabled()) { SMSEntry.debug.message("CreateServiceConfig." + "checkAndCreateOrgUnitNode() creating entry: " + dn); } if (e.isNewEntry()) { // Add needed object classes e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_ORG_UNIT); e.save(); } } static void checkAndCreateServiceNode(SSOToken token, String dn) throws SMSException, SSOException { SMSEntry e = new SMSEntry(token, dn); if (e.isNewEntry()) { int ndx = dn.indexOf(SMSEntry.SERVICES_RDN); if (ndx >= 0) { if (dn.indexOf(SMSEntry.SERVICES_RDN, ndx+11) >= 0) { // Add needed object classes for the 'ou=services' node // under the subrealms created. e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE); } else { // Add needed object classes e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE_COMP); } } } e.save(); } static void checkAndCreateServiceVersionNode(SSOToken t, String dn, String serviceName) throws SMSException, SSOException { SMSEntry e = new SMSEntry(t, dn); if (e.isNewEntry()) { int ndx = dn.indexOf(SMSEntry.SERVICES_RDN); if (ndx >= 0) { String firstSvc = dn.substring(ndx); if (firstSvc.indexOf(SMSEntry.SERVICES_RDN) >= 0) { // Add needed object classes for the 'ou=services' node // under the subrealms created. e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE); } else { // Add needed object classes and service name. e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_SERVICE); e.addAttribute(SMSEntry.PLACEHOLDER_RDN, serviceName); } } } e.save(); } static void updateSubEntriesNode(SSOToken token, String sdn) throws SMSException { // Get the name DN dn = DN.valueOf(sdn); String name = LDAPUtils.rdnValueFromDn(dn); // Get the parent DN DN parent = dn.parent(); CachedSubEntries subEntries = CachedSubEntries.getInstanceIfCached( token, parent.toString(), true); if (subEntries != null) { subEntries.add(name); } } // Returns a map that contains attribute value pairs // %%% This must be moved to XMLUtils public static Map getAttributeValuePairs(Node n) { if (n == null) { return (null); } Map answer = null; Iterator attrNodes = XMLUtils.getChildNodes(n, SMSUtils.ATTRIBUTE_VALUE_PAIR).iterator(); while (attrNodes.hasNext()) { Node attrValuePair = (Node) attrNodes.next(); Node attrNode = XMLUtils.getChildNode(attrValuePair, SMSUtils.ATTRIBUTE); if (attrNode == null) { continue; } String attrName = XMLUtils.getNodeAttributeValue(attrNode, SMSUtils.NAME); Set values = XMLUtils.getAttributeValuePair(attrValuePair); if (answer == null) { answer = new HashMap(); } answer.put(attrName, values); } return (answer); } // Returns a map that contains attribute value pairs // If 'unescape' is set to false, xml escaped chars will not // be unescaped. public static Map getAttributeValuePairs(Node n, boolean unescape) { if (n == null) { return (null); } Map answer = null; Iterator attrNodes = XMLUtils.getChildNodes(n, SMSUtils.ATTRIBUTE_VALUE_PAIR).iterator(); while (attrNodes.hasNext()) { Node attrValuePair = (Node) attrNodes.next(); Node attrNode = XMLUtils.getChildNode(attrValuePair, SMSUtils.ATTRIBUTE); if (attrNode == null) { continue; } String attrName = XMLUtils.getNodeAttributeValue(attrNode, SMSUtils.NAME); Set values = XMLUtils.getAttributeValuePair(attrValuePair, unescape); if (answer == null) { answer = new HashMap(); } answer.put(attrName, values); } return (answer); } /* * create the sub-organization. */ static void createOrganization(SSOToken token, String orgDN) throws SMSException { // Check if the organization already exists try { // Normalize DN, so it can be parsed and compared Object args1[] = {orgDN}; DN ldapName = DN.valueOf(orgDN); orgDN = ldapName.toString(); if (orgDN.length() == 0) { SMSEntry.debug.error("CreateServiceConfig."+ "createOrganization() : Detected invalid characters. "+ "Invalid realm name: "+ args1[0]); throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, "sms-invalid-org-name", args1)); } CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, orgDN); if (cEntry.isDirty()) { cEntry.refresh(); } SMSEntry e = cEntry.getClonedSMSEntry(); if (!e.isNewEntry()) { SMSEntry.debug.error("Organization already exists: " + orgDN); throw (new OrganizationAlreadyExistsException( IUMSConstants.UMS_BUNDLE_NAME, IUMSConstants.SMS_organization_already_exists_no_args, null)); } // Reverse RDN order List rdns = new ArrayList<>(); for (RDN rdn : ldapName) { rdns.add(0, rdn); } // Need to start from baseDN, to create intermediate nodes String partdn = rdns.get(0).toString(); // Obtain the baseDN int index = 0; while (index < rdns.size() - 1 && !partdn.equalsIgnoreCase(DNMapper.serviceDN)) { partdn = rdns.get(++index).toString() + "," + partdn; } // Check the intermediate nodes while (index < rdns.size() - 1) { partdn = rdns.get(++index).toString() + "," + partdn; cEntry = CachedSMSEntry.getInstance(token, partdn); if (cEntry.isDirty()) { cEntry.refresh(); } e = cEntry.getClonedSMSEntry(); if (e.isNewEntry()) { // Create the realm // Add needed object classes e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_REALM_SERVICE); e.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); e.save(token); cEntry.refresh(e); } } } catch (SSOException ssoe) { SMSEntry.debug.error("CreateServiceConfig: Unable to " + "create organization ", ssoe); throw (new SMSException(SMSEntry.bundle .getString("sms-INVALID_SSO_TOKEN"), "sms-INVALID_SSO_TOKEN")); } } }