View Javadoc
1   /*
2    * Copyright 2013-2019 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5    * the License. You may obtain a copy of the License at
6    *
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10   * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11   * specific language governing permissions and limitations under the License.
12   */
13  
14  package org.springframework.security.oauth2.provider.token.store;
15  
16  import java.io.IOException;
17  import java.io.InputStream;
18  import java.security.KeyFactory;
19  import java.security.KeyPair;
20  import java.security.KeyStore;
21  import java.security.PublicKey;
22  import java.security.interfaces.RSAPrivateCrtKey;
23  import java.security.spec.RSAPublicKeySpec;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.springframework.core.io.Resource;
28  
29  /**
30   * Factory for RSA key pairs from a JKS keystore file. User provides a {@link Resource} location of a keystore file and
31   * the password to unlock it, and the factory grabs the keypairs from the store by name (and optionally password).
32   * 
33   * @author Dave Syer
34   *
35   */
36  public class KeyStoreKeyFactory {
37  	
38  	private static final Log logger = LogFactory.getLog(KeyStoreKeyFactory.class);
39  
40  	private Resource resource;
41  
42  	private char[] password;
43  
44  	private KeyStore store;
45  
46  	private Object lock = new Object();
47  
48  	public KeyStoreKeyFactory(Resource resource, char[] password) {
49  		this.resource = resource;
50  		this.password = password;
51  	}
52  
53  	public KeyPair getKeyPair(String alias) {
54  		return getKeyPair(alias, password);
55  	}
56  
57  	public KeyPair getKeyPair(String alias, char[] password) {
58  		InputStream inputStream = null;
59  		try {
60  			synchronized (lock) {
61  				if (store == null) {
62  					synchronized (lock) {
63  						store = KeyStore.getInstance("jks");
64  						inputStream = resource.getInputStream();
65  						store.load(inputStream, this.password);
66  					}
67  				}
68  			}
69  			RSAPrivateCrtKey key = (RSAPrivateCrtKey) store.getKey(alias, password);
70  			RSAPublicKeySpec spec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
71  			PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
72  			return new KeyPair(publicKey, key);
73  		}
74  		catch (Exception e) {
75  			throw new IllegalStateException("Cannot load keys from store: " + resource, e);
76  		}
77  		finally {
78  			try {
79  				if (inputStream != null) {
80  					inputStream.close();
81  				}
82  			} 
83  			catch (IOException e) {
84  				logger.warn("Cannot close open stream: ", e);
85  			}
86  		}
87  	}
88  }