embulk-output-ftp 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
}
|