This repository has been archived by the owner on Nov 29, 2022. It is now read-only.
/
JKSKeyManager.java
220 lines (198 loc) · 7.84 KB
/
JKSKeyManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/* Copyright 2009 Vladimir Sch�fer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.saml.key;
import org.opensaml.common.SAMLRuntimeException;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.credential.CredentialResolver;
import org.opensaml.xml.security.credential.KeyStoreCredentialResolver;
import org.opensaml.xml.security.criteria.EntityIDCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Class provides access to private and trusted keys for SAML Extension configuration. Keys are stored in the underlaying
* KeyStore object. Class also provides additional convenience methods for loading of certificates and public keys.
*
* @author Vladimir Schafer
*/
public class JKSKeyManager implements KeyManager {
private final Logger log = LoggerFactory.getLogger(JKSKeyManager.class);
private CredentialResolver credentialResolver;
private KeyStore keyStore;
private Set<String> availableKeys;
private String defaultKey;
/**
* Default constructor which uses an existing KeyStore instance for loading of credentials. Available keys are
* calculated automatically.
*
* @param keyStore key store to use
* @param passwords passwords used to access private keys
* @param defaultKey default key
*/
public JKSKeyManager(KeyStore keyStore, Map<String, String> passwords, String defaultKey) {
this.keyStore = keyStore;
this.availableKeys = getAvailableKeys(keyStore);
this.credentialResolver = new KeyStoreCredentialResolver(keyStore, passwords);
this.defaultKey = defaultKey;
}
/**
* Default constructor which instantiates a new KeyStore used to load all credentials. Available keys are
* calculated automatically.
*
* @param storeFile file pointing to the JKS keystore
* @param storePass password to access the keystore, or null for no password
* @param passwords passwords used to access private keys
* @param defaultKey default key
*/
public JKSKeyManager(Resource storeFile, String storePass, Map<String, String> passwords, String defaultKey) {
this.keyStore = initialize(storeFile, storePass, "JKS");
this.availableKeys = getAvailableKeys(keyStore);
this.credentialResolver = new KeyStoreCredentialResolver(keyStore, passwords);
this.defaultKey = defaultKey;
}
/**
* Loads all aliases available in the keyStore.
*
* @param keyStore key store to load aliases from
* @return aliases
*/
private Set<String> getAvailableKeys(KeyStore keyStore) {
try {
Set<String> availableKeys = new HashSet<String>();
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
availableKeys.add(aliases.nextElement());
}
return availableKeys;
} catch (KeyStoreException e) {
throw new RuntimeException("Unable to load aliases from keyStore", e);
}
}
/**
* Initializes the keystore using given properties.
*
* @param storeFile file pointing to the JKS keystore
* @param storePass password to open the keystore, or null for no password
* @param storeType type of keystore
* @return initialized key store
*/
private KeyStore initialize(Resource storeFile, String storePass, String storeType) {
InputStream inputStream = null;
try {
inputStream = storeFile.getInputStream();
KeyStore ks = KeyStore.getInstance(storeType);
ks.load(inputStream, storePass == null ? null : storePass.toCharArray());
return ks;
} catch (Exception e) {
log.error("Error initializing key store", e);
throw new RuntimeException("Error initializing keystore", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.debug("Error closing input stream for keystore.", e);
}
}
}
}
/**
* Returns certificate with the given alias from the keystore.
*
* @param alias alias of certificate to find
* @return certificate with the given alias or null if not found
*/
public X509Certificate getCertificate(String alias) {
if (alias == null || alias.length() == 0) {
return null;
}
try {
return (X509Certificate) keyStore.getCertificate(alias);
} catch (Exception e) {
log.error("Error loading certificate", e);
}
return null;
}
/**
* Returns public key with the given alias
*
* @param alias alias of the key to find
* @return public key of the alias or null if not found
*/
public PublicKey getPublicKey(String alias) {
X509Certificate x509Certificate = getCertificate(alias);
if (x509Certificate != null) {
return x509Certificate.getPublicKey();
} else {
return null;
}
}
public Iterable<Credential> resolve(CriteriaSet criteriaSet) throws org.opensaml.xml.security.SecurityException {
return credentialResolver.resolve(criteriaSet);
}
public Credential resolveSingle(CriteriaSet criteriaSet) throws SecurityException {
return credentialResolver.resolveSingle(criteriaSet);
}
/**
* Returns Credential object used to sign the messages issued by this entity.
* Public, X509 and Private keys are set in the credential.
*
* @param keyName name of the key to use, in case of null default key is used
* @return credential
*/
public Credential getCredential(String keyName) {
if (keyName == null) {
keyName = defaultKey;
}
try {
CriteriaSet cs = new CriteriaSet();
EntityIDCriteria criteria = new EntityIDCriteria(keyName);
cs.add(criteria);
return resolveSingle(cs);
} catch (org.opensaml.xml.security.SecurityException e) {
throw new SAMLRuntimeException("Can't obtain SP signing key", e);
}
}
/**
* Returns Credential object used to sign the messages issued by this entity.
* Public, X509 and Private keys are set in the credential.
*
* @return credential
*/
public Credential getDefaultCredential() {
return getCredential(null);
}
public String getDefaultCredentialName() {
return defaultKey;
}
public Set<String> getAvailableCredentials() {
return availableKeys;
}
public KeyStore getKeyStore() {
return keyStore;
}
}