Author: sergeyb
Date: Thu Jan 30 17:34:44 2014
New Revision: 1562902
URL: http://svn.apache.org/r1562902
Log:
[CXF-5513] Optional compression before the encryption, initial support for
encryption/decryption with certificates
Added:
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
(with props)
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServiceException.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptingDataProvider.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/DeflateEncoderDecoder.java
Added:
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java?rev=1562902&view=auto
==============================================================================
---
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
(added)
+++
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
Thu Jan 30 17:34:44 2014
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.common.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+public final class CompressionUtils {
+ private CompressionUtils() {
+
+ }
+ public static InputStream decompress(byte[] deflatedToken)
+ throws DataFormatException {
+ return decompress(deflatedToken, true);
+ }
+ public static InputStream decompress(byte[] deflatedToken, boolean nowrap)
+ throws DataFormatException {
+ Inflater inflater = new Inflater(nowrap);
+ inflater.setInput(deflatedToken);
+
+ byte[] input = new byte[deflatedToken.length * 2];
+ int inflatedLen = 0;
+ int inputLen = 0;
+ byte[] inflatedToken = input;
+ while (!inflater.finished()) {
+ inputLen = inflater.inflate(input);
+ if (!inflater.finished()) {
+
+ if (inputLen == 0) {
+ if (inflater.needsInput()) {
+ throw new DataFormatException("Inflater can not
inflate all the token bytes");
+ } else {
+ break;
+ }
+ }
+
+ inflatedToken = new byte[input.length + inflatedLen];
+ System.arraycopy(input, 0, inflatedToken, inflatedLen,
inputLen);
+ inflatedLen += inputLen;
+ }
+ }
+ InputStream is = new ByteArrayInputStream(input, 0, inputLen);
+ if (inflatedToken != input) {
+ is = new SequenceInputStream(new
ByteArrayInputStream(inflatedToken, 0, inflatedLen),
+ is);
+ }
+ return is;
+ }
+
+ public static byte[] compress(byte[] tokenBytes) {
+ return compress(tokenBytes, true);
+ }
+
+ public static byte[] compress(byte[] tokenBytes, boolean nowrap) {
+ Deflater compresser = new Deflater(Deflater.DEFLATED, nowrap);
+
+ compresser.setInput(tokenBytes);
+ compresser.finish();
+
+ byte[] output = new byte[tokenBytes.length * 2];
+
+ int compressedDataLength = compresser.deflate(output);
+
+ byte[] result = new byte[compressedDataLength];
+ System.arraycopy(output, 0, result, 0, compressedDataLength);
+ return result;
+ }
+}
Propchange:
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
cxf/trunk/core/src/main/java/org/apache/cxf/common/util/CompressionUtils.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServiceException.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServiceException.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServiceException.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServiceException.java
Thu Jan 30 17:34:44 2014
@@ -31,6 +31,10 @@ public class OAuthServiceException exten
private static final long serialVersionUID = 343738539234766320L;
private OAuthError error;
+ public OAuthServiceException() {
+ super(OAuthConstants.SERVER_ERROR);
+ }
+
public OAuthServiceException(String message) {
super(message);
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtils.java
Thu Jan 30 17:34:44 2014
@@ -20,6 +20,7 @@
package org.apache.cxf.rs.security.oauth2.utils;
import java.security.Key;
+import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
@@ -28,6 +29,8 @@ import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
+import org.apache.cxf.common.util.CompressionUtils;
+import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
@@ -125,8 +128,14 @@ public final class EncryptionUtils {
}
}
- public static byte[] processBytes(byte[] bytes, Key secretKey,
- SecretKeyProperties keyProps, int mode) {
+ public static byte[] processBytes(byte[] bytes,
+ Key secretKey,
+ SecretKeyProperties keyProps,
+ int mode) {
+ boolean compressionSupported = keyProps != null &&
keyProps.isCompressionSupported();
+ if (compressionSupported && mode == Cipher.ENCRYPT_MODE) {
+ bytes = CompressionUtils.compress(bytes, false);
+ }
try {
Cipher c = Cipher.getInstance(secretKey.getAlgorithm());
if (keyProps == null || keyProps.getAlgoSpec() == null &&
keyProps.getSecureRandom() == null) {
@@ -142,12 +151,38 @@ public final class EncryptionUtils {
c.init(mode, secretKey, algoSpec, random);
}
}
- return c.doFinal(bytes);
+ byte[] result = new byte[0];
+ int blockSize = keyProps != null ? keyProps.getBlockSize() : -1;
+ if (secretKey instanceof SecretKey && blockSize == -1) {
+ result = c.doFinal(bytes);
+ } else {
+ if (blockSize == -1) {
+ blockSize = secretKey instanceof PublicKey ? 117 : 128;
+ }
+ int offset = 0;
+ for (; offset + blockSize < bytes.length; offset += blockSize)
{
+ result = addToResult(result, c.doFinal(bytes, offset,
blockSize));
+ }
+ if (offset < bytes.length) {
+ result = addToResult(result, c.doFinal(bytes, offset,
bytes.length - offset));
+ }
+ }
+ if (compressionSupported && mode == Cipher.DECRYPT_MODE) {
+ result =
IOUtils.readBytesFromStream(CompressionUtils.decompress(result, false));
+ }
+ return result;
} catch (Exception ex) {
throw new OAuthServiceException(ex);
}
}
+ private static byte[] addToResult(byte[] prefix, byte[] suffix) {
+ byte[] result = new byte[prefix.length + suffix.length];
+ System.arraycopy(prefix, 0, result, 0, prefix.length);
+ System.arraycopy(suffix, 0, result, prefix.length, suffix.length);
+ return result;
+ }
+
public static SecretKey decodeSecretKey(String encodedSecretKey, String
algo) {
try {
byte[] secretKeyBytes = decodeSequence(encodedSecretKey);
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/SecretKeyProperties.java
Thu Jan 30 17:34:44 2014
@@ -24,8 +24,10 @@ import java.security.spec.AlgorithmParam
public class SecretKeyProperties {
private String keyAlgo;
private int keySize;
+ private int blockSize = -1;
private SecureRandom secureRandom;
private AlgorithmParameterSpec algoSpec;
+ private boolean compressionSupported = true;
public SecretKeyProperties() {
this("AES", 128);
}
@@ -60,6 +62,19 @@ public class SecretKeyProperties {
public void setAlgoSpec(AlgorithmParameterSpec algoSpec) {
this.algoSpec = algoSpec;
}
+ public int getBlockSize() {
+ return blockSize;
+ }
+ public void setBlockSize(int blockSize) {
+ this.blockSize = blockSize;
+ }
+ public boolean isCompressionSupported() {
+ return compressionSupported;
+ }
+ public void setCompressionSupported(boolean compressionSupported) {
+ this.compressionSupported = compressionSupported;
+ }
+
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptingDataProvider.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptingDataProvider.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptingDataProvider.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptingDataProvider.java
Thu Jan 30 17:34:44 2014
@@ -100,14 +100,18 @@ public class EncryptingDataProvider impl
}
@Override
- public ServerAccessToken getPreauthorizedToken(Client client, List<String>
requestedScopes,
- UserSubject subject, String
grantType)
- throws OAuthServiceException {
- return null;
+ public List<OAuthPermission> convertScopeToPermissions(Client client,
List<String> requestedScope) {
+ // assuming that no specific scopes is documented/supported
+ return Collections.emptyList();
}
@Override
- public List<OAuthPermission> convertScopeToPermissions(Client client,
List<String> requestedScope) {
+ public ServerAccessToken getPreauthorizedToken(Client client, List<String>
requestedScopes,
+ UserSubject subject, String
grantType)
+ throws OAuthServiceException {
+ // This is an optimization useful in cases where a client requests an
authorization code:
+ // if a user has already provided a given client with a pre-authorized
token then challenging
+ // a user with yet another form asking for the authorization is
redundant
return null;
}
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
(original)
+++
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/EncryptionUtilsTest.java
Thu Jan 30 17:34:44 2014
@@ -21,6 +21,10 @@ package org.apache.cxf.rs.security.oauth
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.annotation.Annotation;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.util.Collections;
import java.util.List;
@@ -63,7 +67,6 @@ public class EncryptionUtilsTest extends
// encrypt
ServerAccessToken token = p.createAccessToken(atr);
- // decrypt
ServerAccessToken token2 = p.getAccessToken(token.getTokenKey());
// compare tokens
@@ -105,6 +108,37 @@ public class EncryptionUtilsTest extends
}
@Test
+ public void testBearerTokenJSONCertificate() throws Exception {
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ KeyPair keyPair = kpg.generateKeyPair();
+ PublicKey publicKey = keyPair.getPublic();
+ PrivateKey privateKey = keyPair.getPrivate();
+
+ AccessTokenRegistration atr = prepareTokenRegistration();
+
+ BearerAccessToken token = p.createAccessTokenInternal(atr);
+ JSONProvider<BearerAccessToken> jsonp = new
JSONProvider<BearerAccessToken>();
+ jsonp.setMarshallAsJaxbElement(true);
+ jsonp.setUnmarshallAsJaxbElement(true);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ jsonp.writeTo(token, BearerAccessToken.class, new Annotation[]{},
MediaType.APPLICATION_JSON_TYPE,
+ new MetadataMap<String, Object>(), bos);
+
+ SecretKeyProperties props1 = new
SecretKeyProperties(publicKey.getAlgorithm());
+ String encrypted = EncryptionUtils.encryptSequence(bos.toString(),
publicKey, props1);
+ SecretKeyProperties props2 = new
SecretKeyProperties(privateKey.getAlgorithm());
+ String decrypted = EncryptionUtils.decryptSequence(encrypted,
privateKey, props2);
+ ServerAccessToken token2 = jsonp.readFrom(BearerAccessToken.class,
BearerAccessToken.class,
+ new Annotation[]{},
MediaType.APPLICATION_JSON_TYPE,
+ new MetadataMap<String,
String>(),
+ new
ByteArrayInputStream(decrypted.getBytes()));
+
+ // compare tokens
+ compareAccessTokens(token, token2);
+ }
+
+ @Test
public void testClientJSON() throws Exception {
Client c = new Client("client", "secret", true);
c.setSubject(new UserSubject("subject", "id"));
@@ -199,5 +233,20 @@ public class EncryptionUtilsTest extends
return atr;
}
-
+// TODO: remove once the wiki documentation is updated
+// KeyStore keyStore = loadKeyStore();
+// Certificate cert = keyStore.getCertificate("alice");
+// PublicKey publicKey = cert.getPublicKey();
+// KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+// keyStore.getEntry("alice", new KeyStore.PasswordProtection(
+// new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}));
+// PrivateKey privateKey = pkEntry.getPrivateKey();
+
+
+// private KeyStore loadKeyStore() throws Exception {
+// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+// InputStream is = this.getClass().getResourceAsStream("alice.jks");
+// ks.load(is, new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'});
+// return ks;
+// }
}
Modified:
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/DeflateEncoderDecoder.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/DeflateEncoderDecoder.java?rev=1562902&r1=1562901&r2=1562902&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/DeflateEncoderDecoder.java
(original)
+++
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/DeflateEncoderDecoder.java
Thu Jan 30 17:34:44 2014
@@ -18,60 +18,18 @@
*/
package org.apache.cxf.rs.security.saml;
-import java.io.ByteArrayInputStream;
import java.io.InputStream;
-import java.io.SequenceInputStream;
import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
+
+import org.apache.cxf.common.util.CompressionUtils;
public class DeflateEncoderDecoder {
public InputStream inflateToken(byte[] deflatedToken)
throws DataFormatException {
- Inflater inflater = new Inflater(true);
- inflater.setInput(deflatedToken);
-
- byte[] input = new byte[deflatedToken.length * 2];
- int inflatedLen = 0;
- int inputLen = 0;
- byte[] inflatedToken = input;
- while (!inflater.finished()) {
- inputLen = inflater.inflate(input);
- if (!inflater.finished()) {
-
- if (inputLen == 0) {
- if (inflater.needsInput()) {
- throw new DataFormatException("Inflater can not
inflate all the token bytes");
- } else {
- break;
- }
- }
-
- inflatedToken = new byte[input.length + inflatedLen];
- System.arraycopy(input, 0, inflatedToken, inflatedLen,
inputLen);
- inflatedLen += inputLen;
- }
- }
- InputStream is = new ByteArrayInputStream(input, 0, inputLen);
- if (inflatedToken != input) {
- is = new SequenceInputStream(new
ByteArrayInputStream(inflatedToken, 0, inflatedLen),
- is);
- }
- return is;
+ return CompressionUtils.decompress(deflatedToken);
}
public byte[] deflateToken(byte[] tokenBytes) {
- Deflater compresser = new Deflater(Deflater.DEFLATED, true);
-
- compresser.setInput(tokenBytes);
- compresser.finish();
-
- byte[] output = new byte[tokenBytes.length * 2];
-
- int compressedDataLength = compresser.deflate(output);
-
- byte[] result = new byte[compressedDataLength];
- System.arraycopy(output, 0, result, 0, compressedDataLength);
- return result;
+ return CompressionUtils.compress(tokenBytes);
}
}