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.encryption;
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.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  /**
28   * An implementation of {@link EncryptedKeyResolver} which chains multiple other resolver implementations together,
29   * calling them in the order specified in the resolver list.
30   */
31  public class ChainingEncryptedKeyResolver extends AbstractEncryptedKeyResolver {
32  
33      /** The list of resolvers which form the resolution chain. */
34      private final List<EncryptedKeyResolver> resolvers;
35  
36      /** Class logger. */
37      private final Logger log = LoggerFactory.getLogger(ChainingEncryptedKeyResolver.class);
38  
39      /** Constructor. */
40      public ChainingEncryptedKeyResolver() {
41          resolvers = new ArrayList<EncryptedKeyResolver>();
42      }
43  
44      /**
45       * Get the list of resolvers which form the resolution chain.
46       * 
47       * @return a list of EncryptedKeyResolver instances
48       */
49      public List<EncryptedKeyResolver> getResolverChain() {
50          return resolvers;
51      }
52  
53      /** {@inheritDoc} */
54      public Iterable<EncryptedKey> resolve(EncryptedData encryptedData) {
55          if (resolvers.isEmpty()) {
56              log.warn("Chaining encrypted key resolver resolution was attempted with an empty resolver chain");
57              throw new IllegalStateException("The resolver chain is empty");
58          }
59          return new ChainingIterable(this, encryptedData);
60      }
61  
62      /**
63       * Implementation of {@link Iterable} to be returned by {@link ChainingEncryptedKeyResolver}.
64       */
65      public class ChainingIterable implements Iterable<EncryptedKey> {
66  
67          /** The chaining encrypted key resolver which owns this instance. */
68          private ChainingEncryptedKeyResolver parent;
69  
70          /** The EncryptedData context for resolution. */
71          private EncryptedData encryptedData;
72  
73          /**
74           * Constructor.
75           * 
76           * @param resolver the ChainingEncryptedKeyResolver parent
77           * @param encData the EncryptedData context for resolution
78           */
79          public ChainingIterable(ChainingEncryptedKeyResolver resolver, EncryptedData encData) {
80              parent = resolver;
81              encryptedData = encData;
82          }
83  
84          /** {@inheritDoc} */
85          public Iterator<EncryptedKey> iterator() {
86              return new ChainingIterator(parent, encryptedData);
87          }
88  
89      }
90  
91      /**
92       * Implementation of {@link Iterator} to be (indirectly) returned by {@link ChainingEncryptedKeyResolver}.
93       * 
94       */
95      public class ChainingIterator implements Iterator<EncryptedKey> {
96  
97          /** Class logger. */
98          private final Logger log = LoggerFactory.getLogger(ChainingEncryptedKeyResolver.ChainingIterator.class);
99  
100         /** The chaining encrypted key resolver which owns this instance. */
101         private ChainingEncryptedKeyResolver parent;
102 
103         /** The EncryptedData context for resolution. */
104         private EncryptedData encryptedData;
105 
106         /** The iterator over resolvers in the chain. */
107         private Iterator<EncryptedKeyResolver> resolverIterator;
108 
109         /** The iterator over EncryptedKey instances from the current resolver. */
110         private Iterator<EncryptedKey> keyIterator;
111 
112         /** The current resolver which is returning encrypted keys. */
113         private EncryptedKeyResolver currentResolver;
114 
115         /** The next encrypted key that is safe to return. */
116         private EncryptedKey nextKey;
117 
118         /**
119          * Constructor.
120          * 
121          * @param resolver the ChainingEncryptedKeyResolver parent
122          * @param encData the EncryptedData context for resolution
123          */
124         public ChainingIterator(ChainingEncryptedKeyResolver resolver, EncryptedData encData) {
125             parent = resolver;
126             encryptedData = encData;
127             resolverIterator = parent.getResolverChain().iterator();
128             keyIterator = getNextKeyIterator();
129             nextKey = null;
130         }
131 
132         /** {@inheritDoc} */
133         public boolean hasNext() {
134             if (nextKey != null) {
135                 return true;
136             }
137             nextKey = getNextKey();
138             if (nextKey != null) {
139                 return true;
140             }
141             return false;
142         }
143 
144         /** {@inheritDoc} */
145         public EncryptedKey next() {
146             EncryptedKey tempKey;
147             if (nextKey != null) {
148                 tempKey = nextKey;
149                 nextKey = null;
150                 return tempKey;
151             }
152             tempKey = getNextKey();
153             if (tempKey != null) {
154                 return tempKey;
155             } else {
156                 throw new NoSuchElementException("No more EncryptedKey elements are available");
157             }
158         }
159 
160         /** {@inheritDoc} */
161         public void remove() {
162             throw new UnsupportedOperationException("Remove operation is not supported by this iterator");
163         }
164 
165         /**
166          * Get the iterator from the next resolver in the chain.
167          * 
168          * @return an iterator of encrypted keys
169          */
170         private Iterator<EncryptedKey> getNextKeyIterator() {
171             if (resolverIterator.hasNext()) {
172                 currentResolver = resolverIterator.next();
173                 log.debug("Getting key iterator from next resolver: {}", currentResolver.getClass().toString());
174                 return currentResolver.resolve(encryptedData).iterator();
175             } else {
176                 log.debug("No more resolvers available in the resolver chain");
177                 currentResolver = null;
178                 return null;
179             }
180         }
181 
182         /**
183          * Get the next encrypted key that will be returned by this iterator.
184          * 
185          * @return the next encrypted key to return
186          */
187         private EncryptedKey getNextKey() {
188             EncryptedKey tempKey;
189 
190             if (keyIterator != null) {
191                 while (keyIterator.hasNext()) {
192                     tempKey = keyIterator.next();
193                     if (parent.matchRecipient(tempKey.getRecipient())) {
194                         log.debug("Found matching encrypted key: {}", tempKey.toString());
195                         return tempKey;
196                     }
197                 }
198             }
199 
200             keyIterator = getNextKeyIterator();
201             while (keyIterator != null) {
202                 while (keyIterator.hasNext()) {
203                     tempKey = keyIterator.next();
204                     if (parent.matchRecipient(tempKey.getRecipient())) {
205                         log.debug("Found matching encrypted key: {}", tempKey.toString());
206                         return tempKey;
207                     }
208                 }
209                 keyIterator = getNextKeyIterator();
210             }
211 
212             return null;
213         }
214 
215     }
216 
217 }