From ftweedal at redhat.com Tue Dec 1 04:56:51 2015 From: ftweedal at redhat.com (Fraser Tweedale) Date: Tue, 1 Dec 2015 14:56:51 +1000 Subject: [Pki-devel] [PATCH] 0057..0061 LDAPProfileSubsystem concurrency fixes Message-ID: <20151201045650.GM23644@dhcp-40-8.bne.redhat.com> The attached patches resolve concurrency issues in the LDAPProfileSubsystem (which conducts its LDAP persisent search in background thread). Ticket: https://fedorahosted.org/pki/ticket/1700 Thanks, Fraser -------------- next part -------------- From 9b3408e446811df06ee83fc4c8078a21bc8a1063 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Fri, 27 Nov 2015 14:31:18 +1100 Subject: [PATCH 57/61] Extract LDAPControl search function to LDAPUtil --- .../netscape/cmscore/profile/LDAPProfileSubsystem.java | 15 ++++----------- base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java index cc2e43dfa2e9b1a4eb3bdb53eeb3ace6cfd1d6ac..7be70dff1315c150422be303d7be50fb2fb245f0 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java @@ -25,7 +25,6 @@ import java.util.LinkedHashMap; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPConnection; -import netscape.ldap.LDAPControl; import netscape.ldap.LDAPDN; import netscape.ldap.LDAPEntry; import netscape.ldap.LDAPException; @@ -47,6 +46,7 @@ import com.netscape.certsrv.profile.IProfileSubsystem; import com.netscape.certsrv.registry.IPluginInfo; import com.netscape.certsrv.registry.IPluginRegistry; import com.netscape.cmscore.base.LDAPConfigStore; +import com.netscape.cmsutil.ldap.LDAPUtil; public class LDAPProfileSubsystem extends AbstractProfileSubsystem @@ -290,16 +290,9 @@ public class LDAPProfileSubsystem null, false, cons); while (!stopped && results.hasMoreElements()) { LDAPEntry entry = results.next(); - LDAPEntryChangeControl changeControl = null; - LDAPControl[] changeControls = results.getResponseControls(); - if (changeControls != null) { - for (LDAPControl control : changeControls) { - if (control instanceof LDAPEntryChangeControl) { - changeControl = (LDAPEntryChangeControl) control; - break; - } - } - } + LDAPEntryChangeControl changeControl = (LDAPEntryChangeControl) + LDAPUtil.getControl( + LDAPEntryChangeControl.class, results.getResponseControls()); CMS.debug("Profile change monitor: Processed change controls."); if (changeControl != null) { int changeType = changeControl.getChangeType(); diff --git a/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java index b02ffee787121b252e9f97e3c0358a200c8940ac..f8162235d191763eb17d798096804b7ba55a9840 100644 --- a/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java +++ b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java @@ -18,11 +18,13 @@ package com.netscape.cmsutil.ldap; import java.io.IOException; +import java.lang.Class; import java.util.ArrayList; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPAttributeSet; import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPControl; import netscape.ldap.LDAPEntry; import netscape.ldap.LDAPException; import netscape.ldap.LDAPModification; @@ -145,4 +147,20 @@ public class LDAPUtil { } } } + + /** + * Get the control of the specified class from the array of controls. + * + * @return the LDAPControl, or null if not found + */ + public static LDAPControl getControl( + Class cls, LDAPControl[] controls) { + if (controls != null) { + for (LDAPControl control : controls) { + if (cls.isInstance(control)) + return control; + } + } + return null; + } } -- 2.4.3 -------------- next part -------------- From 9b3c2abb8f7c1089b4653dd2fee8d0c9f557dde6 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Mon, 30 Nov 2015 14:01:38 +1100 Subject: [PATCH 58/61] Add LDAPPostReadControl class The LDAPPostReadControl can be used to read an entry after perfoming an add, modify or modrdn, giving atomic access to operational attributes. Part of: https://fedorahosted.org/pki/ticket/1700 --- .../netscape/cmsutil/ldap/LDAPPostReadControl.java | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 base/util/src/com/netscape/cmsutil/ldap/LDAPPostReadControl.java diff --git a/base/util/src/com/netscape/cmsutil/ldap/LDAPPostReadControl.java b/base/util/src/com/netscape/cmsutil/ldap/LDAPPostReadControl.java new file mode 100644 index 0000000000000000000000000000000000000000..501c476ef87eeac6bb5551b246466a5fe62f764e --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/ldap/LDAPPostReadControl.java @@ -0,0 +1,109 @@ +// --- 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) 2015 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.ldap; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPControl; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; +import netscape.ldap.ber.stream.BERElement; +import netscape.ldap.ber.stream.BEROctetString; +import netscape.ldap.ber.stream.BERSequence; +import netscape.ldap.ber.stream.BERTag; +import netscape.ldap.client.JDAPBERTagDecoder; + +public class LDAPPostReadControl extends LDAPControl { + + private static final long serialVersionUID = -3988578305868188089L; + + public final static String OID_POSTREAD = "1.3.6.1.1.13.2"; + + private LDAPEntry entry = null; + + static { + try { + register(OID_POSTREAD, LDAPPostReadControl.class); + } catch (Throwable e) { + } + } + + /** + * Response control constructor. + * + * This is called automatically by response processing code, + * should not need to be called by user. + */ + public LDAPPostReadControl(String oid, boolean critical, byte[] value) + throws LDAPException, IOException { + super(OID_POSTREAD, critical, value); + if (!oid.equals(OID_POSTREAD)) { + throw new LDAPException( + "oid must be LDAPPostReadControl.OID_POSTREAD", + LDAPException.PARAM_ERROR); + } + + ByteArrayInputStream in = new ByteArrayInputStream(value); + int[] numRead = new int[1]; + BERTag tag = (BERTag) + BERElement.getElement(new JDAPBERTagDecoder(), in, numRead); + BERSequence seq = (BERSequence)tag.getValue(); + + BEROctetString name = (BEROctetString)seq.elementAt(0); + byte buf[] = name.getValue(); + String dn = null; + if (buf != null) { + try { + dn = new String(buf, "UTF8"); + } catch(Throwable e) { + } + } + + BERSequence attrs = (BERSequence)seq.elementAt(1); + LDAPAttributeSet attrSet = new LDAPAttributeSet(); + for (int i = 0; i < attrs.size(); i++) { + attrSet.add(new LDAPAttribute(attrs.elementAt(i))); + } + + entry = new LDAPEntry(dn, attrSet); + } + + /** + * Request control constructor. + */ + public LDAPPostReadControl(boolean critical, String[] attrs) { + super(OID_POSTREAD, critical, null); + BERSequence ber_attrs = new BERSequence(); + for (int i = 0; i < attrs.length; i++) { + ber_attrs.addElement(new BEROctetString(attrs[i])); + } + m_value = flattenBER(ber_attrs); + } + + /** + * Get the entry from the control. + * + * Returns null if constructed as a request control. + */ + public LDAPEntry getEntry() { + return entry; + } +}; -- 2.4.3 -------------- next part -------------- From e585953a1c8dc32b74ba1a1293286e2d555114eb Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Mon, 30 Nov 2015 14:04:08 +1100 Subject: [PATCH 59/61] Avoid profile race conditions by tracking entryUSN Avoid race conditions in the LDAPProfileSubsystem by tracking the most recently known entryUSN of profiles' LDAP entries. As part of this change, add the commitProfile method to the IProfileSubsystem interface, remove commit behaviour from the enableProfile and disableProfile methods and update ProfileService and ProfileApproveServlet to commit the profile (using the commitProfile method) where needed. Part of: https://fedorahosted.org/pki/ticket/1700 --- .../dogtagpki/server/ca/rest/ProfileService.java | 12 +++-- .../certsrv/profile/IProfileSubsystem.java | 5 ++ .../cms/servlet/profile/ProfileApproveServlet.java | 3 ++ .../com/netscape/cmscore/base/LDAPConfigStore.java | 57 ++++++++++++++++------ .../cmscore/profile/AbstractProfileSubsystem.java | 15 ++++-- .../cmscore/profile/LDAPProfileSubsystem.java | 56 ++++++++++++++++++--- 6 files changed, 118 insertions(+), 30 deletions(-) diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java index 488dd5ab960fd45fa3dad0dd83398b4317f2cb4f..807c3f98bd4df57d33b8e427b5d3f59b522c2c0b 100644 --- a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java +++ b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java @@ -419,6 +419,7 @@ public class ProfileService extends PKIService implements ProfileResource { } try { ps.enableProfile(profileId, principal.getName()); + ps.commitProfile(profileId); auditProfileChangeState(profileId, "approve", ILogger.SUCCESS); } catch (EProfileException e) { CMS.debug("modifyProfileState: error enabling profile. " + e); @@ -436,6 +437,7 @@ public class ProfileService extends PKIService implements ProfileResource { if (ps.checkOwner()) { if (ps.getProfileEnableBy(profileId).equals(userid)) { ps.disableProfile(profileId); + ps.commitProfile(profileId); auditProfileChangeState(profileId, "disapprove", ILogger.SUCCESS); } else { auditProfileChangeState(profileId, "disapprove", ILogger.FAILURE); @@ -444,6 +446,7 @@ public class ProfileService extends PKIService implements ProfileResource { } } else { ps.disableProfile(profileId); + ps.commitProfile(profileId); auditProfileChangeState(profileId, "disapprove", ILogger.SUCCESS); } } catch (EProfileException e) { @@ -493,7 +496,7 @@ public class ProfileService extends PKIService implements ProfileResource { profile.setName(getLocale(headers), data.getName()); profile.setDescription(getLocale(headers), data.getDescription()); profile.setVisible(data.isVisible()); - profile.getConfigStore().commit(false); + ps.commitProfile(profileId); if (profile instanceof IProfileEx) { // populates profile specific plugins such as @@ -606,7 +609,8 @@ public class ProfileService extends PKIService implements ProfileResource { // no error thrown, proceed with profile creation profile = ps.createProfile(profileId, classId, className); profile.getConfigStore().load(new ByteArrayInputStream(data)); - ps.disableProfile(profileId); // also commits + ps.disableProfile(profileId); + ps.commitProfile(profileId); auditProfileChange( ScopeDef.SC_PROFILE_RULES, @@ -740,7 +744,7 @@ public class ProfileService extends PKIService implements ProfileResource { // no error thrown, so commit updated profile config profile.getConfigStore().load(new ByteArrayInputStream(data)); ps.disableProfile(profileId); - profile.getConfigStore().commit(false); + ps.commitProfile(profileId); return createOKResponse(data); } catch (EBaseException | IOException e) { @@ -817,7 +821,7 @@ public class ProfileService extends PKIService implements ProfileResource { populateProfileInputs(data, profile); populateProfileOutputs(data, profile); populateProfilePolicies(data, profile); - profile.getConfigStore().commit(false); + ps.commitProfile(profileId); } catch (EBaseException e) { CMS.debug("changeProfileData: Error changing profile inputs/outputs/policies: " + e); e.printStackTrace(); diff --git a/base/common/src/com/netscape/certsrv/profile/IProfileSubsystem.java b/base/common/src/com/netscape/certsrv/profile/IProfileSubsystem.java index b7071fe7526132d7f9ff1945819f0d1f67c18719..b7b06b92b92bf74f9d7ce9fd504a9e99fdd4839c 100644 --- a/base/common/src/com/netscape/certsrv/profile/IProfileSubsystem.java +++ b/base/common/src/com/netscape/certsrv/profile/IProfileSubsystem.java @@ -94,6 +94,11 @@ public interface IProfileSubsystem extends ISubsystem { throws EProfileException; /** + * Commit a profile's underlying config store. + */ + public void commitProfile(String id) throws EProfileException; + + /** * Retrieves the id of the implementation of the given profile. * * @param id profile id diff --git a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileApproveServlet.java b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileApproveServlet.java index 7ae623f32eeae02290432e7e218ade93ce038213..89ba1bd8c785a745f0dd64a1e4be97626fd0e251 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileApproveServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileApproveServlet.java @@ -267,6 +267,7 @@ public class ProfileApproveServlet extends ProfileServlet { if (ps.checkOwner()) { if (ps.getProfileEnableBy(profileId).equals(userid)) { ps.disableProfile(profileId); + ps.commitProfile(profileId); } else { // only enableBy can disable profile args.set(ARG_ERROR_CODE, "1"); @@ -288,9 +289,11 @@ public class ProfileApproveServlet extends ProfileServlet { } } else { ps.disableProfile(profileId); + ps.commitProfile(profileId); } } else { ps.enableProfile(profileId, userid); + ps.commitProfile(profileId); } // store a message in the signed audit log file diff --git a/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java b/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java index b7b4ca46ee3e4cebfd169338dede3c9f64a45410..0b4ff707dddee6bd40447b85219f5a84edfe76db 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java +++ b/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java @@ -26,13 +26,17 @@ import java.util.Map; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPAttributeSet; import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPConstraints; +import netscape.ldap.LDAPControl; import netscape.ldap.LDAPEntry; import netscape.ldap.LDAPException; import netscape.ldap.LDAPModification; -import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ldap.ELdapException; import com.netscape.certsrv.ldap.ILdapConnFactory; +import com.netscape.cmsutil.ldap.LDAPPostReadControl; +import com.netscape.cmsutil.ldap.LDAPUtil; /** * LDAPConfigStore: @@ -65,8 +69,6 @@ public class LDAPConfigStore extends PropConfigStore implements IConfigStore { * @param attr Name of attribute containing config store * @param createAttrs Set of initial attributes if creating the entry. Should * contain cn, objectclass and possibly other attributes. - * - * @exception EBaseException failed to create file configuration */ public LDAPConfigStore( ILdapConnFactory dbFactory, @@ -102,7 +104,17 @@ public class LDAPConfigStore extends PropConfigStore implements IConfigStore { * * @param createBackup Ignored. */ - public void commit(boolean createBackup) throws EBaseException { + public void commit(boolean createBackup) throws ELdapException { + String[] attrs = {}; + commitReturn(createBackup, attrs); + } + + /** + * This version of commit also returns the post-read entry that + * the change resulted in. + */ + public LDAPEntry commitReturn(boolean createBackup, String[] attrs) + throws ELdapException { ByteArrayOutputStream data = new ByteArrayOutputStream(); save(data, null); @@ -110,26 +122,37 @@ public class LDAPConfigStore extends PropConfigStore implements IConfigStore { LDAPConnection conn = dbFactory.getConn(); + LDAPConstraints cons = new LDAPConstraints(); + cons.setServerControls(new LDAPPostReadControl(true, attrs)); + + LDAPControl[] responseControls; + // first attempt to modify; if modification fails (due // to no such object), try and add the entry instead. try { try { - commitModify(conn, configAttr); + commitModify(conn, configAttr, cons); } catch (LDAPException e) { if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) { - commitAdd(conn, configAttr); + commitAdd(conn, configAttr, cons); } else { throw e; } } + responseControls = conn.getResponseControls(); } catch (LDAPException e) { - throw new EBaseException( + throw new ELdapException( "Error writing LDAPConfigStore '" + dn + "': " + e.toString() ); } finally { dbFactory.returnConn(conn); } + + LDAPPostReadControl control = (LDAPPostReadControl) + LDAPUtil.getControl(LDAPPostReadControl.class, responseControls); + + return control.getEntry(); } /** @@ -139,12 +162,14 @@ public class LDAPConfigStore extends PropConfigStore implements IConfigStore { * @param configAttr Config store attribute. * @return true on success, false if the entry does not exist. */ - private void commitModify(LDAPConnection conn, LDAPAttribute configAttr) - throws LDAPException - { + private void commitModify( + LDAPConnection conn, + LDAPAttribute configAttr, + LDAPConstraints cons) + throws LDAPException { LDAPModification ldapMod = new LDAPModification(LDAPModification.REPLACE, configAttr); - conn.modify(dn, ldapMod); + conn.modify(dn, ldapMod, cons); } /** @@ -154,12 +179,14 @@ public class LDAPConfigStore extends PropConfigStore implements IConfigStore { * @param configAttr Config store attribute. * @return true on success, false if the entry already exists. */ - private void commitAdd(LDAPConnection conn, LDAPAttribute configAttr) - throws LDAPException - { + private void commitAdd( + LDAPConnection conn, + LDAPAttribute configAttr, + LDAPConstraints cons) + throws LDAPException { LDAPAttributeSet attrSet = new LDAPAttributeSet(createAttrs); attrSet.add(configAttr); LDAPEntry ldapEntry = new LDAPEntry(dn, attrSet); - conn.add(ldapEntry); + conn.add(ldapEntry, cons); } } diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java index cf5d77f191af93b05e71f0b1cce085a7d8161874..076e9c93e461f00e7a6dcde92f9fdd06d23a0283 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java @@ -95,10 +95,6 @@ public abstract class AbstractProfileSubsystem implements IProfileSubsystem { profile.getConfigStore().putString(PROP_ENABLE, "true"); profile.getConfigStore().putString(PROP_ENABLE_BY, enableBy); - try { - profile.getConfigStore().commit(false); - } catch (EBaseException e) { - } } /** @@ -117,9 +113,18 @@ public abstract class AbstractProfileSubsystem implements IProfileSubsystem { IProfile profile = mProfiles.get(id); profile.getConfigStore().putString(PROP_ENABLE, "false"); + } + + /** + * Commits a profile. + */ + public void commitProfile(String id) + throws EProfileException { try { - profile.getConfigStore().commit(false); + mProfiles.get(id).getConfigStore().commit(false); } catch (EBaseException e) { + throw new EProfileException( + "Failed to commit config store of profile '" + id + ": " + e); } } diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java index 7be70dff1315c150422be303d7be50fb2fb245f0..b16a33fe25881956051e2f65a5a99b73f7a624b4 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java @@ -19,9 +19,9 @@ package com.netscape.cmscore.profile; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; +import java.util.TreeMap; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPConnection; @@ -58,6 +58,10 @@ public class LDAPProfileSubsystem private boolean stopped = false; private Thread monitor; + /* Map of profileId -> entryUSN for the most recent view + * of the profile entry that this instance has seen */ + private TreeMap entryUSNs; + /** * Initializes this subsystem with the given configuration * store. @@ -74,6 +78,7 @@ public class LDAPProfileSubsystem // (re)init member collections mProfiles = new LinkedHashMap(); mProfileClassIds = new Hashtable(); + entryUSNs = new TreeMap<>(); IConfigStore cs = CMS.getConfigStore(); IConfigStore dbCfg = cs.getSubStore("internaldb"); @@ -101,7 +106,7 @@ public class LDAPProfileSubsystem /** * Read the given LDAPEntry into the profile subsystem. */ - private void readProfile(LDAPEntry ldapProfile) { + private synchronized void readProfile(LDAPEntry ldapProfile) { IPluginRegistry registry = (IPluginRegistry) CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY); @@ -113,12 +118,24 @@ public class LDAPProfileSubsystem } profileId = LDAPDN.explodeDN(dn, true)[0]; + Integer newEntryUSN = new Integer( + ldapProfile.getAttribute("entryUSN").getStringValueArray()[0]); + CMS.debug("readProfile: new entryUSN = " + newEntryUSN); + + Integer knownEntryUSN = entryUSNs.get(profileId); + if (knownEntryUSN != null) { + CMS.debug("readProfile: known entryUSN = " + knownEntryUSN); + if (newEntryUSN <= knownEntryUSN) { + CMS.debug("readProfile: data is current"); + return; + } + } + String classId = (String) ldapProfile.getAttribute("classId").getStringValues().nextElement(); - Enumeration vals = - ldapProfile.getAttribute("certProfileConfig").getStringValues(); - InputStream data = new ByteArrayInputStream(vals.nextElement().getBytes()); + InputStream data = new ByteArrayInputStream( + ldapProfile.getAttribute("certProfileConfig").getByteValueArray()[0]); IPluginInfo info = registry.getPluginInfo("profile", classId); if (info == null) { @@ -127,6 +144,7 @@ public class LDAPProfileSubsystem try { CMS.debug("Start Profile Creation - " + profileId + " " + classId + " " + info.getClassName()); createProfile(profileId, classId, info.getClassName(), data); + entryUSNs.put(profileId, newEntryUSN); CMS.debug("Done Profile Creation - " + profileId); } catch (EProfileException e) { CMS.debug("Error creating profile '" + profileId + "'; skipping."); @@ -210,6 +228,29 @@ public class LDAPProfileSubsystem readProfile(entry); } + @Override + public synchronized void commitProfile(String id) throws EProfileException { + LDAPConfigStore cs = (LDAPConfigStore) mProfiles.get(id).getConfigStore(); + try { + String[] attrs = {"entryUSN"}; + LDAPEntry entry = cs.commitReturn(false, attrs); + + LDAPAttribute attr = null; + if (entry != null) + attr = entry.getAttribute("entryUSN"); + + Integer entryUSN = null; + if (attr != null) + entryUSN = new Integer(attr.getStringValueArray()[0]); + + entryUSNs.put(id, entryUSN); + CMS.debug("commitProfile: new entryUSN = " + entryUSN); + } catch (ELdapException e) { + throw new EProfileException( + "Failed to commit config store of profile '" + id + ": " + e); + } + } + /** * Forget a profile without deleting it from the database. * @@ -219,6 +260,7 @@ public class LDAPProfileSubsystem private void forgetProfile(String id) { mProfiles.remove(id); mProfileClassIds.remove(id); + entryUSNs.remove(id); } private void forgetProfile(LDAPEntry entry) { @@ -253,6 +295,7 @@ public class LDAPProfileSubsystem private void forgetAllProfiles() { mProfiles.clear(); mProfileClassIds.clear(); + entryUSNs.clear(); } /** @@ -285,9 +328,10 @@ public class LDAPProfileSubsystem cons.setServerControls(persistCtrl); cons.setBatchSize(1); cons.setServerTimeLimit(0 /* seconds */); + String[] attrs = {"*", "entryUSN"}; LDAPSearchResults results = conn.search( dn, LDAPConnection.SCOPE_ONE, "(objectclass=*)", - null, false, cons); + attrs, false, cons); while (!stopped && results.hasMoreElements()) { LDAPEntry entry = results.next(); LDAPEntryChangeControl changeControl = (LDAPEntryChangeControl) -- 2.4.3 -------------- next part -------------- From 5fe0116aaa649de28f5770fda079072b87fdf21c Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Mon, 30 Nov 2015 16:05:03 +1100 Subject: [PATCH 60/61] Handle LDAPProfileSubsystem delete-then-recreate races Deleting and then immediately recreating a profile can result in the new profile temporarily going missing, if the DELETE EntryChangeControl is processed after profile readdition. Handle this case by tracking the nsUniqueId of entries that are deleted by an LDAPProfileSubsystem and NOT (re-)forgetting the profile when the subsequent EntryChangeControl gets processed. Fixes: https://fedorahosted.org/pki/ticket/1700 --- .../cmscore/profile/LDAPProfileSubsystem.java | 112 +++++++++++++++++---- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java index b16a33fe25881956051e2f65a5a99b73f7a624b4..f48aea3918e6fc4a08c9bc90a433b834a29f35d3 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.TreeMap; +import java.util.TreeSet; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPConnection; @@ -62,6 +63,11 @@ public class LDAPProfileSubsystem * of the profile entry that this instance has seen */ private TreeMap entryUSNs; + private TreeMap nsUniqueIds; + + /* Set of nsUniqueIds of deleted entries */ + private TreeSet deletedNsUniqueIds; + /** * Initializes this subsystem with the given configuration * store. @@ -79,6 +85,8 @@ public class LDAPProfileSubsystem mProfiles = new LinkedHashMap(); mProfileClassIds = new Hashtable(); entryUSNs = new TreeMap<>(); + nsUniqueIds = new TreeMap<>(); + deletedNsUniqueIds = new TreeSet<>(); IConfigStore cs = CMS.getConfigStore(); IConfigStore dbCfg = cs.getSubStore("internaldb"); @@ -110,6 +118,14 @@ public class LDAPProfileSubsystem IPluginRegistry registry = (IPluginRegistry) CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY); + String nsUniqueId = + ldapProfile.getAttribute("nsUniqueId").getStringValueArray()[0]; + if (deletedNsUniqueIds.contains(nsUniqueId)) { + CMS.debug("readProfile: ignoring entry with nsUniqueId '" + + nsUniqueId + "' due to deletion"); + return; + } + String profileId = null; String dn = ldapProfile.getDN(); if (!dn.startsWith("cn=")) { @@ -145,6 +161,7 @@ public class LDAPProfileSubsystem CMS.debug("Start Profile Creation - " + profileId + " " + classId + " " + info.getClassName()); createProfile(profileId, classId, info.getClassName(), data); entryUSNs.put(profileId, newEntryUSN); + nsUniqueIds.put(profileId, nsUniqueId); CMS.debug("Done Profile Creation - " + profileId); } catch (EProfileException e) { CMS.debug("Error creating profile '" + profileId + "'; skipping."); @@ -192,7 +209,7 @@ public class LDAPProfileSubsystem } } - public void deleteProfile(String id) throws EProfileException { + public synchronized void deleteProfile(String id) throws EProfileException { if (isProfileEnable(id)) { throw new EProfileException("CMS_PROFILE_DELETE_ENABLEPROFILE"); } @@ -215,9 +232,31 @@ public class LDAPProfileSubsystem } } + deletedNsUniqueIds.add(nsUniqueIds.get(id)); forgetProfile(id); } + private synchronized void handleDELETE(LDAPEntry entry) { + LDAPAttribute attr = entry.getAttribute("nsUniqueId"); + String nsUniqueId = null; + if (attr != null) + nsUniqueId = attr.getStringValueArray()[0]; + + if (deletedNsUniqueIds.remove(nsUniqueId)) { + CMS.debug("handleDELETE: delete was already effected"); + return; + } + + String profileId = null; + String dn = entry.getDN(); + if (!dn.startsWith("cn=")) { + CMS.debug("handleDELETE: DN " + dn + " does not start with 'cn='"); + return; + } + profileId = LDAPDN.explodeDN(dn, true)[0]; + forgetProfile(profileId); + } + private synchronized void handleMODDN(DN oldDN, LDAPEntry entry) { DN profilesDN = new DN(dn); @@ -231,20 +270,61 @@ public class LDAPProfileSubsystem @Override public synchronized void commitProfile(String id) throws EProfileException { LDAPConfigStore cs = (LDAPConfigStore) mProfiles.get(id).getConfigStore(); + + // first create a *new* profile object from the configStore + // and initialise it with the updated configStore + // + IPluginRegistry registry = (IPluginRegistry) + CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY); + String classId = mProfileClassIds.get(id); + IPluginInfo info = registry.getPluginInfo("profile", classId); + String className = info.getClassName(); + IProfile newProfile = null; try { - String[] attrs = {"entryUSN"}; + newProfile = (IProfile) Class.forName(className).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + throw new EProfileException("Could not instantiate class '" + + classId + "' for profile '" + id + "': " + e); + } + newProfile.setId(id); + try { + newProfile.init(this, cs); + } catch (EBaseException e) { + throw new EProfileException( + "Failed to initialise profile '" + id + "': " + e); + } + + // next replace the existing profile with the new profile; + // this is to avoid any intermediate state where the profile + // is not fully initialised with its inputs, outputs and + // policy objects. + // + mProfiles.put(id, newProfile); + + // finally commit the configStore and track the resulting + // entryUSN and (in case of add) the nsUniqueId + // + try { + String[] attrs = {"entryUSN", "nsUniqueId"}; LDAPEntry entry = cs.commitReturn(false, attrs); - - LDAPAttribute attr = null; - if (entry != null) - attr = entry.getAttribute("entryUSN"); + if (entry == null) { + // shouldn't happen, but let's be sure not to crash anyway + return; + } Integer entryUSN = null; + LDAPAttribute attr = entry.getAttribute("entryUSN"); if (attr != null) entryUSN = new Integer(attr.getStringValueArray()[0]); - entryUSNs.put(id, entryUSN); CMS.debug("commitProfile: new entryUSN = " + entryUSN); + + String nsUniqueId = null; + attr = entry.getAttribute("nsUniqueId"); + if (attr != null) + nsUniqueId = attr.getStringValueArray()[0]; + CMS.debug("commitProfile: nsUniqueId = " + nsUniqueId); + nsUniqueIds.put(id, nsUniqueId); } catch (ELdapException e) { throw new EProfileException( "Failed to commit config store of profile '" + id + ": " + e); @@ -261,17 +341,7 @@ public class LDAPProfileSubsystem mProfiles.remove(id); mProfileClassIds.remove(id); entryUSNs.remove(id); - } - - private void forgetProfile(LDAPEntry entry) { - String profileId = null; - String dn = entry.getDN(); - if (!dn.startsWith("cn=")) { - CMS.debug("forgetProfile: DN " + dn + " does not start with 'cn='"); - return; - } - profileId = LDAPDN.explodeDN(dn, true)[0]; - forgetProfile(profileId); + nsUniqueIds.remove(id); } /** @@ -296,6 +366,8 @@ public class LDAPProfileSubsystem mProfiles.clear(); mProfileClassIds.clear(); entryUSNs.clear(); + nsUniqueIds.clear(); + deletedNsUniqueIds.clear(); } /** @@ -328,7 +400,7 @@ public class LDAPProfileSubsystem cons.setServerControls(persistCtrl); cons.setBatchSize(1); cons.setServerTimeLimit(0 /* seconds */); - String[] attrs = {"*", "entryUSN"}; + String[] attrs = {"*", "entryUSN", "nsUniqueId"}; LDAPSearchResults results = conn.search( dn, LDAPConnection.SCOPE_ONE, "(objectclass=*)", attrs, false, cons); @@ -347,7 +419,7 @@ public class LDAPProfileSubsystem break; case LDAPPersistSearchControl.DELETE: CMS.debug("Profile change monitor: DELETE"); - forgetProfile(entry); + handleDELETE(entry); break; case LDAPPersistSearchControl.MODIFY: CMS.debug("Profile change monitor: MODIFY"); -- 2.4.3 -------------- next part -------------- From 2b790945f75257d098ca965644d222975f395d4b Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 1 Dec 2015 14:21:08 +1100 Subject: [PATCH 61/61] Ensure config store commits refresh file-based profile data The file-based LDAP profile subsystem does not update profiles correctly. Ensure that each commit of the underlying config store refreshes the profile inputs, outputs and policy objects. Part of: https://fedorahosted.org/pki/ticket/1700 --- .../cmscore/profile/AbstractProfileSubsystem.java | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java index 076e9c93e461f00e7a6dcde92f9fdd06d23a0283..fc26131112d73c40930e5630049e71644007d934 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/AbstractProfileSubsystem.java @@ -22,12 +22,15 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; +import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.ISubsystem; import com.netscape.certsrv.profile.EProfileException; import com.netscape.certsrv.profile.IProfile; import com.netscape.certsrv.profile.IProfileSubsystem; +import com.netscape.certsrv.registry.IPluginInfo; +import com.netscape.certsrv.registry.IPluginRegistry; public abstract class AbstractProfileSubsystem implements IProfileSubsystem { protected static final String PROP_CHECK_OWNER = "checkOwner"; @@ -120,8 +123,42 @@ public abstract class AbstractProfileSubsystem implements IProfileSubsystem { */ public void commitProfile(String id) throws EProfileException { + IConfigStore cs = mProfiles.get(id).getConfigStore(); + + // first create a *new* profile object from the configStore + // and initialise it with the updated configStore + // + IPluginRegistry registry = (IPluginRegistry) + CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY); + String classId = mProfileClassIds.get(id); + IPluginInfo info = registry.getPluginInfo("profile", classId); + String className = info.getClassName(); + IProfile newProfile = null; try { - mProfiles.get(id).getConfigStore().commit(false); + newProfile = (IProfile) Class.forName(className).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + throw new EProfileException("Could not instantiate class '" + + classId + "' for profile '" + id + "': " + e); + } + newProfile.setId(id); + try { + newProfile.init(this, cs); + } catch (EBaseException e) { + throw new EProfileException( + "Failed to initialise profile '" + id + "': " + e); + } + + // next replace the existing profile with the new profile; + // this is to avoid any intermediate state where the profile + // is not fully initialised with its inputs, outputs and + // policy objects. + // + mProfiles.put(id, newProfile); + + // finally commit the configStore + // + try { + cs.commit(false); } catch (EBaseException e) { throw new EProfileException( "Failed to commit config store of profile '" + id + ": " + e); -- 2.4.3 From ftweedal at redhat.com Tue Dec 1 05:57:18 2015 From: ftweedal at redhat.com (Fraser Tweedale) Date: Tue, 1 Dec 2015 15:57:18 +1000 Subject: [Pki-devel] [PATCH] 0062 Block startup until initial profile load completed Message-ID: <20151201055718.GN23644@dhcp-40-8.bne.redhat.com> Hi all, The attached patch fixes https://fedorahosted.org/pki/ticket/1702 Cheers, Fraser -------------- next part -------------- From cc1b04d255158a507e4afe68da8d0911e8c32edc Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 1 Dec 2015 16:49:03 +1100 Subject: [PATCH] Block startup until initial profile load completed It is possible for the CMS getStatus resource to indicate that CMS is ready when the initial loading of profiles (which is performed by another thread) is not complete. During startup, wait for the initial loading of profiles to complete before continuing. Fixes: https://fedorahosted.org/pki/ticket/1702 --- .../cmscore/profile/LDAPProfileSubsystem.java | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java index cc2e43dfa2e9b1a4eb3bdb53eeb3ace6cfd1d6ac..15caff68d93347a29736ef0886b021ae9ac35302 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java @@ -19,9 +19,11 @@ package com.netscape.cmscore.profile; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.util.Arrays; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; +import java.util.concurrent.CountDownLatch; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPConnection; @@ -58,6 +60,10 @@ public class LDAPProfileSubsystem private boolean stopped = false; private Thread monitor; + private Integer initialNumProfiles = null; + private int numProfilesLoaded = 0; + private CountDownLatch initialLoadDone = new CountDownLatch(1); + /** * Initializes this subsystem with the given configuration * store. @@ -96,6 +102,11 @@ public class LDAPProfileSubsystem monitor = new Thread(this, "profileChangeMonitor"); monitor.start(); + try { + initialLoadDone.await(); + } catch (InterruptedException e) { + } + CMS.debug("LDAPProfileSubsystem: finished init"); } /** @@ -265,6 +276,12 @@ public class LDAPProfileSubsystem return "cn=" + id + "," + dn; } + private void checkInitialLoadDone() { + if (initialNumProfiles != null + && numProfilesLoaded >= initialNumProfiles) + initialLoadDone.countDown(); + } + public void run() { int op = LDAPPersistSearchControl.ADD | LDAPPersistSearchControl.MODIFY @@ -285,11 +302,23 @@ public class LDAPProfileSubsystem cons.setServerControls(persistCtrl); cons.setBatchSize(1); cons.setServerTimeLimit(0 /* seconds */); + String[] attrs = {"*", "numSubordinates"}; LDAPSearchResults results = conn.search( - dn, LDAPConnection.SCOPE_ONE, "(objectclass=*)", - null, false, cons); + dn, LDAPConnection.SCOPE_SUB, "(objectclass=*)", + attrs, false, cons); while (!stopped && results.hasMoreElements()) { LDAPEntry entry = results.next(); + + String[] objectClasses = + entry.getAttribute("objectClass").getStringValueArray(); + if (Arrays.asList(objectClasses).contains("organizationalUnit")) { + initialNumProfiles = new Integer( + entry.getAttribute("numSubordinates") + .getStringValueArray()[0]); + checkInitialLoadDone(); + continue; + } + LDAPEntryChangeControl changeControl = null; LDAPControl[] changeControls = results.getResponseControls(); if (changeControls != null) { @@ -327,6 +356,8 @@ public class LDAPProfileSubsystem } else { CMS.debug("Profile change monitor: immediate result"); readProfile(entry); + numProfilesLoaded += 1; + checkInitialLoadDone(); } } } catch (ELdapException e) { -- 2.4.3 From edewata at redhat.com Tue Dec 1 23:16:30 2015 From: edewata at redhat.com (Endi Sukma Dewata) Date: Tue, 1 Dec 2015 17:16:30 -0600 Subject: [Pki-devel] [PATCH] 661 Fixed selftest error handling. Message-ID: <565E2A4E.9060105@redhat.com> The selftest has been modified to throw an exception and provide more specific error message if a test fails in order to help troubleshoot the problem. https://fedorahosted.org/pki/ticket/1328 -- Endi S. Dewata -------------- next part -------------- From f7dc87a2d0d7261e01f8eea3b2f4b13dc84b03ef Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Tue, 1 Dec 2015 23:34:41 +0100 Subject: [PATCH] Fixed selftest error handling. The selftest has been modified to throw an exception and provide more specific error message if a test fails in order to help troubleshoot the problem. https://fedorahosted.org/pki/ticket/1328 --- base/common/src/com/netscape/certsrv/apps/CMS.java | 12 +-- .../src/com/netscape/certsrv/apps/ICMSEngine.java | 28 ++--- .../selftests/common/SystemCertsVerification.java | 18 ++-- .../cms/selftests/tks/TKSKnownSessionKey.java | 2 - .../cms/servlet/admin/CMSAdminServlet.java | 25 +++-- .../src/com/netscape/cmscore/apps/CMSEngine.java | 57 +++++----- .../src/com/netscape/cmscore/cert/CertUtils.java | 120 ++++++++++----------- .../cmscore/selftests/SelfTestSubsystem.java | 30 ++++-- .../netscape/cmscore/app/CMSEngineDefaultStub.java | 27 +++-- 9 files changed, 161 insertions(+), 158 deletions(-) diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java index 84fc3f743a7c6fed0206404019df8cb440b97a74..94f5c1687322cbe4a4b194b22e0f483bc8e012dc 100644 --- a/base/common/src/com/netscape/certsrv/apps/CMS.java +++ b/base/common/src/com/netscape/certsrv/apps/CMS.java @@ -1377,23 +1377,23 @@ public final class CMS { * Verifies all system certs * with tags defined in .cert.list */ - public static boolean verifySystemCerts() { - return _engine.verifySystemCerts(); + public static void verifySystemCerts() throws Exception { + _engine.verifySystemCerts(); } /** * Verify a system cert by tag name * with tags defined in .cert.list */ - public static boolean verifySystemCertByTag(String tag) { - return _engine.verifySystemCertByTag(tag); + public static void verifySystemCertByTag(String tag) throws Exception { + _engine.verifySystemCertByTag(tag); } /** * Verify a system cert by certificate nickname */ - public static boolean verifySystemCertByNickname(String nickname, String certificateUsage) { - return _engine.verifySystemCertByNickname(nickname, certificateUsage); + public static void verifySystemCertByNickname(String nickname, String certificateUsage) throws Exception { + _engine.verifySystemCertByNickname(nickname, certificateUsage); } /** diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java index e9b5b765fca2c949db0db91494f48c12b4fee35a..e024208fdcfdf83d3cf25478355d1a6d867a9ab3 100644 --- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java +++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java @@ -29,14 +29,6 @@ import java.util.Hashtable; import java.util.Locale; import java.util.Vector; -import netscape.ldap.LDAPConnection; -import netscape.ldap.LDAPException; -import netscape.ldap.LDAPSSLSocketFactoryExt; -import netscape.security.util.ObjectIdentifier; -import netscape.security.x509.Extension; -import netscape.security.x509.GeneralName; -import netscape.security.x509.X509CertInfo; - import org.mozilla.jss.CryptoManager.CertificateUsage; import org.mozilla.jss.util.PasswordCallback; @@ -80,6 +72,14 @@ import com.netscape.certsrv.request.IRequest; import com.netscape.cmsutil.net.ISocketFactory; import com.netscape.cmsutil.password.IPasswordStore; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPSSLSocketFactoryExt; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.Extension; +import netscape.security.x509.GeneralName; +import netscape.security.x509.X509CertInfo; + /** * This interface represents the CMS core framework. The * framework contains a set of services that provide @@ -798,24 +798,24 @@ public interface ICMSEngine extends ISubsystem { /** * Verifies all system certificates * - * @return true if all passed, false otherwise + * @throws Exception if something is wrong */ - public boolean verifySystemCerts(); + public void verifySystemCerts() throws Exception; /** * Verifies a system certificate by its tag name * as defined in .cert.list * - * @return true if passed, false otherwise + * @throws Exception if something is wrong */ - public boolean verifySystemCertByTag(String tag); + public void verifySystemCertByTag(String tag) throws Exception; /** * Verifies a system certificate by its nickname * - * @return true if passed, false otherwise + * @throws Exception if something is wrong */ - public boolean verifySystemCertByNickname(String nickname, String certificateUsage); + public void verifySystemCertByNickname(String nickname, String certificateUsage) throws Exception; /** * get the CertificateUsage as defined in JSS CryptoManager diff --git a/base/server/cms/src/com/netscape/cms/selftests/common/SystemCertsVerification.java b/base/server/cms/src/com/netscape/cms/selftests/common/SystemCertsVerification.java index 5c1e97bfaa558ba9394eca0b88543482c6bece9a..e4fc1cbe2554180762dbdd331ab08de2cf9052bb 100644 --- a/base/server/cms/src/com/netscape/cms/selftests/common/SystemCertsVerification.java +++ b/base/server/cms/src/com/netscape/cms/selftests/common/SystemCertsVerification.java @@ -189,18 +189,20 @@ public class SystemCertsVerification */ public void runSelfTest(ILogEventListener logger) throws Exception { - boolean status = CMS.verifySystemCerts(); - if (!status) { + try { + CMS.verifySystemCerts(); + + String logMessage = CMS.getLogMessage( + "SELFTESTS_COMMON_SYSTEM_CERTS_VERIFICATION_SUCCESS", + getSelfTestName()); + mSelfTestSubsystem.log(logger, logMessage); + + } catch (Exception e) { String logMessage = CMS.getLogMessage( "SELFTESTS_COMMON_SYSTEM_CERTS_VERIFICATION_FAILURE", getSelfTestName()); mSelfTestSubsystem.log(logger, logMessage); - throw new Exception(logMessage); + throw e; } - - String logMessage = CMS.getLogMessage( - "SELFTESTS_COMMON_SYSTEM_CERTS_VERIFICATION_SUCCESS", - getSelfTestName()); - mSelfTestSubsystem.log(logger, logMessage); } } diff --git a/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java b/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java index 1686ba564be428a35ad4c5d0aa42def09e97c5e8..f734f67c003420f73194d71877a6537e7b122e68 100644 --- a/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java +++ b/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java @@ -363,8 +363,6 @@ public class TKSKnownSessionKey mSelfTestSubsystem.log(logger, logMessage); throw e; } - - return; } private void generateSessionKey(String sharedSecretName) throws Exception { diff --git a/base/server/cms/src/com/netscape/cms/servlet/admin/CMSAdminServlet.java b/base/server/cms/src/com/netscape/cms/servlet/admin/CMSAdminServlet.java index b6325b71d0bceac9589775cbaf1643400775abf8..18be8a854f148ab682aabe5d731b3dfe6d73aee1 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/admin/CMSAdminServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/admin/CMSAdminServlet.java @@ -38,11 +38,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import netscape.security.x509.BasicConstraintsExtension; -import netscape.security.x509.CertificateExtensions; -import netscape.security.x509.X509CertImpl; -import netscape.security.x509.X509CertInfo; - import org.mozilla.jss.CryptoManager; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.PQGParams; @@ -80,6 +75,11 @@ import com.netscape.cmsutil.util.Cert; import com.netscape.cmsutil.util.Utils; import com.netscape.symkey.SessionKey; +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + /** * A class representings an administration servlet. This * servlet is responsible to serve Certificate Server @@ -2191,9 +2191,12 @@ public final class CMSAdminServlet extends AdminServlet { modifyRADMCert(nickname); } - boolean verified = CMS.verifySystemCertByNickname(nickname, null); - if (verified == true) { - CMS.debug("CMSAdminServlet: installCert(): verifySystemCertByNickname() succeeded: " + nickname); + boolean verified = false; + try { + CMS.debug("CMSAdminServlet: verifying system certificate " + nickname); + CMS.verifySystemCertByNickname(nickname, null); + verified = true; + auditMessage = CMS.getLogMessage( LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, auditSubjectID, @@ -2201,8 +2204,9 @@ public final class CMSAdminServlet extends AdminServlet { nickname); audit(auditMessage); - } else { - CMS.debug("CMSAdminServlet: installCert(): verifySystemCertByNickname() failed: " + nickname); + + } catch (Exception e) { + CMS.debug(e); auditMessage = CMS.getLogMessage( LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, auditSubjectID, @@ -2211,6 +2215,7 @@ public final class CMSAdminServlet extends AdminServlet { audit(auditMessage); } + // store a message in the signed audit log file auditMessage = CMS.getLogMessage( LOGGING_SIGNED_AUDIT_CONFIG_TRUSTED_PUBLIC_KEY, diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java index 77f913636bda6a490755d3ea88b9d6c56b341c74..1e1f844cd85d444703ae81ee273c14f7b1170834 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java +++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java @@ -24,7 +24,6 @@ import java.io.FileReader; import java.io.IOException; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; @@ -44,32 +43,15 @@ import java.util.Vector; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; -import netscape.ldap.LDAPConnection; -import netscape.ldap.LDAPException; -import netscape.ldap.LDAPSSLSocketFactoryExt; -import netscape.security.extensions.CertInfo; -import netscape.security.pkcs.ContentInfo; -import netscape.security.pkcs.PKCS7; -import netscape.security.pkcs.SignerInfo; -import netscape.security.util.ObjectIdentifier; -import netscape.security.x509.AlgorithmId; -import netscape.security.x509.CertificateChain; -import netscape.security.x509.Extension; -import netscape.security.x509.GeneralName; -import netscape.security.x509.X509CRLImpl; -import netscape.security.x509.X509CertImpl; -import netscape.security.x509.X509CertInfo; - import org.apache.commons.lang.StringUtils; import org.apache.xerces.parsers.DOMParser; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.CryptoManager.CertificateUsage; -import org.mozilla.jss.util.PasswordCallback; +import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.Signature; import org.mozilla.jss.crypto.SignatureAlgorithm; -import org.mozilla.jss.crypto.CryptoToken; - +import org.mozilla.jss.util.PasswordCallback; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -184,8 +166,24 @@ import com.netscape.cmscore.util.Debug; import com.netscape.cmsutil.net.ISocketFactory; import com.netscape.cmsutil.password.IPasswordStore; import com.netscape.cmsutil.password.NuxwdogPasswordStore; -import com.netscape.cmsutil.util.Utils; import com.netscape.cmsutil.util.Cert; +import com.netscape.cmsutil.util.Utils; + +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPSSLSocketFactoryExt; +import netscape.security.extensions.CertInfo; +import netscape.security.pkcs.ContentInfo; +import netscape.security.pkcs.PKCS7; +import netscape.security.pkcs.SignerInfo; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.Extension; +import netscape.security.x509.GeneralName; +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; public class CMSEngine implements ICMSEngine { private static final String ID = "MAIN"; @@ -1259,7 +1257,7 @@ public class CMSEngine implements ICMSEngine { return; } CMS.debug(method + "autoShutdown allowed"); - CryptoToken token = + CryptoToken token = ((org.mozilla.jss.pkcs11.PK11PrivKey) mSigningKey).getOwningToken(); SignatureAlgorithm signAlg = Cert.mapAlgorithmToJss("SHA256withRSA"); Signature signer = token.getSignatureContext(signAlg); @@ -1731,17 +1729,16 @@ public class CMSEngine implements ICMSEngine { } } - public boolean verifySystemCerts() { - return CertUtils.verifySystemCerts(); + public void verifySystemCerts() throws Exception { + CertUtils.verifySystemCerts(); } - public boolean verifySystemCertByTag(String tag) { - return CertUtils.verifySystemCertByTag(tag); + public void verifySystemCertByTag(String tag) throws Exception { + CertUtils.verifySystemCertByTag(tag); } - public boolean verifySystemCertByNickname(String nickname, String certificateUsage) { - CMS.debug("CMSEngine: verifySystemCertByNickname(" + nickname + ", " + certificateUsage + ")"); - return CertUtils.verifySystemCertByNickname(nickname, certificateUsage); + public void verifySystemCertByNickname(String nickname, String certificateUsage) throws Exception { + CertUtils.verifySystemCertByNickname(nickname, certificateUsage); } public CertificateUsage getCertificateUsage(String certusage) { @@ -1995,7 +1992,7 @@ public class CMSEngine implements ICMSEngine { crumb.createNewFile(); } catch (IOException e) { CMS.debug(method + " create autoShutdown crumb file failed on " + - mAutoSD_CrumbFile + "; nothing to do...keep shutting down:" + e.toString()); + mAutoSD_CrumbFile + "; nothing to do...keep shutting down:" + e); e.printStackTrace(); } } diff --git a/base/server/cmscore/src/com/netscape/cmscore/cert/CertUtils.java b/base/server/cmscore/src/com/netscape/cmscore/cert/CertUtils.java index 244c36dc7e0bbac181ce37d6344cc849a70ba873..8c5c2ccc10970426bc161c9fcfb3f0e3732ca2b8 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/cert/CertUtils.java +++ b/base/server/cmscore/src/com/netscape/cmscore/cert/CertUtils.java @@ -35,6 +35,15 @@ import java.util.Arrays; import java.util.Date; import java.util.StringTokenizer; +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.CryptoManager.CertificateUsage; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmsutil.util.Utils; + import netscape.security.extensions.NSCertTypeExtension; import netscape.security.pkcs.PKCS10; import netscape.security.pkcs.PKCS7; @@ -54,15 +63,6 @@ import netscape.security.x509.X509CertImpl; import netscape.security.x509.X509CertInfo; import netscape.security.x509.X509Key; -import org.mozilla.jss.CryptoManager; -import org.mozilla.jss.CryptoManager.CertificateUsage; - -import com.netscape.certsrv.apps.CMS; -import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.IConfigStore; -import com.netscape.certsrv.logging.ILogger; -import com.netscape.cmsutil.util.Utils; - /** * Utility class with assorted methods to check for * smime pairs, determining the type of cert - signature @@ -828,43 +828,42 @@ public class CertUtils { /* * verify a certificate by its nickname - * returns true if it verifies; false if any not + * @throws Exception if something is wrong */ - public static boolean verifySystemCertByNickname(String nickname, String certusage) { - CMS.debug("CertUtils: verifySystemCertByNickname(" + nickname + "," + certusage + ")"); - boolean r = true; - CertificateUsage cu = null; - cu = getCertificateUsage(certusage); + public static void verifySystemCertByNickname(String nickname, String certusage) throws Exception { + CMS.debug("CertUtils: verifySystemCertByNickname(" + nickname + ", " + certusage + ")"); + CertificateUsage cu = getCertificateUsage(certusage); int ccu = 0; if (cu == null) { CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + nickname + " with unsupported certusage =" + certusage); - return false; + throw new Exception("Unsupported certificate usage " + certusage + " in certificate " + nickname); } if (certusage == null || certusage.equals("")) CMS.debug("CertUtils: verifySystemCertByNickname(): required certusage not defined, getting current certusage"); + CMS.debug("CertUtils: verifySystemCertByNickname(): calling isCertValid()"); try { CryptoManager cm = CryptoManager.getInstance(); if (cu.getUsage() != CryptoManager.CertificateUsage.CheckAllUsages.getUsage()) { if (cm.isCertValid(nickname, true, cu)) { - r = true; CMS.debug("CertUtils: verifySystemCertByNickname() passed: " + nickname); } else { CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + nickname); - r = false; + throw new Exception("Invalid certificate " + nickname); } + } else { // find out about current cert usage ccu = cm.isCertValid(nickname, true); if (ccu == CertificateUsage.basicCertificateUsages) { /* cert is good for nothing */ - r = false; CMS.debug("CertUtils: verifySystemCertByNickname() failed: cert is good for nothing:" + nickname); + throw new Exception("Unusable certificate " + nickname); + } else { - r = true; CMS.debug("CertUtils: verifySystemCertByNickname() passed: " + nickname); if ((ccu & CryptoManager.CertificateUsage.SSLServer.getUsage()) != 0) @@ -893,31 +892,31 @@ public class CertUtils { CMS.debug("CertUtils: verifySystemCertByNickname(): cert is AnyCA"); } } + } catch (Exception e) { - CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + - e.toString()); - r = false; + CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + e); + throw e; } - return r; } /* * verify a certificate by its tag name - * returns true if it verifies; false if any not + * @throws Exception if something is wrong */ - public static boolean verifySystemCertByTag(String tag) { + public static void verifySystemCertByTag(String tag) throws Exception { CMS.debug("CertUtils: verifySystemCertByTag(" + tag + ")"); String auditMessage = null; IConfigStore config = CMS.getConfigStore(); - boolean r = true; + try { String subsysType = config.getString("cs.type", ""); if (subsysType.equals("")) { CMS.debug("CertUtils: verifySystemCertByTag() cs.type not defined in CS.cfg. System certificates verification not done"); - r = false; + throw new Exception("Missing cs.type in CS.cfg"); } + subsysType = toLowerCaseSubsystemType(subsysType); if (subsysType == null) { CMS.debug("CertUtils: verifySystemCerts() invalid cs.type in CS.cfg. System certificates verification not done"); @@ -928,39 +927,32 @@ public class CertUtils { ""); audit(auditMessage); - r = false; - return r; + throw new Exception("Invalid cs.type in CS.cfg"); } + String nickname = config.getString(subsysType + ".cert." + tag + ".nickname", ""); if (nickname.equals("")) { CMS.debug("CertUtils: verifySystemCertByTag() nickname for cert tag " + tag + " undefined in CS.cfg"); - r = false; + throw new Exception("Missing nickname for " + tag + " certificate"); } + String certusage = config.getString(subsysType + ".cert." + tag + ".certusage", ""); if (certusage.equals("")) { CMS.debug("CertUtils: verifySystemCertByTag() certusage for cert tag " + tag + " undefined in CS.cfg, getting current certificate usage"); + // throw new Exception("Missing certificate usage for " + tag + " certificate"); ? } - r = verifySystemCertByNickname(nickname, certusage); - if (r == true) { - // audit here - auditMessage = CMS.getLogMessage( - LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, - ILogger.SYSTEM_UID, - ILogger.SUCCESS, - nickname); - audit(auditMessage); - } else { - // audit here - auditMessage = CMS.getLogMessage( - LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, - ILogger.SYSTEM_UID, - ILogger.FAILURE, - nickname); + verifySystemCertByNickname(nickname, certusage); + + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.SUCCESS, + nickname); + + audit(auditMessage); - audit(auditMessage); - } } catch (Exception e) { CMS.debug("CertUtils: verifySystemCertsByTag() failed: " + e.toString()); @@ -971,10 +963,8 @@ public class CertUtils { ""); audit(auditMessage); - r = false; + throw e; } - - return r; } /* @@ -1015,13 +1005,13 @@ public class CertUtils { /* * goes through all system certs and check to see if they are good * and audit the result - * returns true if all verifies; false if any not + * @throws Exception if something is wrong */ - public static boolean verifySystemCerts() { + public static void verifySystemCerts() throws Exception { + String auditMessage = null; IConfigStore config = CMS.getConfigStore(); - boolean verifyResult = true; - boolean r = true; /* the final return value */ + try { String subsysType = config.getString("cs.type", ""); if (subsysType.equals("")) { @@ -1033,8 +1023,9 @@ public class CertUtils { ""); audit(auditMessage); - return false; + throw new Exception("Missing cs.type in CS.cfg"); } + subsysType = toLowerCaseSubsystemType(subsysType); if (subsysType == null) { CMS.debug("CertUtils: verifySystemCerts() invalid cs.type in CS.cfg. System certificates verification not done"); @@ -1045,8 +1036,9 @@ public class CertUtils { ""); audit(auditMessage); - return false; + throw new Exception("Invalid cs.type in CS.cfg"); } + String certlist = config.getString(subsysType + ".cert.list", ""); if (certlist.equals("")) { CMS.debug("CertUtils: verifySystemCerts() " @@ -1058,17 +1050,17 @@ public class CertUtils { ""); audit(auditMessage); - return false; + throw new Exception("Missing " + subsysType + ".cert.list in CS.cfg"); } + StringTokenizer tokenizer = new StringTokenizer(certlist, ","); while (tokenizer.hasMoreTokens()) { String tag = tokenizer.nextToken(); tag = tag.trim(); CMS.debug("CertUtils: verifySystemCerts() cert tag=" + tag); - verifyResult = verifySystemCertByTag(tag); - if (verifyResult == false) - r = false; //r captures the value for final return + verifySystemCertByTag(tag); } + } catch (Exception e) { // audit here auditMessage = CMS.getLogMessage( @@ -1078,10 +1070,8 @@ public class CertUtils { ""); audit(auditMessage); - r = false; - CMS.debug("CertUtils: verifySystemCerts():" + e.toString()); + throw e; } - return r; } public static String toLowerCaseSubsystemType(String s) { diff --git a/base/server/cmscore/src/com/netscape/cmscore/selftests/SelfTestSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/selftests/SelfTestSubsystem.java index d060f8180ff8e91cff69b3576bfedecea96fbae6..14fab26e4d3f9ffdfc305acbd94b742be6141604 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/selftests/SelfTestSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/selftests/SelfTestSubsystem.java @@ -1328,13 +1328,24 @@ public class SelfTestSubsystem loggerFullName, loggerValue)); - throw new EInvalidSelfTestException(loggerFullName, - loggerValue); + throw new EInvalidSelfTestException( + "The self test plugin named " + + loggerFullName + " contains a value " + + loggerValue + " which is not an instance of ILogEventListener."); } // initialize the self tests logger mLogger = (ILogEventListener) o; mLogger.init(this, loggerConfig); + + } catch (EMissingSelfTestException e) { + // already logged + throw e; + + } catch (EInvalidSelfTestException e) { + // already logged + throw e; + } catch (EBaseException e) { // self test property name EBaseException @@ -1351,8 +1362,8 @@ public class SelfTestSubsystem loggerFullName, loggerValue)); - throw new EInvalidSelfTestException(loggerFullName, - loggerValue); + throw e; + } catch (Exception e) { // NOTE: These messages can only be logged to the // "transactions" log, since the "selftests.log" @@ -1369,8 +1380,7 @@ public class SelfTestSubsystem CMS.debugStackTrace(); - throw new EInvalidSelfTestException(loggerFullName, - loggerValue); + throw new EBaseException(e); } } @@ -1481,6 +1491,11 @@ public class SelfTestSubsystem throw new EMissingSelfTestException(instanceFullName, instanceValue); } + + } catch (EMissingSelfTestException e) { + // already logged + throw e; + } catch (EBaseException e) { // self test property name EBaseException log(mLogger, @@ -1489,8 +1504,7 @@ public class SelfTestSubsystem instanceFullName, instanceValue)); - throw new EInvalidSelfTestException(instanceFullName, - instanceValue); + throw e; } // verify that the associated class is a valid instance of ISelfTest diff --git a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java index b45b33b5feb57eaa510b3b2d239152cb48c6e740..5d43af7d136c83e1c436d0e9222338f747f5b685 100644 --- a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java +++ b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java @@ -12,14 +12,6 @@ import java.util.Hashtable; import java.util.Locale; import java.util.Vector; -import netscape.ldap.LDAPConnection; -import netscape.ldap.LDAPException; -import netscape.ldap.LDAPSSLSocketFactoryExt; -import netscape.security.util.ObjectIdentifier; -import netscape.security.x509.Extension; -import netscape.security.x509.GeneralName; -import netscape.security.x509.X509CertInfo; - import org.mozilla.jss.CryptoManager.CertificateUsage; import org.mozilla.jss.util.PasswordCallback; @@ -65,6 +57,14 @@ import com.netscape.certsrv.request.IRequest; import com.netscape.cmsutil.net.ISocketFactory; import com.netscape.cmsutil.password.IPasswordStore; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPSSLSocketFactoryExt; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.Extension; +import netscape.security.x509.GeneralName; +import netscape.security.x509.X509CertInfo; + /** * Default engine stub for testing. */ @@ -572,19 +572,16 @@ public class CMSEngineDefaultStub implements ICMSEngine { } @Override - public boolean verifySystemCerts() { - return false; + public void verifySystemCerts() throws Exception { } @Override - public boolean verifySystemCertByTag(String tag) { - return false; + public void verifySystemCertByTag(String tag) throws Exception { } @Override - public boolean verifySystemCertByNickname(String nickname, - String certificateUsage) { - return false; + public void verifySystemCertByNickname(String nickname, + String certificateUsage) throws Exception { } @Override -- 2.5.0 From cfu at redhat.com Tue Dec 1 23:59:38 2015 From: cfu at redhat.com (Christina Fu) Date: Tue, 1 Dec 2015 15:59:38 -0800 Subject: [Pki-devel] [PATCH] 661 Fixed selftest error handling. In-Reply-To: <565E2A4E.9060105@redhat.com> References: <565E2A4E.9060105@redhat.com> Message-ID: <565E346A.2060305@redhat.com> looks fine. ACK. One little thing you might want to consider. In CMSAdminServlet.java, you have + CMS.debug(e); you might want to add info on what file/method you are at so that the debug message will come out stating exactly where it is at in the code. Christina On 12/01/2015 03:16 PM, Endi Sukma Dewata wrote: > The selftest has been modified to throw an exception and provide > more specific error message if a test fails in order to help > troubleshoot the problem. > > https://fedorahosted.org/pki/ticket/1328 > > > > _______________________________________________ > Pki-devel mailing list > Pki-devel at redhat.com > https://www.redhat.com/mailman/listinfo/pki-devel -------------- next part -------------- An HTML attachment was scrubbed... URL: From edewata at redhat.com Wed Dec 2 01:23:18 2015 From: edewata at redhat.com (Endi Sukma Dewata) Date: Tue, 1 Dec 2015 19:23:18 -0600 Subject: [Pki-devel] [PATCH] 661 Fixed selftest error handling. In-Reply-To: <565E346A.2060305@redhat.com> References: <565E2A4E.9060105@redhat.com> <565E346A.2060305@redhat.com> Message-ID: <565E4806.2070501@redhat.com> On 12/1/2015 5:59 PM, Christina Fu wrote: > looks fine. ACK. Thanks! Pushed to master. > One little thing you might want to consider. In CMSAdminServlet.java, > you have > > + CMS.debug(e); > > you might want to add info on what file/method you are at so that the > debug message will come out stating exactly where it is at in the code. The above statement will actually log the stack trace which will show the origin of the exception. I also added a debug log before calling verifySystemCertByNickname() so we know where we are. If this is not sufficient please let me know, we can add it in a separate patch. -- Endi S. Dewata From ftweedal at redhat.com Thu Dec 3 06:31:41 2015 From: ftweedal at redhat.com (Fraser Tweedale) Date: Thu, 3 Dec 2015 16:31:41 +1000 Subject: [Pki-devel] [PATCH] 0063 Extract common base class for SSLAuthenticatorWithFallback Message-ID: <20151203063141.GY23644@dhcp-40-8.bne.redhat.com> The attached patch was written as part of work implementing GSS-API authentication. We actually might not end up using SSLAuthenticatorWithFallback to interpret the authentication data but I think this refactor is worthwhile on its own, so here's the patch. Cheers, Fraser -------------- next part -------------- From 52268df4e892ac150abb13240708dee3b3544ac6 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Thu, 3 Dec 2015 16:09:04 +1100 Subject: [PATCH] Extract common base class for SSLAuthenticatorWithFallback Two Tomcat version-specific implementations of SSLAuthenticatorWithFallback exist, with much duplicate code. Extract an abstract base class 'AbstractPKIAuthenticator' and implement just the unique bits in the concrete classes. Part of: https://fedorahosted.org/pki/ticket/1359 --- .../cms/tomcat/AbstractPKIAuthenticator.java} | 35 +++--- base/server/tomcat7/src/CMakeLists.txt | 3 + .../cms/tomcat/SSLAuthenticatorWithFallback.java | 139 ++------------------ base/server/tomcat8/src/CMakeLists.txt | 3 + .../cms/tomcat/SSLAuthenticatorWithFallback.java | 140 ++------------------- 5 files changed, 46 insertions(+), 274 deletions(-) copy base/server/{tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java => tomcat/src/com/netscape/cms/tomcat/AbstractPKIAuthenticator.java} (86%) diff --git a/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java b/base/server/tomcat/src/com/netscape/cms/tomcat/AbstractPKIAuthenticator.java similarity index 86% copy from base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java copy to base/server/tomcat/src/com/netscape/cms/tomcat/AbstractPKIAuthenticator.java index 3678791b927a9d6bca523d6a79a5fbfff1b675cf..f98377dc2322d7fa525d360a401348468f840f43 100644 --- a/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java +++ b/base/server/tomcat/src/com/netscape/cms/tomcat/AbstractPKIAuthenticator.java @@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletResponseWrapper; import org.apache.catalina.Container; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; +import org.apache.catalina.Authenticator; import org.apache.catalina.authenticator.AuthenticatorBase; import org.apache.catalina.authenticator.BasicAuthenticator; import org.apache.catalina.authenticator.FormAuthenticator; @@ -37,7 +38,7 @@ import org.apache.catalina.connector.Request; /** * @author Endi S. Dewata */ -public class SSLAuthenticatorWithFallback extends AuthenticatorBase { +public abstract class AbstractPKIAuthenticator extends AuthenticatorBase { public final static String BASIC_AUTHENTICATOR = "BASIC"; public final static String FORM_AUTHENTICATOR = "FORM"; @@ -47,7 +48,7 @@ public class SSLAuthenticatorWithFallback extends AuthenticatorBase { AuthenticatorBase sslAuthenticator = new SSLAuthenticator(); AuthenticatorBase fallbackAuthenticator = new BasicAuthenticator(); - public SSLAuthenticatorWithFallback() { + public AbstractPKIAuthenticator() { log("Creating SSL authenticator with fallback"); } @@ -68,9 +69,7 @@ public class SSLAuthenticatorWithFallback extends AuthenticatorBase { } - @Override - public boolean authenticate(Request request, HttpServletResponse response) throws IOException { - + public boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException { X509Certificate certs[] = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); boolean result; @@ -84,7 +83,7 @@ public class SSLAuthenticatorWithFallback extends AuthenticatorBase { log("SSL auth return code: "+code); } }; - result = sslAuthenticator.authenticate(request, wrapper); + result = doSubAuthenticate(sslAuthenticator, request, wrapper); } else { log("Authenticating with "+fallbackMethod+" authentication"); @@ -96,30 +95,28 @@ public class SSLAuthenticatorWithFallback extends AuthenticatorBase { log("Fallback auth return code: "+code); } }; - result = fallbackAuthenticator.authenticate(request, wrapper); + result = doSubAuthenticate(fallbackAuthenticator, request, wrapper); } if (result) return true; log("Result: "+result); - String realmName = AuthenticatorBase.getRealmName(request.getContext()); - - - StringBuilder value = new StringBuilder(16); - value.append("Basic realm=\""); - if (realmName != null) { - value.append(REALM_NAME); - } else { - value.append(realmName); - } - value.append('\"'); - response.setHeader(AUTH_HEADER_NAME, value.toString()); + String realmName = doGetRealmName(request); + response.setHeader(AUTH_HEADER_NAME, + "Basic realm=\"" + (realmName == null ? REALM_NAME : realmName) + "\""); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } + public abstract boolean doSubAuthenticate( + Authenticator auth, Request req, HttpServletResponse resp) + throws IOException; + + public abstract String doGetRealmName(Request req); + + @Override protected String getAuthMethod() { return HttpServletRequest.CLIENT_CERT_AUTH; diff --git a/base/server/tomcat7/src/CMakeLists.txt b/base/server/tomcat7/src/CMakeLists.txt index 77293a654d5335ad134afaac30e4678360e0cc05..bb42bfe0a4a840f0b271a83600f79686f76cc353 100644 --- a/base/server/tomcat7/src/CMakeLists.txt +++ b/base/server/tomcat7/src/CMakeLists.txt @@ -124,8 +124,11 @@ javac(pki-tomcat7-classes com/netscape/cms/tomcat/*.java CLASSPATH ${SERVLET_JAR} ${TOMCAT_CATALINA_JAR} ${TOMCAT_UTIL_SCAN_JAR} + ${CMAKE_BINARY_DIR}/../../tomcat OUTPUT_DIR ${CMAKE_BINARY_DIR}/../../tomcat + DEPENDS + pki-tomcat-classes ) configure_file( diff --git a/base/server/tomcat7/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java b/base/server/tomcat7/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java index 20bf85d221bac3f5dbd1cac73aa9b8252a1cc6e8..66d4a7e732725a008c9b4984333c1c1207c0837a 100644 --- a/base/server/tomcat7/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java +++ b/base/server/tomcat7/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java @@ -19,154 +19,41 @@ package com.netscape.cms.tomcat; import java.io.IOException; -import java.security.cert.X509Certificate; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import org.apache.catalina.Container; -import org.apache.catalina.Globals; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.authenticator.AuthenticatorBase; -import org.apache.catalina.authenticator.BasicAuthenticator; -import org.apache.catalina.authenticator.FormAuthenticator; -import org.apache.catalina.authenticator.SSLAuthenticator; +import org.apache.catalina.Authenticator; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; /** * @author Endi S. Dewata */ -public class SSLAuthenticatorWithFallback extends AuthenticatorBase { +public class SSLAuthenticatorWithFallback extends AbstractPKIAuthenticator { - public final static String BASIC_AUTHENTICATOR = "BASIC"; - public final static String FORM_AUTHENTICATOR = "FORM"; - - String fallbackMethod = BASIC_AUTHENTICATOR; - - AuthenticatorBase sslAuthenticator = new SSLAuthenticator(); - AuthenticatorBase fallbackAuthenticator = new BasicAuthenticator(); - - public SSLAuthenticatorWithFallback() { - log("Creating SSL authenticator with fallback"); - } + protected LoginConfig loginConfig; @Override public String getInfo() { return "SSL authenticator with "+fallbackMethod+" fallback."; } - public String getFallbackMethod() { - return fallbackMethod; + @Override + public boolean doSubAuthenticate( + Authenticator auth, Request req, HttpServletResponse resp) + throws IOException { + return auth.authenticate(req, resp, loginConfig); } - public void setFallbackMethod(String fallbackMethod) { - log("Fallback method: "+fallbackMethod); - this.fallbackMethod = fallbackMethod; - - if (BASIC_AUTHENTICATOR.equalsIgnoreCase(fallbackMethod)) { - fallbackAuthenticator = new BasicAuthenticator(); - - } else if (FORM_AUTHENTICATOR.equalsIgnoreCase(fallbackMethod)) { - fallbackAuthenticator = new FormAuthenticator(); - } - + @Override + public String doGetRealmName(Request request /* ignored */) { + return loginConfig.getRealmName(); } @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { - - X509Certificate certs[] = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); - boolean result; - - if (certs != null && certs.length > 0) { - log("Authenticate with client certificate authentication"); - HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) { - public void setHeader(String name, String value) { - log("SSL auth header: "+name+"="+value); - }; - public void sendError(int code) { - log("SSL auth return code: "+code); - } - }; - result = sslAuthenticator.authenticate(request, wrapper, config); - - } else { - log("Authenticating with "+fallbackMethod+" authentication"); - HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) { - public void setHeader(String name, String value) { - log("Fallback auth header: "+name+"="+value); - }; - public void sendError(int code) { - log("Fallback auth return code: "+code); - } - }; - result = fallbackAuthenticator.authenticate(request, wrapper, config); - } - - if (result) - return true; - - log("Result: "+result); - - StringBuilder value = new StringBuilder(16); - value.append("Basic realm=\""); - if (config.getRealmName() == null) { - value.append(REALM_NAME); - } else { - value.append(config.getRealmName()); - } - value.append('\"'); - response.setHeader(AUTH_HEADER_NAME, value.toString()); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - - return false; - } - - @Override - protected String getAuthMethod() { - return HttpServletRequest.CLIENT_CERT_AUTH; - }; - - @Override - public void setContainer(Container container) { - log("Setting container"); - super.setContainer(container); - sslAuthenticator.setContainer(container); - fallbackAuthenticator.setContainer(container); + loginConfig = config; + return doAuthenticate(request, response); } - @Override - protected void initInternal() throws LifecycleException { - log("Initializing authenticators"); - - super.initInternal(); - - sslAuthenticator.setAlwaysUseSession(alwaysUseSession); - sslAuthenticator.init(); - - fallbackAuthenticator.setAlwaysUseSession(alwaysUseSession); - fallbackAuthenticator.init(); - } - - @Override - public void startInternal() throws LifecycleException { - log("Starting authenticators"); - super.startInternal(); - sslAuthenticator.start(); - fallbackAuthenticator.start(); - } - - @Override - public void stopInternal() throws LifecycleException { - log("Stopping authenticators"); - super.stopInternal(); - sslAuthenticator.stop(); - fallbackAuthenticator.stop(); - } - - public void log(String message) { - System.out.println("SSLAuthenticatorWithFallback: "+message); - } } diff --git a/base/server/tomcat8/src/CMakeLists.txt b/base/server/tomcat8/src/CMakeLists.txt index a2badac69837023ca7078cfeaa80cdf98ba2a63b..df55916bc0bc0e2bb010239115c68b8bc5ad6c84 100644 --- a/base/server/tomcat8/src/CMakeLists.txt +++ b/base/server/tomcat8/src/CMakeLists.txt @@ -124,8 +124,11 @@ javac(pki-tomcat8-classes com/netscape/cms/tomcat/*.java CLASSPATH ${SERVLET_JAR} ${TOMCAT_CATALINA_JAR} ${TOMCAT_UTIL_SCAN_JAR} + ${CMAKE_BINARY_DIR}/../../tomcat OUTPUT_DIR ${CMAKE_BINARY_DIR}/../../tomcat + DEPENDS + pki-tomcat-classes ) configure_file( diff --git a/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java b/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java index 3678791b927a9d6bca523d6a79a5fbfff1b675cf..12ca0bb7c5213f8e833f75bfb92826dbc8718d87 100644 --- a/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java +++ b/base/server/tomcat8/src/com/netscape/cms/tomcat/SSLAuthenticatorWithFallback.java @@ -19,150 +19,32 @@ package com.netscape.cms.tomcat; import java.io.IOException; -import java.security.cert.X509Certificate; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import org.apache.catalina.Container; -import org.apache.catalina.Globals; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.authenticator.AuthenticatorBase; -import org.apache.catalina.authenticator.BasicAuthenticator; -import org.apache.catalina.authenticator.FormAuthenticator; -import org.apache.catalina.authenticator.SSLAuthenticator; +import org.apache.catalina.Authenticator; import org.apache.catalina.connector.Request; /** * @author Endi S. Dewata */ -public class SSLAuthenticatorWithFallback extends AuthenticatorBase { +public class SSLAuthenticatorWithFallback extends AbstractPKIAuthenticator { - public final static String BASIC_AUTHENTICATOR = "BASIC"; - public final static String FORM_AUTHENTICATOR = "FORM"; - - String fallbackMethod = BASIC_AUTHENTICATOR; - - AuthenticatorBase sslAuthenticator = new SSLAuthenticator(); - AuthenticatorBase fallbackAuthenticator = new BasicAuthenticator(); - - public SSLAuthenticatorWithFallback() { - log("Creating SSL authenticator with fallback"); - } - - public String getFallbackMethod() { - return fallbackMethod; + @Override + public boolean doSubAuthenticate( + Authenticator auth, Request req, HttpServletResponse resp) + throws IOException { + return auth.authenticate(req, resp); } - public void setFallbackMethod(String fallbackMethod) { - log("Fallback method: "+fallbackMethod); - this.fallbackMethod = fallbackMethod; - - if (BASIC_AUTHENTICATOR.equalsIgnoreCase(fallbackMethod)) { - fallbackAuthenticator = new BasicAuthenticator(); - - } else if (FORM_AUTHENTICATOR.equalsIgnoreCase(fallbackMethod)) { - fallbackAuthenticator = new FormAuthenticator(); - } - + @Override + public String doGetRealmName(Request request) { + return getRealmName(request.getContext()); } @Override public boolean authenticate(Request request, HttpServletResponse response) throws IOException { - - X509Certificate certs[] = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); - boolean result; - - if (certs != null && certs.length > 0) { - log("Authenticate with client certificate authentication"); - HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) { - public void setHeader(String name, String value) { - log("SSL auth header: "+name+"="+value); - }; - public void sendError(int code) { - log("SSL auth return code: "+code); - } - }; - result = sslAuthenticator.authenticate(request, wrapper); - - } else { - log("Authenticating with "+fallbackMethod+" authentication"); - HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) { - public void setHeader(String name, String value) { - log("Fallback auth header: "+name+"="+value); - }; - public void sendError(int code) { - log("Fallback auth return code: "+code); - } - }; - result = fallbackAuthenticator.authenticate(request, wrapper); - } - - if (result) - return true; - - log("Result: "+result); - String realmName = AuthenticatorBase.getRealmName(request.getContext()); - - - StringBuilder value = new StringBuilder(16); - value.append("Basic realm=\""); - if (realmName != null) { - value.append(REALM_NAME); - } else { - value.append(realmName); - } - value.append('\"'); - response.setHeader(AUTH_HEADER_NAME, value.toString()); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - - return false; - } - - @Override - protected String getAuthMethod() { - return HttpServletRequest.CLIENT_CERT_AUTH; - }; - - @Override - public void setContainer(Container container) { - log("Setting container"); - super.setContainer(container); - sslAuthenticator.setContainer(container); - fallbackAuthenticator.setContainer(container); + return doAuthenticate(request, response); } - @Override - protected void initInternal() throws LifecycleException { - log("Initializing authenticators"); - - super.initInternal(); - - sslAuthenticator.setAlwaysUseSession(alwaysUseSession); - sslAuthenticator.init(); - - fallbackAuthenticator.setAlwaysUseSession(alwaysUseSession); - fallbackAuthenticator.init(); - } - - @Override - public void startInternal() throws LifecycleException { - log("Starting authenticators"); - super.startInternal(); - sslAuthenticator.start(); - fallbackAuthenticator.start(); - } - - @Override - public void stopInternal() throws LifecycleException { - log("Stopping authenticators"); - super.stopInternal(); - sslAuthenticator.stop(); - fallbackAuthenticator.stop(); - } - - public void log(String message) { - System.out.println("SSLAuthenticatorWithFallback: "+message); - } } -- 2.4.3 From ftweedal at redhat.com Fri Dec 4 06:18:01 2015 From: ftweedal at redhat.com (Fraser Tweedale) Date: Fri, 4 Dec 2015 16:18:01 +1000 Subject: [Pki-devel] GSS-API authnz design review Message-ID: <20151204061801.GB23644@dhcp-40-8.bne.redhat.com> Hi Ade et al, I've opened a pagure PR with a draft (and incomplete) design for the GSS-API authentication: https://pagure.io/test_dogtag_designs/pull-request/8 There are still some areas to be investigated and some open questions. Please give it a once over and provide your thoughts. In particular I would like feedback on the idea to use alternative IAuthManager plugins for authorisation; identities from different IdPs would use different plugins (or different instances of plugins). I think this gives a nice integration when the system providing external identities (e.g. FreeIPA) already has concepts for authorisation of PKI-related operations (again, FreeIPA, certainly for CA and probably also for KRA too). Thanks, and have a nice weekend! Fraser From nkinder at redhat.com Tue Dec 15 00:04:19 2015 From: nkinder at redhat.com (Nathan Kinder) Date: Mon, 14 Dec 2015 16:04:19 -0800 Subject: [Pki-devel] GSS-API authnz design review In-Reply-To: <20151204061801.GB23644@dhcp-40-8.bne.redhat.com> References: <20151204061801.GB23644@dhcp-40-8.bne.redhat.com> Message-ID: <566F5903.3060709@redhat.com> On 12/03/2015 10:18 PM, Fraser Tweedale wrote: > Hi Ade et al, > > I've opened a pagure PR with a draft (and incomplete) design for the > GSS-API authentication: > > https://pagure.io/test_dogtag_designs/pull-request/8 This should also probably be shared with the FreeIPA development list since it will allow for better integration there. Thanks, -NGK > > There are still some areas to be investigated and some open > questions. Please give it a once over and provide your thoughts. > > In particular I would like feedback on the idea to use alternative > IAuthManager plugins for authorisation; identities from different > IdPs would use different plugins (or different instances of > plugins). I think this gives a nice integration when the system > providing external identities (e.g. FreeIPA) already has concepts > for authorisation of PKI-related operations (again, FreeIPA, > certainly for CA and probably also for KRA too). > > Thanks, and have a nice weekend! > Fraser > > _______________________________________________ > Pki-devel mailing list > Pki-devel at redhat.com > https://www.redhat.com/mailman/listinfo/pki-devel > > From mharmsen at redhat.com Tue Dec 15 23:56:40 2015 From: mharmsen at redhat.com (Matthew Harmsen) Date: Tue, 15 Dec 2015 16:56:40 -0700 Subject: [Pki-devel] Karma Request for Dogtag 10.2.6 in Fedora 23 Message-ID: <5670A8B8.2050608@redhat.com> Everyone, Please provide Karma for the following Dogtag 10.2.6 packages in Fedora 23: * pki-core-10.2.6-13.fc23 This build addresses the following issue related to an IPA issue: * PKI TRAC Ticket #1704 - After uninstalling all KRA instances, dogtag still returns info that KRA instance exists somewhere Thanks, -- Matt P. S. - A build containing these fixes is still under construction for 'rawhide' (Fedora 24). -------------- next part -------------- An HTML attachment was scrubbed... URL: From mharmsen at redhat.com Thu Dec 17 00:26:50 2015 From: mharmsen at redhat.com (Matthew Harmsen) Date: Wed, 16 Dec 2015 17:26:50 -0700 Subject: [Pki-devel] Karma Request for Dogtag 10.2.6 in Fedora 23 In-Reply-To: <5670A8B8.2050608@redhat.com> References: <5670A8B8.2050608@redhat.com> Message-ID: <5672014A.2060901@redhat.com> On 12/15/2015 04:56 PM, Matthew Harmsen wrote: > Everyone, > > Please provide Karma for the following Dogtag 10.2.6 packages in > Fedora 23: > > * pki-core-10.2.6-13.fc23 > > > This build addresses the following issue related to an IPA issue: > > * PKI TRAC Ticket #1704 - After uninstalling all KRA instances, > dogtag still returns info that KRA instance exists somewhere > > > Thanks, > -- Matt > > P. S. - A build containing these fixes is still under construction for > 'rawhide' (Fedora 24). > Fixed - pki-core-10.2.6-13.fc24 > > > > _______________________________________________ > Pki-devel mailing list > Pki-devel at redhat.com > https://www.redhat.com/mailman/listinfo/pki-devel -------------- next part -------------- An HTML attachment was scrubbed... URL: From edewata at redhat.com Fri Dec 18 23:30:42 2015 From: edewata at redhat.com (Endi Sukma Dewata) Date: Fri, 18 Dec 2015 17:30:42 -0600 Subject: [Pki-devel] [PATCH] 662 Fixed external CA case for IPA compatibility. Message-ID: <56749722.4040408@redhat.com> The installation code for external CA case has been fixed such that IPA can detect step 1 completion properly. The code that handles certificate data conversion has been fixed to reformat base-64 data for PEM output properly. The installation summary for step 1 has been updated to provide more accurate information. https://fedorahosted.org/pki/ticket/456 -- Endi S. Dewata -------------- next part -------------- From 4f87ef1595152e48df8cdbe2f6e726ff62ce4eae Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Sat, 12 Dec 2015 04:10:54 +0100 Subject: [PATCH] Fixed external CA case for IPA compatibility. The installation code for external CA case has been fixed such that IPA can detect step 1 completion properly. The code that handles certificate data conversion has been fixed to reformat base-64 data for PEM output properly. The installation summary for step 1 has been updated to provide more accurate information. https://fedorahosted.org/pki/ticket/456 --- base/common/python/pki/nss.py | 8 ++++++-- .../python/pki/server/deployment/pkihelper.py | 7 +++++-- .../server/deployment/scriptlets/configuration.py | 10 +++++++--- base/server/sbin/pkispawn | 23 +++++++++++++++++++++- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/base/common/python/pki/nss.py b/base/common/python/pki/nss.py index 196fe462fac4e5f6fdcf4604f6d5c95af82838db..67fd90b4cf8046e64b9291296489a5f04e22efcd 100644 --- a/base/common/python/pki/nss.py +++ b/base/common/python/pki/nss.py @@ -43,9 +43,13 @@ def convert_data(data, input_format, output_format, header=None, footer=None): if input_format == 'base64' and output_format == 'pem': - # split a single line into multiple lines - data = data.rstrip('\r\n') + # join base-64 data into a single line + data = data.replace('\r', '').replace('\n', '') + + # re-split the line into fixed-length lines lines = [data[i:i+64] for i in range(0, len(data), 64)] + + # add header and footer return '%s\n%s\n%s\n' % (header, '\n'.join(lines), footer) if input_format == 'pem' and output_format == 'base64': diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py index 9c9b40454a41b42f2c089f045ac9ac662093a409..7a1a8c7d145628313868b614123977165b9015bf 100644 --- a/base/server/python/pki/server/deployment/pkihelper.py +++ b/base/server/python/pki/server/deployment/pkihelper.py @@ -502,15 +502,18 @@ class ConfigurationFile: # generic extension support in CSR - for external CA self.add_req_ext = config.str2bool( self.mdict['pki_req_ext_add']) + self.external = config.str2bool(self.mdict['pki_external']) + self.external_step_one = not config.str2bool(self.mdict['pki_external_step_two']) + self.external_step_two = not self.external_step_one + if self.external: # generic extension support in CSR - for external CA if self.add_req_ext: self.req_ext_oid = self.mdict['pki_req_ext_oid'] self.req_ext_critical = self.mdict['pki_req_ext_critical'] self.req_ext_data = self.mdict['pki_req_ext_data'] - self.external_step_two = config.str2bool( - self.mdict['pki_external_step_two']) + self.skip_configuration = config.str2bool( self.mdict['pki_skip_configuration']) self.standalone = config.str2bool(self.mdict['pki_standalone']) diff --git a/base/server/python/pki/server/deployment/scriptlets/configuration.py b/base/server/python/pki/server/deployment/scriptlets/configuration.py index b8b8fc69197f661ac4a9106cbad91ae8bb81d0c8..a80239374da7a4184bbf593bb9069673a9d9c8dd 100644 --- a/base/server/python/pki/server/deployment/scriptlets/configuration.py +++ b/base/server/python/pki/server/deployment/scriptlets/configuration.py @@ -94,9 +94,9 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): token = deployer.mdict['pki_token_name'] nssdb = instance.open_nssdb(token) - external = config.str2bool(deployer.mdict['pki_external']) - step_one = not config.str2bool(deployer.mdict['pki_external_step_two']) - step_two = not step_one + external = deployer.configuration_file.external + step_one = deployer.configuration_file.external_step_one + step_two = deployer.configuration_file.external_step_two try: if external and step_one: # external/existing CA step 1 @@ -142,6 +142,10 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): signing_csr = pki.nss.convert_csr(signing_csr, 'pem', 'base64') subsystem.config['ca.signing.certreq'] = signing_csr + # This is needed by IPA to detect step 1 completion. + # See is_step_one_done() in ipaserver/install/cainstance.py. + subsystem.config['preop.ca.type'] = 'otherca' + subsystem.save() elif external and step_two: # external/existing CA step 2 diff --git a/base/server/sbin/pkispawn b/base/server/sbin/pkispawn index f29dec33398e3fb5b7414d32043c547a83a3d1d4..9c2aa2d665b2e523bae242bebb27c06c471ce2c7 100755 --- a/base/server/sbin/pkispawn +++ b/base/server/sbin/pkispawn @@ -614,7 +614,13 @@ def main(argv): config.pki_log.debug(pkilogging.log_format(parser.mdict), extra=config.PKI_INDENTATION_LEVEL_0) - print_install_information(parser.mdict) + external = deployer.configuration_file.external + step_one = deployer.configuration_file.external_step_one + + if external and step_one: + print_step_one_information(parser.mdict) + else: + print_install_information(parser.mdict) def set_port(parser, tag, prompt, existing_data): @@ -624,6 +630,21 @@ def set_port(parser, tag, prompt, existing_data): parser.read_text(prompt, config.pki_subsystem, tag) +def print_step_one_information(mdict): + + print(log.PKI_SPAWN_INFORMATION_HEADER) + print(" The %s subsystem of the '%s' instance is still incomplete." % + (config.pki_subsystem, mdict['pki_instance_name'])) + print() + print(" A CSR for the CA certificate has been generated at:\n" + " %s" + % mdict['pki_external_csr_path']) + print() + print(" Submit the CSR to an external CA to generate a CA certificate\n" + " for this subsystem.") + print(log.PKI_SPAWN_INFORMATION_FOOTER) + + def print_install_information(mdict): skip_configuration = config.str2bool(mdict['pki_skip_configuration']) -- 2.4.3 From edewata at redhat.com Sun Dec 20 20:52:13 2015 From: edewata at redhat.com (Endi Sukma Dewata) Date: Sun, 20 Dec 2015 14:52:13 -0600 Subject: [Pki-devel] [PATCH] 663 Fixed mismatching certificate validity calculation. Message-ID: <567714FD.80209@redhat.com> The CAValidityDefault has been modified to use Calendar API to calculate the certificate validity range to be consistent with the ValidityConstraint and ValidityDefault. https://fedorahosted.org/pki/ticket/1682 -- Endi S. Dewata -------------- next part -------------- From 8e885712768e5e36ef623abcc565b01cfa01c145 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Sun, 20 Dec 2015 21:46:56 +0100 Subject: [PATCH] Fixed mismatching certificate validity calculation. The CAValidityDefault has been modified to use Calendar API to calculate the certificate validity range to be consistent with the ValidityConstraint and ValidityDefault. https://fedorahosted.org/pki/ticket/1682 --- .../cms/profile/def/CAValidityDefault.java | 79 ++++++++++++++++++---- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/base/server/cms/src/com/netscape/cms/profile/def/CAValidityDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/CAValidityDefault.java index 44ffd474f8aa23abff922f6fc37e92cd12536dec..a98b2c28c12c78ac6ffa420c880ba0c317f5f94b 100644 --- a/base/server/cms/src/com/netscape/cms/profile/def/CAValidityDefault.java +++ b/base/server/cms/src/com/netscape/cms/profile/def/CAValidityDefault.java @@ -20,14 +20,10 @@ package com.netscape.cms.profile.def; import java.io.IOException; import java.text.ParsePosition; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; import java.util.Locale; -import netscape.security.x509.BasicConstraintsExtension; -import netscape.security.x509.CertificateValidity; -import netscape.security.x509.PKIXExtensions; -import netscape.security.x509.X509CertInfo; - import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.ca.ICertificateAuthority; @@ -38,6 +34,11 @@ import com.netscape.certsrv.property.EPropertyException; import com.netscape.certsrv.property.IDescriptor; import com.netscape.certsrv.request.IRequest; +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.PKIXExtensions; +import netscape.security.x509.X509CertInfo; + /** * This class implements a CA signing cert enrollment default policy * that populates a server-side configurable validity @@ -46,6 +47,7 @@ import com.netscape.certsrv.request.IRequest; */ public class CAValidityDefault extends EnrollDefault { public static final String CONFIG_RANGE = "range"; + public static final String CONFIG_RANGE_UNIT = "rangeUnit"; public static final String CONFIG_START_TIME = "startTime"; public static final String CONFIG_BYPASS_CA_NOTAFTER = "bypassCAnotafter"; @@ -61,6 +63,7 @@ public class CAValidityDefault extends EnrollDefault { public CAValidityDefault() { super(); addConfigName(CONFIG_RANGE); + addConfigName(CONFIG_RANGE_UNIT); addConfigName(CONFIG_START_TIME); addConfigName(CONFIG_BYPASS_CA_NOTAFTER); @@ -103,6 +106,12 @@ public class CAValidityDefault extends EnrollDefault { "7305", /* 20 years */ CMS.getUserMessage(locale, "CMS_PROFILE_VALIDITY_RANGE")); + } else if (name.equals(CONFIG_RANGE_UNIT)) { + return new Descriptor(IDescriptor.STRING, + null, + "day", + CMS.getUserMessage(locale, + "CMS_PROFILE_VALIDITY_RANGE_UNIT")); } else if (name.equals(CONFIG_START_TIME)) { return new Descriptor(IDescriptor.STRING, null, @@ -299,6 +308,28 @@ public class CAValidityDefault extends EnrollDefault { return CMS.getUserMessage(locale, "CMS_PROFILE_DEF_VALIDITY", params); } + public int convertRangeUnit(String unit) throws Exception { + + if (unit.equals("year")) { + return Calendar.YEAR; + + } else if (unit.equals("month")) { + return Calendar.MONTH; + + } else if (unit.equals("day")) { + return Calendar.DAY_OF_YEAR; + + } else if (unit.equals("hour")) { + return Calendar.HOUR_OF_DAY; + + } else if (unit.equals("minute")) { + return Calendar.MINUTE; + + } else { + throw new Exception("Invalid range unit: " + unit); + } + } + /** * Populates the request with this policy default. */ @@ -307,6 +338,7 @@ public class CAValidityDefault extends EnrollDefault { // always + 60 seconds String startTimeStr = getConfig(CONFIG_START_TIME); + CMS.debug("CAValidityDefault: start time: " + startTimeStr); try { startTimeStr = mapPattern(request, startTimeStr); } catch (IOException e) { @@ -317,21 +349,42 @@ public class CAValidityDefault extends EnrollDefault { startTimeStr = "60"; } int startTime = Integer.parseInt(startTimeStr); + Date notBefore = new Date(CMS.getCurrentDate().getTime() + (1000 * startTime)); - long notAfterVal = 0; + CMS.debug("CAValidityDefault: not before: " + notBefore); + String rangeStr = getConfig(CONFIG_RANGE, "7305"); + CMS.debug("CAValidityDefault: range: " + rangeStr); + + int range; try { - String rangeStr = getConfig(CONFIG_RANGE); rangeStr = mapPattern(request, rangeStr); - notAfterVal = notBefore.getTime() + - (mDefault * Integer.parseInt(rangeStr)); - } catch (Exception e) { - // configured value is not correct - CMS.debug("CAValidityDefault: populate " + e.toString()); + range = Integer.parseInt(rangeStr); + } catch (IOException e) { + CMS.debug(e); throw new EProfileException(CMS.getUserMessage( getLocale(request), "CMS_INVALID_PROPERTY", CONFIG_RANGE)); } - Date notAfter = new Date(notAfterVal); + + String rangeUnitStr = getConfig(CONFIG_RANGE_UNIT, "day"); + CMS.debug("CAValidityDefault: range unit: " + rangeUnitStr); + + int rangeUnit; + try { + rangeUnit = convertRangeUnit(rangeUnitStr); + } catch (Exception e) { + CMS.debug(e); + throw new EProfileException(CMS.getUserMessage( + getLocale(request), "CMS_INVALID_PROPERTY", CONFIG_RANGE_UNIT)); + } + + // calculate the end of validity range + Calendar date = Calendar.getInstance(); + date.setTime(notBefore); + date.add(rangeUnit, range); + + Date notAfter = date.getTime(); + CMS.debug("CAValidityDefault: not after: " + notAfter); CertificateValidity validity = new CertificateValidity(notBefore, notAfter); -- 2.4.3 From ftweedal at redhat.com Tue Dec 22 01:14:06 2015 From: ftweedal at redhat.com (Fraser Tweedale) Date: Tue, 22 Dec 2015 11:14:06 +1000 Subject: [Pki-devel] [PATCH] 0064 Remove unused constant Message-ID: <20151222011406.GS23644@dhcp-40-8.bne.redhat.com> Drive-by cleanup; pushed under one-liner/trivial rule: master 9d64c0b8e58fa4bb1b5504167b7d80b90e0ae1ff Cheers, Fraser -------------- next part -------------- From 9d64c0b8e58fa4bb1b5504167b7d80b90e0ae1ff Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 22 Dec 2015 10:56:16 +1000 Subject: [PATCH] Remove unused constant --- base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java b/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java index 99b15c77d09d8fec0422403a7ef41e1e8f7b08df..146be519b5b46c8ae37c8b7958db39add0a84931 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java @@ -201,9 +201,6 @@ public abstract class CMSServlet extends HttpServlet { /* input http params */ protected final static String AUTHMGR_PARAM = "authenticator"; - /* fixed credential passed to auth managers */ - protected final static String CERT_AUTH_CRED = "sslClientCert"; - public static final String CERT_ATTR = "javax.servlet.request.X509Certificate"; -- 2.4.3 From edewata at redhat.com Tue Dec 22 21:18:37 2015 From: edewata at redhat.com (Endi Sukma Dewata) Date: Tue, 22 Dec 2015 15:18:37 -0600 Subject: [Pki-devel] [PATCH] 664 Fixed TPS UI to display accessible services only. Message-ID: <5679BE2D.9050708@redhat.com> The TPS UI has been modified to display the accessible services based on the user's roles. A TPS admin has access to all services. A TPS agent has access to tokens, certificates, activities, and profiles. A TPS operator has access to tokens, certificates, and activities only. https://fedorahosted.org/pki/ticket/1476 -- Endi S. Dewata -------------- next part -------------- From abd5d67dafed8836debb630d375d301fb3538541 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Tue, 22 Dec 2015 22:01:10 +0100 Subject: [PATCH] Fixed TPS UI to display accessible services only. The TPS UI has been modified to display the accessible services based on the user's roles. A TPS admin has access to all services. A TPS agent has access to tokens, certificates, activities, and profiles. A TPS operator has access to tokens, certificates, and activities only. https://fedorahosted.org/pki/ticket/1476 --- base/tps/shared/webapps/tps/js/tps.js | 16 +++++++++++++++- base/tps/shared/webapps/tps/ui/home.html | 4 ++-- base/tps/shared/webapps/tps/ui/index.html | 23 ++++++++++++++++++----- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/base/tps/shared/webapps/tps/js/tps.js b/base/tps/shared/webapps/tps/js/tps.js index f6e3897846f8108dd23ae04314bfdbc4a454b1ad..cf1cc0b836812c2aa28e0544aa24d07cfb61e0f0 100644 --- a/base/tps/shared/webapps/tps/js/tps.js +++ b/base/tps/shared/webapps/tps/js/tps.js @@ -118,18 +118,32 @@ var PropertiesTable = Table.extend({ var HomePage = Page.extend({ load: function() { + var self = this; + self.update(); + }, + update: function() { + if (!tps.user) return; var roles = tps.user.Roles.Role; var home_accounts = self.$("[name=home-accounts]"); var home_system = self.$("[name=home-system]"); if (_.contains(roles, "Administrators")) { home_accounts.show(); + } else { + home_accounts.hide(); + } + + if (_.contains(roles, "Administrators")) { + home_system.show(); $("li", home_system).show(); } else if (_.contains(roles, "TPS Agents")) { - home_accounts.hide(); + home_system.show(); $("li", home_system).hide(); $("[name=profiles]", home_system).show(); + + } else { + home_system.hide(); } } }); diff --git a/base/tps/shared/webapps/tps/ui/home.html b/base/tps/shared/webapps/tps/ui/home.html index eb6874e50840be1081be91e9402972ce34f58684..6ad28507619fd669c1f83069faf0a0092668fc21 100644 --- a/base/tps/shared/webapps/tps/ui/home.html +++ b/base/tps/shared/webapps/tps/ui/home.html @@ -36,7 +36,7 @@ -
+
-
+