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        boolean initialized = false;
102        if (crlPath != null) {
103            if (trustStoreAlgorithm.equalsIgnoreCase("PKIX")) {
104                Collection<? extends CRL> crlList = loadCRL();
105
106                if (crlList != null) {
107                    PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ks, null);
108                    pkixParams.setRevocationEnabled(true);
109                    pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
110                    tmf.init(new CertPathTrustManagerParameters(pkixParams));
111                    initialized = true;
112                }
113
114            } else {
115                LOG.warn("Revocation checking is only supported with 'trustStoreAlgorithm=\"PKIX\"'. Ignoring CRL: " + crlPath);
116            }
117        }
118
119        if (!initialized) {
120            tmf.init(ks);
121        }
122
123        return Arrays.asList(tmf.getTrustManagers());
124    }
125
126    private Collection<KeyManager> createKeyManagers() throws Exception {
127        KeyStore ks = createKeyManagerKeyStore();
128        if( ks ==null ) {
129            return new ArrayList<KeyManager>(0);
130        }
131
132        KeyManagerFactory tmf  = KeyManagerFactory.getInstance(keyStoreAlgorithm);
133        tmf.init(ks, keyStoreKeyPassword == null ? (keyStorePassword==null? null : keyStorePassword.toCharArray()) : keyStoreKeyPassword.toCharArray());
134        return Arrays.asList(tmf.getKeyManagers());
135    }
136
137    private KeyStore createTrustManagerKeyStore() throws Exception {
138        if( trustStore ==null ) {
139            return null;
140        }
141
142        KeyStore ks = KeyStore.getInstance(trustStoreType);
143        InputStream is=Utils.resourceFromString(trustStore).getInputStream();
144        try {
145            ks.load(is, trustStorePassword==null? null : trustStorePassword.toCharArray());
146        } finally {
147            is.close();
148        }
149        return ks;
150    }
151
152    private KeyStore createKeyManagerKeyStore() throws Exception {
153        if( keyStore ==null ) {
154            return null;
155        }
156
157        KeyStore ks = KeyStore.getInstance(keyStoreType);
158        InputStream is=Utils.resourceFromString(keyStore).getInputStream();
159        try {
160            ks.load(is, keyStorePassword==null? null : keyStorePassword.toCharArray());
161        } finally {
162            is.close();
163        }
164        return ks;
165    }
166
167    public String getTrustStoreType() {
168        return trustStoreType;
169    }
170
171    public String getKeyStoreType() {
172        return keyStoreType;
173    }
174
175    public String getKeyStore() {
176        return keyStore;
177    }
178
179    public void setKeyStore(String keyStore) throws MalformedURLException {
180        this.keyStore = keyStore;
181    }
182
183    public String getTrustStore() {
184        return trustStore;
185    }
186
187    public void setTrustStore(String trustStore) throws MalformedURLException {
188        this.trustStore = trustStore;
189    }
190
191    public String getKeyStoreAlgorithm() {
192        return keyStoreAlgorithm;
193    }
194
195    public void setKeyStoreAlgorithm(String keyAlgorithm) {
196        this.keyStoreAlgorithm = keyAlgorithm;
197    }
198
199    public String getTrustStoreAlgorithm() {
200        return trustStoreAlgorithm;
201    }
202
203    public void setTrustStoreAlgorithm(String trustAlgorithm) {
204        this.trustStoreAlgorithm = trustAlgorithm;
205    }
206
207    public String getKeyStoreKeyPassword() {
208        return keyStoreKeyPassword;
209    }
210
211    public void setKeyStoreKeyPassword(String keyPassword) {
212        this.keyStoreKeyPassword = keyPassword;
213    }
214
215    public String getKeyStorePassword() {
216        return keyStorePassword;
217    }
218
219    public void setKeyStorePassword(String keyPassword) {
220        this.keyStorePassword = keyPassword;
221    }
222
223    public String getTrustStorePassword() {
224        return trustStorePassword;
225    }
226
227    public void setTrustStorePassword(String trustPassword) {
228        this.trustStorePassword = trustPassword;
229    }
230
231    public void setKeyStoreType(String keyType) {
232        this.keyStoreType = keyType;
233    }
234
235    public void setTrustStoreType(String trustType) {
236        this.trustStoreType = trustType;
237    }
238
239    public String getSecureRandomAlgorithm() {
240        return secureRandomAlgorithm;
241    }
242
243    public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
244        this.secureRandomAlgorithm = secureRandomAlgorithm;
245    }
246
247    public String getCrlPath() {
248        return crlPath;
249    }
250
251    public void setCrlPath(String crlPath) {
252        this.crlPath = crlPath;
253    }
254
255    private Collection<? extends CRL> loadCRL() throws Exception {
256        if (crlPath == null) {
257            return null;
258        }
259        Resource resource = Utils.resourceFromString(crlPath);
260        InputStream is = resource.getInputStream();
261        try {
262            return CertificateFactory.getInstance("X.509").generateCRLs(is);
263        } finally {
264            is.close();
265        }
266    }
267
268}