embulk-output-ftp 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +10 -0
- data/CHANGELOG.md +3 -0
- data/README.md +98 -0
- data/build.gradle +80 -0
- data/classpath/bcpkix-jdk15on-1.52.jar +0 -0
- data/classpath/bcprov-jdk15on-1.52.jar +0 -0
- data/classpath/embulk-output-ftp-0.1.0.jar +0 -0
- data/classpath/ftp4j-1.7.2.jar +0 -0
- data/config/checkstyle/checkstyle.xml +128 -0
- data/config/checkstyle/default.xml +108 -0
- data/embulk-output-ftp.gemspec +18 -0
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/gradlew +160 -0
- data/gradlew.bat +90 -0
- data/lib/embulk/output/ftp.rb +3 -0
- data/libs/ftp4j-1.7.2.jar +0 -0
- data/src/main/java/org/embulk/output/ftp/BlockingTransfer.java +277 -0
- data/src/main/java/org/embulk/output/ftp/FtpFileOutputPlugin.java +456 -0
- data/src/main/java/org/embulk/output/ftp/SSLPlugins.java +260 -0
- data/src/main/java/org/embulk/output/ftp/TrustManagers.java +285 -0
- data/src/test/java/org/embulk/output/ftp/TestBlockingTransfer.java +5 -0
- data/src/test/java/org/embulk/output/ftp/TestFtpFileOutputPlugin.java +5 -0
- data/src/test/java/org/embulk/output/ftp/TestSSLPlugins.java +5 -0
- data/src/test/java/org/embulk/output/ftp/TrustedManagers.java +5 -0
- metadata +98 -0
@@ -0,0 +1,285 @@
|
|
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
|
+
}
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: embulk-output-ftp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Satoshi Akama
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ~>
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.0'
|
19
|
+
name: bundler
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '10.0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Stores files on FTP.
|
42
|
+
email:
|
43
|
+
- satoshiakama@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .travis.yml
|
50
|
+
- CHANGELOG.md
|
51
|
+
- README.md
|
52
|
+
- build.gradle
|
53
|
+
- config/checkstyle/checkstyle.xml
|
54
|
+
- config/checkstyle/default.xml
|
55
|
+
- embulk-output-ftp.gemspec
|
56
|
+
- gradle/wrapper/gradle-wrapper.jar
|
57
|
+
- gradle/wrapper/gradle-wrapper.properties
|
58
|
+
- gradlew
|
59
|
+
- gradlew.bat
|
60
|
+
- lib/embulk/output/ftp.rb
|
61
|
+
- libs/ftp4j-1.7.2.jar
|
62
|
+
- src/main/java/org/embulk/output/ftp/BlockingTransfer.java
|
63
|
+
- src/main/java/org/embulk/output/ftp/FtpFileOutputPlugin.java
|
64
|
+
- src/main/java/org/embulk/output/ftp/SSLPlugins.java
|
65
|
+
- src/main/java/org/embulk/output/ftp/TrustManagers.java
|
66
|
+
- src/test/java/org/embulk/output/ftp/TestBlockingTransfer.java
|
67
|
+
- src/test/java/org/embulk/output/ftp/TestFtpFileOutputPlugin.java
|
68
|
+
- src/test/java/org/embulk/output/ftp/TestSSLPlugins.java
|
69
|
+
- src/test/java/org/embulk/output/ftp/TrustedManagers.java
|
70
|
+
- classpath/bcpkix-jdk15on-1.52.jar
|
71
|
+
- classpath/bcprov-jdk15on-1.52.jar
|
72
|
+
- classpath/embulk-output-ftp-0.1.0.jar
|
73
|
+
- classpath/ftp4j-1.7.2.jar
|
74
|
+
homepage: https://github.com/sakama/embulk-output-ftp
|
75
|
+
licenses:
|
76
|
+
- Apache 2.0
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.1.9
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: FTP file output plugin for Embulk
|
98
|
+
test_files: []
|