Author: amitj Date: Thu Oct 5 09:47:39 2017 New Revision: 1811179 URL: http://svn.apache.org/viewvc?rev=1811179&view=rev Log: OAK-6575: Provide a secure external URL to a DataStore binary
Patch from Ian Boston Added: jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/ jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java (with props) jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java (with props) jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java (with props) jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java (with props) Modified: jackrabbit/oak/trunk/oak-blob-cloud/pom.xml Added: jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java?rev=1811179&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java (added) +++ jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java Thu Oct 5 09:47:39 2017 @@ -0,0 +1,38 @@ +/* + * 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.jackrabbit.oak.api.conversion; + +import org.osgi.annotation.versioning.ProviderType; + +import javax.jcr.Value; +import java.net.URI; + +/** + * + * Provides a URI in exchange for a Value. + * Typically the Value will represent something where a URI is valuable and useful. + * Implementations of this interface must ensure that the Oak security model is delegated + * securely and not circumvented. Only Oak bundles should implement this provider as in most cases + * internal implementation details of Oak will be required to achieve the implementation. Ideally + * implementations should be carefully reviewed by peers. + */ +@ProviderType +public interface URIProvider { + + URI toURI(Value value); +} Propchange: jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/URIProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Added: jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java?rev=1811179&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java (added) +++ jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java Thu Oct 5 09:47:39 2017 @@ -0,0 +1,20 @@ +/* + * 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. + */ +@Version("1.0.0") +package org.apache.jackrabbit.oak.api.conversion; + +import org.osgi.annotation.versioning.Version; Propchange: jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/conversion/package-info.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: jackrabbit/oak/trunk/oak-blob-cloud/pom.xml URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-cloud/pom.xml?rev=1811179&r1=1811178&r2=1811179&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-blob-cloud/pom.xml (original) +++ jackrabbit/oak/trunk/oak-blob-cloud/pom.xml Thu Oct 5 09:47:39 2017 @@ -120,6 +120,12 @@ <artifactId>aws-java-sdk-s3</artifactId> <version>1.11.24</version> </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-cloudfront</artifactId> + <version>1.11.24</version> + <scope>provided</scope> + </dependency> <dependency> <groupId>com.google.guava</groupId> @@ -171,6 +177,11 @@ <version>1.10.19</version> <scope>test</scope> </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <version>2.0.1</version> + </dependency> </dependencies> </project> Added: jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java?rev=1811179&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java (added) +++ jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java Thu Oct 5 09:47:39 2017 @@ -0,0 +1,236 @@ +/* + * 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.jackrabbit.oak.blob.cloud.aws.s3; + +import com.amazonaws.services.cloudfront.CloudFrontUrlSigner; +import com.google.common.io.Closeables; +import org.apache.commons.codec.binary.Base64; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Service; +import org.apache.jackrabbit.oak.api.Blob; +import org.apache.jackrabbit.oak.api.conversion.URIProvider; +import org.apache.jackrabbit.oak.plugins.value.OakValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import javax.jcr.Value; +import java.io.FileReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.SignatureException; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + + +/** + * Adapts from Value to URI where Value has a Binary value. + * If running as an OSGi Component would expect an OSGi AdapterManager to pick it up. + * other. + * + * To generate keys in PKCS8 format use OpenSSL + * openssl genrsa -out private_key.pem 1024 + * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private_key.pem -out private_key.pkcs8 + * See http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#private-content-creating-cloudfront-key-pairs for + * details on how to configure CloudFront. + */ +@Component(immediate = true, metatype = true, policy = ConfigurationPolicy.REQUIRE) +@Service(URIProvider.class) +public class CloudFrontS3SignedUrlProvider implements URIProvider { + + @Property( description = "The cloud front URL, including a trailing slash. Normally this is the http://<coudfrontdomain>/") + public static final String CLOUD_FRONT_URL = "cloudFrontUrl"; + + @Property(intValue = 60, description = "Time each signed url is valid for before it expires, in seconds.") + public static final String TTL = "ttl"; + + @Property(intValue = 100, description = "Minimum size over which a binary is redirected, in kb.") + public static final String MIN_SIZE = "minSize"; + + @Property(description = "Path to the PKCS8 formatted private key file, probably an absolute path.") + public static final String PRIVATE_KEY_FILE = "privateKeyFile"; + + @Property(description = "The keypair ID generated by AWS Console when the public key was generated or uploaded.") + public static final String KEY_PAIR_ID = "keyPairId"; + + public static final String BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----"; + public static final String END_PRIVATE_KEY = "-----END PRIVATE KEY-----"; + + private static final Logger LOGGER = LoggerFactory.getLogger(CloudFrontS3SignedUrlProvider.class); + private String cloudFrontUrl; + private long ttl; + private String keyPairId; + private RSAPrivateKey privateKey; + private long minimumSize; + + /** + * Default Constructor used by OSGi. + */ + public CloudFrontS3SignedUrlProvider() { + } + + /** + * Non OSGi IoC constructor, close must be called when done. + * @param cloudFrontUrl + * @param ttl + * @param privateKeyPEM + * @param privateKeyId + * @throws InvalidKeySpecException + * @throws NoSuchAlgorithmException + */ + public CloudFrontS3SignedUrlProvider(String cloudFrontUrl, + long ttl, + long minSize, + String privateKeyPEM, + String privateKeyId) throws InvalidKeySpecException, NoSuchAlgorithmException { + init(cloudFrontUrl, ttl, minSize, privateKeyPEM, privateKeyId); + } + + public void close() { + deactivate(new HashMap<String, Object>()); + } + + @Deactivate + public void deactivate(Map<String, Object> properties) { + } + + + @Activate + public void activate(Map<String, Object> properties) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException { + LOGGER.debug("Property {}: {} ",CLOUD_FRONT_URL, properties.get(CLOUD_FRONT_URL)); + LOGGER.debug("Property {}: {} ",TTL, properties.get(TTL)); + LOGGER.debug("Property {}: {} ", PRIVATE_KEY_FILE, properties.get(PRIVATE_KEY_FILE)); + LOGGER.debug("Property {}: {} ",KEY_PAIR_ID, properties.get(KEY_PAIR_ID)); + LOGGER.debug("Property {}: {} ",MIN_SIZE, properties.get(MIN_SIZE)); + init((String) properties.get(CLOUD_FRONT_URL), + (Integer) properties.get(TTL), + (Integer) properties.get(MIN_SIZE), + loadPrivateKey((String) properties.get(PRIVATE_KEY_FILE)), + (String) properties.get(KEY_PAIR_ID)); + } + + private String loadPrivateKey(String keyFile) throws IOException { + FileReader fr = null; + StringBuilder key = new StringBuilder(); + try { + fr = new FileReader(keyFile); + char[] b = new char[4096]; + for (; ; ) { + int i = fr.read(b); + if (i < 0) { + break; + } + key.append(b, 0, i); + } + } finally { + Closeables.close(fr, false); + } + return key.toString(); + } + + private void init(String cloudFrontUrl, long ttl, long minSize, String privateKeyPEM, String privateKeyId) + throws InvalidKeySpecException, NoSuchAlgorithmException { + this.cloudFrontUrl = cloudFrontUrl; + this.ttl = ttl; + this.minimumSize = minSize*1024; + this.privateKey = getPrivateKey(privateKeyPEM); + this.keyPairId = privateKeyId; + } + + + @Override + public URI toURI(Value value) { + // The conversion is javax.jcr.Value -> URI, but for Oak all Values are OakValues and we can only do it for Values. + if ( value instanceof OakValue ) { + try { + Blob b = ((OakValue) value).getBlob(); + if (b != null) { + if ( b.length() > minimumSize ) { + String contentId = b.getContentIdentity(); + if (contentId != null) { + URI uri = new URI(signS3Url(contentId, ttl, cloudFrontUrl, keyPairId, privateKey)); + LOGGER.info("Generated URI {} ", uri.toString()); + return uri; + } + } + } + } catch (Exception e) { + LOGGER.error("Unable to get or sign content identity",e); + } + + } + return null; + } + + + /** + * Convert the content identity to a S3 url, see the {@link org.apache.jackrabbit.oak.blob.cloud.s3.S3Backend} class. + * @param contentIdentity + * @return + */ + @Nonnull + private String getS3Key(@Nonnull String contentIdentity) { + return contentIdentity.substring(0, 4) + "-" + contentIdentity.substring(4); + } + + @Nonnull + private String signS3Url(@Nonnull String contentIdentity, long ttl, @Nonnull String cloudFrontUrl, + @Nonnull String keyPairId, @Nonnull RSAPrivateKey privateKey) + throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException { + + long expiry = (System.currentTimeMillis()/1000)+ttl; + StringBuilder urlToSign = new StringBuilder(); + + urlToSign.append(cloudFrontUrl) + .append(getS3Key(contentIdentity)); + return CloudFrontUrlSigner.getSignedURLWithCannedPolicy(urlToSign.toString(), keyPairId, privateKey, new Date(expiry)); + } + + + private RSAPrivateKey getPrivateKey(String privateKeyPKCS8) throws NoSuchAlgorithmException, InvalidKeySpecException { + int is = privateKeyPKCS8.indexOf(BEGIN_PRIVATE_KEY); + int ie = privateKeyPKCS8.indexOf(END_PRIVATE_KEY); + if (ie < 0 || is < 0) { + throw new IllegalArgumentException("Private Key is not correctly encoded, need a PEM encoded key with " + + "-----BEGIN PRIVATE KEY----- headers to indicate PKCS8 encoding."); + } + privateKeyPKCS8 = privateKeyPKCS8.substring(is + BEGIN_PRIVATE_KEY.length(), ie).trim(); + byte[] privateKeyBytes = Base64.decodeBase64(privateKeyPKCS8); + + // load the private key + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + KeySpec ks = new PKCS8EncodedKeySpec(privateKeyBytes); + return (RSAPrivateKey) keyFactory.generatePrivate(ks); + } +} Propchange: jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Added: jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java?rev=1811179&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java (added) +++ jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java Thu Oct 5 09:47:39 2017 @@ -0,0 +1,177 @@ +/* + * 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.jackrabbit.oak.blob.cloud.aws.s3; + +import org.apache.jackrabbit.oak.api.Blob; +import org.apache.jackrabbit.oak.plugins.value.OakValue; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import java.net.URI; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +/** + * Tests Signing URLS with a 1024 key and a 4096 key. + */ +public class CloudFrontS3SignedUrlProviderTest { + + + /** + * To generate keys in PKCS8 format use OpenSSL + * openssl genrsa -out private_key.pem 1024 + * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private_key.pem -out private_key.pkcs8 + */ + + private static final String PRIVATE_KEY_4096 = + + "-----BEGIN PRIVATE KEY-----\n"+ + "MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCjlLRiXaRiWzJV\n"+ + "Y+dJb5msXIpReDqpqu5NX2UYP6mALSERpUjVg4QyHmLczCYYAKIWlez6oFg4oPnd\n"+ + "FluC5eiUpsJn4TjuTwsxlLlPlx5L7TUSeIGlkTygZ0bu1DqdgKsxpQbMEID7lEun\n"+ + "AvEEYOlSgIpqzXVMFQA+eK2PHXFqdhxKaxm8/ngJJN13bIhMtPi6+RF9mO5Slc5W\n"+ + "tj9GIdwtw3a2yb+HLd/VF0tUYz/ez6kUtAWnGBQqXot1oKOl0UuoyHhYoSk54P+4\n"+ + "eOb/Cb/d4SZ97xy8536PVMDlsbb3QDufOd/yUns6pz+clIDLmb0pHmqe+ureBjND\n"+ + "s64+Aie0W8rQseg7Kqz7QPjxEegdidzRPziRjJ/F5nkooFDV8l9z4DNrxfKTEGmB\n"+ + "Mjyhqob3jgpXlfpbZPvtiwmyV0kkaTtoWCcwtT1ug6QepwqA7nSHyfJrsHNR8WUy\n"+ + "2G10mNh5lPrcTeMDow5HplhY6EpvUnPZIuFH8ZZeKucN9SDmF+xefjN8K+AmpHfZ\n"+ + "1ujZD3LhmAq5HGHDWVKs+LS1L6MUM3yTd0VE20C96hkYH15ONRErl4GZ0UgX9QTV\n"+ + "tX5KaialhgXaxaQX/8YF5uzbLsWR27LI7hP/sEBpgnSpQd7r/vseW/Z3trxBki6d\n"+ + "VCnxTPiJsPUOEno6fdNwShJQucpc2QIDAQABAoICADsuK2yC8FvdHoKiGCULSQ+A\n"+ + "k1ISKzcC7h/z6UEylwIWUaZuo8ELSaJQN/glq4p3gCynpQqvQ/uI0ZzY39alktVk\n"+ + "12R5qP0ef7A6XCidRYq2kMLT8iOSPdrSQmlZQrOEv2rAh4sAVYmvBwevGr84yHDe\n"+ + "rDUji9IwrtvrEO97+XJItMd/o9oqPgcg3Ta9fzoxJuOOBHPqBh6+r93TJWUcDupH\n"+ + "kwViS/Z99ELFoK0xEwRrIIKq9niTT4hcmBvAODRfWf4AOPnnpGCaNCnrI7cVMeL1\n"+ + "99UL0tvM7I6yXO88sjMVe/yJFao3iPmZVHwzhb0jK7palLxbjukwWQ+fS+SHJxGW\n"+ + "6TVV4a+bFRwC8XBgFr+1fykItx2th6edjuZnJbJThcELCgJjzngbNpAhVXj7eyV8\n"+ + "53+m/awuK3NVpjQMN4yFKMx91t78WHsF51KazvxEzamdEtwP5W71BgTgo5QOFRAS\n"+ + "ua4ychDKXWYHOV0Hpho83D+Dr6cTaOikSNeMeaNJfnDuyrBiSre46K86qXEnvMGq\n"+ + "RjLY6wyQamoI/kSc8ds/1DwEZmIqkbdIlpSLzVGNE5mKxVTs3DzUr4P37BJGh5It\n"+ + "x2TN9P23EuA/A4Mu2YVFnOiysQjo39cAeUUS0E39S9POx559fniYAjOvWlKRaqi9\n"+ + "s1TNuTty/ecoIQqRDV65AoIBAQDY9DOiz204+HpWFCHUnS7JmFQl+FPMrsfif9x5\n"+ + "dlNOtjWRHEDzZozLHrdSmWTRAw3z61ZsCp6DACEKlGBx3LYRrHt7R2BISPI49eE8\n"+ + "UHiFZTEljrSlEqJXMJJvkPa1YcMJdy+44lkmKq5CXJCaXU37N6Z7vDBLMDtToKr9\n"+ + "nfW9Ks+wsmog6Oz/YETyNFdJuslw1fGHuurpsa/mlVFSakOt9ROuEMVh750m7KvB\n"+ + "mVgEPlxSc9XBsgJ9O2Uu8I3cYKZiwHaQaBSHiJvj2CfuYdT5E6Q9a6C+nF47Va2l\n"+ + "1CoxmtyFpoz6eH43uRHsJIcYxBBVpZirZLpygJGaGtsYES9jAoIBAQDBBW1d+D7w\n"+ + "SzK5YlKfwBrzrJE50D/FzPXtGZTQ4r5QDBiIMiqQt+eszs0oMtuULLnbSC3FtARc\n"+ + "iPdEpaw4b68NaTQuh3EH1bhy/k5S5BvC2X/bjsiHEzfV7L2IffHPaYRtTn/Fx/1B\n"+ + "BxiNbfLVjDHfH2MW7QD8c8h6RiaeRWtdZL22ue/kR0vq7G9OCOCwIDTtW0qq2g0R\n"+ + "KjyhDUFSYyimtCLb5sCilbaD7Ob++NaNBMAgzyVRwpfNCYu9jccQT/nwyc0ZKgHq\n"+ + "CQilClq7k8ikUfvRAkAhP4CjpkabAyAm4t50LCSjowk6Ksncm8bNjd9ivO+i69qQ\n"+ + "odEgNiPf9W2TAoIBAAeKhXj1SNCgInB3hq2DQSsUtmgTd6Y3tQ70bs9yA3dK8hW3\n"+ + "K7LKL76ntKuUVWLGfmeqGHjs7ZGUIZHikm+iwlle63PfiUM59eFw+oFEMsxANjMe\n"+ + "AL10JlxtfcmO+mRXn5XmpKwCgiLHfQMlgIk9EQbYalsGsY8LgCRqA0eJhA8tO8bi\n"+ + "jLnUHtjJmdvpYddYPMRFS33yS1QQLxMOwaLhurSDPkngn1vGHmpJ87ZpBBwxprfe\n"+ + "+uEetONxexTkm6m7Wk04b2aZl40WfISw8MJieCqoOh9AbHfzq3rYgY6wDz9mKKAk\n"+ + "p+XU5l49epgAtQlxVzgC54mdmLV+LpFyuYbeog0CggEAMXQJhFTxEzHBCjxFvQZE\n"+ + "IYBqKOzRGgWcUKYIOciOSAYBVwu7Wh60LdNCPvVgysL2z1bb21Z285pn99+Wk1MR\n"+ + "/5aftvgenopEWroLKTOmZTLCjmczu1/SI24nVUwnYyO+uR6un+bQXRPLV5j+6XWk\n"+ + "5WyuP5ZzdTrY93L3u/8/Nct0y9cxvkQCEGuJTO37W0S1KscEB2gchvRSWlUCEnCz\n"+ + "Xpqyf7LMUhuXio9s05C/r5uy+fT4s8zuharXcbZcdTJ4cBfUA4l+ug6cd2SCwKJp\n"+ + "eqhCo1c3RQ13EPauClMvrqbbpdoVfRNtbsi9tVb4BXw+6pZLs2tIMVw0L1OPt3az\n"+ + "HwKCAQEApp92MrvBGPUseLgyz0BCrFrZ4pdGE0H25+lxeF0Knl7ytVLiWZdptcxV\n"+ + "XMMRmUdh94CkAZlw/ap/Jd4i7CmKN21YzaqAILCdgQfkFiSUqsKPIAeC9Mr8yoGW\n"+ + "mMCeIrn564IAKVcKtzCP1jKj6f3DqYFq8zUAKH04g+pmw5sbZeXI4kIX5N+Z83A9\n"+ + "DYdpqhb9/ZxxHl+2O4/QfqXXMTLG9r+EzuIJBo6Hv49OcG8eDL7z+ol3wwbnnyyl\n"+ + "I0yravltR78WsZSw/sLCB+VZ9sZ+MS/iigvuFCv0Mh71qXd9FL20abwBYPa/9Pdu\n"+ + "UzLAsK9qu+BccvxEnDDUQIxMjGUa1w==\n"+ + "-----END PRIVATE KEY-----\n"; + + private static final String PRIVATE_KEY_1024 = + + "-----BEGIN PRIVATE KEY-----\n" + + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJsc0nqu+4mRGu2P\n" + + "E39fD8awAwYRS4HyIujJaVKqXNgVTBd8R8ocSaMYPBYURQMuhKEyzc197pAxEDN8\n" + + "g+d0pnRXS5YFUspPCehH6vsXaJSF1tW9T9J4aGSvQU+DD4G6UP9GciD2V9RRlrns\n" + + "1K8VzJn4YvWnym5nIH/2ld1HnK8DAgMBAAECgYBCzrgtFR7L0o65kO1B5+zAk+DJ\n" + + "hTtzXZoBj3Zon23bt9iNKP82otZog7ClhddvlmKTl3Eit8G/oxIqSs/5KbnjKFn2\n" + + "JzHgltA64t4E+g2wfjfX/THGgq4Gf2qLABJ8XPzl4lhNhBjcp/yls+R/aaXO6Tpg\n" + + "ot7PdSstlCJH4iHJSQJBAMzHlSXPysV4K8goh8FC392Nif4u42sMulS3yh/8hWoZ\n" + + "zGftc/1Av9HxLYYPI7VojGVl8ZEi7mWWFpYhnjGi4MUCQQDB6Pe603RFg8EPX49Z\n" + + "3BNuxk4/17znWktbhCzo/MxOGZ/xoCqEIO59jIUYgrWzp4PD7tLd8uPw8CKyV6RA\n" + + "H70nAkEAtxg4Rd+dmKQS2VtLzkOh7/FOkYOQ+TUfIQJXafQZwb0hY0cPbz/GgssW\n" + + "fgfpUJkS9tKIg9FswE3LEh8q14yfVQJBAJhDG8tq4QD4zS8KJWE1K1kvhCAjgmTU\n" + + "BRpOdolYgADPpEUyNFBeH4ccQSKW+KCiaBgBPzki0ZPOrCAIK6Rih78CQQDIICap\n" + + "QByVjsFDed4Te13qthgFthy6iGyk1JZFu9lCnAaiAdg4AA0OyF9FxFUzCsOGD1HS\n" + + "GoRuVX4I/AZR74Sx \n" + + "-----END PRIVATE KEY-----"; + private static final Logger LOGGER = LoggerFactory.getLogger(CloudFrontS3SignedUrlProviderTest.class); + @Mock + private Blob blob; + + interface MockJCRValue extends Value, OakValue { + } + + @Mock + private MockJCRValue value; + + + public CloudFrontS3SignedUrlProviderTest() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testSignedURL() throws InvalidKeySpecException, NoSuchAlgorithmException, RepositoryException { + long t2 = System.currentTimeMillis(); + CloudFrontS3SignedUrlProvider provider = new CloudFrontS3SignedUrlProvider( + "http://applicationA1.cloudfront.net/", + 60, + 1, + PRIVATE_KEY_1024, + "123"); + LOGGER.info("Loaded 1024 private key in {} ms "+(System.currentTimeMillis()-t2)); + + long t = System.currentTimeMillis(); + CloudFrontS3SignedUrlProvider provider4096 = new CloudFrontS3SignedUrlProvider( + "http://applicationA1.cloudfront.net/", + 60, + 1, + PRIVATE_KEY_4096, + "PRIVATE_KEY_4096"); + LOGGER.info("Loaded 4096 private key in {} ms "+(System.currentTimeMillis()-t)); + + + + t = System.currentTimeMillis(); + Mockito.when(blob.length()).thenReturn((long)1024*1024); // 1MB + Mockito.when(value.getBlob()).thenReturn(blob); + Mockito.when(blob.getContentIdentity()).thenReturn("1234567891ABCDEFGH"); + URI u = provider4096.toURI(value); + Assert.assertNotNull(u); + LOGGER.info("Signed with 4096 key in {} ms ",(System.currentTimeMillis()-t)); + + t = System.currentTimeMillis(); + Mockito.when(blob.length()).thenReturn((long)1024*1024); // 1MB + Mockito.when(value.getBlob()).thenReturn(blob); + Mockito.when(blob.getContentIdentity()).thenReturn("1234567891ABCDEFGH"); + u = provider.toURI(value); + Assert.assertNotNull(u); + LOGGER.info("Signed with 1024 key in {} ms ",(System.currentTimeMillis()-t)); + } +} Propchange: jackrabbit/oak/trunk/oak-blob-cloud/src/test/java/org/apache/jackrabbit/oak/blob/cloud/aws/s3/CloudFrontS3SignedUrlProviderTest.java ------------------------------------------------------------------------------ svn:eol-style = native