You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2014/06/26 17:49:33 UTC
git commit: [CXF-5311] Updating Base64Utility to support urlsafe mode
and stream to OutputStream and JweOutputStream accordingly
Repository: cxf
Updated Branches:
refs/heads/master 60bad6d65 -> 53270bde1
[CXF-5311] Updating Base64Utility to support urlsafe mode and stream to OutputStream and JweOutputStream accordingly
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/53270bde
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/53270bde
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/53270bde
Branch: refs/heads/master
Commit: 53270bde15a66fbfbf3896ef398740400719f5d2
Parents: 60bad6d
Author: Sergey Beryozkin <sb...@talend.com>
Authored: Thu Jun 26 16:49:15 2014 +0100
Committer: Sergey Beryozkin <sb...@talend.com>
Committed: Thu Jun 26 16:49:15 2014 +0100
----------------------------------------------------------------------
.../apache/cxf/common/util/Base64Utility.java | 147 ++++++++++++++++---
.../cxf/common/util/Base64UtilityTest.java | 10 ++
.../oauth2/jwe/AbstractJweEncryptor.java | 10 +-
.../security/oauth2/jwe/JweCompactProducer.java | 19 +++
.../rs/security/oauth2/jwe/JweOutputStream.java | 7 +-
.../security/oauth2/utils/Base64UrlUtility.java | 34 ++---
6 files changed, 174 insertions(+), 53 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/core/src/main/java/org/apache/cxf/common/util/Base64Utility.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/common/util/Base64Utility.java b/core/src/main/java/org/apache/cxf/common/util/Base64Utility.java
index c134fc8..1888d69 100644
--- a/core/src/main/java/org/apache/cxf/common/util/Base64Utility.java
+++ b/core/src/main/java/org/apache/cxf/common/util/Base64Utility.java
@@ -28,6 +28,9 @@ package org.apache.cxf.common.util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
import java.util.logging.Logger;
import org.apache.cxf.common.i18n.Message;
@@ -66,7 +69,9 @@ public final class Base64Utility {
'8', '9', '+', '/'
};
- // base 64 wadding
+ private static final char[] BCS_URL_SAFE = Arrays.copyOf(BCS, BCS.length);
+
+ // base 64 padding
private static final char PAD = '=';
// size of base 64 decode table
@@ -80,7 +85,9 @@ public final class Base64Utility {
private static final int PAD_SIZE4 = 2;
private static final int PAD_SIZE8 = 3;
- // class static intializer for building decode table
+ private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
+
+ // class static initializer for building decode table
static {
for (int i = 0; i < BDTSIZE; i++) {
BDT[i] = Byte.MAX_VALUE;
@@ -89,6 +96,9 @@ public final class Base64Utility {
for (int i = 0; i < BCS.length; i++) {
BDT[BCS[i]] = (byte)i;
}
+
+ BCS_URL_SAFE[62] = '-';
+ BCS_URL_SAFE[63] = '_';
}
@@ -96,6 +106,8 @@ public final class Base64Utility {
//utility class, never constructed
}
+
+
/**
* The <code>decode_chunk</code> routine decodes a chunk of data
* into its native encoding.
@@ -173,6 +185,26 @@ public final class Base64Utility {
}
public static byte[] decode(String id) throws Base64Exception {
+ return decode(id, false);
+ }
+
+ public static byte[] decode(String id, boolean urlSafe) throws Base64Exception {
+ if (urlSafe) {
+ //TODO: optimize further
+ id = id.replace("-", "+").replace('_', '/');
+ switch (id.length() % 4) {
+ case 0:
+ break;
+ case 2:
+ id += "==";
+ break;
+ case 3:
+ id += "=";
+ break;
+ default:
+ throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG));
+ }
+ }
try {
char[] cd = id.toCharArray();
return decodeChunk(cd, 0, cd.length);
@@ -214,6 +246,10 @@ public final class Base64Utility {
// Returns base64 representation of specified byte array.
//
public static String encode(byte[] id) {
+ return encode(id, false);
+ }
+
+ public static String encode(byte[] id, boolean urlSafe) {
char[] cd = encodeChunk(id, 0, id.length);
return new String(cd, 0, cd.length);
}
@@ -223,6 +259,13 @@ public final class Base64Utility {
public static char[] encodeChunk(byte[] id,
int o,
int l) {
+ return encodeChunk(id, o, l, false);
+ }
+
+ public static char[] encodeChunk(byte[] id,
+ int o,
+ int l,
+ boolean urlSafe) {
if (l <= 0) {
return null;
}
@@ -235,42 +278,111 @@ public final class Base64Utility {
if (l % 3 == 0) {
out = new char[l / 3 * 4];
} else {
- out = new char[l / 3 * 4 + 4];
+ int finalLen = !urlSafe ? 4 : l % 3 == 1 ? 2 : 3;
+ out = new char[l / 3 * 4 + finalLen];
}
int rindex = o;
int windex = 0;
int rest = l;
+ final char[] base64Table = urlSafe ? BCS_URL_SAFE : BCS;
while (rest >= 3) {
int i = ((id[rindex] & 0xff) << 16)
+ ((id[rindex + 1] & 0xff) << 8)
+ (id[rindex + 2] & 0xff);
- out[windex++] = BCS[i >> 18];
- out[windex++] = BCS[(i >> 12) & 0x3f];
- out[windex++] = BCS[(i >> 6) & 0x3f];
- out[windex++] = BCS[i & 0x3f];
+ out[windex++] = base64Table[i >> 18];
+ out[windex++] = base64Table[(i >> 12) & 0x3f];
+ out[windex++] = base64Table[(i >> 6) & 0x3f];
+ out[windex++] = base64Table[i & 0x3f];
rindex += 3;
rest -= 3;
}
if (rest == 1) {
int i = id[rindex] & 0xff;
- out[windex++] = BCS[i >> 2];
- out[windex++] = BCS[(i << 4) & 0x3f];
- out[windex++] = PAD;
- out[windex++] = PAD;
+ out[windex++] = base64Table[i >> 2];
+ out[windex++] = base64Table[(i << 4) & 0x3f];
+ if (!urlSafe) {
+ out[windex++] = PAD;
+ out[windex++] = PAD;
+ }
} else if (rest == 2) {
int i = ((id[rindex] & 0xff) << 8) + (id[rindex + 1] & 0xff);
- out[windex++] = BCS[i >> 10];
- out[windex++] = BCS[(i >> 4) & 0x3f];
- out[windex++] = BCS[(i << 2) & 0x3f];
- out[windex++] = PAD;
+ out[windex++] = base64Table[i >> 10];
+ out[windex++] = base64Table[(i >> 4) & 0x3f];
+ out[windex++] = base64Table[(i << 2) & 0x3f];
+ if (!urlSafe) {
+ out[windex++] = PAD;
+ }
}
return out;
}
+
+ public static void encodeAndStream(byte[] id,
+ int o,
+ int l,
+ OutputStream os) throws IOException {
+ encodeAndStream(id, o, l, false, os);
+ }
+
+ public static void encodeAndStream(byte[] id,
+ int o,
+ int l,
+ boolean urlSafe,
+ OutputStream os) throws IOException {
+ if (l <= 0) {
+ return;
+ }
+ int rindex = o;
+ int rest = l;
+ final char[] base64Table = urlSafe ? BCS_URL_SAFE : BCS;
+
+ char[] chunk = new char[4];
+ while (rest >= 3) {
+ int i = ((id[rindex] & 0xff) << 16)
+ + ((id[rindex + 1] & 0xff) << 8)
+ + (id[rindex + 2] & 0xff);
+ chunk[0] = base64Table[i >> 18];
+ chunk[1] = base64Table[(i >> 12) & 0x3f];
+ chunk[2] = base64Table[(i >> 6) & 0x3f];
+ chunk[3] = base64Table[i & 0x3f];
+ writeCharArrayToStream(chunk, 4, os);
+ rindex += 3;
+ rest -= 3;
+ }
+ if (rest == 0) {
+ return;
+ }
+ if (rest == 1) {
+ int i = id[rindex] & 0xff;
+ chunk[0] = base64Table[i >> 2];
+ chunk[1] = base64Table[(i << 4) & 0x3f];
+ if (!urlSafe) {
+ chunk[2] = PAD;
+ chunk[3] = PAD;
+ }
+ } else if (rest == 2) {
+ int i = ((id[rindex] & 0xff) << 8) + (id[rindex + 1] & 0xff);
+ chunk[0] = base64Table[i >> 10];
+ chunk[1] = base64Table[(i >> 4) & 0x3f];
+ chunk[2] = base64Table[(i << 2) & 0x3f];
+ if (!urlSafe) {
+ chunk[3] = PAD;
+ }
+ }
+ int finalLenToWrite = !urlSafe ? 4 : rest == 1 ? 2 : 3;
+ writeCharArrayToStream(chunk, finalLenToWrite, os);
+ }
+
+ private static void writeCharArrayToStream(char[] chunk, int len, OutputStream os) throws IOException {
+ // may be we can just cast to byte when creating chunk[] earlier on
+ byte[] bytes = CHARSET_UTF8.encode(CharBuffer.wrap(chunk, 0, len)).array();
+ os.write(bytes);
+ }
+
//
// Outputs base64 representation of the specified byte array
// to a byte stream.
@@ -285,8 +397,7 @@ public final class Base64Utility {
throw new Base64Exception(new Message("BASE64_ENCODE_IOEXCEPTION", LOG), e);
}
}
-
-
+
// Outputs base64 representation of the specified byte
// array to a character stream.
//
@@ -300,8 +411,6 @@ public final class Base64Utility {
throw new Base64Exception(new Message("BASE64_ENCODE_WRITER_IOEXCEPTION", LOG), e);
}
}
-
-
//---- Private static methods --------------------------------------
/**
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/core/src/test/java/org/apache/cxf/common/util/Base64UtilityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/cxf/common/util/Base64UtilityTest.java b/core/src/test/java/org/apache/cxf/common/util/Base64UtilityTest.java
index f62e8d8..213dcd0 100644
--- a/core/src/test/java/org/apache/cxf/common/util/Base64UtilityTest.java
+++ b/core/src/test/java/org/apache/cxf/common/util/Base64UtilityTest.java
@@ -61,6 +61,16 @@ public class Base64UtilityTest extends Assert {
}
@Test
+ public void testEncodeAndStream() throws Exception {
+ final String text = "The true sign of intelligence is not knowledge but imagination.";
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] bytes = text.getBytes("UTF-8");
+ Base64Utility.encodeAndStream(bytes, 0, bytes.length, bos);
+ String decodedText = new String(Base64Utility.decode(bos.toString()));
+ assertEquals(decodedText, text);
+ }
+
+ @Test
public void testEncodeDecodeChunk() throws Exception {
byte bytes[] = new byte[100];
for (int x = 0; x < bytes.length; x++) {
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryptor.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryptor.java
index 132eca8..6dfa93a 100644
--- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryptor.java
+++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryptor.java
@@ -124,14 +124,14 @@ public abstract class AbstractJweEncryptor implements JweEncryptor {
@Override
public JweOutputStream createJweStream(OutputStream os, String contentType) {
JweEncryptorInternalState state = getInternalState(contentType);
- String jweStart = JweCompactProducer.startJweContent(state.theHeaders,
- writer,
- state.jweContentEncryptionKey,
- state.theIv);
Cipher c = CryptoUtils.initCipher(state.secretKey, state.keyProps,
Cipher.ENCRYPT_MODE);
try {
- os.write(jweStart.getBytes("UTF-8"));
+ JweCompactProducer.startJweContent(os,
+ state.theHeaders,
+ writer,
+ state.jweContentEncryptionKey,
+ state.theIv);
} catch (IOException ex) {
throw new SecurityException(ex);
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java
index bb0a24d..72d3d84 100644
--- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java
+++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java
@@ -19,6 +19,9 @@
package org.apache.cxf.rs.security.oauth2.jwe;
+import java.io.IOException;
+import java.io.OutputStream;
+
import org.apache.cxf.rs.security.oauth2.jwt.JwtHeadersWriter;
import org.apache.cxf.rs.security.oauth2.jwt.JwtTokenReaderWriter;
import org.apache.cxf.rs.security.oauth2.utils.Base64UrlUtility;
@@ -101,6 +104,22 @@ public class JweCompactProducer {
return sb;
}
+ public static void startJweContent(OutputStream os,
+ JweHeaders headers,
+ JwtHeadersWriter writer,
+ byte[] encryptedContentEncryptionKey,
+ byte[] cipherInitVector) throws IOException {
+ writer = writer == null ? new JwtTokenReaderWriter() : writer;
+ byte[] jsonBytes = writer.headersToJson(headers).getBytes("UTF-8");
+ Base64UrlUtility.encodeAndStream(jsonBytes, 0, jsonBytes.length, os);
+ os.write('.');
+ Base64UrlUtility.encodeAndStream(encryptedContentEncryptionKey, 0,
+ encryptedContentEncryptionKey.length, os);
+ os.write('.');
+ Base64UrlUtility.encodeAndStream(cipherInitVector, 0, cipherInitVector.length, os);
+ os.write('.');
+ }
+
public String getJweContent() {
return jweContentBuilder.append(encodedEncryptedContent)
.append('.')
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweOutputStream.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweOutputStream.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweOutputStream.java
index fa954f6..ebf80df 100644
--- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweOutputStream.java
+++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweOutputStream.java
@@ -87,7 +87,7 @@ public class JweOutputStream extends FilterOutputStream {
theChunk = encryptedChunk;
}
int rem = finalWrite ? 0 : lenToEncode % 3;
- encodeAndWriteFinally(theChunk, off, lenToEncode - rem);
+ Base64UrlUtility.encodeAndStream(theChunk, off, lenToEncode - rem, out);
if (rem > 0) {
lastEncryptedDataChunk = newArray(theChunk, lenToEncode - rem, rem);
@@ -95,11 +95,6 @@ public class JweOutputStream extends FilterOutputStream {
lastEncryptedDataChunk = null;
}
}
- private void encodeAndWriteFinally(byte[] chunk, int off, int len) throws IOException {
- String encoded = Base64UrlUtility.encodeChunk(chunk, off, len);
- byte[] encodedBytes = encoded.getBytes("UTF-8");
- out.write(encodedBytes, 0, encodedBytes.length);
- }
@Override
public void flush() throws IOException {
http://git-wip-us.apache.org/repos/asf/cxf/blob/53270bde/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/Base64UrlUtility.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/Base64UrlUtility.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/Base64UrlUtility.java
index d8d795c..9433b97 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/Base64UrlUtility.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/Base64UrlUtility.java
@@ -27,37 +27,21 @@ package org.apache.cxf.rs.security.oauth2.utils;
*
*/
+import java.io.IOException;
+import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import java.util.logging.Logger;
-import org.apache.cxf.common.i18n.Message;
-import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.Base64Exception;
import org.apache.cxf.common.util.Base64Utility;
public final class Base64UrlUtility {
- private static final Logger LOG = LogUtils.getL7dLogger(Base64UrlUtility.class);
-
private Base64UrlUtility() {
//utility class, never constructed
}
public static byte[] decode(String encoded) throws Base64Exception {
- encoded = encoded.replace("-", "+").replace('_', '/');
- switch (encoded.length() % 4) {
- case 0:
- break;
- case 2:
- encoded += "==";
- break;
- case 3:
- encoded += "=";
- break;
- default:
- throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG));
- }
- return Base64Utility.decode(encoded);
+ return Base64Utility.decode(encoded, true);
}
public static String encode(String str) {
@@ -73,14 +57,18 @@ public final class Base64UrlUtility {
}
public static String encodeChunk(byte[] id, int offset, int length) {
- char[] chunk = Base64Utility.encodeChunk(id, offset, length);
+ char[] chunk = Base64Utility.encodeChunk(id, offset, length, true);
if (chunk != null) {
- String encoded = new String(chunk);
- return encoded.replace("+", "-").replace('/', '_').replace("=", "");
+ return new String(chunk);
} else {
return null;
}
}
-
+ public static void encodeAndStream(byte[] id,
+ int o,
+ int l,
+ OutputStream os) throws IOException {
+ Base64Utility.encodeAndStream(id, o, l, true, os);
+ }
}