View Javadoc

1   /*
2    * Licensed to the University Corporation for Advanced Internet Development, 
3    * Inc. (UCAID) under one or more contributor license agreements.  See the 
4    * NOTICE file distributed with this work for additional information regarding
5    * copyright ownership. The UCAID licenses this file to You under the Apache 
6    * License, Version 2.0 (the "License"); you may not use this file except in 
7    * compliance with the License.  You may obtain a copy of the License at
8    *
9    *    http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package edu.internet2.middleware.shibboleth.common.config.security;
19  
20  import java.security.cert.CRLException;
21  import java.security.cert.CertificateException;
22  import java.security.cert.X509CRL;
23  import java.security.cert.X509Certificate;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.xml.namespace.QName;
30  
31  import org.opensaml.xml.security.x509.X509Util;
32  import org.opensaml.xml.util.DatatypeHelper;
33  import org.opensaml.xml.util.XMLHelper;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  import org.springframework.beans.FatalBeanException;
37  import org.springframework.beans.factory.support.AbstractBeanDefinition;
38  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
39  import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
40  import org.springframework.beans.factory.xml.ParserContext;
41  import org.w3c.dom.Element;
42  
43  /**
44   * Base class for PKIXValidationInformation beans.
45   */
46  public abstract class AbstractPKIXValidationInformationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
47  
48      /** Class logger. */
49      private final Logger log = LoggerFactory.getLogger(AbstractX509CredentialBeanDefinitionParser.class);
50  
51      /** {@inheritDoc} */
52      protected Class getBeanClass(Element element) {
53          return PKIXValidationInformationFactoryBean.class;
54      }
55  
56      /** {@inheritDoc} */
57      protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
58          return element.getAttributeNS(null, "id");
59      }
60  
61      /** {@inheritDoc} */
62      protected void doParse(Element element, BeanDefinitionBuilder builder) {
63          log.debug("Parsing PKIX ValidationInfo: {}", element.getAttributeNS(null, "id"));
64  
65          int depth = 1;
66          if (element.hasAttributeNS(null, "verifyDepth")) {
67              depth = new Integer(DatatypeHelper.safeTrim(element.getAttributeNS(null, "verifyDepth")));
68          }
69          
70          builder.addPropertyValue("verifyDepth", depth);
71  
72          Map<QName, List<Element>> configChildren = XMLHelper.getChildElements(element);
73  
74          parseCertificates(configChildren, builder);
75          parseCRLs(configChildren, builder);
76      }
77  
78      /**
79       * Parses the certificates from the validation info configuration.
80       * 
81       * @param configChildren children of the validation set element
82       * @param builder validation set build
83       */
84      protected void parseCertificates(Map<QName, List<Element>> configChildren, BeanDefinitionBuilder builder) {
85          List<Element> certElems = configChildren.get(new QName(SecurityNamespaceHandler.NAMESPACE, "Certificate"));
86          if (certElems == null || certElems.isEmpty()) {
87              return;
88          }
89  
90          log.debug("Parsing PKIX validation info certificates");
91          ArrayList<X509Certificate> certs = new ArrayList<X509Certificate>();
92          byte[] encodedCert;
93          Collection<X509Certificate> decodedCerts;
94          for (Element certElem : certElems) {
95              encodedCert = getEncodedCertificate(DatatypeHelper.safeTrimOrNullString(certElem.getTextContent()));
96              if (encodedCert == null) {
97                  continue;
98              }
99  
100             try {
101                 decodedCerts = X509Util.decodeCertificate(encodedCert);
102                 certs.addAll(decodedCerts);
103             } catch (CertificateException e) {
104                 throw new FatalBeanException("Unable to create PKIX validation info, unable to parse certificates", e);
105             }
106         }
107 
108         builder.addPropertyValue("certificates", certs);
109     }
110 
111     /**
112      * Extracts the certificate bytes from the content of a Certificate configuration element.
113      * 
114      * @param certConfigContent content of a Certificate configuration element
115      * 
116      * @return certificate bytes
117      */
118     protected abstract byte[] getEncodedCertificate(String certConfigContent);
119 
120     /**
121      * Parses the CRLs from the validation info configuration.
122      * 
123      * @param configChildren children of the validation info element
124      * @param builder validation info build
125      */
126     protected void parseCRLs(Map<QName, List<Element>> configChildren, BeanDefinitionBuilder builder) {
127         List<Element> crlElems = configChildren.get(new QName(SecurityNamespaceHandler.NAMESPACE, "CRL"));
128         if (crlElems == null || crlElems.isEmpty()) {
129             return;
130         }
131 
132         log.debug("Parsing PKIX validation info CRLs");
133         ArrayList<X509CRL> crls = new ArrayList<X509CRL>();
134         byte[] encodedCRL;
135         Collection<X509CRL> decodedCRLs;
136         for (Element crlElem : crlElems) {
137             encodedCRL = getEncodedCRL(DatatypeHelper.safeTrimOrNullString(crlElem.getTextContent()));
138             if (encodedCRL == null) {
139                 continue;
140             }
141 
142             try {
143                 decodedCRLs = X509Util.decodeCRLs(encodedCRL);
144                 crls.addAll(decodedCRLs);
145             } catch (CRLException e) {
146                 throw new FatalBeanException("Unable to create PKIX validation info, unable to parse CRLs", e);
147             }
148         }
149 
150         builder.addPropertyValue("crls", crls);
151     }
152 
153     /**
154      * Extracts the CRL(s) bytes from the content of a CRL configuration element.
155      * 
156      * @param certCRLContent content of a CRL configuration element
157      * 
158      * @return CRL bytes
159      */
160     protected abstract byte[] getEncodedCRL(String certCRLContent);
161 }