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}