Skip to content

Commit 6af3638

Browse files
author
Madhav Chhura
committed
Replaces the Partner Auth with the new Token Auth.
1 parent a71d432 commit 6af3638

File tree

8 files changed

+372
-425
lines changed

8 files changed

+372
-425
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ repositories {
3838
dependencies {
3939
testCompile group: 'junit', name: 'junit', version: '[4.3,5.0['
4040
testCompile group: 'com.github.tomakehurst', name: 'wiremock', version: '[1.45,1.99999)'
41-
testCompile group: 'commons-lang', name: 'commons-lang', version: '[2.6,2.99999)'
41+
compile group: 'commons-lang', name: 'commons-lang', version: '[2.6,2.99999)'
4242
compile group: 'com.ning', name: 'async-http-client', version: '[1.9,2.0['
4343
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '[2.3.1,2.99999)'
4444
compile group: 'commons-validator', name: 'commons-validator', version: '[1.4.0,1.99999)'
4545
compile group: 'commons-codec', name: 'commons-codec', version: '[1.9,1.99999]'
46+
compile group: 'org.bitbucket.b_c', name: 'jose4j', version: '0.5.1'
4647
// TODO: find out how to initialize these dependencies properly, or remove them
4748
//compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.5'
4849
//compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.5'

src/main/java/com/opentok/OpenTok.java

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,25 @@
77
*/
88
package com.opentok;
99

10-
import java.io.IOException;
11-
import java.io.StringReader;
12-
import java.io.UnsupportedEncodingException;
13-
import java.net.Proxy;
14-
import java.util.Collection;
15-
import java.util.List;
16-
import java.util.Map;
17-
18-
import javax.xml.xpath.XPath;
19-
import javax.xml.xpath.XPathExpressionException;
20-
import javax.xml.xpath.XPathFactory;
21-
22-
import com.fasterxml.jackson.core.JsonParseException;
2310
import com.fasterxml.jackson.core.JsonProcessingException;
24-
import com.fasterxml.jackson.databind.JsonMappingException;
25-
import com.opentok.exception.OpenTokException;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.ObjectReader;
2613
import com.opentok.exception.InvalidArgumentException;
14+
import com.opentok.exception.OpenTokException;
2715
import com.opentok.exception.RequestException;
28-
import com.opentok.util.Crypto;
2916
import com.opentok.util.HttpClient;
30-
31-
import com.fasterxml.jackson.databind.ObjectMapper;
32-
import com.fasterxml.jackson.databind.ObjectReader;
17+
import com.opentok.util.TokenGenerator;
3318
import org.xml.sax.InputSource;
3419

20+
import javax.xml.xpath.XPath;
21+
import javax.xml.xpath.XPathExpressionException;
22+
import javax.xml.xpath.XPathFactory;
23+
import java.io.IOException;
24+
import java.io.StringReader;
25+
import java.net.Proxy;
26+
import java.util.Collection;
27+
import java.util.Map;
28+
3529
/**
3630
* Contains methods for creating OpenTok sessions, generating tokens, and working with archives.
3731
* <p>
@@ -48,9 +42,9 @@ public class OpenTok {
4842
private String apiSecret;
4943
protected HttpClient client;
5044
static protected ObjectReader archiveReader = new ObjectMapper()
51-
.reader(Archive.class);
45+
.readerFor(Archive.class);
5246
static protected ObjectReader archiveListReader = new ObjectMapper()
53-
.reader(ArchiveList.class);
47+
.readerFor(ArchiveList.class);
5448
static final String defaultApiUrl = "https://api.opentok.com";
5549

5650
/**
@@ -133,24 +127,9 @@ public OpenTok(int apiKey, String apiSecret, String apiUrl, Proxy proxy) {
133127
*
134128
* @return The token string.
135129
*/
136-
public String generateToken(String sessionId, TokenOptions tokenOptions) throws OpenTokException {
137-
List<String> sessionIdParts = null;
138-
if(sessionId == null || sessionId == "") {
139-
throw new InvalidArgumentException("Session not valid");
140-
}
141-
142-
try {
143-
sessionIdParts = Crypto.decodeSessionId(sessionId);
144-
} catch (UnsupportedEncodingException e) {
145-
throw new InvalidArgumentException("Session ID was not valid");
146-
}
147-
if (!sessionIdParts.contains(Integer.toString(this.apiKey))) {
148-
throw new InvalidArgumentException("Session ID was not valid");
149-
}
150-
151-
// NOTE: kind of wasteful of a Session instance
152-
Session session = new Session(sessionId, apiKey, apiSecret);
153-
return session.generateToken(tokenOptions);
130+
public String generateToken(String sessionId, TokenOptions tokenOptions)
131+
throws OpenTokException {
132+
return TokenGenerator.generateToken(sessionId, tokenOptions, apiKey, apiSecret);
154133
}
155134

156135
/**
@@ -255,11 +234,8 @@ public Session createSession(SessionProperties properties) throws OpenTokExcepti
255234
String xpathQuery = "/sessions/Session/session_id";
256235

257236
// NOTE: doing this null check twice is kind of ugly
258-
if(properties != null) {
259-
params = properties.toMap();
260-
} else {
261-
params = new SessionProperties.Builder().build().toMap();
262-
}
237+
params = properties != null ? properties.toMap() :
238+
new SessionProperties.Builder().build().toMap();
263239

264240
String xmlResponse = this.client.createSession(params);
265241

@@ -368,12 +344,6 @@ public ArchiveList listArchives(int offset, int count) throws OpenTokException {
368344
String archives = this.client.getArchives(offset, count);
369345
try {
370346
return archiveListReader.readValue(archives);
371-
372-
// if we only wanted Java 7 and above, we could DRY this into one catch clause
373-
} catch (JsonMappingException e) {
374-
throw new RequestException("Exception mapping json: " + e.getMessage());
375-
} catch (JsonParseException e) {
376-
throw new RequestException("Exception mapping json: " + e.getMessage());
377347
} catch (JsonProcessingException e) {
378348
throw new RequestException("Exception mapping json: " + e.getMessage());
379349
} catch (IOException e) {

src/main/java/com/opentok/Session.java

Lines changed: 2 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,8 @@
77
*/
88
package com.opentok;
99

10-
import java.io.UnsupportedEncodingException;
11-
import java.net.URLEncoder;
12-
import java.security.InvalidKeyException;
13-
import java.security.NoSuchAlgorithmException;
14-
import java.security.SignatureException;
15-
import java.util.Random;
16-
17-
import com.opentok.exception.InvalidArgumentException;
18-
import com.opentok.util.Crypto;
19-
import org.apache.commons.codec.binary.Base64;
20-
2110
import com.opentok.exception.OpenTokException;
11+
import com.opentok.util.TokenGenerator;
2212

2313
/**
2414
* Represents an OpenTok session. Use the {@link OpenTok#createSession(SessionProperties properties)}
@@ -103,95 +93,6 @@ public String generateToken() throws OpenTokException {
10393
* @return The token string.
10494
*/
10595
public String generateToken(TokenOptions tokenOptions) throws OpenTokException {
106-
107-
// Token format
108-
//
109-
// | ------------------------------ tokenStringBuilder ----------------------------- |
110-
// | "T1=="+Base64Encode(| --------------------- innerBuilder --------------------- |)|
111-
// | "partner_id={apiKey}&sig={sig}:| -- dataStringBuilder -- |
112-
113-
if (tokenOptions == null) {
114-
throw new InvalidArgumentException("Token options cannot be null");
115-
}
116-
117-
Role role = tokenOptions.getRole();
118-
double expireTime = tokenOptions.getExpireTime(); // will be 0 if nothing was explicitly set
119-
String data = tokenOptions.getData(); // will be null if nothing was explicitly set
120-
Long create_time = new Long(System.currentTimeMillis() / 1000).longValue();
121-
122-
StringBuilder dataStringBuilder = new StringBuilder();
123-
Random random = new Random();
124-
int nonce = random.nextInt();
125-
dataStringBuilder.append("session_id=");
126-
dataStringBuilder.append(sessionId);
127-
dataStringBuilder.append("&create_time=");
128-
dataStringBuilder.append(create_time);
129-
dataStringBuilder.append("&nonce=");
130-
dataStringBuilder.append(nonce);
131-
dataStringBuilder.append("&role=");
132-
dataStringBuilder.append(role);
133-
134-
double now = System.currentTimeMillis() / 1000L;
135-
if (expireTime == 0) {
136-
expireTime = now + (60*60*24); // 1 day
137-
} else if(expireTime < now-1) {
138-
throw new InvalidArgumentException(
139-
"Expire time must be in the future. relative time: "+ (expireTime - now));
140-
} else if(expireTime > (now + (60*60*24*30) /* 30 days */)) {
141-
throw new InvalidArgumentException(
142-
"Expire time must be in the next 30 days. too large by "+ (expireTime - (now + (60*60*24*30))));
143-
}
144-
// NOTE: Double.toString() would print the value with scientific notation
145-
dataStringBuilder.append(String.format("&expire_time=%.0f", expireTime));
146-
147-
if (data != null) {
148-
if(data.length() > 1000) {
149-
throw new InvalidArgumentException(
150-
"Connection data must be less than 1000 characters. length: " + data.length());
151-
}
152-
dataStringBuilder.append("&connection_data=");
153-
try {
154-
dataStringBuilder.append(URLEncoder.encode(data, "UTF-8"));
155-
} catch (UnsupportedEncodingException e) {
156-
throw new InvalidArgumentException(
157-
"Error during URL encode of your connection data: " + e.getMessage());
158-
}
159-
}
160-
161-
162-
StringBuilder tokenStringBuilder = new StringBuilder();
163-
try {
164-
tokenStringBuilder.append("T1==");
165-
166-
StringBuilder innerBuilder = new StringBuilder();
167-
innerBuilder.append("partner_id=");
168-
innerBuilder.append(this.apiKey);
169-
170-
innerBuilder.append("&sig=");
171-
172-
innerBuilder.append(Crypto.signData(dataStringBuilder.toString(), this.apiSecret));
173-
innerBuilder.append(":");
174-
innerBuilder.append(dataStringBuilder.toString());
175-
176-
tokenStringBuilder.append(
177-
Base64.encodeBase64String(
178-
innerBuilder.toString().getBytes("UTF-8")
179-
)
180-
.replace("+", "-")
181-
.replace("/", "_")
182-
);
183-
184-
// if we only wanted Java 7 and above, we could DRY this into one catch clause
185-
} catch (SignatureException e) {
186-
throw new OpenTokException("Could not generate token, a signing error occurred.", e);
187-
} catch (NoSuchAlgorithmException e) {
188-
throw new OpenTokException("Could not generate token, a signing error occurred.", e);
189-
} catch (InvalidKeyException e) {
190-
throw new OpenTokException("Could not generate token, a signing error occurred.", e);
191-
} catch (UnsupportedEncodingException e) {
192-
throw new OpenTokException("Could not generate token, a signing error occurred.", e);
193-
}
194-
195-
return tokenStringBuilder.toString();
96+
return TokenGenerator.generateToken(sessionId, tokenOptions, apiKey, apiSecret);
19697
}
19798
}

src/main/java/com/opentok/TokenOptions.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import com.opentok.exception.InvalidArgumentException;
1111

12+
import java.util.List;
13+
1214
/**
1315
* Defines values for the <code>tokenOptions</code> parameter of the
1416
* {@link OpenTok#generateToken(String sessionId, TokenOptions tokenOptions)} method
@@ -19,8 +21,9 @@
1921
public class TokenOptions {
2022

2123
private Role role;
22-
private double expireTime;
24+
private long expireTime;
2325
private String data;
26+
private List<String> initialLayoutClassList;
2427

2528
private TokenOptions(Builder builder) {
2629
this.role = builder.role != null ? builder.role : Role.PUBLISHER;
@@ -30,6 +33,9 @@ private TokenOptions(Builder builder) {
3033

3134
// default value of null means to omit the key "connection_data" from the token
3235
this.data = builder.data;
36+
37+
// default value of null means to omit the key "initialLayoutClassList" from the token
38+
this.initialLayoutClassList = builder.initialLayoutClassList;
3339
}
3440

3541
/**
@@ -41,9 +47,9 @@ public Role getRole() {
4147

4248
/**
4349
* Returns the expiration time the token, as the number of seconds since the UNIX epoch.
44-
* See {@link TokenOptions.Builder#expireTime(double expireTime)}.
50+
* See {@link TokenOptions.Builder#expireTime(long expireTime)}.
4551
*/
46-
public double getExpireTime() {
52+
public long getExpireTime() {
4753
return expireTime;
4854
}
4955

@@ -55,15 +61,20 @@ public String getData() {
5561
return data;
5662
}
5763

64+
public List<String> getInitialLayoutClassList() {
65+
return initialLayoutClassList;
66+
}
67+
5868
/**
5969
* Use this class to create a TokenOptions object.
6070
*
6171
* @see TokenOptions
6272
*/
6373
public static class Builder {
6474
private Role role;
65-
private double expireTime = 0;
75+
private long expireTime = 0;
6676
private String data;
77+
private List<String> initialLayoutClassList;
6778

6879
/**
6980
* Sets the role for the token. Each role defines a set of permissions granted to the token.
@@ -93,7 +104,7 @@ public Builder role(Role role) {
93104
* the default expiration time of 24 hours after the token creation time. The maximum
94105
* expiration time is 30 days after the creation time.
95106
*/
96-
public Builder expireTime(double expireTime) {
107+
public Builder expireTime(long expireTime) {
97108
// NOTE: since this object can be stored/cached, validation should occur at token generation time
98109
this.expireTime = expireTime;
99110
return this;
@@ -116,6 +127,11 @@ public Builder data(String data) throws InvalidArgumentException {
116127
return this;
117128
}
118129

130+
public Builder initialLayoutClassList (List<String> initialLayoutClassList) {
131+
this.initialLayoutClassList = initialLayoutClassList;
132+
return this;
133+
}
134+
119135
/**
120136
* Builds the TokenOptions object.
121137
*

0 commit comments

Comments
 (0)