cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject git commit: [CXF-5311] Updating Base64Utility to support urlsafe mode and stream to OutputStream and JweOutputStream accordingly
Date Thu, 26 Jun 2014 15:49:33 GMT
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 <sberyozkin@talend.com>
Authored: Thu Jun 26 16:49:15 2014 +0100
Committer: Sergey Beryozkin <sberyozkin@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);
+    }
 }


Mime
View raw message