diff options
author | jesus m. rodriguez <jesusr@redhat.com> | 2009-11-11 10:23:53 -0500 |
---|---|---|
committer | jesus m. rodriguez <jesusr@redhat.com> | 2009-11-11 10:23:53 -0500 |
commit | d260d8e35640c5d4ee8ceec7def2ee640a888e24 (patch) | |
tree | 4d1ce09be229278a748801f2b1a107f539de403b | |
parent | c180c375652ac88d2fc84874aabf6b12b9c567f8 (diff) | |
parent | 2a1aa07eae5cf63e1440456ca4a3bf78239a957f (diff) | |
download | candlepin-d260d8e35640c5d4ee8ceec7def2ee640a888e24.tar.gz candlepin-d260d8e35640c5d4ee8ceec7def2ee640a888e24.tar.xz candlepin-d260d8e35640c5d4ee8ceec7def2ee640a888e24.zip |
Merge branch 'master' into buildr
11 files changed, 1221 insertions, 5 deletions
diff --git a/proxy/buildconf/build.properties b/proxy/buildconf/build.properties index e22e124..0360629 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 <foo />. A spaceBefore value of false would've rendered + * <foo/>. + * @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..634adde 100644 --- a/proxy/ivy.xml +++ b/proxy/ivy.xml @@ -6,12 +6,12 @@ <!-- 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" /> <dependency org="candlepin" name="checkstyle" rev="4.1" /> - <!-- dependency org="candlepin" name="commons-beanutils" rev="1.7.0" / --> + <dependency org="candlepin" name="commons-beanutils" rev="1.7.0" /> <!-- dependency org="candlepin" name="commons-cli" rev="1.0" / --> <!-- dependency org="candlepin" name="commons-codec" rev="1.2" / --> <dependency org="candlepin" name="commons-collections" rev="3.1" /> @@ -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" / --> |