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/23 11:43:57 UTC
svn commit: r1401223 - in /cxf/trunk/api/src:
main/java/org/apache/cxf/io/CachedOutputStream.java
test/java/org/apache/cxf/io/CachedOutputStreamTest.java
Author: ay
Date: Tue Oct 23 09:43:57 2012
New Revision: 1401223
URL: http://svn.apache.org/viewvc?rev=1401223&view=rev
Log:
[CXF-4596] adding an option for encrypting tmp files generated by COS
Modified:
cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java
cxf/trunk/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java
Modified: cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java?rev=1401223&r1=1401222&r2=1401223&view=diff
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java (original)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java Tue Oct 23 09:43:57 2012
@@ -33,10 +33,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 +54,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 +71,7 @@ public class CachedOutputStream extends
setDefaultThreshold(-1);
setDefaultMaxSize(-1);
+ setDefaultCipherTransformation(null);
}
protected boolean outputLocked;
@@ -78,6 +88,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 +249,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 +279,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
return IOUtils.readBytesFromStream(fin);
}
}
@@ -280,7 +294,7 @@ public class CachedOutputStream extends
}
} else {
// read the file
- FileInputStream fin = new FileInputStream(tempFile);
+ InputStream fin = createInputStream(tempFile);
IOUtils.copyAndCloseInput(fin, out);
}
}
@@ -310,7 +324,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);
@@ -350,7 +364,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);
@@ -439,7 +453,7 @@ public class CachedOutputStream extends
tempFile = FileUtils.createTempFile("cos", "tmp", outputDir, false);
}
- currentStream = new FileOutputStream(tempFile);
+ currentStream = createOutputStream(tempFile);
bout.writeTo(currentStream);
currentStream = new BufferedOutputStream(currentStream);
inmem = false;
@@ -475,7 +489,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) {
@@ -486,6 +500,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());
@@ -527,6 +553,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) {
@@ -548,4 +578,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/trunk/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java?rev=1401223&r1=1401222&r2=1401223&view=diff
==============================================================================
--- cxf/trunk/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java (original)
+++ cxf/trunk/api/src/test/java/org/apache/cxf/io/CachedOutputStreamTest.java Tue Oct 23 09:43:57 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";