Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added an ability to provide additional key stores to be used in the
redmine authentication process.
- Loading branch information
Maxim Karvonen
authored and
Maxim Karvonen
committed
Oct 10, 2015
1 parent
cc3041c
commit eac07d1
Showing
4 changed files
with
161 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,10 @@ | |
.idea | ||
build | ||
target | ||
bin | ||
|
||
/.settings/** | ||
/.classpath | ||
/.project | ||
/.settings | ||
/.nb-gradle/** | ||
/.nb-gradle/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
src/main/java/com/taskadapter/redmineapi/internal/comm/betterssl/BetterSSLFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.taskadapter.redmineapi.internal.comm.betterssl; | ||
|
||
import java.security.KeyManagementException; | ||
import java.security.KeyStore; | ||
import java.security.KeyStoreException; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
|
||
import javax.net.ssl.SSLContext; | ||
import javax.net.ssl.TrustManager; | ||
import javax.net.ssl.TrustManagerFactory; | ||
import javax.net.ssl.X509TrustManager; | ||
|
||
import org.apache.http.conn.ssl.SSLSocketFactory; | ||
|
||
/** | ||
* SSL Socket factory. Provides more authentication than the naive one and | ||
* allows stored (custom) certificates to be added into the trust chain. | ||
* <p> | ||
* This work is based on | ||
* http://codyaray.com/2013/04/java-ssl-with-multiple-keystores and common | ||
* sense. | ||
*/ | ||
public class BetterSSLFactory { | ||
/** | ||
* Creates a new SSL socket factory which supports both system-installed | ||
* keys and all additional keys in the provided keystores. | ||
* | ||
* @param extraStores | ||
* extra keystores containing root certificate authorities. | ||
* @return Socket factory supporting authorization for both system (default) | ||
* keystores and all the extraStores. | ||
* @throws KeyStoreException if key store have problems. | ||
* @throws KeyManagementException if new SSL context could not be initialized. | ||
*/ | ||
public static SSLSocketFactory createSocketFactory(Collection<KeyStore> extraStores) throws KeyStoreException, KeyManagementException { | ||
final Collection<X509TrustManager> managers = new ArrayList<X509TrustManager>(); | ||
for (KeyStore ks : extraStores) { | ||
addX509Managers(managers, ks); | ||
} | ||
/* Add default manager. */ | ||
addX509Managers(managers, null); | ||
final TrustManager tm = new CompositeTrustManager(managers); | ||
|
||
try { | ||
final SSLContext ctx = SSLContext.getInstance("SSL"); | ||
ctx.init(null, new TrustManager[] {tm}, null); | ||
return new SSLSocketFactory(ctx); | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new Error("No SSL protocols supported :(", e); | ||
} | ||
} | ||
|
||
/** | ||
* Adds X509 keystore-backed trust manager into the list of managers. | ||
* @param managers list of the managers to add to. | ||
* @param ks key store with target keys. | ||
* @throws KeyStoreException if key store could not be accessed. | ||
*/ | ||
private static void addX509Managers(final Collection<X509TrustManager> managers, KeyStore ks) | ||
throws KeyStoreException, Error { | ||
try { | ||
final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
tmf.init(ks); | ||
for (TrustManager tm : tmf.getTrustManagers()) { | ||
if (tm instanceof X509TrustManager) { | ||
managers.add((X509TrustManager) tm); | ||
} | ||
} | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new Error("Default trust manager algorithm is not supported!", e); | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
src/main/java/com/taskadapter/redmineapi/internal/comm/betterssl/CompositeTrustManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package com.taskadapter.redmineapi.internal.comm.betterssl; | ||
|
||
import java.security.cert.CertificateException; | ||
import java.security.cert.X509Certificate; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
import javax.net.ssl.X509TrustManager; | ||
|
||
/** | ||
* Trust manager which trusts a host when at least one peer trusts the target. | ||
*/ | ||
final class CompositeTrustManager implements X509TrustManager { | ||
|
||
/** Peers to delegate to. */ | ||
private final Collection<X509TrustManager> peers; | ||
|
||
/** All accepted issuers. */ | ||
private final X509Certificate[] allCerts; | ||
|
||
/** | ||
* Creates a new composite manager. | ||
* @param peers peers to delegate to. | ||
*/ | ||
CompositeTrustManager(Collection<X509TrustManager> peers) { | ||
this.peers = peers; | ||
final List<X509Certificate> certs = new ArrayList<X509Certificate>(); | ||
for (X509TrustManager peer: peers) { | ||
certs.addAll(Arrays.asList(peer.getAcceptedIssuers())); | ||
} | ||
this.allCerts = certs.toArray(new X509Certificate[certs.size()]); | ||
} | ||
|
||
@Override | ||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
for (X509TrustManager peer : peers) { | ||
try { | ||
peer.checkClientTrusted(chain, authType); | ||
return; | ||
} catch (CertificateException e) { | ||
//Let other manager to check this. | ||
} | ||
} | ||
throw new CertificateException("Could not authenticate client, nobody trusts it."); | ||
} | ||
|
||
@Override | ||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
for (X509TrustManager peer : peers) { | ||
try { | ||
peer.checkServerTrusted(chain, authType); | ||
return; | ||
} catch (CertificateException e) { | ||
//Let other manager to check this. | ||
} | ||
} | ||
throw new CertificateException("Could not authenticate server, nobody trusts it."); | ||
} | ||
|
||
@Override | ||
public X509Certificate[] getAcceptedIssuers() { | ||
return allCerts; | ||
} | ||
|
||
} |