// --- BEGIN COPYRIGHT BLOCK --- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (C) 2007 Red Hat, Inc. // All rights reserved. // --- END COPYRIGHT BLOCK --- package com.netscape.cmscore.policy; import java.util.*; import java.text.*; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IPolicy; import com.netscape.certsrv.request.PolicyResult; import com.netscape.certsrv.apps.*; import com.netscape.certsrv.policy.*; import com.netscape.certsrv.authority.*; import com.netscape.certsrv.common.*; import com.netscape.certsrv.logging.*; import com.netscape.certsrv.base.*; import com.netscape.cmscore.base.*; import com.netscape.certsrv.base.IConfigStore; import com.netscape.cmscore.util.*; import com.netscape.cmscore.request.ARequestQueue; /** * This is a Generic policy processor. The three main functions of * this class are: * 1. To initialize policies by reading policy configuration from the * config file, and maintain 5 sets of policies - viz Enrollment, * Renewal, Revocation and KeyRecovery and KeyArchival. * 2. To apply the configured policies on the given request. * 3. To enable policy listing/configuration via MCC console. * * Since the policy processor also implements the IPolicy interface * the processor itself presents itself as one big policy to the * request processor. * * @author kanda * @version $Revision$, $Date$ */ public class GenericPolicyProcessor implements IPolicyProcessor { protected IConfigStore mConfig = null; protected IConfigStore mGlobalStore = null; protected IAuthority mAuthority = null; // Default System Policies public final static String[] DEF_POLICIES = {"com.netscape.cms.policy.constraints.ManualAuthentication"}; // Policies that can't be deleted nor disabled. public final static Hashtable DEF_UNDELETABLE_POLICIES = new Hashtable(); private String mId = "Policy"; private Vector mPolicyOrder = new Vector(); private Hashtable mImplTable = new Hashtable(); private Hashtable mInstanceTable = new Hashtable(); PolicySet mEnrollmentRules = new PolicySet("EnrollmentRules"); PolicySet mRenewalRules = new PolicySet("RenewalRules"); PolicySet mRevocationRules = new PolicySet("RevocationRules"); PolicySet mKeyRecoveryRules = new PolicySet("KeyRecoveryRules"); PolicySet mKeyArchivalRules = new PolicySet("KeyArchivalRules"); private String[] mSystemDefaults = null; private boolean mInitSystemPolicies; // A Table of persistent policies and their predicates. // The predicates cannot be changed during configuration. private Hashtable mUndeletablePolicies = null; public GenericPolicyProcessor() { mInitSystemPolicies = true; // CA & RA } public GenericPolicyProcessor(boolean initSystemPolicies) { mInitSystemPolicies = initSystemPolicies; // KRA } public void setId(String id) throws EBaseException { mId = id; } public String getId() { return mId; } public void startup() throws EBaseException { } /** * Shuts down this subsystem. *

