View Javadoc

1   /*
2    * Copyright [2007] [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.credential;
18  
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.NoSuchElementException;
23  
24  import org.opensaml.xml.security.CriteriaSet;
25  import org.opensaml.xml.security.SecurityException;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  /**
30   * An implementation of {@link CredentialResolver} which chains together one or more underlying credential resolver
31   * implementations. Resolved credentials are returned from all underlying resolvers in the chain, in the order implied
32   * by the order of the resolvers in the chain.
33   */
34  public class ChainingCredentialResolver extends AbstractCredentialResolver {
35  
36      /** Logger. */
37      private final Logger log = LoggerFactory.getLogger(ChainingCredentialResolver.class);
38  
39      /** List of credential resolvers in the chain. */
40      private List<CredentialResolver> resolvers;
41  
42      /**
43       * Constructor.
44       */
45      public ChainingCredentialResolver() {
46          resolvers = new ArrayList<CredentialResolver>();
47      }
48  
49      /**
50       * Get the (modifiable) list of credential resolvers which comprise the resolver chain.
51       * 
52       * @return the list of credential resolvers in the chain
53       */
54      public List<CredentialResolver> getResolverChain() {
55          return resolvers;
56      }
57  
58      /** {@inheritDoc} */
59      public Iterable<Credential> resolve(CriteriaSet criteriaSet) throws SecurityException {
60          if (resolvers.isEmpty()) {
61              log.warn("Chaining credential resolver resolution was attempted with an empty resolver chain");
62              throw new IllegalStateException("The resolver chain is empty");
63          }
64          return new CredentialIterable(this, criteriaSet);
65      }
66  
67      /**
68       * Implementation of {@link Iterable} to be returned by {@link ChainingCredentialResolver}.
69       */
70      public class CredentialIterable implements Iterable<Credential> {
71  
72          /** The chaining credential resolver which owns this instance. */
73          private ChainingCredentialResolver parent;
74  
75          /** The criteria set on which to base resolution. */
76          private CriteriaSet critSet;
77  
78          /**
79           * Constructor.
80           * 
81           * @param resolver the chaining parent of this iterable
82           * @param criteriaSet the set of criteria which is input to the underyling resolvers
83           */
84          public CredentialIterable(ChainingCredentialResolver resolver, CriteriaSet criteriaSet) {
85              parent = resolver;
86              critSet = criteriaSet;
87          }
88  
89          /** {@inheritDoc} */
90          public Iterator<Credential> iterator() {
91              return new CredentialIterator(parent, critSet);
92          }
93  
94      }
95  
96      /**
97       * Implementation of {@link Iterator} to be returned (indirectly) by {@link ChainingCredentialResolver}.
98       */
99      public class CredentialIterator implements Iterator<Credential> {
100 
101         /** Logger. */
102         private final Logger log = LoggerFactory.getLogger(CredentialIterator.class);
103 
104         /** The chaining credential resolver which owns this instance. */
105         private ChainingCredentialResolver parent;
106 
107         /** The criteria set on which to base resolution. */
108         private CriteriaSet critSet;
109 
110         /** The iterator over resolvers in the chain. */
111         private Iterator<CredentialResolver> resolverIterator;
112 
113         /** The iterator over Credential instances from the current resolver. */
114         private Iterator<Credential> credentialIterator;
115 
116         /** The current resolver which is returning credentials. */
117         private CredentialResolver currentResolver;
118 
119         /** The next credential that is safe to return. */
120         private Credential nextCredential;
121 
122         /**
123          * Constructor.
124          * 
125          * @param resolver the chaining parent of this iterable
126          * @param criteriaSet the set of criteria which is input to the underyling resolvers
127          */
128         public CredentialIterator(ChainingCredentialResolver resolver, CriteriaSet criteriaSet) {
129             parent = resolver;
130             critSet = criteriaSet;
131             resolverIterator = parent.getResolverChain().iterator();
132             credentialIterator = getNextCredentialIterator();
133             nextCredential = null;
134         }
135 
136         /** {@inheritDoc} */
137         public boolean hasNext() {
138             if (nextCredential != null) {
139                 return true;
140             }
141             nextCredential = getNextCredential();
142             if (nextCredential != null) {
143                 return true;
144             }
145             return false;
146         }
147 
148         /** {@inheritDoc} */
149         public Credential next() {
150             Credential tempCred;
151             if (nextCredential != null) {
152                 tempCred = nextCredential;
153                 nextCredential = null;
154                 return tempCred;
155             }
156             tempCred = getNextCredential();
157             if (tempCred != null) {
158                 return tempCred;
159             } else {
160                 throw new NoSuchElementException("No more Credential elements are available");
161             }
162         }
163 
164         /** {@inheritDoc} */
165         public void remove() {
166             throw new UnsupportedOperationException("Remove operation is not supported by this iterator");
167         }
168 
169         /**
170          * Get the iterator from the next resolver in the chain.
171          * 
172          * @return an iterator of credentials
173          */
174         private Iterator<Credential> getNextCredentialIterator() {
175             while (resolverIterator.hasNext()) {
176                 currentResolver = resolverIterator.next();
177                     log.debug("Getting credential iterator from next resolver in chain: {}", currentResolver.getClass().toString());
178                 try {
179                     return currentResolver.resolve(critSet).iterator();
180                 } catch (SecurityException e) {
181                     log.error(String.format("Error resolving credentials from chaining resolver member '%s'",
182                             currentResolver.getClass().getName()), e);
183                     if (resolverIterator.hasNext()) {
184                         log.error("Will attempt to resolve credentials from next member of resolver chain");
185                     }
186                 }
187             }
188 
189             log.debug("No more credential resolvers available in the resolver chain");
190             currentResolver = null;
191             return null;
192         }
193 
194         /**
195          * Get the next credential that will be returned by this iterator.
196          * 
197          * @return the next credential to return
198          */
199         private Credential getNextCredential() {
200             if (credentialIterator != null) {
201                 if (credentialIterator.hasNext()) {
202                     return credentialIterator.next();
203                 }
204             }
205 
206             credentialIterator = getNextCredentialIterator();
207             while (credentialIterator != null) {
208                 if (credentialIterator.hasNext()) {
209                     return credentialIterator.next();
210                 }
211                 credentialIterator = getNextCredentialIterator();
212             }
213 
214             return null;
215         }
216 
217     }
218 
219 }