View Javadoc

1   /*
2    * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.xml.security.x509;
18  
19  import java.util.Set;
20  
21  import org.opensaml.xml.security.CriteriaSet;
22  import org.opensaml.xml.security.SecurityException;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  /**
27   * Trust engine implementation which evaluates an X509Credential token based on PKIX validation processing using
28   * validation information from a trusted source.
29   * 
30   */
31  public class PKIXX509CredentialTrustEngine implements PKIXTrustEngine<X509Credential> {
32  
33      /** Class logger. */
34      private final Logger log = LoggerFactory.getLogger(PKIXX509CredentialTrustEngine.class);
35  
36      /** Resolver used for resolving trusted credentials. */
37      private PKIXValidationInformationResolver pkixResolver;
38  
39      /** The external PKIX trust evaluator used to establish trust. */
40      private PKIXTrustEvaluator pkixTrustEvaluator;
41      
42      /** The external credential name evaluator used to establish trusted name compliance. */
43      private X509CredentialNameEvaluator credNameEvaluator;
44  
45      /**
46       * Constructor.
47       * 
48       * <p>The PKIX trust evaluator used defaults to {@link CertPathPKIXTrustEvaluator}.</p>
49       * 
50       * <p>The X.509 credential name evaluator used defaults to {@link BasicX509CredentialNameEvaluator}.</p>
51       * 
52       * @param resolver credential resolver used to resolve trusted credentials
53       */
54      public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver) {
55          if (resolver == null) {
56              throw new IllegalArgumentException("PKIX trust information resolver may not be null");
57          }
58          pkixResolver = resolver;
59  
60          pkixTrustEvaluator = new CertPathPKIXTrustEvaluator();
61          credNameEvaluator = new BasicX509CredentialNameEvaluator();
62      }
63      
64      /**
65       * Constructor.
66       * 
67       * @param resolver credential resolver used to resolve trusted credentials
68       * @param pkixEvaluator the PKIX trust evaluator to use
69       * @param nameEvaluator the X.509 credential name evaluator to use (may be null)
70       */
71      public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver, PKIXTrustEvaluator pkixEvaluator,
72              X509CredentialNameEvaluator nameEvaluator) {
73          if (resolver == null) {
74              throw new IllegalArgumentException("PKIX trust information resolver may not be null");
75          }
76          pkixResolver = resolver;
77  
78          if (pkixEvaluator == null) {
79              throw new IllegalArgumentException("PKIX trust evaluator may not be null");
80          }
81          pkixTrustEvaluator = pkixEvaluator;
82          credNameEvaluator = nameEvaluator;
83      }
84  
85      /** {@inheritDoc} */
86      public PKIXValidationInformationResolver getPKIXResolver() {
87          return pkixResolver;
88      }
89  
90      /**
91       * Get the PKIXTrustEvaluator instance used to evalute trust.
92       * 
93       * <p>The parameters of this evaluator may be modified to
94       * adjust trust evaluation processing.</p>
95       * 
96       * @return the PKIX trust evaluator instance that will be used
97       */
98      public PKIXTrustEvaluator getPKIXTrustEvaluator() {
99          return pkixTrustEvaluator;
100     }
101     
102     /**
103      * Get the X509CredentialNameEvaluator instance used to evalute a credential 
104      * against trusted names.
105      * 
106      * <p>The parameters of this evaluator may be modified to
107      * adjust trust evaluation processing.</p>
108      * 
109      * @return the PKIX trust evaluator instance that will be used
110      */
111     public X509CredentialNameEvaluator getX509CredentialNameEvaluator() {
112         return credNameEvaluator;
113     }
114 
115     /** {@inheritDoc} */
116     public boolean validate(X509Credential untrustedCredential, CriteriaSet trustBasisCriteria)
117         throws SecurityException {
118         
119         log.debug("Attempting PKIX validation of untrusted credential");
120 
121         if (untrustedCredential == null) {
122             log.error("X.509 credential was null, unable to perform validation");
123             return false;
124         }
125 
126         if (untrustedCredential.getEntityCertificate() == null) {
127             log.error("Untrusted X.509 credential's entity certificate was null, unable to perform validation");
128             return false;
129         }
130 
131         Set<String> trustedNames = null;
132         if (pkixResolver.supportsTrustedNameResolution()) {
133             trustedNames = pkixResolver.resolveTrustedNames(trustBasisCriteria);
134         } else {
135             log.debug("PKIX resolver does not support resolution of trusted names, skipping name checking");
136         }
137 
138         return validate(untrustedCredential, trustedNames, pkixResolver.resolve(trustBasisCriteria));
139     }
140 
141     /**
142      * Perform PKIX validation on the untrusted credential, using PKIX validation information based on the supplied set
143      * of trusted credentials.
144      * 
145      * @param untrustedX509Credential the credential to evaluate
146      * @param validationInfoSet the set of validation information which serves as ths basis for trust evaluation
147      * @param trustedNames the set of trusted names for name checking purposes
148      * 
149      * @return true if PKIX validation of the untrusted credential is successful, otherwise false
150      * @throws SecurityException thrown if there is an error validating the untrusted credential
151      *          against trusted names or validation information
152      */
153     protected boolean validate(X509Credential untrustedX509Credential, Set<String> trustedNames,
154             Iterable<PKIXValidationInformation> validationInfoSet) throws SecurityException {
155         
156         log.debug("Beginning PKIX validation using trusted validation information");
157 
158         if (!checkNames(trustedNames, untrustedX509Credential)) {
159             log.error("Evaluation of credential against trusted names failed. Aborting PKIX validation");
160             return false;
161         }
162 
163         for (PKIXValidationInformation validationInfo : validationInfoSet) {
164             try {
165                 if (pkixTrustEvaluator.validate(validationInfo, untrustedX509Credential)) {
166                     log.debug("Credential trust established via PKIX validation");
167                     return true;
168                 }
169             } catch (SecurityException e) {
170                 // log the operational error, but allow other validation info sets to be tried
171                 log.error("Error performing PKIX validation on untrusted credential", e);
172             }
173         }
174         log.debug("Trust of untrusted credential could not be established via PKIX validation");
175         return false;
176     }
177     
178     /**
179      * Evaluate the credential against the set of trusted names.
180      * 
181      * <p>Evaluates to true if no intsance of {@link X509CredentialNameEvaluator} is configured.</p>
182      * 
183      * @param trustedNames set of trusted names
184      * @param untrustedCredential the credential being evaluated
185      * @return true if evaluation is successful, false otherwise
186      * @throws SecurityException thrown if there is an error evaluation the credential
187      */
188     protected boolean checkNames(Set<String> trustedNames, X509Credential untrustedCredential) 
189             throws SecurityException {
190         
191         if (credNameEvaluator == null) {
192             log.debug("No credential name evaluator was available, skipping trusted name evaluation");
193            return true; 
194         } else {
195             return credNameEvaluator.evaluate(untrustedCredential, trustedNames);
196         }
197 
198     }
199 
200 }