*/ public void shutdown() { } public ISubsystem getAuthority() { return mAuthority; } /** * Returns the configuration store. *

* * @return configuration store */ public IConfigStore getConfigStore() { return mConfig; } /** * Initializes the PolicyProcessor *

* * @param owner owner of this subsystem * @param config configuration of this subsystem * @exception EBaseException failed to initialize this Subsystem. */ public synchronized void init(ISubsystem owner, IConfigStore config) throws EBaseException { // Debug.trace("GenericPolicyProcessor::init"); CMS.debug("GenericPolicyProcessor::init begins"); mAuthority = (IAuthority) owner; mConfig = config; mGlobalStore = SubsystemRegistry.getInstance().get("MAIN").getConfigStore(); try { IConfigStore configStore = CMS.getConfigStore(); String PKI_Subsystem = configStore.getString( "subsystem.0.id", null ); // CMS 6.1 began utilizing the "Certificate Profiles" framework // instead of the legacy "Certificate Policies" framework. // // Beginning with CS 8.1, to meet the Common Criteria evaluation // performed on this version of the product, it was determined // that this legacy "Certificate Policies" framework would be // deprecated and disabled by default (see Bugzilla Bug #472597). // // NOTE: The "Certificate Policies" framework ONLY applied to // to CA, KRA, and legacy RA (pre-CMS 7.0) subsystems. // if( PKI_Subsystem.trim().equalsIgnoreCase( "ca" ) || PKI_Subsystem.trim().equalsIgnoreCase( "kra" ) ) { String policyStatus = PKI_Subsystem.trim().toLowerCase() + "." + "Policy" + "." + IPolicyProcessor.PROP_ENABLE; if( configStore.getBoolean( policyStatus, true ) == true ) { // NOTE: If ".Policy.enable=" is // missing, then the referenced instance existed // prior to this name=value pair existing in its // 'CS.cfg' file, and thus we err on the // side that the user may still need to // use the policy framework. CMS.debug( "GenericPolicyProcessor::init Certificate " + "Policy Framework (deprecated) " + "is ENABLED" ); } else { // CS 8.1 Default: .Policy.enable=false CMS.debug( "GenericPolicyProcessor::init Certificate " + "Policy Framework (deprecated) " + "is DISABLED" ); return; } } } catch( EBaseException e ) { throw e; } // Initialize default policies system that would be // present in the system always. if (mInitSystemPolicies) { initSystemPolicies(mConfig); } // Read listing of undeletable policies if any. initUndeletablePolicies(mConfig); // Read all registered policies first.. IConfigStore c; c = config.getSubStore(PROP_IMPL); Enumeration mImpls = c.getSubStoreNames(); while (mImpls.hasMoreElements()) { String id = (String) mImpls.nextElement(); // The implementation id should be unique if (mImplTable.containsKey(id)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DUPLICATE_IMPL_ID", id)); String clPath = c.getString(id + "." + PROP_CLASS); // We should n't let the CatchAll policies to be configurable. if (isSystemDefaultPolicy(clPath)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_SYSTEM_POLICY_CONFIG_ERROR", clPath)); // Verify if the class is a valid implementation of // IPolicyRule try { Object o = Class.forName(clPath).newInstance(); if (!(o instanceof IEnrollmentPolicy) && !(o instanceof IRenewalPolicy) && !(o instanceof IRevocationPolicy) && !(o instanceof IKeyRecoveryPolicy) && !(o instanceof IKeyArchivalPolicy)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_IMPL", clPath)); } catch (EBaseException e) { throw e; } catch (Exception e) { Debug.printStackTrace(e); throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_NO_POLICY_IMPL", id)); } // Register the implementation. RegisteredPolicy regPolicy = new RegisteredPolicy(id, clPath); mImplTable.put(id, regPolicy); } // Now read the priority ordering of rule configurations. String policyOrder = config.getString(PROP_ORDER, null); if (policyOrder == null) { return; // throw new EPolicyException(PolicyResources.NO_POLICY_ORDERING); } else { StringTokenizer tokens = new StringTokenizer(policyOrder, ","); while (tokens.hasMoreTokens()) { mPolicyOrder.addElement(tokens.nextToken().trim()); } } // Now Read Policy configurations and construct policy objects int numPolicies = mPolicyOrder.size(); IConfigStore ruleStore = config.getSubStore(PROP_RULE); for (int i = 0; i < numPolicies; i++) { String instanceName = (String) mPolicyOrder.elementAt(i); // The instance id should be unique if (mInstanceTable.containsKey(instanceName)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DUPLICATE_INST_ID", instanceName)); c = ruleStore.getSubStore(instanceName); if (c == null || c.size() == 0) throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_NO_POLICY_CONFIG", instanceName)); IPolicyRule rule = null; String implName; boolean enabled; IExpression filterExp; // If the policy rule is not enabled, skip it. String enabledStr = c.getString(PROP_ENABLE, null); if (enabledStr == null || enabledStr.trim().length() == 0 || enabledStr.trim().equalsIgnoreCase("true")) enabled = true; else enabled = false; implName = c.getString(PROP_IMPL_NAME, null); if (implName == null) { throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_NO_POLICY_CONFIG", instanceName)); } // Make an instance of the specified policy. RegisteredPolicy regPolicy = (RegisteredPolicy) mImplTable.get(implName); if (regPolicy == null) { String[] params = {implName, instanceName}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_IMPL_NOT_FOUND", params)); } String classpath = regPolicy.getClassPath(); try { rule = (IPolicyRule) Class.forName(classpath).newInstance(); if (rule instanceof IPolicyRule) ((IPolicyRule) rule).setInstanceName(instanceName); rule.init(this, c); } catch (Throwable e) { mAuthority.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_POLICY_INIT_FAILED", instanceName, e.toString())); // disable rule initialized if there is // configuration error enabled = false; c.putString(PROP_ENABLE, "false"); } if (rule == null) continue; // Read the predicate expression if any associated // with the rule String exp = c.getString(GenericPolicyProcessor.PROP_PREDICATE, null); if (exp != null) exp = exp.trim(); if (exp != null && exp.length() > 0) { filterExp = PolicyPredicateParser.parse(exp); rule.setPredicate(filterExp); } // Add the rule to the instance table mInstanceTable.put(instanceName, new PolicyInstance(instanceName, implName, rule, enabled)); if (!enabled) continue; // Add the rule to the policy set according to category if a // rule is enabled. addRule(instanceName, rule); } // Verify that the default policies are present and enabled. verifyDefaultPolicyConfig(); // printPolicies(); } public boolean isProfileRequest(IRequest request) { String profileId = request.getExtDataInString("profileId"); if (profileId == null || profileId.equals("")) return false; else return true; } /** * Apply policies on the given request. * * @param IRequest The given request * @return The policy result object. */ public PolicyResult apply(IRequest req) { IPolicySet rules = null; String op = (String) req.getRequestType(); CMS.debug("GenericPolicyProcessor: apply begins"); if (op == null) { CMS.debug("GenericPolicyProcessor: apply op null"); // throw new AssertionException("Missing operation type in request. Can't happen!"); // Return ACCEPTED for now. Looks like even get CA chain // is being passed in here with request type set elsewhere // on the request. return PolicyResult.ACCEPTED; } if (isProfileRequest(req)) { Debug.trace("GenericPolicyProcessor: Profile-base Request " + req.getRequestId().toString()); return PolicyResult.ACCEPTED; } CMS.debug("GenericPolicyProcessor: apply not ProfileRequest. op="+op); if (op.equalsIgnoreCase(IRequest.ENROLLMENT_REQUEST)) rules = mEnrollmentRules; else if (op.equalsIgnoreCase(IRequest.RENEWAL_REQUEST)) rules = mRenewalRules; else if (op.equalsIgnoreCase(IRequest.REVOCATION_REQUEST)) rules = mRevocationRules; else if (op.equalsIgnoreCase(IRequest.KEY_RECOVERY_REQUEST)) rules = mKeyRecoveryRules; else if (op.equalsIgnoreCase(IRequest.KEY_ARCHIVAL_REQUEST)) rules = mKeyArchivalRules; else { // It aint' a CMP request. We don't care. return PolicyResult.ACCEPTED; // throw new AssertionException("Invalid request type. Can't Happen!"); } // ((PolicySet)rules).printPolicies(); // If there are no rules, then it is a serious error. if (rules.count() == 0) { CMS.debug("GenericPolicyProcessor: apply: rule count 0"); // if no policy is specified, just accept the request. // KRA has no policy configured by default return PolicyResult.ACCEPTED; /** setError(req, PolicyResources.NO_RULES_CONFIGURED, op); return PolicyResult.REJECTED; **/ } CMS.debug("GenericPolicyProcessor: apply: rules.count="+ rules.count()); // request must be up to date or can't process it. PolicyResult res = PolicyResult.ACCEPTED; String mVersion = ARequestQueue.REQUEST_VERSION; String vers = req.getRequestVersion(); if (vers == null || !vers.equals(mVersion)) { if (vers == null || vers.length() == 0) vers = "none"; res = PolicyResult.REJECTED; } if (res == PolicyResult.REJECTED) return res; CMS.debug("GenericPolicyProcessor: apply: calling rules.apply()"); // Apply the policy rules. return rules.apply(req); } public void printPolicies() { mEnrollmentRules.printPolicies(); mRenewalRules.printPolicies(); mRevocationRules.printPolicies(); mKeyRecoveryRules.printPolicies(); mKeyArchivalRules.printPolicies(); } public String getPolicySubstoreId() { return mAuthority.getId() + ".Policy"; } private void setError(IRequest req, String format, String arg) { if (format == null) return; EPolicyException ex = new EPolicyException(format, arg); Vector ev = req.getExtDataInStringVector(IRequest.ERRORS); if (ev == null) { ev = new Vector(); } ev.addElement(ex.toString()); req.setExtData(IRequest.ERRORS, ev); } public Enumeration getPolicyImpls() { Vector impls = new Vector(); Enumeration enum1 = mImplTable.elements(); Enumeration ret = null; try { while (enum1.hasMoreElements()) { RegisteredPolicy regPolicy = (RegisteredPolicy) enum1.nextElement(); // Make an Instance of it IPolicyRule ruleImpl = (IPolicyRule) Class.forName(regPolicy.getClassPath()).newInstance(); impls.addElement(ruleImpl); } ret = impls.elements(); } catch (Exception e) { Debug.printStackTrace(e); } return ret; } public Enumeration getPolicyImplsInfo() { Vector impls = new Vector(); Enumeration enum1 = mImplTable.elements(); Enumeration ret = null; try { while (enum1.hasMoreElements()) { RegisteredPolicy regPolicy = (RegisteredPolicy) enum1.nextElement(); impls.addElement(regPolicy.getId()); } ret = impls.elements(); } catch (Exception e) { Debug.printStackTrace(e); } return ret; } public IPolicyRule getPolicyImpl(String id) { RegisteredPolicy regImpl = (RegisteredPolicy) mImplTable.get(id); if (regImpl == null) return null; IPolicyRule impl = null; try { impl = (IPolicyRule) Class.forName(regImpl.getClassPath()).newInstance(); } catch (Exception e) { Debug.printStackTrace(e); } return impl; } public Vector getPolicyImplConfig(String id) { IPolicyRule rp = getPolicyImpl(id); if (rp == null) return null; Vector v = rp.getDefaultParams(); if (v == null) v = new Vector(); v.insertElementAt(IPolicyRule.PROP_ENABLE + "=" + "true", 0); v.insertElementAt(IPolicyRule.PROP_PREDICATE + "=" + " ", 1); return v; } public void deletePolicyImpl(String id) throws EBaseException { // First check if the id is valid; RegisteredPolicy regPolicy = (RegisteredPolicy) mImplTable.get(id); if (regPolicy == null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_NO_POLICY_IMPL", id)); // If any instance exists for this impl, can't delete it. boolean instanceExist = false; Enumeration e = mInstanceTable.elements(); for (; e.hasMoreElements();) { PolicyInstance inst = (PolicyInstance) e.nextElement(); if (inst.isInstanceOf(id)) { instanceExist = true; break; } } if (instanceExist) // we found an instance throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_ACTIVE_POLICY_RULES_EXIST", id)); // Else delete the implementation mImplTable.remove(id); IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); IConfigStore implStore = policyStore.getSubStore(PROP_IMPL); implStore.removeSubStore(id); // committing try { mGlobalStore.commit(true); } catch (Exception ex) { Debug.printStackTrace(ex); String[] params = {"implementation", id}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DELETING_POLICY_ERROR", params)); } } public void addPolicyImpl(String id, String classPath) throws EBaseException { // See if the id is unique if (mImplTable.containsKey(id)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DUPLICATE_IMPL_ID", id)); // See if the classPath is ok Object impl = null; try { impl = Class.forName(classPath).newInstance(); }catch (Exception e) { throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_NO_POLICY_IMPL", id)); } // Does the class implement one of the four interfaces? if (!(impl instanceof IEnrollmentPolicy) && !(impl instanceof IRenewalPolicy) && !(impl instanceof IRevocationPolicy) && !(impl instanceof IKeyRecoveryPolicy) && !(impl instanceof IKeyArchivalPolicy)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_IMPL", classPath)); // Add the implementation to the registry RegisteredPolicy regPolicy = new RegisteredPolicy(id, classPath); mImplTable.put(id, regPolicy); // Store the impl in the configuration. IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); IConfigStore implStore = policyStore.getSubStore(PROP_IMPL); IConfigStore newStore = implStore.makeSubStore(id); newStore.put(PROP_CLASS, classPath); try { mGlobalStore.commit(true); } catch (Exception e) { String[] params = {"implementation", id}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_ADDING_POLICY_ERROR", params)); } } public Enumeration getPolicyInstances() { Vector rules = new Vector(); Enumeration enum1 = mPolicyOrder.elements(); Enumeration ret = null; try { while (enum1.hasMoreElements()) { PolicyInstance instance = (PolicyInstance) mInstanceTable.get((String) enum1.nextElement()); rules.addElement(instance.getRule()); } ret = rules.elements(); } catch (Exception e) { Debug.printStackTrace(e); } return ret; } public Enumeration getPolicyInstancesInfo() { Vector rules = new Vector(); Enumeration enum1 = mPolicyOrder.elements(); Enumeration ret = null; try { while (enum1.hasMoreElements()) { String ruleName = (String) enum1.nextElement(); PolicyInstance instance = (PolicyInstance) mInstanceTable.get(ruleName); rules.addElement(instance.getRuleInfo()); } ret = rules.elements(); } catch (Exception e) { Debug.printStackTrace(e); } return ret; } public IPolicyRule getPolicyInstance(String id) { PolicyInstance policyInstance = (PolicyInstance) mInstanceTable.get(id); return (policyInstance == null) ? null : policyInstance.getRule(); } public Vector getPolicyInstanceConfig(String id) { PolicyInstance policyInstance = (PolicyInstance) mInstanceTable.get(id); if (policyInstance == null) return null; Vector v = policyInstance.getRule().getInstanceParams(); if (v == null) v = new Vector(); v.insertElementAt(PROP_IMPL_NAME + "=" + policyInstance.getImplId(), 0); v.insertElementAt(PROP_ENABLE + "=" + policyInstance.isActive(), 1); String predicate = " "; if (policyInstance.getRule().getPredicate() != null) predicate = policyInstance.getRule().getPredicate().toString(); v.insertElementAt(PROP_PREDICATE + "=" + predicate, 2); return v; } public void deletePolicyInstance(String id) throws EBaseException { // If the rule is a persistent rule, we can't delete it. if (mUndeletablePolicies.containsKey(id)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_CANT_DELETE_PERSISTENT_POLICY", id)); // First check if the instance is present. PolicyInstance instance = (PolicyInstance) mInstanceTable.get(id); if (instance == null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_INSTANCE", id)); IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); IConfigStore instanceStore = policyStore.getSubStore(PROP_RULE); instanceStore.removeSubStore(id); // Remove the rulename from the rder list int index = mPolicyOrder.indexOf(id); mPolicyOrder.removeElement(id); // Now change the ordering in the config file. policyStore.put(PROP_ORDER, getRuleOrderString(mPolicyOrder)); // Commit changes to file. try { mGlobalStore.commit(true); } catch (Exception e) { // Put the rule back in the rule order vector. mPolicyOrder.insertElementAt(id, index); Debug.printStackTrace(e); String[] params = {"instance", id}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DELETING_POLICY_ERROR", params)); } IPolicyRule rule = instance.getRule(); if (rule instanceof IEnrollmentPolicy) mEnrollmentRules.removeRule(id); if (rule instanceof IRenewalPolicy) mRenewalRules.removeRule(id); if (rule instanceof IRevocationPolicy) mRevocationRules.removeRule(id); if (rule instanceof IKeyRecoveryPolicy) mKeyRecoveryRules.removeRule(id); if (rule instanceof IKeyArchivalPolicy) mKeyArchivalRules.removeRule(id); // Delete the instance mInstanceTable.remove(id); } public void addPolicyInstance(String id, Hashtable ht) throws EBaseException { // The instance id should be unique if (getPolicyInstance(id) != null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_DUPLICATE_INST_ID", id)); // There should be an implmentation for this rule. String implName = (String) ht.get(IPolicyRule.PROP_IMPLNAME); // See if there is an implementation with this name. IPolicyRule rule = getPolicyImpl(implName); if (rule == null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_NO_POLICY_IMPL", implName)); // Prepare config file entries. IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); IConfigStore instanceStore = policyStore.getSubStore(PROP_RULE); IConfigStore newStore = instanceStore.makeSubStore(id); for (Enumeration keys = ht.keys(); keys.hasMoreElements();) { String key = (String) keys.nextElement(); String val = (String) ht.get(key); newStore.put(key, val); } // Set the order string. policyStore.put(PROP_ORDER, getRuleOrderString(mPolicyOrder, id)); // Try to initialize this rule. rule.init(this, newStore); // Add the rule to the table. String enabledStr = (String) ht.get(IPolicyRule.PROP_ENABLE); boolean active = false; if (enabledStr == null || enabledStr.trim().length() == 0 || enabledStr.equalsIgnoreCase("true")) active = true; // Set the predicate if any present on the rule. String predicate = ((String) ht.get(IPolicyRule.PROP_PREDICATE)).trim(); IExpression exp = null; if (predicate.trim().length() > 0) exp = PolicyPredicateParser.parse(predicate.trim()); rule.setPredicate(exp); // Store the changes in the file. try { mGlobalStore.commit(true); } catch (Exception e) { String[] params = {"instance", id}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_ADDING_POLICY_ERROR", params)); } // Add the rule to the instance table. PolicyInstance policyInst = new PolicyInstance(id, implName, rule, active); mInstanceTable.put(id, policyInst); // Add the rule to the end of order table. mPolicyOrder.addElement(id); // If the rule is not active, return. if (!active) return; addRule(id, rule); } public void modifyPolicyInstance(String id, Hashtable ht) throws EBaseException { // The instance id should be there already PolicyInstance policyInstance = (PolicyInstance) mInstanceTable.get(id); if (policyInstance == null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_INSTANCE", id)); IPolicyRule rule = policyInstance.getRule(); // The impl id shouldn't change String implId = (String) ht.get(IPolicyRule.PROP_IMPLNAME); if (!implId.equals(policyInstance.getImplId())) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_IMPLCHANGE_ERROR", id)); // Make a new rule instance IPolicyRule newRule = getPolicyImpl(implId); if (newRule == null) // Can't happen, but just in case.. throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_IMPL", implId)); // Try to init this rule. IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); IConfigStore instanceStore = policyStore.getSubStore(PROP_RULE); IConfigStore oldStore = instanceStore.getSubStore(id); IConfigStore newStore = new PropConfigStore(id); // See if the rule is disabled. String enabledStr = (String) ht.get(IPolicyRule.PROP_ENABLE); boolean active = false; if (enabledStr == null || enabledStr.trim().length() == 0 || enabledStr.equalsIgnoreCase("true")) active = true; // Set the predicate expression. String predicate = ((String) ht.get(IPolicyRule.PROP_PREDICATE)).trim(); IExpression exp = null; if (predicate.trim().length() > 0) exp = PolicyPredicateParser.parse(predicate.trim()); // See if this a persistent rule. if (mUndeletablePolicies.containsKey(id)) { // A persistent rule can't be disabled. if (!active) { throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_INACTIVE", id)); } IExpression defPred = (IExpression) mUndeletablePolicies.get(id); if (defPred == SimpleExpression.NULL_EXPRESSION) defPred = null; if (exp == null && defPred != null) { String[] params = {id, defPred.toString(), "null" }; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } else if (exp != null && defPred == null) { String[] params = {id, "null", exp.toString()}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } else if (exp != null && defPred != null) { if (!defPred.toString().equals(exp.toString())) { String[] params = {id, defPred.toString(), exp.toString() }; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } } } // Predicate for the persistent rule can't be changed. ht.put(IPolicyRule.PROP_ENABLE, String.valueOf(active)); // put old config store parameters first. for (Enumeration oldkeys = oldStore.keys(); oldkeys.hasMoreElements();) { String k = (String) oldkeys.nextElement(); String v = (String) oldStore.getString(k); newStore.put(k, v); } // put modified params. for (Enumeration newkeys = ht.keys(); newkeys.hasMoreElements();) { String k = (String) newkeys.nextElement(); String v = (String) ht.get(k); Debug.trace("newstore key " + k + "=" + v); if (v != null) { if (!k.equals(Constants.OP_TYPE) && !k.equals(Constants.OP_SCOPE) && !k.equals(Constants.RS_ID) && !k.equals("RULENAME")) { Debug.trace("newstore.put(" + k + "=" + v + ")"); newStore.put(k, v); } } } // include impl default params in case we missed any. /* for (Enumeration keys = ht.keys(); keys.hasMoreElements();) { String key = (String)keys.nextElement(); String val = (String)ht.get(key); newStore.put(key, val); } */ // Try to initialize this rule. newRule.init(this, newStore); // If we are successfully initialized, replace the rule // instance policyInstance.setRule(newRule); policyInstance.setActive(active); // Set the predicate expression. if (exp != null) newRule.setPredicate(exp); // Store the changes in the file. try { for (Enumeration e = newStore.keys(); e.hasMoreElements();) { String key = (String) e.nextElement(); if (key != null) { Debug.trace( "oldstore.put(" + key + "," + (String) newStore.getString(key) + ")"); oldStore.put(key, (String) newStore.getString(key)); } } mGlobalStore.commit(true); } catch (Exception e) { String[] params = {"instance", id}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_ADDING_POLICY_ERROR", params)); } // If rule is disabled, we need to remove it from the // policy set. if (!active) { if (rule instanceof IEnrollmentPolicy) mEnrollmentRules.removeRule(id); if (rule instanceof IRenewalPolicy) mRenewalRules.removeRule(id); if (rule instanceof IRevocationPolicy) mRevocationRules.removeRule(id); if (rule instanceof IKeyRecoveryPolicy) mKeyRecoveryRules.removeRule(id); if (rule instanceof IKeyArchivalPolicy) mKeyArchivalRules.removeRule(id); } else // replace the rule { if (rule instanceof IEnrollmentPolicy) mEnrollmentRules.replaceRule(id, newRule); if (rule instanceof IRenewalPolicy) mRenewalRules.replaceRule(id, newRule); if (rule instanceof IRevocationPolicy) mRevocationRules.replaceRule(id, newRule); if (rule instanceof IKeyRecoveryPolicy) mKeyRecoveryRules.replaceRule(id, newRule); if (rule instanceof IKeyArchivalPolicy) mKeyArchivalRules.replaceRule(id, newRule); } } public synchronized void changePolicyInstanceOrdering( String policyOrderStr) throws EBaseException { Vector policyOrder = new Vector(); StringTokenizer tokens = new StringTokenizer(policyOrderStr, ","); // Get all the elements while (tokens.hasMoreTokens()) { String instanceId = tokens.nextToken().trim(); // Check if we have that instance configured. if (!mInstanceTable.containsKey(instanceId)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_INSTANCE", instanceId)); policyOrder.addElement(instanceId); } // Now enforce the new ordering // First if the order is the same as what we have, // return. if (policyOrder.size() == mPolicyOrder.size()) { if (areSameVectors(policyOrder, mPolicyOrder)) return; } PolicySet enrollmentRules = new PolicySet("EnrollmentRules"); PolicySet renewalRules = new PolicySet("RenewalRules"); PolicySet revocationRules = new PolicySet("RevocationRules"); PolicySet keyRecoveryRules = new PolicySet("KeyRecoveryRules"); PolicySet keyArchivalRules = new PolicySet("KeyArchivalRules"); // add system default rules first. try { for (int i = 0; i < mSystemDefaults.length; i++) { String defRuleName = mSystemDefaults[i].substring( mSystemDefaults[i].lastIndexOf('.') + 1); IPolicyRule defRule = (IPolicyRule) Class.forName(mSystemDefaults[i]).newInstance(); IConfigStore ruleConfig = mConfig.getSubStore(PROP_DEF_POLICIES + "." + defRuleName); defRule.init(this, ruleConfig); if (defRule instanceof IEnrollmentPolicy) enrollmentRules.addRule(defRuleName, defRule); else if (defRule instanceof IRenewalPolicy) renewalRules.addRule(defRuleName, defRule); else if (defRule instanceof IRevocationPolicy) revocationRules.addRule(defRuleName, defRule); else if (defRule instanceof IKeyRecoveryPolicy) keyRecoveryRules.addRule(defRuleName, defRule); else if (defRule instanceof IKeyArchivalPolicy) keyArchivalRules.addRule(defRuleName, defRule); // else ignore the darned rule. } } catch (Throwable e) { Debug.printStackTrace(e); EBaseException ex = new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", "Cannot create default policy rule. Error: " + e.getMessage())); mAuthority.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_POLICY_DEF_CREATE", e.toString())); throw ex; } // add rules specified in the new order. for (Enumeration enum1 = policyOrder.elements(); enum1.hasMoreElements();) { String instanceName = (String) enum1.nextElement(); PolicyInstance pInstance = (PolicyInstance) mInstanceTable.get(instanceName); if (!pInstance.isActive()) continue; // Add the rule to the policy set according to category if a // rule is enabled. IPolicyRule rule = pInstance.getRule(); if (rule instanceof IEnrollmentPolicy) enrollmentRules.addRule(instanceName, rule); else if (rule instanceof IRenewalPolicy) renewalRules.addRule(instanceName, rule); else if (rule instanceof IRevocationPolicy) revocationRules.addRule(instanceName, rule); else if (rule instanceof IKeyRecoveryPolicy) keyRecoveryRules.addRule(instanceName, rule); else if (rule instanceof IKeyArchivalPolicy) keyArchivalRules.addRule(instanceName, rule); // else ignore the darned rule. } mEnrollmentRules = enrollmentRules; mRenewalRules = renewalRules; mRevocationRules = revocationRules; mKeyRecoveryRules = keyRecoveryRules; mKeyArchivalRules = keyArchivalRules; mPolicyOrder = policyOrder; // Now change the ordering in the config file. IConfigStore policyStore = mGlobalStore.getSubStore(getPolicySubstoreId()); policyStore.put(PROP_ORDER, policyOrderStr); // committing try { mGlobalStore.commit(true); } catch (Exception ex) { Debug.printStackTrace(ex); throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_ORDER_ERROR", policyOrderStr)); } } private boolean areSameVectors(Vector v1, Vector v2) { if (v1.size() != v2.size()) return false; int size = v1.size(); int i = 0; for (; i < size; i++) if (v2.indexOf(v1.elementAt(i)) != i) break; return (i == size ? true : false); } private String getRuleOrderString(Vector rules) { StringBuffer sb = new StringBuffer(); for (Enumeration e = rules.elements(); e.hasMoreElements();) { sb.append((String) e.nextElement()); sb.append(","); } if (sb.length() > 0) sb.setLength(sb.length() - 1); return new String(sb); } private String getRuleOrderString(Vector rules, String newRule) { String currentRules = getRuleOrderString(rules); if (currentRules == null || currentRules.length() == 0) return newRule; else return currentRules + "," + newRule; } /** * Initializes the default system policies. Currently there is only * one policy - ManualAuthentication. More may be added later on. * * The default policies may be disabled - for example to over-ride * agent approval for testing the system by setting the following * property in the config file: * * .Policy.systemPolicies.enable=false * * By default the value for this property is true. * * Users can over-ride the default system policies by listing their * 'custom' system policies under the following property: * * .Policy.systemPolicies=, * * * There can only be one instance of the system policy in the system * and will apply to all requests, and hence predicates are not used * for a system policy. Due to the same reason, these properties are * not configurable using the Console. * * A System policy may read config properties from a subtree under * .Policy.systemPolicies.. An example is * ra.Policy.systemPolicies.ManualAuthentication.param1=value */ private void initSystemPolicies(IConfigStore mConfig) throws EBaseException { // If system policies are disabled, return. No Deferral of // requests may be done. String enable = mConfig.getString(PROP_DEF_POLICIES + "." + PROP_ENABLE, "true").trim(); if (enable.equalsIgnoreCase("false")) { mSystemDefaults = DEF_POLICIES; return; } // Load default policies that are always present. String configuredDefaults = mConfig.getString(PROP_DEF_POLICIES, null); if (configuredDefaults == null || configuredDefaults.trim().length() == 0) mSystemDefaults = DEF_POLICIES; else { Vector rules = new Vector(); StringTokenizer tokenizer = new StringTokenizer(configuredDefaults.trim(), ","); while (tokenizer.hasMoreTokens()) { String rule = tokenizer.nextToken().trim(); rules.addElement(rule); } if (rules.size() > 0) { mSystemDefaults = new String[rules.size()]; rules.copyInto(mSystemDefaults); } else mSystemDefaults = DEF_POLICIES; } // Now Initialize the rules. These defaults have only one // instance and the rule name is the name of the class itself. // Any configuration parameters required could be read from // .Policy.default.RuleName. for (int i = 0; i < mSystemDefaults.length; i++) { // Load the class and make an instance. // Verify if the class is a valid implementation of // IPolicyRule String ruleName = null; try { Object o = Class.forName(mSystemDefaults[i]).newInstance(); if (!(o instanceof IEnrollmentPolicy) && !(o instanceof IRenewalPolicy) && !(o instanceof IRevocationPolicy) && !(o instanceof IKeyRecoveryPolicy) && !(o instanceof IKeyArchivalPolicy)) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_IMPL", mSystemDefaults[i])); IPolicyRule rule = (IPolicyRule) o; // Initialize the rule. ruleName = mSystemDefaults[i].substring( mSystemDefaults[i].lastIndexOf('.') + 1); IConfigStore ruleConfig = mConfig.getSubStore( PROP_DEF_POLICIES + "." + ruleName); rule.init(this, ruleConfig); // Add the rule to the appropriate PolicySet. addRule(ruleName, rule); } catch (EBaseException e) { throw e; } catch (Exception e) { Debug.printStackTrace(e); throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_NO_POLICY_IMPL", ruleName)); } } } /** * Read list of undeletable policies if any configured in the * system. * * These are required to protect the system from being misconfigured * to the point that the requests wouldn't serialize or certain * fields in the certificate(s) being checked will go unchecked * ..etc. * * For now the following policies are undeletable: * * DirAuthRule: This is a default DirectoryAuthentication policy * for user certificates that interprets directory * credentials. The presence of this policy is needed * if the OOTB DirectoryAuthentication-based automatic * certificate issuance is supported. * * DefaultUserNameRule: This policy verifies/sets subjectDn for user * certificates. * * DefaultServerNameRule: This policy verifies/sets subjectDn for * server certificates. * * DefaultValidityRule: Verifies/sets validty for all certificates. * * DefaultRenewalValidityRule: Verifies/sets validity for certs being * renewed. * * The 'undeletables' cannot be deleted from the config file, nor * can the be disabled. If any predicates are associated with them * the predicates can't be changed either. But, other config parameters * such as maxValidity, renewalInterval ..etc can be changed to suit * local policy requirements. * * During start up the policy processor will verify if the undeletables * are present, and that they are enabled and that their predicates are * not changed. * * The rules mentioned above are currently hard coded. If these need to * read from the config file, the 'undeletables' can be configured as * as follows: * * .Policy.undeletablePolicies= * Example: * ra.Policy.undeletablePolicies=DirAuthRule, DefaultUserNameRule, DefaultServerNameRule, DefaultValidityRule, DefaultRenewalValidityRule * * The predicates if any associated with them may be configured as * follows: * .Policy.undeletablePolicies.DirAuthRule.predicate= certType == client. * * where subsystemId is ra or ca. * * If the undeletables are configured in the file,the configured entries * take precedence over the hardcoded ones in this file. If you are * configuring them in the file, please remember to configure the * predicates if applicable. * * During policy configuration from MCC, the policy processor will not * let you delete an 'undeletable', nor will it let you disable it. * You will not be able to change the predicate either. Other parameters * can be configured as needed. * * If a particular rule needs to be removed from the 'undeletables', * either remove it from the hard coded list above, or configure the * rules required rules only via the config file. The former needs * recompilation of the source. The later is flexible to be able to * make any rule an 'undeletable' or nor an 'undeletable'. * * Example: We want to use only manual forms for enrollment. * We do n't need to burn in DirAuthRule. We need to configure all * other rules except the DirAuthRule as follows: * * ra.Policy.undeletablePolicies = DefaultUserNameRule, DefaultServerNameRule, DefaultValidityRule, DefaultRenewalValidityRule * * The following predicates are necessary: * * ra.Policy.undeletablePolicies.DefaultUserNameRule.predicate = certType == client * ra.Policy.undeletablePolicies.DefaultServerNameRule.predicate = certType == server * * The other two rules do not have any predicates. */ private void initUndeletablePolicies(IConfigStore mConfig) throws EBaseException { // Read undeletable policies if any configured. String configuredUndeletables = mConfig.getString(PROP_UNDELETABLE_POLICIES, null); if (configuredUndeletables == null || configuredUndeletables.trim().length() == 0) { mUndeletablePolicies = DEF_UNDELETABLE_POLICIES; return; } Vector rules = new Vector(); StringTokenizer tokenizer = new StringTokenizer(configuredUndeletables.trim(), ","); while (tokenizer.hasMoreTokens()) { String rule = tokenizer.nextToken().trim(); rules.addElement(rule); } if (rules.size() == 0) { mUndeletablePolicies = DEF_UNDELETABLE_POLICIES; return; } // For each rule read from the config file, see if any // predicate is set. mUndeletablePolicies = new Hashtable(); for (Enumeration e = rules.elements(); e.hasMoreElements();) { String urn = (String) e.nextElement(); // See if there is predicate in the file String pred = mConfig.getString(PROP_UNDELETABLE_POLICIES + "." + urn + "." + PROP_PREDICATE, null); IExpression exp = SimpleExpression.NULL_EXPRESSION; if (pred != null) exp = PolicyPredicateParser.parse(pred); mUndeletablePolicies.put(urn, exp); } } private void addRule(String ruleName, IPolicyRule rule) { if (rule instanceof IEnrollmentPolicy) mEnrollmentRules.addRule(ruleName, rule); if (rule instanceof IRenewalPolicy) mRenewalRules.addRule(ruleName, rule); if (rule instanceof IRevocationPolicy) mRevocationRules.addRule(ruleName, rule); if (rule instanceof IKeyRecoveryPolicy) mKeyRecoveryRules.addRule(ruleName, rule); if (rule instanceof IKeyArchivalPolicy) mKeyArchivalRules.addRule(ruleName, rule); } private boolean isSystemDefaultPolicy(String clPath) { boolean ret = false; if (mSystemDefaults == null) return false; for (int i = 0; i < mSystemDefaults.length; i++) { if (clPath.equals(mSystemDefaults[i])) { ret = true; break; } } return ret; } private void verifyDefaultPolicyConfig() throws EPolicyException { // For each policy in undeletable list make sure that // the policy is present, is not disabled and its predicate // is not tampered with. for (Enumeration e = mUndeletablePolicies.keys(); e.hasMoreElements();) { String urn = (String) e.nextElement(); // See if the rule is in the instance table. PolicyInstance inst = (PolicyInstance) mInstanceTable.get(urn); if (inst == null) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_MISSING_PERSISTENT_RULE", urn)); // See if the instance is disabled. if (!inst.isActive()) throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_INACTIVE", urn)); // See if the predicated is misconfigured. IExpression defPred = (IExpression) mUndeletablePolicies.get(urn); // We used SimpleExpression.NULL_EXPRESSION to indicate a null. if (defPred == SimpleExpression.NULL_EXPRESSION) defPred = null; IExpression confPred = inst.getRule().getPredicate(); if (defPred == null && confPred != null) { String[] params = {urn, "null", confPred.toString()}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } else if (defPred != null && confPred == null) { String[] params = {urn, defPred.toString(), "null"}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } else if (defPred != null && confPred != null) { if (!defPred.toString().equals(confPred.toString())) { String[] params = {urn, defPred.toString(), confPred.toString()}; throw new EPolicyException( CMS.getUserMessage("CMS_POLICY_PERSISTENT_RULE_MISCONFIG", params)); } } } } } /** * Class to keep track of various configurable implementations. */ class RegisteredPolicy { String mId; String mClPath; public RegisteredPolicy (String id, String clPath) { if (id == null || clPath == null) throw new AssertionException("Policy id or classpath can't be null"); mId = id; mClPath = clPath; } public String getClassPath() { return mClPath; } public String getId() { return mId; } } class PolicyInstance { String mInstanceId; String mImplId; IPolicyRule mRule; boolean mIsEnabled; public PolicyInstance(String instanceId, String implId, IPolicyRule rule, boolean isEnabled) { mInstanceId = instanceId; mImplId = implId; mRule = rule; mIsEnabled = isEnabled; } public String getInstanceId() { return mInstanceId; } public String getImplId() { return mImplId; } public String getRuleInfo() { String enabled = mIsEnabled ? "enabled" : "disabled"; return mInstanceId + ";" + mImplId + ";visible;" + enabled; } public IPolicyRule getRule() { return mRule; } public boolean isInstanceOf(String implId) { return mImplId.equals(implId); } public boolean isActive() { return mIsEnabled; } public void setActive(boolean stat) { mIsEnabled = stat; } public void setRule(IPolicyRule newRule) { mRule = newRule; } }