embulk-output-ftp 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -2
- data/CHANGELOG.md +4 -0
- data/build.gradle +8 -4
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/src/main/java/org/embulk/output/ftp/FtpFileOutputPlugin.java +2 -1
- data/src/test/java/org/embulk/output/ftp/TestFtpFileOutputPlugin.java +2 -0
- metadata +4 -5
- data/src/main/java/org/embulk/output/ftp/SSLPlugins.java +0 -260
- data/src/main/java/org/embulk/output/ftp/TrustManagers.java +0 -285
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 174e14d80670723ddaceb63c1a1e509c1470b00b
|
4
|
+
data.tar.gz: dd8e77c8aaf86c32fda61afd3fec7795ef97963a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac46b66aa680cf73dc5f171d14de403d45d375201ade7a950dc5983b6ee67cfcfd6662de15260e88234fdaa494ec08482cb3d419a7d3eb94f4b653269577e291
|
7
|
+
data.tar.gz: f387f775895d3f523f27ec4d8ef902e644960b98e9fdd0096705c1e7ef757e1742ec6731339418ab6086abceb7e040e97ed7c42c3994fe7a17c008ea27a47bd5
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 0.1.8 - 2018-07-04
|
2
|
+
* [maintenance] Only support Java8 [#16](https://github.com/embulk/embulk-output-ftp/pull/16)
|
3
|
+
* [maintenance] Use embulk-util-ftp from Bintray [#15](https://github.com/embulk/embulk-output-ftp/pull/15)
|
4
|
+
|
1
5
|
## 0.1.7 - 2017-02-24
|
2
6
|
|
3
7
|
* [maintenance] Don't retry when Code:550(Permission denied) error happens [#13](https://github.com/embulk/embulk-output-ftp/pull/13)
|
data/build.gradle
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
plugins {
|
2
|
-
id "com.jfrog.bintray" version "1.
|
2
|
+
id "com.jfrog.bintray" version "1.7"
|
3
3
|
id "com.github.jruby-gradle.base" version "0.1.5"
|
4
4
|
id "java"
|
5
5
|
id "checkstyle"
|
@@ -9,20 +9,24 @@ import com.github.jrubygradle.JRubyExec
|
|
9
9
|
repositories {
|
10
10
|
mavenCentral()
|
11
11
|
jcenter()
|
12
|
+
maven {
|
13
|
+
url 'https://dl.bintray.com/embulk-input-ftp/maven'
|
14
|
+
}
|
12
15
|
}
|
13
16
|
configurations {
|
14
17
|
provided
|
15
18
|
}
|
16
19
|
|
17
|
-
version = "0.
|
20
|
+
version = "0.2.0"
|
18
21
|
|
19
|
-
sourceCompatibility = 1.
|
20
|
-
targetCompatibility = 1.
|
22
|
+
sourceCompatibility = 1.8
|
23
|
+
targetCompatibility = 1.8
|
21
24
|
|
22
25
|
dependencies {
|
23
26
|
compile "org.embulk:embulk-core:0.8.9"
|
24
27
|
provided "org.embulk:embulk-core:0.8.9"
|
25
28
|
compile files("libs/ftp4j-1.7.2.jar")
|
29
|
+
compile 'org.embulk.input.ftp:embulk-util-ftp:0.1.6'
|
26
30
|
compile "org.bouncycastle:bcpkix-jdk15on:1.52"
|
27
31
|
testCompile "junit:junit:4.+"
|
28
32
|
testCompile "org.embulk:embulk-core:0.8.9:tests"
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
#Sun Jan 08 00:35:58 PST 2017
|
2
2
|
distributionBase=GRADLE_USER_HOME
|
3
3
|
distributionPath=wrapper/dists
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
5
5
|
zipStorePath=wrapper/dists
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-2.
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-3.2.1-bin.zip
|
@@ -19,13 +19,14 @@ import org.embulk.config.Task;
|
|
19
19
|
import org.embulk.config.TaskReport;
|
20
20
|
import org.embulk.config.TaskSource;
|
21
21
|
import org.embulk.config.UserDataException;
|
22
|
-
import org.embulk.output.ftp.SSLPlugins.SSLPluginConfig;
|
23
22
|
import org.embulk.spi.Buffer;
|
24
23
|
import org.embulk.spi.Exec;
|
25
24
|
import org.embulk.spi.FileOutputPlugin;
|
26
25
|
import org.embulk.spi.TransactionalFileOutput;
|
27
26
|
import org.embulk.spi.util.RetryExecutor.RetryGiveupException;
|
28
27
|
import org.embulk.spi.util.RetryExecutor.Retryable;
|
28
|
+
import org.embulk.util.ftp.SSLPlugins;
|
29
|
+
import org.embulk.util.ftp.SSLPlugins.SSLPluginConfig;
|
29
30
|
import org.slf4j.Logger;
|
30
31
|
import static org.embulk.spi.util.RetryExecutor.retryExecutor;
|
31
32
|
|
@@ -20,6 +20,8 @@ import org.embulk.spi.OutputPlugin;
|
|
20
20
|
import org.embulk.spi.Schema;
|
21
21
|
import org.embulk.spi.TransactionalFileOutput;
|
22
22
|
import org.embulk.standards.CsvParserPlugin;
|
23
|
+
import org.embulk.util.ftp.SSLPlugins;
|
24
|
+
import org.embulk.util.ftp.SSLPlugins.SSLPluginConfig;
|
23
25
|
|
24
26
|
import org.junit.Before;
|
25
27
|
import org.junit.BeforeClass;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-output-ftp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Satoshi Akama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,15 +60,14 @@ files:
|
|
60
60
|
- lib/embulk/output/ftp.rb
|
61
61
|
- libs/ftp4j-1.7.2.jar
|
62
62
|
- src/main/java/org/embulk/output/ftp/FtpFileOutputPlugin.java
|
63
|
-
- src/main/java/org/embulk/output/ftp/SSLPlugins.java
|
64
|
-
- src/main/java/org/embulk/output/ftp/TrustManagers.java
|
65
63
|
- src/test/java/org/embulk/output/ftp/TestFtpFileOutputPlugin.java
|
66
64
|
- src/test/resources/sample_01.csv
|
67
65
|
- src/test/resources/sample_02.csv
|
68
66
|
- classpath/bcpkix-jdk15on-1.52.jar
|
69
67
|
- classpath/bcprov-jdk15on-1.52.jar
|
70
|
-
- classpath/embulk-output-ftp-0.1.7.jar
|
71
68
|
- classpath/ftp4j-1.7.2.jar
|
69
|
+
- classpath/embulk-util-ftp-0.1.6.jar
|
70
|
+
- classpath/embulk-output-ftp-0.2.0.jar
|
72
71
|
homepage: https://github.com/embulk/embulk-output-ftp
|
73
72
|
licenses:
|
74
73
|
- Apache 2.0
|
@@ -1,260 +0,0 @@
|
|
1
|
-
package org.embulk.output.ftp;
|
2
|
-
|
3
|
-
import com.fasterxml.jackson.annotation.JsonCreator;
|
4
|
-
import com.fasterxml.jackson.annotation.JsonIgnore;
|
5
|
-
import com.fasterxml.jackson.annotation.JsonProperty;
|
6
|
-
import com.google.common.base.Function;
|
7
|
-
import com.google.common.base.Optional;
|
8
|
-
import com.google.common.collect.ImmutableList;
|
9
|
-
import com.google.common.collect.Lists;
|
10
|
-
import org.embulk.config.Config;
|
11
|
-
import org.embulk.config.ConfigDefault;
|
12
|
-
import org.embulk.config.ConfigException;
|
13
|
-
|
14
|
-
import javax.net.ssl.SSLSocketFactory;
|
15
|
-
import javax.net.ssl.X509TrustManager;
|
16
|
-
|
17
|
-
import java.io.ByteArrayInputStream;
|
18
|
-
import java.io.FileReader;
|
19
|
-
import java.io.IOException;
|
20
|
-
import java.io.Reader;
|
21
|
-
import java.io.StringReader;
|
22
|
-
import java.security.GeneralSecurityException;
|
23
|
-
import java.security.KeyManagementException;
|
24
|
-
import java.security.cert.CertificateEncodingException;
|
25
|
-
import java.security.cert.CertificateException;
|
26
|
-
import java.security.cert.CertificateFactory;
|
27
|
-
import java.security.cert.X509Certificate;
|
28
|
-
import java.util.List;
|
29
|
-
|
30
|
-
public class SSLPlugins
|
31
|
-
{
|
32
|
-
// SSLPlugins is only for SSL clients. SSL server implementation is out ouf scope.
|
33
|
-
|
34
|
-
private SSLPlugins()
|
35
|
-
{
|
36
|
-
}
|
37
|
-
|
38
|
-
public interface SSLPluginTask
|
39
|
-
{
|
40
|
-
@Config("ssl_verify")
|
41
|
-
@ConfigDefault("null")
|
42
|
-
Optional<Boolean> getSslVerify();
|
43
|
-
|
44
|
-
@Config("ssl_verify_hostname")
|
45
|
-
@ConfigDefault("true")
|
46
|
-
boolean getSslVerifyHostname();
|
47
|
-
|
48
|
-
@Config("ssl_trusted_ca_cert_file")
|
49
|
-
@ConfigDefault("null")
|
50
|
-
Optional<String> getSslTrustedCaCertFile();
|
51
|
-
|
52
|
-
@Config("ssl_trusted_ca_cert_data")
|
53
|
-
@ConfigDefault("null")
|
54
|
-
Optional<String> getSslTrustedCaCertData();
|
55
|
-
}
|
56
|
-
|
57
|
-
private static enum VerifyMode
|
58
|
-
{
|
59
|
-
NO_VERIFY,
|
60
|
-
CERTIFICATES,
|
61
|
-
JVM_DEFAULT;
|
62
|
-
}
|
63
|
-
|
64
|
-
public static class SSLPluginConfig
|
65
|
-
{
|
66
|
-
static SSLPluginConfig NO_VERIFY = new SSLPluginConfig(VerifyMode.NO_VERIFY, false, ImmutableList.<byte[]>of());
|
67
|
-
|
68
|
-
private final VerifyMode verifyMode;
|
69
|
-
private final boolean verifyHostname;
|
70
|
-
private final List<X509Certificate> certificates;
|
71
|
-
|
72
|
-
@JsonCreator
|
73
|
-
private SSLPluginConfig(
|
74
|
-
@JsonProperty("verifyMode") VerifyMode verifyMode,
|
75
|
-
@JsonProperty("verifyHostname") boolean verifyHostname,
|
76
|
-
@JsonProperty("certificates") List<byte[]> certificates)
|
77
|
-
{
|
78
|
-
this.verifyMode = verifyMode;
|
79
|
-
this.verifyHostname = verifyHostname;
|
80
|
-
this.certificates = ImmutableList.copyOf(
|
81
|
-
Lists.transform(certificates, new Function<byte[], X509Certificate>() {
|
82
|
-
public X509Certificate apply(byte[] data)
|
83
|
-
{
|
84
|
-
try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
|
85
|
-
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
86
|
-
return (X509Certificate) cf.generateCertificate(in);
|
87
|
-
}
|
88
|
-
catch (IOException | CertificateException ex) {
|
89
|
-
throw new RuntimeException(ex);
|
90
|
-
}
|
91
|
-
}
|
92
|
-
})
|
93
|
-
);
|
94
|
-
}
|
95
|
-
|
96
|
-
SSLPluginConfig(List<X509Certificate> certificates, boolean verifyHostname)
|
97
|
-
{
|
98
|
-
this.verifyMode = VerifyMode.CERTIFICATES;
|
99
|
-
this.verifyHostname = verifyHostname;
|
100
|
-
this.certificates = certificates;
|
101
|
-
}
|
102
|
-
|
103
|
-
static SSLPluginConfig useJvmDefault(boolean verifyHostname)
|
104
|
-
{
|
105
|
-
return new SSLPluginConfig(VerifyMode.JVM_DEFAULT, verifyHostname, ImmutableList.<byte[]>of());
|
106
|
-
}
|
107
|
-
|
108
|
-
@JsonProperty("verifyMode")
|
109
|
-
private VerifyMode getVerifyMode()
|
110
|
-
{
|
111
|
-
return verifyMode;
|
112
|
-
}
|
113
|
-
|
114
|
-
@JsonProperty("verifyHostname")
|
115
|
-
private boolean getVerifyHostname()
|
116
|
-
{
|
117
|
-
return verifyHostname;
|
118
|
-
}
|
119
|
-
|
120
|
-
@JsonProperty("certificates")
|
121
|
-
private List<byte[]> getCertData()
|
122
|
-
{
|
123
|
-
return Lists.transform(certificates, new Function<X509Certificate, byte[]>() {
|
124
|
-
public byte[] apply(X509Certificate cert)
|
125
|
-
{
|
126
|
-
try {
|
127
|
-
return cert.getEncoded();
|
128
|
-
}
|
129
|
-
catch (CertificateEncodingException ex) {
|
130
|
-
throw new RuntimeException(ex);
|
131
|
-
}
|
132
|
-
}
|
133
|
-
});
|
134
|
-
}
|
135
|
-
|
136
|
-
@JsonIgnore
|
137
|
-
public X509TrustManager[] newTrustManager()
|
138
|
-
{
|
139
|
-
try {
|
140
|
-
switch (verifyMode) {
|
141
|
-
case NO_VERIFY:
|
142
|
-
return new X509TrustManager[] { getNoVerifyTrustManager() };
|
143
|
-
case CERTIFICATES:
|
144
|
-
return TrustManagers.newTrustManager(certificates);
|
145
|
-
default: // JVM_DEFAULT
|
146
|
-
return TrustManagers.newDefaultJavaTrustManager();
|
147
|
-
}
|
148
|
-
}
|
149
|
-
catch (IOException | GeneralSecurityException ex) {
|
150
|
-
throw new RuntimeException(ex);
|
151
|
-
}
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
public static enum DefaultVerifyMode
|
156
|
-
{
|
157
|
-
VERIFY_BY_JVM_TRUSTED_CA_CERTS,
|
158
|
-
NO_VERIFY;
|
159
|
-
}
|
160
|
-
|
161
|
-
public static SSLPluginConfig configure(SSLPluginTask task)
|
162
|
-
{
|
163
|
-
return configure(task, DefaultVerifyMode.VERIFY_BY_JVM_TRUSTED_CA_CERTS);
|
164
|
-
}
|
165
|
-
|
166
|
-
public static SSLPluginConfig configure(SSLPluginTask task, DefaultVerifyMode defaultVerifyMode)
|
167
|
-
{
|
168
|
-
boolean verify = task.getSslVerify().or(defaultVerifyMode != DefaultVerifyMode.NO_VERIFY);
|
169
|
-
if (verify) {
|
170
|
-
Optional<List<X509Certificate>> certs = readTrustedCertificates(task);
|
171
|
-
if (certs.isPresent()) {
|
172
|
-
return new SSLPluginConfig(certs.get(), task.getSslVerifyHostname());
|
173
|
-
}
|
174
|
-
else {
|
175
|
-
return SSLPluginConfig.useJvmDefault(task.getSslVerifyHostname());
|
176
|
-
}
|
177
|
-
}
|
178
|
-
else {
|
179
|
-
return SSLPluginConfig.NO_VERIFY;
|
180
|
-
}
|
181
|
-
}
|
182
|
-
|
183
|
-
private static Optional<List<X509Certificate>> readTrustedCertificates(SSLPluginTask task)
|
184
|
-
{
|
185
|
-
String optionName;
|
186
|
-
Reader reader;
|
187
|
-
if (task.getSslTrustedCaCertData().isPresent()) {
|
188
|
-
optionName = "ssl_trusted_ca_cert_data";
|
189
|
-
reader = new StringReader(task.getSslTrustedCaCertData().get());
|
190
|
-
}
|
191
|
-
else if (task.getSslTrustedCaCertFile().isPresent()) {
|
192
|
-
optionName = "ssl_trusted_ca_cert_file '" + task.getSslTrustedCaCertFile().get() + "'";
|
193
|
-
try {
|
194
|
-
reader = new FileReader(task.getSslTrustedCaCertFile().get());
|
195
|
-
}
|
196
|
-
catch (IOException ex) {
|
197
|
-
throw new ConfigException(String.format("Failed to open %s", optionName), ex);
|
198
|
-
}
|
199
|
-
}
|
200
|
-
else {
|
201
|
-
return Optional.absent();
|
202
|
-
}
|
203
|
-
|
204
|
-
List<X509Certificate> certs;
|
205
|
-
try (Reader r = reader) {
|
206
|
-
certs = TrustManagers.readPemEncodedX509Certificates(r);
|
207
|
-
if (certs.isEmpty()) {
|
208
|
-
throw new ConfigException(String.format("%s does not include valid X.509 PEM certificates", optionName));
|
209
|
-
}
|
210
|
-
}
|
211
|
-
catch (CertificateException | IOException ex) {
|
212
|
-
throw new ConfigException(String.format("Failed to read %s", optionName), ex);
|
213
|
-
}
|
214
|
-
|
215
|
-
return Optional.of(certs);
|
216
|
-
}
|
217
|
-
|
218
|
-
public static SSLSocketFactory newSSLSocketFactory(SSLPluginConfig config, String hostname)
|
219
|
-
{
|
220
|
-
try {
|
221
|
-
return TrustManagers.newSSLSocketFactory(
|
222
|
-
null, // TODO sending client certificate is not implemented yet
|
223
|
-
config.newTrustManager(),
|
224
|
-
config.getVerifyHostname() ? hostname : null);
|
225
|
-
}
|
226
|
-
catch (KeyManagementException ex) {
|
227
|
-
throw new RuntimeException(ex);
|
228
|
-
}
|
229
|
-
}
|
230
|
-
|
231
|
-
private static class NoVerifyTrustManager implements X509TrustManager
|
232
|
-
{
|
233
|
-
static final NoVerifyTrustManager INSTANCE = new NoVerifyTrustManager();
|
234
|
-
|
235
|
-
private NoVerifyTrustManager()
|
236
|
-
{
|
237
|
-
}
|
238
|
-
|
239
|
-
@Override
|
240
|
-
public X509Certificate[] getAcceptedIssuers()
|
241
|
-
{
|
242
|
-
return null;
|
243
|
-
}
|
244
|
-
|
245
|
-
@Override
|
246
|
-
public void checkClientTrusted(X509Certificate[] certs, String authType)
|
247
|
-
{
|
248
|
-
}
|
249
|
-
|
250
|
-
@Override
|
251
|
-
public void checkServerTrusted(X509Certificate[] certs, String authType)
|
252
|
-
{
|
253
|
-
}
|
254
|
-
}
|
255
|
-
|
256
|
-
private static X509TrustManager getNoVerifyTrustManager()
|
257
|
-
{
|
258
|
-
return NoVerifyTrustManager.INSTANCE;
|
259
|
-
}
|
260
|
-
}
|
@@ -1,285 +0,0 @@
|
|
1
|
-
package org.embulk.output.ftp;
|
2
|
-
|
3
|
-
import org.bouncycastle.cert.X509CertificateHolder;
|
4
|
-
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
5
|
-
import org.bouncycastle.openssl.PEMException;
|
6
|
-
import org.bouncycastle.openssl.PEMParser;
|
7
|
-
import sun.security.ssl.SSLSocketImpl;
|
8
|
-
|
9
|
-
import javax.net.ssl.KeyManager;
|
10
|
-
import javax.net.ssl.SSLContext;
|
11
|
-
import javax.net.ssl.SSLParameters;
|
12
|
-
import javax.net.ssl.SSLSocket;
|
13
|
-
import javax.net.ssl.SSLSocketFactory;
|
14
|
-
import javax.net.ssl.TrustManager;
|
15
|
-
import javax.net.ssl.TrustManagerFactory;
|
16
|
-
import javax.net.ssl.X509TrustManager;
|
17
|
-
|
18
|
-
import java.io.File;
|
19
|
-
import java.io.FileInputStream;
|
20
|
-
import java.io.IOException;
|
21
|
-
import java.io.Reader;
|
22
|
-
import java.net.InetAddress;
|
23
|
-
import java.net.Socket;
|
24
|
-
import java.net.UnknownHostException;
|
25
|
-
import java.security.InvalidAlgorithmParameterException;
|
26
|
-
import java.security.KeyManagementException;
|
27
|
-
import java.security.KeyStore;
|
28
|
-
import java.security.KeyStoreException;
|
29
|
-
import java.security.NoSuchAlgorithmException;
|
30
|
-
import java.security.SecureRandom;
|
31
|
-
import java.security.cert.CertificateException;
|
32
|
-
import java.security.cert.CertificateParsingException;
|
33
|
-
import java.security.cert.PKIXParameters;
|
34
|
-
import java.security.cert.TrustAnchor;
|
35
|
-
import java.security.cert.X509Certificate;
|
36
|
-
import java.util.ArrayList;
|
37
|
-
import java.util.List;
|
38
|
-
|
39
|
-
public class TrustManagers
|
40
|
-
{
|
41
|
-
private TrustManagers()
|
42
|
-
{
|
43
|
-
}
|
44
|
-
|
45
|
-
public static KeyStore readDefaultJavaKeyStore()
|
46
|
-
throws IOException, KeyStoreException, CertificateException
|
47
|
-
{
|
48
|
-
String path = (System.getProperty("java.home") + "/lib/security/cacerts").replace('/', File.separatorChar);
|
49
|
-
try {
|
50
|
-
KeyStore keyStore = KeyStore.getInstance("JKS");
|
51
|
-
try (FileInputStream in = new FileInputStream(path)) {
|
52
|
-
keyStore.load(in, null); // password=null because cacerts file is not encrypted
|
53
|
-
}
|
54
|
-
return keyStore;
|
55
|
-
}
|
56
|
-
catch (NoSuchAlgorithmException ex) {
|
57
|
-
throw new RuntimeException(ex); // TODO assertion exception?
|
58
|
-
}
|
59
|
-
}
|
60
|
-
|
61
|
-
public static List<X509Certificate> readDefaultJavaTrustedCertificates()
|
62
|
-
throws IOException, CertificateException, KeyStoreException, InvalidAlgorithmParameterException
|
63
|
-
{
|
64
|
-
KeyStore keyStore = readDefaultJavaKeyStore();
|
65
|
-
PKIXParameters params = new PKIXParameters(keyStore);
|
66
|
-
List<X509Certificate> certs = new ArrayList<>();
|
67
|
-
for (TrustAnchor trustAnchor : params.getTrustAnchors()) {
|
68
|
-
certs.add(trustAnchor.getTrustedCert());
|
69
|
-
}
|
70
|
-
return certs;
|
71
|
-
}
|
72
|
-
|
73
|
-
public static List<X509Certificate> readPemEncodedX509Certificates(Reader reader)
|
74
|
-
throws IOException, CertificateException
|
75
|
-
{
|
76
|
-
// this method abuses CertificateParsingException because its javadoc says
|
77
|
-
// CertificateParsingException is only for DER-encoded formats.
|
78
|
-
|
79
|
-
JcaX509CertificateConverter conv = new JcaX509CertificateConverter();
|
80
|
-
List<X509Certificate> certs = new ArrayList<>();
|
81
|
-
|
82
|
-
try {
|
83
|
-
PEMParser pemParser = new PEMParser(reader);
|
84
|
-
// PEMParser#close is unnecessary because it just closes underlying reader
|
85
|
-
|
86
|
-
while (true) {
|
87
|
-
Object pem = pemParser.readObject();
|
88
|
-
|
89
|
-
if (pem == null) {
|
90
|
-
break;
|
91
|
-
}
|
92
|
-
|
93
|
-
if (pem instanceof X509CertificateHolder) {
|
94
|
-
X509Certificate cert = conv.getCertificate((X509CertificateHolder) pem);
|
95
|
-
certs.add(cert);
|
96
|
-
}
|
97
|
-
}
|
98
|
-
}
|
99
|
-
catch (PEMException ex) {
|
100
|
-
// throw when parsing PemObject to Object fails
|
101
|
-
throw new CertificateParsingException(ex);
|
102
|
-
}
|
103
|
-
catch (IOException ex) {
|
104
|
-
if (ex.getClass().equals(IOException.class)) {
|
105
|
-
String message = ex.getMessage();
|
106
|
-
if (message.startsWith("unrecognised object: ")) {
|
107
|
-
// thrown at org.bouncycastle.openssl.PemParser.readObject when key type (header of a pem) is
|
108
|
-
// unknown.
|
109
|
-
throw new CertificateParsingException(ex);
|
110
|
-
}
|
111
|
-
else if (message.startsWith("-----END ") && message.endsWith(" not found")) {
|
112
|
-
// thrown at org.bouncycastle.util.io.pem.PemReader.loadObject when a pem file format is invalid
|
113
|
-
throw new CertificateParsingException(ex);
|
114
|
-
}
|
115
|
-
}
|
116
|
-
else {
|
117
|
-
throw ex;
|
118
|
-
}
|
119
|
-
}
|
120
|
-
|
121
|
-
return certs;
|
122
|
-
}
|
123
|
-
|
124
|
-
public static KeyStore buildKeyStoreFromTrustedCertificates(List<X509Certificate> certificates)
|
125
|
-
throws KeyStoreException
|
126
|
-
{
|
127
|
-
KeyStore keyStore = KeyStore.getInstance("JKS");
|
128
|
-
try {
|
129
|
-
keyStore.load(null);
|
130
|
-
}
|
131
|
-
catch (IOException | CertificateException | NoSuchAlgorithmException ex) {
|
132
|
-
throw new RuntimeException(ex);
|
133
|
-
}
|
134
|
-
int i = 0;
|
135
|
-
for (X509Certificate cert : certificates) {
|
136
|
-
keyStore.setCertificateEntry("cert_" + i, cert);
|
137
|
-
i++;
|
138
|
-
}
|
139
|
-
return keyStore;
|
140
|
-
}
|
141
|
-
|
142
|
-
public static X509TrustManager[] newTrustManager(List<X509Certificate> trustedCertificates)
|
143
|
-
throws KeyStoreException
|
144
|
-
{
|
145
|
-
try {
|
146
|
-
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
147
|
-
KeyStore keyStore = buildKeyStoreFromTrustedCertificates(trustedCertificates);
|
148
|
-
factory.init(keyStore);
|
149
|
-
List<X509TrustManager> tms = new ArrayList<>();
|
150
|
-
for (TrustManager tm : factory.getTrustManagers()) {
|
151
|
-
if (tm instanceof X509TrustManager) {
|
152
|
-
tms.add((X509TrustManager) tm);
|
153
|
-
}
|
154
|
-
}
|
155
|
-
return tms.toArray(new X509TrustManager[tms.size()]);
|
156
|
-
}
|
157
|
-
catch (NoSuchAlgorithmException ex) {
|
158
|
-
throw new RuntimeException(ex); // TODO assertion exception?
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
public static X509TrustManager[] newDefaultJavaTrustManager()
|
163
|
-
throws IOException, CertificateException, KeyStoreException, InvalidAlgorithmParameterException
|
164
|
-
{
|
165
|
-
return newTrustManager(readDefaultJavaTrustedCertificates());
|
166
|
-
}
|
167
|
-
|
168
|
-
public static SSLContext newSSLContext(KeyManager[] keyManager, X509TrustManager[] trustManager)
|
169
|
-
throws KeyManagementException
|
170
|
-
{
|
171
|
-
try {
|
172
|
-
SSLContext context = SSLContext.getInstance("TLS");
|
173
|
-
context.init(
|
174
|
-
keyManager,
|
175
|
-
trustManager,
|
176
|
-
new SecureRandom());
|
177
|
-
return context;
|
178
|
-
}
|
179
|
-
catch (NoSuchAlgorithmException ex) {
|
180
|
-
throw new RuntimeException(ex);
|
181
|
-
}
|
182
|
-
}
|
183
|
-
|
184
|
-
public static SSLSocketFactory newSSLSocketFactory(KeyManager[] keyManager, X509TrustManager[] trustManager, String verifyHostname)
|
185
|
-
throws KeyManagementException
|
186
|
-
{
|
187
|
-
SSLContext context = newSSLContext(keyManager, trustManager);
|
188
|
-
SSLSocketFactory factory = context.getSocketFactory();
|
189
|
-
if (verifyHostname == null) {
|
190
|
-
return factory;
|
191
|
-
}
|
192
|
-
else {
|
193
|
-
return new VerifyHostNameSSLSocketFactory(factory, verifyHostname);
|
194
|
-
}
|
195
|
-
}
|
196
|
-
|
197
|
-
private static class VerifyHostNameSSLSocketFactory
|
198
|
-
extends SSLSocketFactory
|
199
|
-
{
|
200
|
-
private final SSLSocketFactory next;
|
201
|
-
private final String hostname;
|
202
|
-
|
203
|
-
public VerifyHostNameSSLSocketFactory(SSLSocketFactory next, String hostname)
|
204
|
-
{
|
205
|
-
this.next = next;
|
206
|
-
this.hostname = hostname;
|
207
|
-
}
|
208
|
-
|
209
|
-
@Override
|
210
|
-
public String[] getDefaultCipherSuites()
|
211
|
-
{
|
212
|
-
return next.getDefaultCipherSuites();
|
213
|
-
}
|
214
|
-
|
215
|
-
@Override
|
216
|
-
public String[] getSupportedCipherSuites()
|
217
|
-
{
|
218
|
-
return next.getSupportedCipherSuites();
|
219
|
-
}
|
220
|
-
|
221
|
-
@Override
|
222
|
-
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
|
223
|
-
throws IOException
|
224
|
-
{
|
225
|
-
Socket sock = next.createSocket(s, host, port, autoClose);
|
226
|
-
setSSLParameters(sock, false);
|
227
|
-
return sock;
|
228
|
-
}
|
229
|
-
|
230
|
-
@Override
|
231
|
-
public Socket createSocket(String host, int port)
|
232
|
-
throws IOException, UnknownHostException
|
233
|
-
{
|
234
|
-
Socket sock = next.createSocket(host, port);
|
235
|
-
setSSLParameters(sock, false);
|
236
|
-
return sock;
|
237
|
-
}
|
238
|
-
|
239
|
-
@Override
|
240
|
-
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
|
241
|
-
throws IOException, UnknownHostException
|
242
|
-
{
|
243
|
-
Socket sock = next.createSocket(host, port, localHost, localPort);
|
244
|
-
setSSLParameters(sock, false);
|
245
|
-
return sock;
|
246
|
-
}
|
247
|
-
|
248
|
-
@Override
|
249
|
-
public Socket createSocket(InetAddress host, int port)
|
250
|
-
throws IOException
|
251
|
-
{
|
252
|
-
Socket sock = next.createSocket(host, port);
|
253
|
-
setSSLParameters(sock, true);
|
254
|
-
return sock;
|
255
|
-
}
|
256
|
-
|
257
|
-
@Override
|
258
|
-
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
|
259
|
-
throws IOException
|
260
|
-
{
|
261
|
-
Socket sock = next.createSocket(address, port, localAddress, localPort);
|
262
|
-
setSSLParameters(sock, true);
|
263
|
-
return sock;
|
264
|
-
}
|
265
|
-
|
266
|
-
private void setSSLParameters(Socket sock, boolean setHostname)
|
267
|
-
{
|
268
|
-
if (sock instanceof SSLSocket) {
|
269
|
-
SSLSocket s = (SSLSocket) sock;
|
270
|
-
String identAlgorithm = s.getSSLParameters().getEndpointIdentificationAlgorithm();
|
271
|
-
if (identAlgorithm != null && identAlgorithm.equalsIgnoreCase("HTTPS")) {
|
272
|
-
// hostname verification is already configured.
|
273
|
-
} else {
|
274
|
-
if (setHostname && s instanceof SSLSocketImpl) {
|
275
|
-
((SSLSocketImpl) s).setHost(hostname);
|
276
|
-
}
|
277
|
-
SSLParameters params = s.getSSLParameters();
|
278
|
-
params.setEndpointIdentificationAlgorithm("HTTPS");
|
279
|
-
s.setSSLParameters(params);
|
280
|
-
// s.startHandshake
|
281
|
-
}
|
282
|
-
}
|
283
|
-
}
|
284
|
-
}
|
285
|
-
}
|