You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ay...@apache.org on 2012/10/24 17:03:58 UTC
svn commit: r1401722 - in /cxf/branches/2.6.x-fixes: ./
api/src/main/java/org/apache/cxf/io/CachedOutputStream.java
api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java
Author: ay
Date: Wed Oct 24 15:03:58 2012
New Revision: 1401722
URL: http://svn.apache.org/viewvc?rev=1401722&view=rev
Log:
Merged revisions 1401223 via svn merge from
https://svn.apache.org/repos/asf/cxf/trunk
........
r1401223 | ay | 2012-10-23 11:43:57 +0200 (Tue, 23 Oct 2012) | 1 line
[CXF-4596] adding an option for encrypting tmp files generated by COS
........
Modified:
cxf/branches/2.6.x-fixes/ (props changed)
cxf/branches/2.6.x-fixes/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java
cxf/branches/2.6.x-fixes/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java
Propchange: cxf/branches/2.6.x-fixes/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.
Modified: cxf/branches/2.6.x-fixes/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java?rev=1401722&r1=1401721&r2=1401722&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java (original)
+++ cxf/branches/2.6.x-fixes/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java Wed Oct 24 15:03:58 2012
@@ -19,7 +19,6 @@
package org.apache.cxf.io;
-import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -33,10 +32,18 @@ import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader;
+import java.security.GeneralSecurityException;
+import java.security.Key;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.spec.IvParameterSpec;
+
import org.apache.cxf.common.util.SystemPropertyAction;
import org.apache.cxf.helpers.FileUtils;
import org.apache.cxf.helpers.IOUtils;
@@ -46,6 +53,7 @@ public class CachedOutputStream extends
private static final File DEFAULT_TEMP_DIR;
private static int defaultThreshold;
private static long defaultMaxSize;
+ private static String defaultCipherTransformation;
static {
String s = SystemPropertyAction.getPropertyOrNull("org.apache.cxf.io.CachedOutputStream.OutputDirectory");
@@ -62,6 +70,7 @@ public class CachedOutputStream extends
setDefaultThreshold(-1);
setDefaultMaxSize(-1);
+ setDefaultCipherTransformation(null);
}
protected boolean outputLocked;
@@ -78,6 +87,10 @@ public class CachedOutputStream extends
private File tempFile;
private File outputDir = DEFAULT_TEMP_DIR;
private boolean allowDeleteOfFile = true;
+ private String cipherTransformation = defaultCipherTransformation;
+ private Cipher enccipher;
+ private Cipher deccipher;
+
private List<CachedOutputStreamCallback> callbacks;
@@ -235,7 +248,7 @@ public class CachedOutputStream extends
// read the file
currentStream.close();
if (copyOldContent) {
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
IOUtils.copyAndCloseInput(fin, out);
}
streamList.remove(currentStream);
@@ -265,7 +278,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
return IOUtils.readBytesFromStream(fin);
}
}
@@ -280,7 +293,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
IOUtils.copyAndCloseInput(fin, out);
}
}
@@ -307,7 +320,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
Reader reader = new InputStreamReader(fin, charsetName);
char bytes[] = new char[1024];
long x = reader.read(bytes);
@@ -344,7 +357,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
Reader reader = new InputStreamReader(fin, charsetName);
char bytes[] = new char[1024];
int x = reader.read(bytes);
@@ -433,7 +446,7 @@ public class CachedOutputStream extends
tempFile = FileUtils.createTempFile("cos", "tmp", outputDir, false);
}
- currentStream = new BufferedOutputStream(new FileOutputStream(tempFile));
+ currentStream = createOutputStream(tempFile);
bout.writeTo(currentStream);
inmem = false;
streamList.add(currentStream);
@@ -468,7 +481,7 @@ public class CachedOutputStream extends
}
} else {
try {
- FileInputStream fileInputStream = new FileInputStream(tempFile) {
+ InputStream fileInputStream = new FileInputStream(tempFile) {
boolean closed;
public void close() throws IOException {
if (!closed) {
@@ -479,6 +492,18 @@ public class CachedOutputStream extends
}
};
streamList.add(fileInputStream);
+ if (cipherTransformation != null) {
+ fileInputStream = new CipherInputStream(fileInputStream, deccipher) {
+ boolean closed;
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed = true;
+ }
+ }
+ };
+ }
+
return fileInputStream;
} catch (FileNotFoundException e) {
throw new IOException("Cached file was deleted, " + e.toString());
@@ -520,6 +545,10 @@ public class CachedOutputStream extends
public void setMaxSize(long maxSize) {
this.maxSize = maxSize;
}
+
+ public void setCipherTransformation(String cipherTransformation) {
+ this.cipherTransformation = cipherTransformation;
+ }
public static void setDefaultMaxSize(long l) {
if (l == -1) {
@@ -541,4 +570,72 @@ public class CachedOutputStream extends
defaultThreshold = i;
}
+ public static void setDefaultCipherTransformation(String n) {
+ if (n == null) {
+ n = SystemPropertyAction.getPropertyOrNull("org.apache.cxf.io.CachedOutputStream.CipherTransformation");
+ }
+ defaultCipherTransformation = n;
+ }
+
+ private synchronized void initCiphers() throws GeneralSecurityException {
+ if (enccipher == null) {
+ int d = cipherTransformation.indexOf('/');
+ String a;
+ if (d > 0) {
+ a = cipherTransformation.substring(0, d);
+ } else {
+ a = cipherTransformation;
+ }
+ try {
+ Key key = KeyGenerator.getInstance(a).generateKey();
+ enccipher = Cipher.getInstance(cipherTransformation);
+ deccipher = Cipher.getInstance(cipherTransformation);
+ enccipher.init(Cipher.ENCRYPT_MODE, key);
+ final byte[] ivp = enccipher.getIV();
+ deccipher.init(Cipher.DECRYPT_MODE, key, ivp == null ? null : new IvParameterSpec(ivp));
+ } catch (GeneralSecurityException e) {
+ enccipher = null;
+ deccipher = null;
+ throw e;
+ }
+ }
+ }
+
+ private OutputStream createOutputStream(File file) throws IOException {
+ OutputStream out = new FileOutputStream(file);
+ if (cipherTransformation != null) {
+ try {
+ initCiphers();
+ } catch (GeneralSecurityException e) {
+ throw new IOException(e.getMessage(), e);
+ }
+ out = new CipherOutputStream(out, enccipher) {
+ boolean closed;
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed = true;
+ }
+ }
+ };
+ }
+ return out;
+ }
+
+ private InputStream createInputStream(File file) throws IOException {
+ InputStream in = new FileInputStream(file);
+ if (cipherTransformation != null) {
+ in = new CipherInputStream(in, deccipher) {
+ boolean closed;
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed = true;
+ }
+ }
+ };
+ }
+ return in;
+ }
+
}
Modified: cxf/branches/2.6.x-fixes/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java?rev=1401722&r1=1401721&r2=1401722&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java (original)
+++ cxf/branches/2.6.x-fixes/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java Wed Oct 24 15:03:58 2012
@@ -20,7 +20,9 @@ package org.apache.cxf.io;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import org.junit.Assert;
import org.junit.Test;
@@ -53,6 +55,81 @@ public class CachedOutputStreamTest exte
//assert tmp file is deleted after close the CachedOutputStream
assertFalse(tempFile.exists());
}
+
+ @Test
+ public void testEncryptAndDecryptWithDeleteOnClose() throws IOException {
+ CachedOutputStream cos = new CachedOutputStream();
+ cos.setThreshold(4);
+ // need a 8-bit cipher so that all bytes are flushed when the stream is flushed.
+ cos.setCipherTransformation("DES/CFB8/NoPadding");
+
+ final String text = "Hello Secret World!";
+ cos.write(text.getBytes("UTF-8"));
+ cos.flush();
+
+ File tmpfile = cos.getTempFile();
+ assertNotNull(tmpfile);
+
+ final String enctext = readFromStream(new FileInputStream(tmpfile));
+ assertFalse("text is not encoded", text.equals(enctext));
+
+ InputStream fin = cos.getInputStream();
+
+ assertTrue("file is deleted", tmpfile.exists());
+
+ final String dectext = readFromStream(fin);
+ assertEquals("text is not decoded correctly", text, dectext);
+
+ // the file is deleted when cos is closed while all the associated inputs are closed
+ assertTrue("file is deleted", tmpfile.exists());
+ cos.close();
+ assertFalse("file is not deleted", tmpfile.exists());
+ }
+
+ @Test
+ public void testEncryptAndDecryptWithDeleteOnInClose() throws IOException {
+ CachedOutputStream cos = new CachedOutputStream();
+ cos.setThreshold(4);
+ // need a 8-bit cipher so that all bytes are flushed when the stream is flushed.
+ cos.setCipherTransformation("DES/CFB8/NoPadding");
+
+ final String text = "Hello Secret World!";
+ cos.write(text.getBytes("UTF-8"));
+ cos.flush();
+
+ File tmpfile = cos.getTempFile();
+ assertNotNull(tmpfile);
+
+ final String enctext = readFromStream(new FileInputStream(tmpfile));
+ assertFalse("text is not encoded", text.equals(enctext));
+
+ InputStream fin = cos.getInputStream();
+
+ cos.close();
+ assertTrue("file is deleted", tmpfile.exists());
+
+ // the file is deleted when cos is closed while all the associated inputs are closed
+ final String dectext = readFromStream(fin);
+ assertEquals("text is not decoded correctly", text, dectext);
+ assertFalse("file is not deleted", tmpfile.exists());
+ }
+
+ private static String readFromStream(InputStream is) throws IOException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ try {
+ byte[] b = new byte[100];
+ for (;;) {
+ int n = is.read(b, 0, b.length);
+ if (n < 0) {
+ break;
+ }
+ buf.write(b, 0, n);
+ }
+ } finally {
+ is.close();
+ }
+ return new String(buf.toByteArray(), "UTF-8");
+ }
String initTestData(int packetSize) {
String temp = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+?><[]/0123456789";