001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.spring;
018
019import java.io.InputStream;
020import java.net.MalformedURLException;
021import java.security.KeyStore;
022import java.security.NoSuchAlgorithmException;
023import java.security.SecureRandom;
024import java.security.cert.*;
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collection;
028
029import javax.annotation.PostConstruct;
030import javax.net.ssl.*;
031
032import org.apache.activemq.broker.SslContext;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035import org.springframework.core.io.Resource;
036
037/**
038 * Extends the SslContext so that it's easier to configure from spring.
039 *
040 * @org.apache.xbean.XBean element="sslContext"
041 *
042 *
043 */
044public class SpringSslContext extends SslContext {
045
046    private static final transient Logger LOG = LoggerFactory.getLogger(SpringSslContext.class);
047
048    private String keyStoreType="jks";
049    private String trustStoreType="jks";
050
051    private String secureRandomAlgorithm="SHA1PRNG";
052    private String keyStoreAlgorithm=KeyManagerFactory.getDefaultAlgorithm();
053    private String trustStoreAlgorithm=TrustManagerFactory.getDefaultAlgorithm();
054
055    private String keyStore;
056    private String trustStore;
057
058    private String keyStoreKeyPassword;
059    private String keyStorePassword;
060    private String trustStorePassword;
061
062    private String crlPath;
063
064    /**
065     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
066     *
067     * delegates to afterPropertiesSet, done to prevent backwards incompatible signature change.
068     */
069    @PostConstruct
070    private void postConstruct() {
071        try {
072            afterPropertiesSet();
073        } catch (Exception ex) {
074            throw new RuntimeException(ex);
075        }
076    }
077
078    /**
079     *
080     * @throws Exception
081     * @org.apache.xbean.InitMethod
082     */
083    public void afterPropertiesSet() throws Exception {
084        keyManagers.addAll(createKeyManagers());
085        trustManagers.addAll(createTrustManagers());
086        if( secureRandom == null ) {
087            secureRandom = createSecureRandom();
088        }
089    }
090
091    private SecureRandom createSecureRandom() throws NoSuchAlgorithmException {
092        return SecureRandom.getInstance(secureRandomAlgorithm);
093    }
094
095    private Collection<TrustManager> createTrustManagers() throws Exception {
096        KeyStore ks = createTrustManagerKeyStore();
097        if( ks ==null ) {
098            return new ArrayList<TrustManager>(0);
099        }
100        TrustManagerFactory tmf  = TrustManagerFactory.getInstance(trustStoreAlgorithm);
101        if (crlPath != null) {
102            if (trustStoreAlgorithm.equalsIgnoreCase("PKIX")) {
103                Collection<? extends CRL> crlList = loadCRL();
104
105                if (crlList != null) {
106                    PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ks, null);
107                    pkixParams.setRevocationEnabled(true);
108                    pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
109                    tmf.init(new CertPathTrustManagerParameters(pkixParams));
110                }
111            } else {
112                LOG.warn("Revocation checking is only supported with 'trustStoreAlgorithm=\"PKIX\"'. Ignoring CRL: " + crlPath);
113            }
114        } else {
115            tmf.init(ks);
116        }
117        return Arrays.asList(tmf.getTrustManagers());
118    }
119
120    private Collection<KeyManager> createKeyManagers() throws Exception {
121        KeyStore ks = createKeyManagerKeyStore();
122        if( ks ==null ) {
123            return new ArrayList<KeyManager>(0);
124        }
125
126        KeyManagerFactory tmf  = KeyManagerFactory.getInstance(keyStoreAlgorithm);
127        tmf.init(ks, keyStoreKeyPassword == null ? (keyStorePassword==null? null : keyStorePassword.toCharArray()) : keyStoreKeyPassword.toCharArray());
128        return Arrays.asList(tmf.getKeyManagers());
129    }
130
131    private KeyStore createTrustManagerKeyStore() throws Exception {
132        if( trustStore ==null ) {
133            return null;
134        }
135
136        KeyStore ks = KeyStore.getInstance(trustStoreType);
137        InputStream is=Utils.resourceFromString(trustStore).getInputStream();
138        try {
139            ks.load(is, trustStorePassword==null? null : trustStorePassword.toCharArray());
140        } finally {
141            is.close();
142        }
143        return ks;
144    }
145
146    private KeyStore createKeyManagerKeyStore() throws Exception {
147        if( keyStore ==null ) {
148            return null;
149        }
150
151        KeyStore ks = KeyStore.getInstance(keyStoreType);
152        InputStream is=Utils.resourceFromString(keyStore).getInputStream();
153        try {
154            ks.load(is, keyStorePassword==null? null : keyStorePassword.toCharArray());
155        } finally {
156            is.close();
157        }
158        return ks;
159    }
160
161    public String getTrustStoreType() {
162        return trustStoreType;
163    }
164
165    public String getKeyStoreType() {
166        return keyStoreType;
167    }
168
169    public String getKeyStore() {
170        return keyStore;
171    }
172
173    public void setKeyStore(String keyStore) throws MalformedURLException {
174        this.keyStore = keyStore;
175    }
176
177    public String getTrustStore() {
178        return trustStore;
179    }
180
181    public void setTrustStore(String trustStore) throws MalformedURLException {
182        this.trustStore = trustStore;
183    }
184
185    public String getKeyStoreAlgorithm() {
186        return keyStoreAlgorithm;
187    }
188
189    public void setKeyStoreAlgorithm(String keyAlgorithm) {
190        this.keyStoreAlgorithm = keyAlgorithm;
191    }
192
193    public String getTrustStoreAlgorithm() {
194        return trustStoreAlgorithm;
195    }
196
197    public void setTrustStoreAlgorithm(String trustAlgorithm) {
198        this.trustStoreAlgorithm = trustAlgorithm;
199    }
200
201    public String getKeyStoreKeyPassword() {
202        return keyStoreKeyPassword;
203    }
204
205    public void setKeyStoreKeyPassword(String keyPassword) {
206        this.keyStoreKeyPassword = keyPassword;
207    }
208
209    public String getKeyStorePassword() {
210        return keyStorePassword;
211    }
212
213    public void setKeyStorePassword(String keyPassword) {
214        this.keyStorePassword = keyPassword;
215    }
216
217    public String getTrustStorePassword() {
218        return trustStorePassword;
219    }
220
221    public void setTrustStorePassword(String trustPassword) {
222        this.trustStorePassword = trustPassword;
223    }
224
225    public void setKeyStoreType(String keyType) {
226        this.keyStoreType = keyType;
227    }
228
229    public void setTrustStoreType(String trustType) {
230        this.trustStoreType = trustType;
231    }
232
233    public String getSecureRandomAlgorithm() {
234        return secureRandomAlgorithm;
235    }
236
237    public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
238        this.secureRandomAlgorithm = secureRandomAlgorithm;
239    }
240
241    public String getCrlPath() {
242        return crlPath;
243    }
244
245    public void setCrlPath(String crlPath) {
246        this.crlPath = crlPath;
247    }
248
249    private Collection<? extends CRL> loadCRL() throws Exception {
250        if (crlPath == null) {
251            return null;
252        }
253        Resource resource = Utils.resourceFromString(crlPath);
254        InputStream is = resource.getInputStream();
255        try {
256            return CertificateFactory.getInstance("X.509").generateCRLs(is);
257        } finally {
258            is.close();
259        }
260    }
261
262}