summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjesus m. rodriguez <jesusr@redhat.com>2009-11-10 17:07:41 -0500
committerjesus m. rodriguez <jesusr@redhat.com>2009-11-10 17:07:41 -0500
commit40b4aa7a2f7e51ffeb5cd2ccbd2f868432605dcd (patch)
tree9fd8790f46f672a78be906925ba9083b4d35b618
parent350fb9f0ef9756577161afcb16ee7b064f6309d3 (diff)
downloadcandlepin-40b4aa7a2f7e51ffeb5cd2ccbd2f868432605dcd.tar.gz
candlepin-40b4aa7a2f7e51ffeb5cd2ccbd2f868432605dcd.tar.xz
candlepin-40b4aa7a2f7e51ffeb5cd2ccbd2f868432605dcd.zip
add in the spacewalk certificate parsing library.
this should probably be made into a jar so others can use it.
-rw-r--r--proxy/buildconf/build.properties4
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/Certificate.java431
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/CertificateFactory.java137
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyDescriptor.java77
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyExtractor.java53
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/FieldExtractor.java34
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/PublicKeyRing.java129
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/RhnSecurityProvider.java60
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/SimpleExtractor.java91
-rw-r--r--proxy/code/src/com/redhat/rhn/common/cert/XmlTag.java204
-rw-r--r--proxy/ivy.xml4
11 files changed, 1220 insertions, 4 deletions
diff --git a/proxy/buildconf/build.properties b/proxy/buildconf/build.properties
index f6e2b6c..0704029 100644
--- a/proxy/buildconf/build.properties
+++ b/proxy/buildconf/build.properties
@@ -45,8 +45,8 @@ git.home=${basedir}/../
# =================== jar dependencies =======================
boot.jar.dependencies=ivy
-common.jar.dependencies=bcel bcprov commons-lang jersey-core jersey-server \
- jsr311-api jersey-json stringtree-json
+common.jar.dependencies=bcel bcpg bcprov commons-lang jdom jersey-core \
+jersey-server jsr311-api jersey-json stringtree-json
test.jar.dependencies=antlr checkstyle dom4j emma emma_ant jdom jta \
junit4 log4j mockobjects mockobjects-core mockobjects-jdk1.4-j2ee1.3 \
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/Certificate.java b/proxy/code/src/com/redhat/rhn/common/cert/Certificate.java
new file mode 100644
index 0000000..3b5f22a
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/Certificate.java
@@ -0,0 +1,431 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import com.redhat.rhn.common.cert.XmlTag;
+
+import java.security.SignatureException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A server certificate.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class Certificate {
+
+ public static final String CURRENT_GENERATION = "2";
+ // Some of these properties should probably be int's or Date's
+ // But until that is really needed, we'll stick with Strings
+
+ private String product;
+ private String owner;
+ private String issued;
+ private String expires;
+ private String slots;
+ private String provisioningSlots;
+ private String monitoringSlots;
+ private String virtualizationSlots;
+ private String virtualizationPlatformSlots;
+ private String nonlinuxSlots;
+ private String satelliteVersion;
+ private String generation;
+ private String signature;
+ private List channelFamilies;
+ private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+
+ /**
+ * Construct an empty certificate.
+ */
+ Certificate() {
+ channelFamilies = new ArrayList();
+ }
+
+ /**
+ * States whether or not this certificate is expired.
+ * @return true iff <code>expires</code> is after current system time
+ * @throws ParseException this shouldn't happen, means the date format in
+ * the cert is not what we expect
+ */
+ public boolean isExpired() throws ParseException {
+ Date now = Calendar.getInstance().getTime();
+ return now.after(this.getExpiresDate());
+ }
+
+ /**
+ * Convert this certificate into the canonical form used for signing.
+ *
+ * @return the certificate in the canonical form used for signing
+ */
+ public String asChecksumString() {
+ StringBuffer result = new StringBuffer();
+ // Fields must appear in the output in alphabetical order
+ // The channelFamilies are sorted in their very own way
+ // (see ChannelFamily.compareTo)
+ Collections.sort(channelFamilies);
+ for (int i = 0; i < channelFamilies.size(); i++) {
+ ChannelFamilyDescriptor cf = (ChannelFamilyDescriptor) channelFamilies.get(i);
+ result.append(cf.asChecksumString()).append("\n");
+ }
+ appendField(result, "expires", getExpires());
+ appendField(result, "generation", getGeneration());
+ appendField(result, "issued", getIssued());
+ appendField(result, "monitoring-slots", getMonitoringSlots());
+ appendField(result, "nonlinux-slots", getNonlinuxSlots());
+ appendField(result, "owner", getOwner());
+ appendField(result, "product", getProduct());
+ appendField(result, "provisioning-slots", getProvisioningSlots());
+ appendField(result, "satellite-version", getSatelliteVersion());
+ appendField(result, "slots", getSlots());
+ appendField(result, "virtualization_host", this.getVirtualizationSlots());
+ appendField(result, "virtualization_host_platform", this
+ .getVirtualizationPlatformSlots());
+ return result.toString();
+ }
+
+ /**
+ * Returns the XML representation of the cert.
+ * @return the XML representation of the cert.
+ */
+ public String asXmlString() {
+ StringBuffer buf = new StringBuffer();
+
+ buf.append(XML_HEADER).append("\n");
+
+ XmlTag t = new XmlTag("rhn-cert");
+ t.setAttribute("version", "0.1");
+ buf.append(t.renderOpenTag()).append("\n");
+
+ appendXmlField(buf, "product", getProduct());
+ appendXmlField(buf, "owner", getOwner());
+ appendXmlField(buf, "issued", getIssued());
+ appendXmlField(buf, "expires", getExpires());
+ appendXmlField(buf, "slots", getSlots());
+ appendXmlField(buf, "monitoring-slots", getMonitoringSlots());
+ appendXmlField(buf, "provisioning-slots", getProvisioningSlots());
+ appendXmlField(buf, "nonlinux-slots", getNonlinuxSlots());
+ appendXmlField(buf, "virtualization_host", this.getVirtualizationSlots());
+ appendXmlField(buf, "virtualization_host_platform", this
+ .getVirtualizationPlatformSlots());
+
+ for (int i = 0; i < channelFamilies.size(); i++) {
+ ChannelFamilyDescriptor cf = (ChannelFamilyDescriptor) channelFamilies.get(i);
+ buf.append(" ").append(cf.asXmlString()).append("\n");
+ }
+
+ appendXmlField(buf, "satellite-version", getSatelliteVersion());
+ appendXmlField(buf, "generation", getGeneration());
+
+ XmlTag sig = new XmlTag("rhn-cert-signature");
+ sig.addBody(getSignature());
+ buf.append(" ").append(sig.render()).append("\n");
+
+ buf.append(t.renderCloseTag()).append("\n");
+ return buf.toString();
+ }
+
+ private void appendXmlField(StringBuffer result, String fieldName, String value) {
+ if (value != null) {
+ XmlTag t = new XmlTag("rhn-cert-field", false);
+ t.setAttribute("name", fieldName);
+ t.addBody(value);
+ result.append(" ").append(t.render()).append('\n');
+ }
+ }
+
+ /**
+ * Check that this certificate was signed with a private key whose public
+ * counterpart is on <code>keyRing</code>
+ * @param keyRing the public keys with which to check the signatures
+ * @return <code>true</code> if this certificate was signed with a private
+ * key whose public counterpart is on <code>keyRing</code>,
+ * <code>false</code> otherwise
+ * @throws SignatureException if processing the sigature fails
+ */
+ public boolean verifySignature(PublicKeyRing keyRing) throws SignatureException {
+ return keyRing.verifySignature(asChecksumString(), getSignature());
+ }
+
+ // Setters. They shouldn't be public, but have to be
+ // since we use reflection to populate the certificate
+ // when reading from XML.
+
+ /**
+ * Add a channel family
+ * @param family the channel family to add
+ */
+ public void addChannelFamily(ChannelFamilyDescriptor family) {
+ channelFamilies.add(family);
+ }
+
+ /**
+ * Set the expiration date for the certificate
+ * @param expires0 the expiration date
+ */
+ public void setExpires(String expires0) {
+ expires = expires0;
+ }
+
+ /**
+ * Set the generation
+ * @param generation0 the generation
+ */
+ public void setGeneration(String generation0) {
+ generation = generation0;
+ }
+
+ /**
+ * Set the date of issue
+ * @param issued0 date of issue
+ */
+ public void setIssued(String issued0) {
+ issued = issued0;
+ }
+
+ /**
+ * Set the number of non-linux slots
+ * @param nonlinuxSlots0 the number of non-linux slots
+ */
+ public void setNonlinuxSlots(String nonlinuxSlots0) {
+ nonlinuxSlots = nonlinuxSlots0;
+ }
+
+ /**
+ * Set the number of monitoring slots
+ * @param monitoringSlots0 the number of monitoring slots
+ */
+ public void setMonitoringSlots(String monitoringSlots0) {
+ monitoringSlots = monitoringSlots0;
+ }
+
+ /**
+ * Set the owner
+ * @param owner0 the owner
+ */
+ public void setOwner(String owner0) {
+ owner = owner0;
+ }
+
+ /**
+ * Set the product
+ * @param product0 the product
+ */
+ public void setProduct(String product0) {
+ product = product0;
+ }
+
+ /**
+ * Set the number of provisioning slots
+ * @param provisioningSlots0 the number of provisioning slots
+ */
+ public void setProvisioningSlots(String provisioningSlots0) {
+ provisioningSlots = provisioningSlots0;
+ }
+
+ /**
+ * Set the satellite version
+ * @param satelliteVersion0 the satellite version
+ */
+ public void setSatelliteVersion(String satelliteVersion0) {
+ satelliteVersion = satelliteVersion0;
+ }
+
+ /**
+ * Set the signature as an ASCII armored string
+ * @param signature0 the ASCII armored signature
+ */
+ public void setSignature(String signature0) {
+ signature = signature0;
+ }
+
+ /**
+ * Set the number of slots
+ * @param slots0 the number of slots
+ */
+ public void setSlots(String slots0) {
+ slots = slots0;
+ }
+
+ /**
+ * Set the number of virtualization slots
+ * @param virtualizationSlots0 the number of virtualization slots
+ */
+ public void setVirtualizationSlots(String virtualizationSlots0) {
+ virtualizationSlots = virtualizationSlots0;
+ }
+
+ /**
+ * Set the number of virtualization platform slots
+ * @param virtualizationSlots0 the number of virtualization platform slots
+ */
+ public void setVirtualizationPlatformSlots(String virtualizationSlots0) {
+ virtualizationPlatformSlots = virtualizationSlots0;
+ }
+
+ // Getters
+
+ /**
+ * Return an unmodifiable list of the channel families
+ * @return an unmodifiable list of the channel families
+ */
+ public List getChannelFamilies() {
+ return Collections.unmodifiableList(channelFamilies);
+ }
+
+ /**
+ * Return the channel family with name <code>family</code>, or
+ * <code>null</code> if no such family exists.
+ * @param family the name of the family
+ * @return the channel family with name <code>family</code>, or
+ * <code>null</code> if no such family exists.
+ */
+ public ChannelFamilyDescriptor getChannelFamily(String family) {
+ for (int i = 0; i < channelFamilies.size(); i++) {
+ ChannelFamilyDescriptor f = (ChannelFamilyDescriptor) channelFamilies.get(i);
+ if (f.getFamily().equals(family)) {
+ return f;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the expiration date
+ * @return the expiration date
+ */
+ public String getExpires() {
+ return expires;
+ }
+
+ /**
+ * Convenience function, returns java.util.Date equivalent of
+ * <code>expires</code>
+ * @return Date obj equivalent of <code>expires</code>
+ * @throws ParseException format of <code>expires</code> not what we
+ * expected
+ */
+ public Date getExpiresDate() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return sdf.parse(expires);
+ }
+
+ /**
+ * Get the generation
+ * @return the generation
+ */
+ public String getGeneration() {
+ return generation;
+ }
+
+ /**
+ * Get the issue date
+ * @return the issue date
+ */
+ public String getIssued() {
+ return issued;
+ }
+
+ /**
+ * Get the nonlinux slots
+ * @return the nonlinux slots
+ */
+ public String getNonlinuxSlots() {
+ return nonlinuxSlots;
+ }
+
+ /**
+ * Get the monitoring slots
+ * @return the monitoring slots
+ */
+ public String getMonitoringSlots() {
+ return monitoringSlots;
+ }
+
+ /**
+ * Get the owner
+ * @return the owner
+ */
+ public String getOwner() {
+ return owner;
+ }
+
+ /**
+ * Get the product
+ * @return the product
+ */
+ public String getProduct() {
+ return product;
+ }
+
+ /**
+ * Get the number of provisioning slots
+ * @return the number of provisioning slots
+ */
+ public String getProvisioningSlots() {
+ return provisioningSlots;
+ }
+
+ /**
+ * Get the satellite version
+ * @return the satellite version
+ */
+ public String getSatelliteVersion() {
+ return satelliteVersion;
+ }
+
+ /**
+ * Get the ASCII armoured signature
+ * @return the ASCII armoured signature
+ */
+ public String getSignature() {
+ return signature;
+ }
+
+ /**
+ * Get the number of slots
+ * @return the number of slots
+ */
+ public String getSlots() {
+ return slots;
+ }
+
+ /**
+ * Get the number of virtualization slots
+ * @return the number of virtualization slots
+ */
+ public String getVirtualizationSlots() {
+ return virtualizationSlots;
+ }
+
+ /**
+ * Get the number of virtualization platform slots
+ * @return the number of virtualizationPlatform slots
+ */
+ public String getVirtualizationPlatformSlots() {
+ return virtualizationPlatformSlots;
+ }
+
+ private void appendField(StringBuffer result, String fieldName, String value) {
+ if (value != null) {
+ result.append(fieldName).append("-").append(value).append('\n');
+ }
+ }
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/CertificateFactory.java b/proxy/code/src/com/redhat/rhn/common/cert/CertificateFactory.java
new file mode 100644
index 0000000..a57586f
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/CertificateFactory.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+
+/**
+ * A class for parsing certificates from their XML form. The XML
+ * format is identical to the one used by the perl code.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class CertificateFactory {
+
+ private static final String ELEM_SIGNATURE = "rhn-cert-signature";
+ private static final String ELEM_FIELD = "rhn-cert-field";
+ private static final String ELEM_CERT = "rhn-cert";
+
+ private static final FieldExtractor[] FIELD_EXTRACTORS = {
+ new SimpleExtractor("product", true),
+ new SimpleExtractor("owner", true),
+ new SimpleExtractor("issued", true),
+ new SimpleExtractor("expires", true),
+ new SimpleExtractor("slots", true),
+ new SimpleExtractor("monitoring-slots", "monitoringSlots"),
+ new SimpleExtractor("provisioning-slots", "provisioningSlots"),
+ new SimpleExtractor("virtualization_host", "virtualizationSlots"),
+ new SimpleExtractor("virtualization_host_platform",
+ "virtualizationPlatformSlots"),
+ new SimpleExtractor("nonlinux-slots", "nonlinuxSlots"),
+ new SimpleExtractor("satellite-version", "satelliteVersion"),
+ new SimpleExtractor("generation"),
+ new ChannelFamilyExtractor("channel-families") };
+
+ private static final HashMap FIELD_MAP = new HashMap();
+
+ static {
+ for (int i = 0; i < FIELD_EXTRACTORS.length; i++) {
+ FIELD_MAP.put(FIELD_EXTRACTORS[i].getFieldName(), FIELD_EXTRACTORS[i]);
+ }
+ }
+
+ private CertificateFactory() {
+ }
+
+ /**
+ * Parse the certificate from <code>certString</code>.
+ * @param certString valid Satellite Certificate in string form
+ * @return the certificate from <code>certString</code>
+ * @throws JDOMException XML parsing fails
+ * @throws IOException unknown
+ */
+ public static Certificate read(String certString) throws JDOMException, IOException {
+ return readDocument(new SAXBuilder().build(new StringReader(certString)),
+ certString);
+ }
+
+ /**
+ * Parse a certificate from <code>file</code>. The file must contain the
+ * certificate in XML form.
+ *
+ * @param file the file with the XML certificate
+ * @return the certificate from <code>fle</code>
+ * @throws JDOMException if parsing the XML fails
+ * @throws IOException if reading the file fails
+ */
+ public static Certificate read(File file) throws JDOMException, IOException {
+ return readDocument(new SAXBuilder().build(file), file.getAbsolutePath());
+ }
+
+ /**
+ * Parse a certificate from the contents of <code>url</code>. The file must
+ * contain the certificate in XML form.
+ *
+ * @param url the URL at which the XML certificate is located
+ * @return the certificate from <code>fle</code>
+ * @throws JDOMException if parsing the XML fails
+ * @throws IOException if reading the contents of <code>url</code> fails
+ */
+ public static Certificate read(URL url) throws JDOMException, IOException {
+ return readDocument(new SAXBuilder().build(url), url.toExternalForm());
+ }
+
+ private static Certificate readDocument(Document doc, String source)
+ throws JDOMException {
+ Certificate result = new Certificate();
+ Element root = doc.getRootElement();
+ if (!ELEM_CERT.equals(root.getName())) {
+ throw new JDOMException("Expected root element in " + source + " to be " +
+ ELEM_CERT + " but found " + root.getName());
+ }
+ Element signature = root.getChild(ELEM_SIGNATURE);
+ if (signature == null) {
+ throw new JDOMException("Could not find signature element ");
+ }
+ result.setSignature(signature.getText());
+ List children = root.getChildren(ELEM_FIELD);
+ for (int i = 0; i < children.size(); i++) {
+ Element child = (Element) children.get(i);
+ extractField(result, child);
+ }
+ return result;
+ }
+
+ private static void extractField(Certificate result, Element child)
+ throws JDOMException {
+ String name = child.getAttributeValue("name");
+ FieldExtractor e = (FieldExtractor) FIELD_MAP.get(name);
+ if (name == null) {
+ throw new JDOMException("The field " + name +
+ " is not one of the possible fields for " + ELEM_FIELD);
+ }
+ e.extract(result, child);
+ }
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyDescriptor.java b/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyDescriptor.java
new file mode 100644
index 0000000..eed8e6f
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyDescriptor.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import com.redhat.rhn.common.cert.XmlTag;
+
+/**
+ * The entitlements for a channel family, consisting of the family name and a
+ * quantity.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class ChannelFamilyDescriptor implements Comparable {
+
+ private String family;
+ private String quantity;
+
+ ChannelFamilyDescriptor(String family0, String quantity0) {
+ family = family0;
+ quantity = quantity0;
+ }
+
+ /**
+ * Return the name of this channel family
+ * @return the name of this channel family
+ */
+ public String getFamily() {
+ return family;
+ }
+
+ /**
+ * Return the quantity for this family
+ * @return the quantity for this family
+ */
+ public String getQuantity() {
+ return quantity;
+ }
+
+ String asChecksumString() {
+ return "channel-families-family-" + getFamily() + "-quantity-" + getQuantity();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(Object obj) {
+ ChannelFamilyDescriptor other = (ChannelFamilyDescriptor) obj;
+ // The sort order for families is kinda odd; this replicates
+ // exactly the way the Perl code sorts the fields so that
+ // signature checking on the result is possible across Perl and Java
+ return asSortKey().compareTo(other.asSortKey());
+ }
+
+ private String asSortKey() {
+ return getQuantity() + "familyquantity" + getFamily();
+ }
+
+ String asXmlString() {
+ XmlTag tag = new XmlTag("rhn-cert-field", false);
+ tag.setAttribute("name", "channel-families");
+ tag.setAttribute("quantity", getQuantity());
+ tag.setAttribute("family", getFamily());
+ return tag.render();
+ }
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyExtractor.java b/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyExtractor.java
new file mode 100644
index 0000000..eea8ee4
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/ChannelFamilyExtractor.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import org.jdom.Element;
+
+/**
+ * ChannelFamilyExtractor
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class ChannelFamilyExtractor implements FieldExtractor {
+
+ private String fieldName;
+
+ /**
+ *
+ */
+ public ChannelFamilyExtractor(String fieldName0) {
+ fieldName = fieldName0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void extract(Certificate target, Element field) {
+ String quantity = field.getAttributeValue("quantity");
+ String family = field.getAttributeValue("family");
+ ChannelFamilyDescriptor cf = new ChannelFamilyDescriptor(family, quantity);
+ target.addChannelFamily(cf);
+ }
+
+ public boolean isRequired() {
+ return false;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/FieldExtractor.java b/proxy/code/src/com/redhat/rhn/common/cert/FieldExtractor.java
new file mode 100644
index 0000000..25265b4
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/FieldExtractor.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+
+/**
+ * An interface to describe how a field is to be extracted from the DOM
+ * representation of the XML certificate.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+interface FieldExtractor {
+
+ void extract(Certificate target, Element field) throws JDOMException;
+
+ boolean isRequired();
+
+ String getFieldName();
+
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/PublicKeyRing.java b/proxy/code/src/com/redhat/rhn/common/cert/PublicKeyRing.java
new file mode 100644
index 0000000..b7b808a
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/PublicKeyRing.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.SignatureException;
+
+import org.bouncycastle.bcpg.ArmoredInputStream;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPObjectFactory;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureList;
+import org.bouncycastle.openpgp.PGPUtil;
+
+/**
+ * A GPG public keyring.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class PublicKeyRing {
+
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ Security.addProvider(new RhnSecurityProvider());
+ }
+
+ private PGPPublicKeyRingCollection keyRing;
+
+ /**
+ * Read the key ring from <code>keyRingStream</code>.
+ * @param keyRingStream the stream from which the key ring will be read
+ * @throws IOException if reading the stream fails
+ * @throws KeyException if the keyring can not be created from the stream
+ */
+ public PublicKeyRing(InputStream keyRingStream) throws IOException, KeyException {
+ super();
+ try {
+ keyRing = new PGPPublicKeyRingCollection(PGPUtil
+ .getDecoderStream(keyRingStream));
+ }
+ catch (PGPException e) {
+ // We recast this as a KeyException so that we don't leak
+ // any dependency on bouncycastle here
+ throw (KeyException) new KeyException("Reading the keyring failed - " +
+ e.getMessage()).initCause(e);
+ }
+ }
+
+ /**
+ * Verify that <code>asciiSig</code> is a valid signature for
+ * <code>message</code> using this key ring.
+ *
+ * @param message the cleartext message
+ * @param asciiSig the ASCII armored sigature
+ * @return <code>true</code> if the signature was generated from
+ * <code>message</code> using one of the private keys corresponding to the
+ * public keys on this key ring
+ * @throws SignatureException if processing hte signature fails
+ */
+ public boolean verifySignature(String message, String asciiSig)
+ throws SignatureException {
+ PGPSignature sig = decodeSignature(asciiSig);
+ PGPPublicKey key;
+ boolean result = false;
+ try {
+ key = keyRing.getPublicKey(sig.getKeyID());
+ sig.initVerify(key, RhnSecurityProvider.NAME);
+ sig.update(message.getBytes());
+
+ result = sig.verify();
+ }
+ catch (PGPException e) {
+ // We recast this as a SignatureException so that we don't leak
+ // any dependency on bouncycastle here
+ throw (SignatureException) new SignatureException("Verification failed - " +
+ e.getMessage()).initCause(e);
+ }
+ catch (NoSuchProviderException e) {
+ // We define the provider in the static block. Something weird is
+ // afoot
+ throw (IllegalStateException) new IllegalStateException("The provider " +
+ RhnSecurityProvider.NAME + " should be defined").initCause(e);
+ }
+ return result;
+ }
+
+ /**
+ * Turn the ASCII armored signature <code>asciiSig</code> into a
+ * <code>PGPSignature</code>
+ * @param asciiSig an ASCII armored signature
+ * @return the signature
+ */
+ private static PGPSignature decodeSignature(String asciiSig) {
+ PGPSignature result = null;
+ ByteArrayInputStream bais = new ByteArrayInputStream(asciiSig.getBytes());
+ try {
+ InputStream in = PGPUtil.getDecoderStream(new ArmoredInputStream(bais));
+ result = ((PGPSignatureList) new PGPObjectFactory(in).nextObject()).get(0);
+ in.close();
+ }
+ catch (IOException e) {
+ // This is so unlikely that we convert it to a runtime exception
+ throw (IllegalArgumentException) new IllegalArgumentException(
+ "The string asciiSig is not a valid signature").initCause(e);
+ }
+ return result;
+ }
+
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/RhnSecurityProvider.java b/proxy/code/src/com/redhat/rhn/common/cert/RhnSecurityProvider.java
new file mode 100644
index 0000000..e2df174
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/RhnSecurityProvider.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import java.security.Provider;
+
+import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+import org.bouncycastle.crypto.signers.DSASigner;
+import org.bouncycastle.jce.provider.JDKDSASigner;
+import org.bouncycastle.jce.provider.JDKKeyFactory;
+
+/**
+ * This JCE provider exists solely to hack around the fact that the bouncycastle
+ * provider does not offer <code>RIPEMD160 + DSA</code> signature processing. It
+ * cobbles the existing bits from bouncycastle together to add processing of
+ * these signatures.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+final class RhnSecurityProvider extends Provider {
+
+ /**
+ * The name under which this provider registers
+ */
+ public static final String NAME = "RHNSP";
+ private static final String INFO = "RHN Security Provider (provides RIPEMD160WithDSA signatures)";
+
+ /**
+ * Create the provider
+ */
+ public RhnSecurityProvider() {
+ super(NAME, 1.0, INFO);
+ put("KeyFactory.DSA", JDKKeyFactory.DSA.class.getName());
+ put("Signature.RIPEMD160WithDSA", RIPEMD160WithDSA.class.getName());
+ }
+
+ /**
+ * The signer that combines <code>RIPEMD160</code> hashing with DSA signing.
+ */
+ public static class RIPEMD160WithDSA extends JDKDSASigner {
+
+ public RIPEMD160WithDSA() {
+ super(new RIPEMD160Digest(), new DSASigner());
+ }
+
+ }
+
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/SimpleExtractor.java b/proxy/code/src/com/redhat/rhn/common/cert/SimpleExtractor.java
new file mode 100644
index 0000000..e6240f6
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/SimpleExtractor.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+
+/**
+ * SimpleExtractor.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+class SimpleExtractor implements FieldExtractor {
+
+ private String fieldName;
+ private String propertyName;
+ private boolean required;
+
+ public SimpleExtractor(String name) {
+ this(name, name, false);
+ }
+
+ public SimpleExtractor(String fieldName0, String propertyName0) {
+ this(fieldName0, propertyName0, false);
+ }
+
+ public SimpleExtractor(String name, boolean required0) {
+ this(name, name, required0);
+ }
+
+ /**
+ *
+ */
+ public SimpleExtractor(String fieldName0, String propertyName0, boolean required0) {
+ fieldName = fieldName0;
+ propertyName = propertyName0;
+ required = required0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws JDOMException
+ */
+ public void extract(Certificate target, Element field) throws JDOMException {
+ if (!PropertyUtils.isWriteable(target, propertyName)) {
+ throw new JDOMException("Property " + propertyName +
+ " is not writable in target " + target);
+ }
+
+ try {
+ BeanUtils.setProperty(target, propertyName, field.getTextTrim());
+ }
+ catch (IllegalAccessException e) {
+ throw new JDOMException("Could not set value of property " + propertyName, e);
+ }
+ catch (InvocationTargetException e) {
+ throw new JDOMException("Could not set value of property " + propertyName, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isRequired() {
+ return required;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+}
diff --git a/proxy/code/src/com/redhat/rhn/common/cert/XmlTag.java b/proxy/code/src/com/redhat/rhn/common/cert/XmlTag.java
new file mode 100644
index 0000000..ee4e0dc
--- /dev/null
+++ b/proxy/code/src/com/redhat/rhn/common/cert/XmlTag.java
@@ -0,0 +1,204 @@
+/**
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * This software is licensed to you under the GNU General Public License,
+ * version 2 (GPLv2). There is NO WARRANTY for this software, express or
+ * implied, including the implied warranties of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+ * along with this software; if not, see
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * Red Hat trademarks are not licensed under GPLv2. No permission is
+ * granted to use or replicate Red Hat trademarks that are incorporated
+ * in this software or its documentation.
+ */
+package com.redhat.rhn.common.cert;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * XmlTag a simple class to render an XML tag.
+ *
+ * Borrowed from project Spacewalk: http://spacewalk.redhat.com
+ */
+public class XmlTag {
+
+ private String tag;
+ private Map attribs;
+ private List body;
+ private boolean spaceBeforeEndTag;
+ private List keys;
+
+ /**
+ * Standard xml header with utf-8 encoding. Example usage:<br />
+ * <code>
+ * StringBuffer buf = new StringBuffer();
+ * buf.append(XmlTag.XML_HDR_UTF8);
+ * buf.append(new XmlTag("foo").render());
+ * </code>
+ */
+ public static final String XML_HDR_UTF8 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+
+ /**
+ * Standard xml header with no encoding. Example usage:<br />
+ * <code>
+ * StringBuffer buf = new StringBuffer();
+ * buf.append(XmlTag.XML_HDR);
+ * buf.append(new XmlTag("foo").render());
+ * </code>
+ */
+ public static final String XML_HDR = "<?xml version=\"1.0\"?>";
+
+ /**
+ * Public constructor
+ * @param tagIn the name of the tag
+ */
+ protected XmlTag(String tagIn) {
+ this(tagIn, true);
+ }
+
+ /**
+ * Constructs an XmlTag. The <code>spaceBefore</code> attribute controls
+ * whether a space is inserted before the closing tag of a single line
+ * element.<br />
+ * For example, a true value for spaceBefore and a tagIn of "foo" will
+ * render &lt;foo /&gt;. A spaceBefore value of false would've rendered
+ * &lt;foo/&gt;.
+ * @param tagIn the name of the tag
+ * @param spaceBefore true if you want a space before the closing tag.
+ */
+
+ protected XmlTag(String tagIn, boolean spaceBefore) {
+ attribs = new HashMap();
+ tag = tagIn;
+ body = new ArrayList();
+ keys = new ArrayList();
+ spaceBeforeEndTag = spaceBefore;
+ }
+
+ /**
+ * set an attribute of the html tag
+ * @param name the attribute name
+ * @param value the attribute value
+ */
+ public void setAttribute(String name, String value) {
+ attribs.put(name, value);
+ keys.add(name);
+ }
+
+ /**
+ * Removes an attribute of the html tag.
+ * @param name the attribute name to be removed.
+ */
+ public void removeAttribute(String name) {
+ attribs.remove(name);
+ keys.remove(name);
+ }
+
+ /**
+ * set the body of the tag
+ * @param bodyIn the new body
+ */
+ public void addBody(String bodyIn) {
+ body.add(bodyIn);
+ }
+
+ /**
+ * Adds the given tag to the body of this tag.
+ * @param bodyTag Tag to be added to the body of this tag.
+ */
+ public void addBody(XmlTag bodyTag) {
+ body.add(bodyTag);
+ }
+
+ /**
+ * render the tag into a string
+ * @return the string version
+ */
+ public String render() {
+ StringBuffer ret = new StringBuffer();
+ ret.append(renderOpenTag());
+ if (!hasBody()) {
+ ret.deleteCharAt(ret.length() - 1);
+ if (spaceBeforeEndTag) {
+ ret.append(" />");
+ }
+ else {
+ ret.append("/>");
+ }
+ }
+ else {
+ ret.append(renderBody());
+ ret.append(renderCloseTag());
+ }
+ return ret.toString();
+ }
+
+ /**
+ * render the open tag and attributes
+ * @return the open tag as a string
+ */
+ public String renderOpenTag() {
+ StringBuffer ret = new StringBuffer("<");
+ ret.append(tag);
+
+ Iterator i = keys.iterator();
+ while (i.hasNext()) {
+ String attrib = (String) i.next();
+ ret.append(" ");
+ ret.append(attrib);
+ ret.append("=\"");
+ ret.append((String) attribs.get(attrib));
+ ret.append("\"");
+ }
+ ret.append(">");
+
+ return ret.toString();
+ }
+
+ /**
+ * render the tag body
+ * @return the tag body as a string
+ */
+ public String renderBody() {
+ StringBuffer buf = new StringBuffer();
+
+ for (Iterator itr = body.iterator(); itr.hasNext();) {
+ buf.append(convertToString(itr.next()));
+ }
+
+ return buf.toString();
+ }
+
+ private String convertToString(Object o) {
+ if (o instanceof XmlTag) {
+ return ((XmlTag) o).render();
+ }
+ else if (o instanceof String) {
+ return (String) o;
+ }
+ else {
+ return o.toString();
+ }
+ }
+
+ /**
+ * render the close tag
+ * @return the close tag as a string
+ */
+ public String renderCloseTag() {
+ return "</" + tag + ">";
+ }
+
+ /**
+ * Returns true if this tag has a body defined.
+ * @return true if this tag has a body defined.
+ */
+ public boolean hasBody() {
+ return (body.size() > 0);
+ }
+}
diff --git a/proxy/ivy.xml b/proxy/ivy.xml
index 178adce..39ae2c3 100644
--- a/proxy/ivy.xml
+++ b/proxy/ivy.xml
@@ -6,7 +6,7 @@
<!-- dependency org="candlepin" name="asm" rev="1.5.3" / -->
<!-- dependency org="candlepin" name="asm-attrs" rev="1.5.3" / -->
<dependency org="candlepin" name="bcel" rev="5.2" />
- <!-- dependency org="candlepin" name="bcpg" rev="1.37" / -->
+ <dependency org="candlepin" name="bcpg" rev="1.43" />
<dependency org="candlepin" name="bcprov" rev="1.43" />
<!-- dependency org="candlepin" name="c3p0" rev="0.9.0" / -->
<dependency org="candlepin" name="cglib" rev="2.2" />
@@ -51,7 +51,7 @@
<!-- dependency org="candlepin" name="jasper5-compiler" rev="5.0.19" / -->
<!-- dependency org="candlepin" name="jasper5-runtime" rev="5.0.19" / -->
<!-- dependency org="candlepin" name="jcommon" rev="1.0.12" / -->
- <!-- dependency org="candlepin" name="jdom" rev="1.0" / -->
+ <dependency org="candlepin" name="jdom" rev="1.0" />
<!-- dependency org="candlepin" name="jfreechart" rev="1.0.9" / -->
<!-- dependency org="candlepin" name="jmock" rev="1.2.0" / -->
<!-- dependency org="candlepin" name="jmock-cglib" rev="1.2.0" / -->