001package co.codewizards.cloudstore.rest.client.ssl;
002
003import static co.codewizards.cloudstore.core.oio.OioFileFactory.*;
004import static java.util.Objects.*;
005
006import java.net.URL;
007import java.security.GeneralSecurityException;
008
009import javax.net.ssl.SSLContext;
010import javax.net.ssl.TrustManager;
011
012import co.codewizards.cloudstore.core.config.ConfigDir;
013import co.codewizards.cloudstore.core.oio.File;
014
015public final class SSLContextBuilder {
016
017        private URL remoteURL;
018        private File trustStoreFile;
019        private DynamicX509TrustManagerCallback callback;
020
021        private SSLContextBuilder() { }
022
023        public static SSLContextBuilder create() {
024                return new SSLContextBuilder();
025        }
026
027        public DynamicX509TrustManagerCallback getCallback() {
028                return callback;
029        }
030        public void setCallback(final DynamicX509TrustManagerCallback callback) {
031                this.callback = callback;
032        }
033        public SSLContextBuilder callback(final DynamicX509TrustManagerCallback callback) {
034                setCallback(callback);
035                return this;
036        }
037
038        public URL getRemoteURL() {
039                return remoteURL;
040        }
041        public void setRemoteURL(final URL remoteURL) {
042                this.remoteURL = remoteURL;
043        }
044        public SSLContextBuilder remoteURL(final URL remoteURL) {
045                setRemoteURL(remoteURL);
046                return this;
047        }
048
049        public File getTrustStoreFile() {
050                return trustStoreFile;
051        }
052        public void setTrustStoreFile(final File trustStoreFile) {
053                this.trustStoreFile = trustStoreFile;
054        }
055        public SSLContextBuilder trustStoreFile(final File trustStoreFile) {
056                setTrustStoreFile(trustStoreFile);
057                return this;
058        }
059
060        public SSLContext build() throws GeneralSecurityException {
061                final File trustStoreFile = getTrustStoreFile();
062                if (trustStoreFile != null) {
063                        if (getRemoteURL() != null)
064                                throw new IllegalStateException("remoteURL and trustStoreFile are both set! Only one of these should be set!");
065
066                        return getSSLContext(trustStoreFile, getCallback());
067                }
068                else
069                        return getSSLContext(getRemoteURL(), getCallback());
070        }
071
072        private SSLContext getSSLContext(final File trustStoreFile, final DynamicX509TrustManagerCallback callback) throws GeneralSecurityException {
073                requireNonNull(trustStoreFile, "trustStoreFile");
074                requireNonNull(callback, "callback");
075                final TrustManager[] trustManagers = new TrustManager[] {
076                                new DynamicX509TrustManager(trustStoreFile, callback)
077                };
078
079                // http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
080                // http://en.wikipedia.org/wiki/Secure_Sockets_Layer#Cipher
081                final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
082                sslContext.init(null, trustManagers, null);
083                return sslContext;
084        }
085
086        private SSLContext getSSLContext(final URL remoteURL, final DynamicX509TrustManagerCallback callback) throws GeneralSecurityException {
087                requireNonNull(remoteURL, "remoteURL");
088                requireNonNull(callback, "callback");
089
090                String trustStoreFileName = remoteURL.getHost();
091                if (remoteURL.getPort() >= 0)
092                        trustStoreFileName += "_" + remoteURL.getPort();
093
094                trustStoreFileName += ".truststore";
095
096                final File sslClient = createFile(ConfigDir.getInstance().getFile(), "ssl.client");
097
098                if (!sslClient.isDirectory())
099                        sslClient.mkdirs();
100
101                if (!sslClient.isDirectory())
102                        throw new IllegalStateException("Could not create directory (permissions?): " + sslClient);
103
104                return getSSLContext(createFile(sslClient, trustStoreFileName), callback);
105        }
106}