Skip to content

Commit edb1883

Browse files
daniel-sanchelesv
authored andcommitted
added CloudCDN url signing samples (#1020)
1 parent 1dcc8c0 commit edb1883

File tree

5 files changed

+200
-0
lines changed

5 files changed

+200
-0
lines changed

cdn/signed-urls/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Google Cloud CDN - Signing URLs
2+
Java implementation of [`gcloud alpha compute sign-url`](https://cloud.google.com/sdk/gcloud/reference/alpha/compute/sign-url)
3+
- uses a private key to create a time-sensitive URL that can be used to access a private Cloud CDN endpoint
4+
- requires [random 128-bit key](https://cloud.google.com/cdn/docs/signed-urls#creatingkeys) encoded as base64 and [uploaded to a backend bucket](https://cloud.google.com/sdk/gcloud/reference/alpha/compute/backend-buckets/add-signed-url-key)
5+
6+
## Getting Started
7+
8+
1. [Download](https://maven.apache.org/download.cgi) and [install](https://maven.apache.org/install.html) maven to handle the project's dependencies
9+
2. run `mvn clean verify` to build the project and run the tests

cdn/signed-urls/pom.xml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>com.google.cdn</groupId>
6+
<artifactId>signedurls</artifactId>
7+
<version>1.0</version>
8+
<packaging>jar</packaging>
9+
10+
<!--
11+
The parent pom defines common style checks and testing strategies for our samples.
12+
Removing or replacing it should not affect the execution of the samples in anyway.
13+
-->
14+
<parent>
15+
<groupId>com.google.cloud.samples</groupId>
16+
<artifactId>shared-configuration</artifactId>
17+
<version>1.0.8</version>
18+
</parent>
19+
20+
<name>signedurls</name>
21+
<url>http://maven.apache.org</url>
22+
23+
<properties>
24+
<maven.compiler.target>1.8</maven.compiler.target>
25+
<maven.compiler.source>1.8</maven.compiler.source>
26+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
27+
</properties>
28+
29+
<dependencies>
30+
<dependency>
31+
<groupId>junit</groupId>
32+
<artifactId>junit</artifactId>
33+
<version>4.12</version>
34+
<scope>test</scope>
35+
</dependency>
36+
</dependencies>
37+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2018 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cdn;
18+
19+
import java.nio.file.Files;
20+
import java.nio.file.Paths;
21+
import java.security.InvalidKeyException;
22+
import java.security.Key;
23+
import java.security.NoSuchAlgorithmException;
24+
import java.util.Base64;
25+
import java.util.Calendar;
26+
import java.util.Date;
27+
import javax.crypto.Mac;
28+
import javax.crypto.spec.SecretKeySpec;
29+
30+
/**
31+
* Samples to create a signed URL for a Cloud CDN endpoint
32+
*/
33+
public class SignedUrls {
34+
35+
// [START signUrl]
36+
/**
37+
* Creates a signed URL for a Cloud CDN endpoint with the given key
38+
* URL must start with http:// or https://, and must contain a forward
39+
* slash (/) after the hostname.
40+
* @param url the Cloud CDN endpoint to sign
41+
* @param key url signing key uploaded to the backend service/bucket, as a 16-byte array
42+
* @param keyName the name of the signing key added to the back end bucket or service
43+
* @param expirationTime the date that the signed URL expires
44+
* @return a properly formatted signed URL
45+
* @throws InvalidKeyException when there is an error generating the signature for the input key
46+
* @throws NoSuchAlgorithmException when HmacSHA1 algorithm is not available in the environment
47+
*/
48+
public static String signUrl(String url,
49+
byte[] key,
50+
String keyName,
51+
Date expirationTime)
52+
throws InvalidKeyException, NoSuchAlgorithmException {
53+
54+
final long unixTime = expirationTime.getTime() / 1000;
55+
56+
String urlToSign = url
57+
+ (url.contains("?") ? "&" : "?")
58+
+ "Expires=" + unixTime
59+
+ "&KeyName=" + keyName;
60+
61+
String encoded = SignedUrls.getSignature(key, urlToSign);
62+
return urlToSign + "&Signature=" + encoded;
63+
}
64+
65+
public static String getSignature(byte[] privateKey, String input)
66+
throws InvalidKeyException, NoSuchAlgorithmException {
67+
68+
final String algorithm = "HmacSHA1";
69+
final int offset = 0;
70+
Key key = new SecretKeySpec(privateKey, offset, privateKey.length, algorithm);
71+
Mac mac = Mac.getInstance(algorithm);
72+
mac.init(key);
73+
return Base64.getUrlEncoder().encodeToString(mac.doFinal(input.getBytes()));
74+
}
75+
// [END signUrl]
76+
77+
public static void main(String[] args) throws Exception {
78+
Calendar cal = Calendar.getInstance();
79+
cal.setTime(new Date());
80+
cal.add(Calendar.DATE, 1);
81+
Date tomorrow = cal.getTime();
82+
83+
//read the key as a base 64 url-safe encoded string, then convert to byte array
84+
final String keyPath = "/path/to/key";
85+
String base64String = new String(Files.readAllBytes(Paths.get(keyPath)));
86+
byte[] keyBytes = Base64.getUrlDecoder().decode(base64String);
87+
88+
String result = signUrl("http://example.com/", keyBytes, "YOUR-KEY-NAME", tomorrow);
89+
System.out.println(result);
90+
}
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2018 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
package com.google.cdn;
19+
20+
import static com.google.cdn.SignedUrls.signUrl;
21+
import static junit.framework.TestCase.assertEquals;
22+
23+
import java.util.Base64;
24+
import java.util.Date;
25+
import org.junit.Test;
26+
import org.junit.runner.RunWith;
27+
import org.junit.runners.JUnit4;
28+
29+
/**
30+
* Test SignedUrls samples
31+
*/
32+
@RunWith(JUnit4.class)
33+
@SuppressWarnings("checkstyle:abbreviationaswordinname")
34+
public class SignedUrlsTest {
35+
private static long TIMESTAMP = 1518135754;
36+
private static Date EXPIRATION = new Date(TIMESTAMP * 1000);
37+
private static byte[] KEY_BYTES = Base64.getUrlDecoder().decode("aaaaaaaaaaaaaaaaaaaaaa==");
38+
private static String KEY_NAME = "my-key";
39+
private static String BASE_URL = "https://www.example.com/";
40+
41+
@Test
42+
public void testUrlPath() throws Exception {
43+
String result = signUrl(BASE_URL + "foo", KEY_BYTES, KEY_NAME, EXPIRATION);
44+
final String expected = "https://www.example.com/foo?Expires=1518135754&KeyName=my-key&Signature=vUfG4yv47dyns1j9e_OI6_5meuA=";
45+
assertEquals(result, expected);
46+
}
47+
48+
@Test
49+
public void testUrlParams() throws Exception {
50+
String result = signUrl(BASE_URL + "?param=true", KEY_BYTES, KEY_NAME, EXPIRATION);
51+
final String expected = "https://www.example.com/?param=true&Expires=1518135754&KeyName=my-key&Signature=6TijW8OMX3gcMI5Kqs8ESiPY97c=";
52+
assertEquals(result, expected);
53+
}
54+
55+
56+
@Test
57+
public void testStandard() throws Exception {
58+
String result = signUrl(BASE_URL, KEY_BYTES, KEY_NAME, EXPIRATION);
59+
final String expected = "https://www.example.com/?Expires=1518135754&KeyName=my-key&Signature=4D0AbT4y0O7ZCzCUcAtPOJDkl2g=";
60+
assertEquals(result, expected);
61+
}
62+
}

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<module>bigquery/datatransfer/cloud-client</module>
4646
<module>bigquery/rest</module>
4747

48+
<module>cdn/signed-urls</module>
4849
<module>cloud-tasks</module>
4950
<module>compute</module>
5051
<module>container-registry/container-analysis</module>

0 commit comments

Comments
 (0)