1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.security.credential;
18
19 import java.security.GeneralSecurityException;
20 import java.security.KeyStore;
21 import java.security.KeyStoreException;
22 import java.security.UnrecoverableEntryException;
23 import java.security.KeyStore.SecretKeyEntry;
24 import java.security.cert.X509Certificate;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Map;
29
30 import org.opensaml.xml.security.CriteriaSet;
31 import org.opensaml.xml.security.SecurityException;
32 import org.opensaml.xml.security.criteria.EntityIDCriteria;
33 import org.opensaml.xml.security.criteria.UsageCriteria;
34 import org.opensaml.xml.security.x509.BasicX509Credential;
35 import org.opensaml.xml.security.x509.X509Credential;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44
45 public class KeyStoreCredentialResolver extends AbstractCriteriaFilteringCredentialResolver {
46
47
48 private final Logger log = LoggerFactory.getLogger(KeyStoreCredentialResolver.class);
49
50
51 private KeyStore keyStore;
52
53
54 private Map<String, String> keyPasswords;
55
56
57 private UsageType keystoreUsage;
58
59
60
61
62
63
64
65
66
67 public KeyStoreCredentialResolver(KeyStore store, Map<String, String> passwords) throws IllegalArgumentException {
68 this(store, passwords, null);
69 }
70
71
72
73
74
75
76
77
78
79
80 public KeyStoreCredentialResolver(KeyStore store, Map<String, String> passwords, UsageType usage)
81 throws IllegalArgumentException {
82 super();
83
84 if (store == null) {
85 throw new IllegalArgumentException("Provided key store may not be null.");
86 }
87
88 try {
89 store.size();
90 } catch (KeyStoreException e) {
91 throw new IllegalArgumentException("Keystore has not been initialized.");
92 }
93
94 keyStore = store;
95
96 if (usage != null) {
97 keystoreUsage = usage;
98 } else {
99 keystoreUsage = UsageType.UNSPECIFIED;
100 }
101
102 keyPasswords = passwords;
103 }
104
105
106 protected Iterable<Credential> resolveFromSource(CriteriaSet criteriaSet) throws SecurityException {
107
108 checkCriteriaRequirements(criteriaSet);
109
110 String entityID = criteriaSet.get(EntityIDCriteria.class).getEntityID();
111 UsageCriteria usageCriteria = criteriaSet.get(UsageCriteria.class);
112 UsageType usage;
113 if (usageCriteria != null) {
114 usage = usageCriteria.getUsage();
115 } else {
116 usage = UsageType.UNSPECIFIED;
117 }
118 if (!matchUsage(keystoreUsage, usage)) {
119 log.debug("Specified usage criteria {} does not match keystore usage {}", usage, keystoreUsage);
120 log.debug("Can not resolve credentials from this keystore");
121 return Collections.emptySet();
122 }
123
124 KeyStore.PasswordProtection keyPassword = null;
125 if (keyPasswords.containsKey(entityID)) {
126 keyPassword = new KeyStore.PasswordProtection(keyPasswords.get(entityID).toCharArray());
127 }
128
129 KeyStore.Entry keyStoreEntry = null;
130 try {
131 keyStoreEntry = keyStore.getEntry(entityID, keyPassword);
132 } catch (UnrecoverableEntryException e) {
133 log.error("Unable to retrieve keystore entry for entityID (keystore alias): " + entityID);
134 log.error("Check for invalid keystore entityID/alias entry password");
135 throw new SecurityException("Could not retrieve entry from keystore", e);
136 } catch (GeneralSecurityException e) {
137 log.error("Unable to retrieve keystore entry for entityID (keystore alias): " + entityID, e);
138 throw new SecurityException("Could not retrieve entry from keystore", e);
139 }
140
141 if (keyStoreEntry == null) {
142 log.debug("Keystore entry for entity ID (keystore alias) {} does not exist", entityID);
143 return Collections.emptySet();
144 }
145
146 Credential credential = buildCredential(keyStoreEntry, entityID, keystoreUsage);
147 return Collections.singleton(credential);
148 }
149
150
151
152
153
154
155 protected void checkCriteriaRequirements(CriteriaSet criteriaSet) {
156 EntityIDCriteria entityCriteria = criteriaSet.get(EntityIDCriteria.class);
157 if (entityCriteria == null) {
158 log.error("EntityIDCriteria was not specified in the criteria set, resolution can not be attempted");
159 throw new IllegalArgumentException("No EntityIDCriteria was available in criteria set");
160 }
161 }
162
163
164
165
166
167
168
169
170 protected boolean matchUsage(UsageType keyStoreUsage, UsageType criteriaUsage) {
171 if (keyStoreUsage == UsageType.UNSPECIFIED || criteriaUsage == UsageType.UNSPECIFIED) {
172 return true;
173 }
174 return keyStoreUsage == criteriaUsage;
175 }
176
177
178
179
180
181
182
183
184
185
186 protected Credential buildCredential(KeyStore.Entry keyStoreEntry, String entityID, UsageType usage)
187 throws SecurityException {
188
189 log.debug("Building credential from keystore entry for entityID {}, usage type {}", entityID, usage);
190
191 Credential credential = null;
192 if (keyStoreEntry instanceof KeyStore.PrivateKeyEntry) {
193 credential = processPrivateKeyEntry((KeyStore.PrivateKeyEntry) keyStoreEntry, entityID, keystoreUsage);
194 } else if (keyStoreEntry instanceof KeyStore.TrustedCertificateEntry) {
195 credential = processTrustedCertificateEntry((KeyStore.TrustedCertificateEntry) keyStoreEntry, entityID,
196 keystoreUsage);
197 } else if (keyStoreEntry instanceof KeyStore.SecretKeyEntry) {
198 credential = processSecretKeyEntry((KeyStore.SecretKeyEntry) keyStoreEntry, entityID, keystoreUsage);
199 } else {
200 throw new SecurityException("KeyStore entry was of an unsupported type: "
201 + keyStoreEntry.getClass().getName());
202 }
203 return credential;
204 }
205
206
207
208
209
210
211
212
213
214 protected X509Credential processTrustedCertificateEntry(KeyStore.TrustedCertificateEntry trustedCertEntry,
215 String entityID, UsageType usage) {
216
217 log.debug("Processing TrustedCertificateEntry from keystore");
218
219 BasicX509Credential credential = new BasicX509Credential();
220 credential.setEntityId(entityID);
221 credential.setUsageType(usage);
222
223 X509Certificate cert = (X509Certificate) trustedCertEntry.getTrustedCertificate();
224
225 credential.setEntityCertificate(cert);
226
227 ArrayList<X509Certificate> certChain = new ArrayList<X509Certificate>();
228 certChain.add(cert);
229 credential.setEntityCertificateChain(certChain);
230
231 return credential;
232 }
233
234
235
236
237
238
239
240
241
242 protected X509Credential processPrivateKeyEntry(KeyStore.PrivateKeyEntry privateKeyEntry, String entityID,
243 UsageType usage) {
244
245 log.debug("Processing PrivateKeyEntry from keystore");
246
247 BasicX509Credential credential = new BasicX509Credential();
248 credential.setEntityId(entityID);
249 credential.setUsageType(usage);
250
251 credential.setPrivateKey(privateKeyEntry.getPrivateKey());
252
253 credential.setEntityCertificate((X509Certificate) privateKeyEntry.getCertificate());
254 credential.setEntityCertificateChain(Arrays.asList((X509Certificate[]) privateKeyEntry.getCertificateChain()));
255
256 return credential;
257 }
258
259
260
261
262
263
264
265
266
267 protected Credential processSecretKeyEntry(SecretKeyEntry secretKeyEntry, String entityID, UsageType usage) {
268 log.debug("Processing SecretKeyEntry from keystore");
269
270 BasicCredential credential = new BasicCredential();
271 credential.setEntityId(entityID);
272 credential.setUsageType(usage);
273
274 credential.setSecretKey(secretKeyEntry.getSecretKey());
275
276 return credential;
277 }
278 }