Skip to content

Commit 14c0d95

Browse files
authored
Validate auth token
1 parent 5bbd803 commit 14c0d95

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

cloudinary-core/src/main/java/com/cloudinary/AuthToken.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class AuthToken {
2929
private long startTime;
3030
private long expiration;
3131
private String ip;
32-
private String acl;
32+
private List<String> acl = new ArrayList<>();
3333
private long duration;
3434
private boolean isNullToken = false;
3535
private static final Pattern UNSAFE_URL_CHARS_PATTERN = Pattern.compile("[ \"#%&'/:;<=>?@\\[\\\\\\]^`{|}~]");
@@ -53,7 +53,16 @@ public AuthToken(Map options) {
5353
this.startTime = ObjectUtils.asLong(options.get("startTime"), 0L);
5454
this.expiration = ObjectUtils.asLong(options.get("expiration"), 0L);
5555
this.ip = (String) options.get("ip");
56-
this.acl = (String) options.get("acl");
56+
57+
Object acl = options.get("acl");
58+
if (acl != null) {
59+
if (acl instanceof String) {
60+
this.acl = Collections.singletonList(acl.toString());
61+
} else if (Collection.class.isAssignableFrom(acl.getClass())) {
62+
this.acl = new ArrayList<String>((Collection<String>)acl);
63+
}
64+
}
65+
5766
this.duration = ObjectUtils.asLong(options.get("duration"), 0L);
5867
}
5968
}
@@ -122,8 +131,8 @@ public AuthToken ip(String ip) {
122131
* @param acl
123132
* @return this
124133
*/
125-
public AuthToken acl(String acl) {
126-
this.acl = acl;
134+
public AuthToken acl(String... acl) {
135+
this.acl = Arrays.asList(acl);
127136
return this;
128137
}
129138

@@ -155,6 +164,11 @@ public String generate() {
155164
* @return a URL token
156165
*/
157166
public String generate(String url) {
167+
168+
if (url == null && (acl == null || acl.size() == 0)) {
169+
throw new IllegalArgumentException("Must provide acl or url");
170+
}
171+
158172
long expiration = this.expiration;
159173
if (expiration == 0) {
160174
if (duration > 0) {
@@ -172,11 +186,11 @@ public String generate(String url) {
172186
tokenParts.add("st=" + startTime);
173187
}
174188
tokenParts.add("exp=" + expiration);
175-
if (acl != null) {
176-
tokenParts.add("acl=" + escapeToLower(acl));
189+
if (acl != null && acl.size() > 0) {
190+
tokenParts.add("acl=" + escapeToLower(String.join("!", acl)));
177191
}
178192
ArrayList<String> toSign = new ArrayList<String>(tokenParts);
179-
if (url != null && acl == null) {
193+
if (url != null && (acl == null || acl.size() == 0)) {
180194
toSign.add("url=" + escapeToLower(url));
181195
}
182196
String auth = digest(StringUtils.join(toSign, "~"));

cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package com.cloudinary;
22

33
import com.cloudinary.utils.Analytics;
4+
import com.cloudinary.utils.ObjectUtils;
5+
6+
import org.hamcrest.CoreMatchers;
47
import org.hamcrest.Matchers;
8+
import org.junit.Assert;
59
import org.junit.Before;
610
import org.junit.Rule;
711
import org.junit.Test;
812
import org.junit.rules.TestName;
913

1014
import java.io.UnsupportedEncodingException;
1115
import java.util.Calendar;
16+
import java.util.Collections;
17+
import java.util.Map;
1218
import java.util.TimeZone;
1319
import java.util.regex.Matcher;
1420
import java.util.regex.Pattern;
@@ -127,4 +133,32 @@ public void testIgnoreUrlIfAclIsProvided() {
127133
String cookieAclToken = aclToken.generate("http://res.cloudinary.com/test123/image/upload/v1486020273/sample.jpg");
128134
assertEquals(cookieToken, cookieAclToken);
129135
}
136+
137+
@Test
138+
public void testMultiplePatternsInAcl() {
139+
AuthToken token = new AuthToken(KEY).duration(3600).acl("/image/authenticated/*", "/image2/authenticated/*", "/image3/authenticated/*").startTime(22222222);
140+
String cookieToken = token.generate();
141+
Assert.assertThat(cookieToken, CoreMatchers.containsString("~acl=%2fimage%2fauthenticated%2f*!%2fimage2%2fauthenticated%2f*!%2fimage3%2fauthenticated%2f*~"));
142+
}
143+
144+
@Test
145+
public void testPublicAclInitializationFromMap() {
146+
Map options = ObjectUtils.asMap(
147+
"acl", Collections.singleton("foo"),
148+
"expiration", 100,
149+
"key", KEY,
150+
"tokenName", "token");
151+
String token = new AuthToken(options).generate();
152+
assertEquals("token=exp=100~acl=foo~hmac=88be250f3a912add862959076ee74f392fa0959a953fddd9128787d5c849efd9", token);
153+
}
154+
155+
@Test(expected = IllegalArgumentException.class)
156+
public void testMissingAclAndUrlShouldThrow() {
157+
String token = new AuthToken(KEY).duration(300).generate();
158+
}
159+
160+
@Test
161+
public void testMissingUrlNotMissingAclShouldNotThrow() {
162+
String token = new AuthToken(KEY).duration(300).generate("http://res.cloudinary.com/test123");
163+
}
130164
}

cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.lang.reflect.Field;
1919
import java.lang.reflect.Modifier;
2020
import java.lang.reflect.Type;
21+
import java.lang.reflect.ParameterizedType;
2122
import java.net.URI;
2223
import java.net.URISyntaxException;
2324
import java.net.URLDecoder;
@@ -1468,6 +1469,8 @@ private void setRandomValue(Random rand, Field field, Object instance) throws Il
14681469
field.set(instance, rand.nextInt());
14691470
} else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) {
14701471
field.set(instance, rand.nextLong());
1472+
} else if (field.get(instance) instanceof List) {
1473+
field.set(instance, Collections.singletonList(cloudinary.randomPublicId()));
14711474
} else if (fieldType.equals(String.class)) {
14721475
field.set(instance, cloudinary.randomPublicId());
14731476
} else if (fieldType.equals(AuthToken.class)) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy