mirror of https://github.com/OpenVidu/openvidu.git
Tests for IceServerProperties. Integrate new attribute to Connection and generation token logic
parent
3274db8a61
commit
fca9c7b2ab
|
@ -86,6 +86,11 @@
|
||||||
<version>${version.junit}</version>
|
<version>${version.junit}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-validator</groupId>
|
||||||
|
<artifactId>commons-validator</artifactId>
|
||||||
|
<version>${version.commons-validator}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|
|
@ -324,6 +324,11 @@ public class Connection {
|
||||||
if (this.connectionProperties.getNetworkCache() != null) {
|
if (this.connectionProperties.getNetworkCache() != null) {
|
||||||
builder.networkCache(this.connectionProperties.getNetworkCache());
|
builder.networkCache(this.connectionProperties.getNetworkCache());
|
||||||
}
|
}
|
||||||
|
if (this.connectionProperties.getCustomIceServers() != null && !this.connectionProperties.getCustomIceServers().isEmpty()) {
|
||||||
|
for (IceServerProperties iceServerProperties: this.connectionProperties.getCustomIceServers()) {
|
||||||
|
builder.addCustomIceServer(iceServerProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.connectionProperties = builder.build();
|
this.connectionProperties = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +422,24 @@ public class Connection {
|
||||||
? OpenViduRole.valueOf(json.get("role").getAsString())
|
? OpenViduRole.valueOf(json.get("role").getAsString())
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
List<IceServerProperties> customIceServers = new ArrayList<>();
|
||||||
|
if (json.has("customIceServers") && json.get("customIceServers").isJsonArray()) {
|
||||||
|
JsonArray customIceServersJsonArray = json.get("customIceServers").getAsJsonArray();
|
||||||
|
customIceServersJsonArray.forEach(iceJsonElem -> {
|
||||||
|
JsonObject iceJsonObj = iceJsonElem.getAsJsonObject();
|
||||||
|
String url = (iceJsonObj.has("url") && !iceJsonObj.get("url").isJsonNull())
|
||||||
|
? json.get("url").getAsString()
|
||||||
|
: null;
|
||||||
|
String username = (iceJsonObj.has("username") && !iceJsonObj.get("username").isJsonNull())
|
||||||
|
? json.get("username").getAsString()
|
||||||
|
: null;
|
||||||
|
String credential = (iceJsonObj.has("credential") && !iceJsonObj.get("credential").isJsonNull())
|
||||||
|
? json.get("credential").getAsString()
|
||||||
|
: null;
|
||||||
|
customIceServers.add(new IceServerProperties.Builder().url(url).username(username).credential(credential).build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// IPCAM
|
// IPCAM
|
||||||
String rtspUri = (json.has("rtspUri") && !json.get("rtspUri").isJsonNull()) ? json.get("rtspUri").getAsString()
|
String rtspUri = (json.has("rtspUri") && !json.get("rtspUri").isJsonNull()) ? json.get("rtspUri").getAsString()
|
||||||
: null;
|
: null;
|
||||||
|
@ -431,25 +454,6 @@ public class Connection {
|
||||||
? json.get("networkCache").getAsInt()
|
? json.get("networkCache").getAsInt()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// External Ice Servers
|
|
||||||
List<IceServerProperties> customIceServers = new ArrayList<>();
|
|
||||||
if (json.has("customIceServers") && json.get("customIceServers").isJsonArray()) {
|
|
||||||
JsonArray customIceServersJsonArray = json.get("customIceServers").getAsJsonArray();
|
|
||||||
customIceServersJsonArray.forEach(iceJsonElem -> {
|
|
||||||
JsonObject iceJsonObj = iceJsonElem.getAsJsonObject();
|
|
||||||
String url = (iceJsonObj.has("urls") && !iceJsonObj.get("urls").isJsonNull())
|
|
||||||
? json.get("urls").getAsString()
|
|
||||||
: null;
|
|
||||||
String username = (iceJsonObj.has("username") && !iceJsonObj.get("username").isJsonNull())
|
|
||||||
? json.get("username").getAsString()
|
|
||||||
: null;
|
|
||||||
String credential = (iceJsonObj.has("credential") && !iceJsonObj.get("credential").isJsonNull())
|
|
||||||
? json.get("credential").getAsString()
|
|
||||||
: null;
|
|
||||||
customIceServers.add(new IceServerProperties.Builder().url(url).username(username).credential(credential).build());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.connectionProperties = new ConnectionProperties(type, data, record, role, null, rtspUri, adaptativeBitrate,
|
this.connectionProperties = new ConnectionProperties(type, data, record, role, null, rtspUri, adaptativeBitrate,
|
||||||
onlyPlayWithSubscribers, networkCache, customIceServers);
|
onlyPlayWithSubscribers, networkCache, customIceServers);
|
||||||
|
|
||||||
|
|
|
@ -399,6 +399,12 @@ public class ConnectionProperties {
|
||||||
} else {
|
} else {
|
||||||
json.add("kurentoOptions", JsonNull.INSTANCE);
|
json.add("kurentoOptions", JsonNull.INSTANCE);
|
||||||
}
|
}
|
||||||
|
JsonArray customIceServersJsonList = new JsonArray();
|
||||||
|
customIceServers.forEach((customIceServer) -> {
|
||||||
|
customIceServersJsonList.add(customIceServer.toJson());
|
||||||
|
});
|
||||||
|
json.add("customIceServers", customIceServersJsonList);
|
||||||
|
|
||||||
// IPCAM
|
// IPCAM
|
||||||
if (getRtspUri() != null) {
|
if (getRtspUri() != null) {
|
||||||
json.addProperty("rtspUri", getRtspUri());
|
json.addProperty("rtspUri", getRtspUri());
|
||||||
|
@ -420,14 +426,6 @@ public class ConnectionProperties {
|
||||||
} else {
|
} else {
|
||||||
json.add("networkCache", JsonNull.INSTANCE);
|
json.add("networkCache", JsonNull.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ice Servers
|
|
||||||
JsonArray customIceServersJsonList = new JsonArray();
|
|
||||||
customIceServers.forEach((customIceServer) -> {
|
|
||||||
customIceServersJsonList.add(customIceServer.toJson());
|
|
||||||
});
|
|
||||||
json.add("customIceServers", customIceServersJsonList);
|
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package io.openvidu.java.client;
|
package io.openvidu.java.client;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import org.apache.commons.validator.routines.DomainValidator;
|
||||||
|
import org.apache.commons.validator.routines.InetAddressValidator;
|
||||||
|
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -37,7 +41,7 @@ public class IceServerProperties {
|
||||||
*/
|
*/
|
||||||
public JsonObject toJson() {
|
public JsonObject toJson() {
|
||||||
JsonObject json = new JsonObject();
|
JsonObject json = new JsonObject();
|
||||||
json.addProperty("urls", getUrl());
|
json.addProperty("url", getUrl());
|
||||||
if (getUsername() != null && !getUsername().isEmpty()) {
|
if (getUsername() != null && !getUsername().isEmpty()) {
|
||||||
json.addProperty("username", getUsername());
|
json.addProperty("username", getUsername());
|
||||||
}
|
}
|
||||||
|
@ -74,13 +78,15 @@ public class IceServerProperties {
|
||||||
throw new IllegalArgumentException("External turn url cannot be null");
|
throw new IllegalArgumentException("External turn url cannot be null");
|
||||||
}
|
}
|
||||||
this.checkValidStunTurn(this.url);
|
this.checkValidStunTurn(this.url);
|
||||||
if (this.username == null ^ this.credential == null) {
|
if (this.url.startsWith("turn")) {
|
||||||
// If one is null when the other is defined, fail...
|
if ((this.username == null || this.credential == null)) {
|
||||||
throw new IllegalArgumentException("You need to define username and credentials if you define one of them");
|
throw new IllegalArgumentException("Credentials must be defined while using turn");
|
||||||
}
|
}
|
||||||
if (this.username != null && this.credential != null && this.url.startsWith("stun")) {
|
} else if (this.url.startsWith("stun")) {
|
||||||
// Credentials can not be defined using stun
|
if (this.username != null || this.credential != null) {
|
||||||
throw new IllegalArgumentException("Credentials can not be defined while using stun.");
|
// Credentials can not be defined using stun
|
||||||
|
throw new IllegalArgumentException("Credentials can not be defined while using stun.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new IceServerProperties(this.url, this.username, this.credential);
|
return new IceServerProperties(this.url, this.username, this.credential);
|
||||||
}
|
}
|
||||||
|
@ -138,32 +144,88 @@ public class IceServerProperties {
|
||||||
|
|
||||||
// Check if port is defined
|
// Check if port is defined
|
||||||
int portColon = hostAndPort.indexOf(':');
|
int portColon = hostAndPort.indexOf(':');
|
||||||
if (portColon != -1) {
|
// IPv6 are defined between brackets
|
||||||
String[] splittedHostAndPort = hostAndPort.split(":");
|
int startIpv6Index = hostAndPort.indexOf('[');
|
||||||
if (splittedHostAndPort.length != 2) {
|
int endIpv6Index = hostAndPort.indexOf(']');
|
||||||
throw new IllegalArgumentException("Host or port are not correctly " +
|
if (startIpv6Index == -1 ^ endIpv6Index == -1) {
|
||||||
"defined in STUN/TURN uri: '" + uri + "'");
|
throw new IllegalArgumentException("Not closed bracket '[' or ']' in uri: " + uri);
|
||||||
}
|
|
||||||
String host = splittedHostAndPort[0];
|
|
||||||
String port = splittedHostAndPort[1];
|
|
||||||
|
|
||||||
// Check if host is defined. Valid Host (Domain or IP) will be done at server side
|
|
||||||
if (host == null || host.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Host defined in '" + uri + "' is empty or null");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port == null || port.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Port defined in '" + uri + "' is empty or null");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
int parsedPort = Integer.parseInt(port);
|
|
||||||
if (parsedPort <= 0 || parsedPort > 65535) {
|
|
||||||
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a valid port number");
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (portColon != -1) {
|
||||||
|
if (startIpv6Index == -1 && endIpv6Index == -1) {
|
||||||
|
// If Ipv4 and port defined
|
||||||
|
String[] splittedHostAndPort = hostAndPort.split(":");
|
||||||
|
if (splittedHostAndPort.length != 2) {
|
||||||
|
throw new IllegalArgumentException("Host or port are not correctly " +
|
||||||
|
"defined in STUN/TURN uri: '" + uri + "'");
|
||||||
|
}
|
||||||
|
String host = splittedHostAndPort[0];
|
||||||
|
String port = splittedHostAndPort[1];
|
||||||
|
|
||||||
|
// Check if host is defined. Valid Host (Domain or IP) will be done at server side
|
||||||
|
checkHostAndPort(uri, host, port);
|
||||||
|
} else {
|
||||||
|
// If portColon is found and Ipv6
|
||||||
|
String ipv6 = hostAndPort.substring(startIpv6Index + 1, endIpv6Index);
|
||||||
|
String auxPort = hostAndPort.substring(endIpv6Index + 1);
|
||||||
|
if (auxPort.startsWith(":")) {
|
||||||
|
if (auxPort.length() == 1) {
|
||||||
|
throw new IllegalArgumentException("Host or port are not correctly defined in STUN/TURN uri: " + uri);
|
||||||
|
}
|
||||||
|
// If port is defined
|
||||||
|
// Get port without colon and check host and port
|
||||||
|
String host = ipv6;
|
||||||
|
String port = auxPort.substring(1);
|
||||||
|
checkHostAndPort(uri, host, port);
|
||||||
|
} else if (auxPort.length() > 0) {
|
||||||
|
// If auxPort = 0, no port is defined
|
||||||
|
throw new IllegalArgumentException("Port is not specified correctly after IPv6 in uri: '" + uri + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If portColon not found, only host is defined
|
||||||
|
String host = hostAndPort;
|
||||||
|
checkHost(uri, host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkHost(String uri, String host) {
|
||||||
|
if (host == null || host.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Host defined in '" + uri + "' is empty or null");
|
||||||
|
}
|
||||||
|
if (DomainValidator.getInstance().isValid(host)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InetAddressValidator ipValidator = InetAddressValidator.getInstance();
|
||||||
|
if (ipValidator.isValid(host)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Inet6Address.getByName(host).getHostAddress();
|
||||||
|
return;
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new IllegalArgumentException("Is not a valid Internet Address (IP or Domain Name): '" + host + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPort(String uri, String port) {
|
||||||
|
if (port == null || port.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Port defined in '" + uri + "' is empty or null");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int parsedPort = Integer.parseInt(port);
|
||||||
|
if (parsedPort <= 0 || parsedPort > 65535) {
|
||||||
|
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a valid port number (0-65535)");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number (0-65535)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkHostAndPort(String uri, String host, String port) {
|
||||||
|
this.checkHost(uri, host);
|
||||||
|
this.checkPort(uri, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.openvidu.server.core;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -51,6 +52,7 @@ import io.openvidu.java.client.KurentoOptions;
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
import io.openvidu.java.client.OpenViduRole;
|
||||||
import io.openvidu.java.client.Recording;
|
import io.openvidu.java.client.Recording;
|
||||||
import io.openvidu.java.client.SessionProperties;
|
import io.openvidu.java.client.SessionProperties;
|
||||||
|
import io.openvidu.java.client.IceServerProperties;
|
||||||
import io.openvidu.server.cdr.CDREventRecordingStatusChanged;
|
import io.openvidu.server.cdr.CDREventRecordingStatusChanged;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.coturn.CoturnCredentialsService;
|
import io.openvidu.server.coturn.CoturnCredentialsService;
|
||||||
|
@ -329,13 +331,13 @@ public abstract class SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
|
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
|
||||||
KurentoOptions kurentoOptions) throws Exception {
|
KurentoOptions kurentoOptions, List<IceServerProperties> customIceServers) throws Exception {
|
||||||
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
|
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
|
||||||
log.error("Data invalid format");
|
log.error("Data invalid format");
|
||||||
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
||||||
}
|
}
|
||||||
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), serverMetadata, record, role,
|
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), serverMetadata, record, role,
|
||||||
kurentoOptions);
|
kurentoOptions, customIceServers);
|
||||||
|
|
||||||
// Internal dev feature: allows customizing connectionId
|
// Internal dev feature: allows customizing connectionId
|
||||||
if (serverMetadata.contains("openviduCustomConnectionId")) {
|
if (serverMetadata.contains("openviduCustomConnectionId")) {
|
||||||
|
|
|
@ -17,18 +17,17 @@
|
||||||
|
|
||||||
package io.openvidu.server.core;
|
package io.openvidu.server.core;
|
||||||
|
|
||||||
|
import io.openvidu.java.client.*;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
import com.google.gson.JsonNull;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.java.client.ConnectionProperties;
|
|
||||||
import io.openvidu.java.client.ConnectionType;
|
|
||||||
import io.openvidu.java.client.KurentoOptions;
|
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
|
||||||
import io.openvidu.server.core.Participant.ParticipantStatus;
|
import io.openvidu.server.core.Participant.ParticipantStatus;
|
||||||
import io.openvidu.server.coturn.TurnCredentials;
|
import io.openvidu.server.coturn.TurnCredentials;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Token {
|
public class Token {
|
||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
|
@ -77,7 +76,8 @@ public class Token {
|
||||||
this.updateConnectionProperties(connectionProperties.getType(), connectionProperties.getData(), newRecord,
|
this.updateConnectionProperties(connectionProperties.getType(), connectionProperties.getData(), newRecord,
|
||||||
connectionProperties.getRole(), connectionProperties.getKurentoOptions(),
|
connectionProperties.getRole(), connectionProperties.getKurentoOptions(),
|
||||||
connectionProperties.getRtspUri(), connectionProperties.adaptativeBitrate(),
|
connectionProperties.getRtspUri(), connectionProperties.adaptativeBitrate(),
|
||||||
connectionProperties.onlyPlayWithSubscribers(), connectionProperties.getNetworkCache());
|
connectionProperties.onlyPlayWithSubscribers(), connectionProperties.getNetworkCache(),
|
||||||
|
connectionProperties.getCustomIceServers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenViduRole getRole() {
|
public OpenViduRole getRole() {
|
||||||
|
@ -88,7 +88,8 @@ public class Token {
|
||||||
this.updateConnectionProperties(connectionProperties.getType(), connectionProperties.getData(),
|
this.updateConnectionProperties(connectionProperties.getType(), connectionProperties.getData(),
|
||||||
connectionProperties.record(), newRole, connectionProperties.getKurentoOptions(),
|
connectionProperties.record(), newRole, connectionProperties.getKurentoOptions(),
|
||||||
connectionProperties.getRtspUri(), connectionProperties.adaptativeBitrate(),
|
connectionProperties.getRtspUri(), connectionProperties.adaptativeBitrate(),
|
||||||
connectionProperties.onlyPlayWithSubscribers(), connectionProperties.getNetworkCache());
|
connectionProperties.onlyPlayWithSubscribers(), connectionProperties.getNetworkCache(),
|
||||||
|
connectionProperties.getCustomIceServers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public KurentoOptions getKurentoOptions() {
|
public KurentoOptions getKurentoOptions() {
|
||||||
|
@ -118,6 +119,10 @@ public class Token {
|
||||||
public String getConnectionId() {
|
public String getConnectionId() {
|
||||||
return connectionId;
|
return connectionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<IceServerProperties> getCustomIceServers() {
|
||||||
|
return this.connectionProperties.getCustomIceServers();
|
||||||
|
}
|
||||||
|
|
||||||
public void setConnectionId(String connectionId) {
|
public void setConnectionId(String connectionId) {
|
||||||
this.connectionId = connectionId;
|
this.connectionId = connectionId;
|
||||||
|
@ -178,7 +183,7 @@ public class Token {
|
||||||
|
|
||||||
private void updateConnectionProperties(ConnectionType type, String data, Boolean record, OpenViduRole role,
|
private void updateConnectionProperties(ConnectionType type, String data, Boolean record, OpenViduRole role,
|
||||||
KurentoOptions kurentoOptions, String rtspUri, Boolean adaptativeBitrate, Boolean onlyPlayWithSubscribers,
|
KurentoOptions kurentoOptions, String rtspUri, Boolean adaptativeBitrate, Boolean onlyPlayWithSubscribers,
|
||||||
Integer networkCache) {
|
Integer networkCache, List<IceServerProperties> iceServerProperties) {
|
||||||
ConnectionProperties.Builder builder = new ConnectionProperties.Builder();
|
ConnectionProperties.Builder builder = new ConnectionProperties.Builder();
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
builder.type(type);
|
builder.type(type);
|
||||||
|
@ -207,6 +212,11 @@ public class Token {
|
||||||
if (networkCache != null) {
|
if (networkCache != null) {
|
||||||
builder.networkCache(networkCache);
|
builder.networkCache(networkCache);
|
||||||
}
|
}
|
||||||
|
if (iceServerProperties != null) {
|
||||||
|
for (IceServerProperties customIceServer: iceServerProperties) {
|
||||||
|
builder.addCustomIceServer(customIceServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.connectionProperties = builder.build();
|
this.connectionProperties = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,15 @@ import io.openvidu.java.client.ConnectionProperties;
|
||||||
import io.openvidu.java.client.ConnectionType;
|
import io.openvidu.java.client.ConnectionType;
|
||||||
import io.openvidu.java.client.KurentoOptions;
|
import io.openvidu.java.client.KurentoOptions;
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
import io.openvidu.java.client.OpenViduRole;
|
||||||
|
import io.openvidu.java.client.IceServerProperties;
|
||||||
import io.openvidu.server.OpenViduServer;
|
import io.openvidu.server.OpenViduServer;
|
||||||
import io.openvidu.server.config.OpenviduBuildInfo;
|
import io.openvidu.server.config.OpenviduBuildInfo;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.coturn.CoturnCredentialsService;
|
import io.openvidu.server.coturn.CoturnCredentialsService;
|
||||||
import io.openvidu.server.coturn.TurnCredentials;
|
import io.openvidu.server.coturn.TurnCredentials;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TokenGenerator {
|
public class TokenGenerator {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -42,7 +45,7 @@ public class TokenGenerator {
|
||||||
protected OpenviduBuildInfo openviduBuildConfig;
|
protected OpenviduBuildInfo openviduBuildConfig;
|
||||||
|
|
||||||
public Token generateToken(String sessionId, String serverMetadata, boolean record, OpenViduRole role,
|
public Token generateToken(String sessionId, String serverMetadata, boolean record, OpenViduRole role,
|
||||||
KurentoOptions kurentoOptions) throws Exception {
|
KurentoOptions kurentoOptions, List<IceServerProperties> customIceServers) throws Exception {
|
||||||
String token = OpenViduServer.wsUrl;
|
String token = OpenViduServer.wsUrl;
|
||||||
token += "?sessionId=" + sessionId;
|
token += "?sessionId=" + sessionId;
|
||||||
token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
|
token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
|
||||||
|
@ -51,8 +54,13 @@ public class TokenGenerator {
|
||||||
if (this.openviduConfig.isTurnadminAvailable()) {
|
if (this.openviduConfig.isTurnadminAvailable()) {
|
||||||
turnCredentials = coturnCredentialsService.createUser();
|
turnCredentials = coturnCredentialsService.createUser();
|
||||||
}
|
}
|
||||||
ConnectionProperties connectionProperties = new ConnectionProperties.Builder().type(ConnectionType.WEBRTC)
|
ConnectionProperties.Builder connectionPropertiesBuilder = new ConnectionProperties.Builder()
|
||||||
.data(serverMetadata).record(record).role(role).kurentoOptions(kurentoOptions).build();
|
.type(ConnectionType.WEBRTC).data(serverMetadata).record(record).role(role)
|
||||||
|
.kurentoOptions(kurentoOptions);
|
||||||
|
for (IceServerProperties customIceServer: customIceServers) {
|
||||||
|
connectionPropertiesBuilder.addCustomIceServer(customIceServer);
|
||||||
|
}
|
||||||
|
ConnectionProperties connectionProperties = connectionPropertiesBuilder.build();
|
||||||
return new Token(token, sessionId, connectionProperties, turnCredentials);
|
return new Token(token, sessionId, connectionProperties, turnCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.net.MalformedURLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -653,7 +654,7 @@ public class SessionRestController {
|
||||||
try {
|
try {
|
||||||
Token token = sessionManager.newToken(session, connectionProperties.getRole(),
|
Token token = sessionManager.newToken(session, connectionProperties.getRole(),
|
||||||
connectionProperties.getData(), connectionProperties.record(),
|
connectionProperties.getData(), connectionProperties.record(),
|
||||||
connectionProperties.getKurentoOptions());
|
connectionProperties.getKurentoOptions(), connectionProperties.getCustomIceServers());
|
||||||
return new ResponseEntity<>(token.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(),
|
return new ResponseEntity<>(token.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(),
|
||||||
HttpStatus.OK);
|
HttpStatus.OK);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -909,7 +910,7 @@ public class SessionRestController {
|
||||||
JsonArray customIceServersJsonArray = null;
|
JsonArray customIceServersJsonArray = null;
|
||||||
if (params.get("customIceServers") != null) {
|
if (params.get("customIceServers") != null) {
|
||||||
try {
|
try {
|
||||||
customIceServersJsonArray = new Gson().toJsonTree(params.get("customIceServers"), Map.class)
|
customIceServersJsonArray = new Gson().toJsonTree(params.get("customIceServers"), List.class)
|
||||||
.getAsJsonArray();
|
.getAsJsonArray();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new Exception("Error in parameter 'customIceServersJson'. It is not a valid JSON object");
|
throw new Exception("Error in parameter 'customIceServersJson'. It is not a valid JSON object");
|
||||||
|
@ -920,7 +921,7 @@ public class SessionRestController {
|
||||||
for (int i = 0; i < customIceServersJsonArray.size(); i++) {
|
for (int i = 0; i < customIceServersJsonArray.size(); i++) {
|
||||||
JsonObject customIceServerJson = customIceServersJsonArray.get(i).getAsJsonObject();
|
JsonObject customIceServerJson = customIceServersJsonArray.get(i).getAsJsonObject();
|
||||||
IceServerProperties.Builder iceServerPropertiesBuilder = new IceServerProperties.Builder();
|
IceServerProperties.Builder iceServerPropertiesBuilder = new IceServerProperties.Builder();
|
||||||
iceServerPropertiesBuilder.url(customIceServerJson.get("urls").getAsString());
|
iceServerPropertiesBuilder.url(customIceServerJson.get("url").getAsString());
|
||||||
if (customIceServerJson.has("username")) {
|
if (customIceServerJson.has("username")) {
|
||||||
iceServerPropertiesBuilder.username(customIceServerJson.get("username").getAsString());
|
iceServerPropertiesBuilder.username(customIceServerJson.get("username").getAsString());
|
||||||
}
|
}
|
||||||
|
@ -931,7 +932,7 @@ public class SessionRestController {
|
||||||
builder.addCustomIceServer(iceServerProperties);
|
builder.addCustomIceServer(iceServerProperties);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new Exception("Type error in some parameter of 'kurentoOptions': " + e.getMessage());
|
throw new Exception("Type error in some parameter of 'customIceServers': " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
package io.openvidu.server.test.unit;
|
||||||
|
|
||||||
|
import io.openvidu.java.client.IceServerProperties;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class IceServerPropertiesTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("IceServerProperty exceptions tests")
|
||||||
|
public void iceServerPropertiesExceptionTest() {
|
||||||
|
// Wrong urls
|
||||||
|
notValidIceServerTest(
|
||||||
|
"wrongurl", null, null,
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: 'wrongurl'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"wrongurl", "anyuser", null,
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: 'wrongurl'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"wrongurl", null, "anypassword",
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: 'wrongurl'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"wrongurl", "anyuser", "anypassword",
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: 'wrongurl'"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wrong prefixes
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turnss:wrongurl", null, null,
|
||||||
|
"The protocol 'turnss' is invalid. Only valid values are: [turn, turns] [stuns, stun]"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stunss:wrongurl", "anyuser", null,
|
||||||
|
"The protocol 'stunss' is invalid. Only valid values are: [turn, turns] [stuns, stun]"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"anything:wrongurl", null, "anypassword",
|
||||||
|
"The protocol 'anything' is invalid. Only valid values are: [turn, turns] [stuns, stun]"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
":", null, null,
|
||||||
|
"The protocol '' is invalid. Only valid values are: [turn, turns] [stuns, stun]"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"", null, null,
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: ''"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try invalid host and ports
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com:99a99", null, null,
|
||||||
|
"The port defined in 'stun:hostname.com:99a99' is not a number (0-65535)"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com:-1", null, null,
|
||||||
|
"The port defined in 'stun:hostname.com:-1' is not a valid port number (0-65535)"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname:port:more", null, null,
|
||||||
|
"Host or port are not correctly defined in STUN/TURN uri: 'stun:hostname:port:more'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com:port more", null, null,
|
||||||
|
"The port defined in 'stun:hostname.com:port more' is not a number (0-65535)"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com:", null, null,
|
||||||
|
"Host or port are not correctly defined in STUN/TURN uri: 'stun:hostname.com:'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:[1:2:3:4:5:6:7:8]junk:1000", null, null,
|
||||||
|
"Port is not specified correctly after IPv6 in uri: 'stun:[1:2:3:4:5:6:7:8]junk:1000'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:[notvalid:]:1000", null, null,
|
||||||
|
"Is not a valid Internet Address (IP or Domain Name): 'notvalid:'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun::5555", null, null,
|
||||||
|
"Host defined in 'stun::5555' is empty or null"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:", null, null,
|
||||||
|
"Host defined in 'stun:' is empty or null"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Illegal Uri tests according to RFC 3986 and RFC 7064 (URI schemes for STUN and TURN)
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:/hostname.com", null, null,
|
||||||
|
"Is not a valid Internet Address (IP or Domain Name): '/hostname.com'"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:?hostname.com", null, null,
|
||||||
|
"STUN uri can't have any '?' query param"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:#hostname.com", null, null,
|
||||||
|
"Is not a valid Internet Address (IP or Domain Name): '#hostname.com'"
|
||||||
|
);
|
||||||
|
|
||||||
|
// illegal ?transport=xxx tests in turn uris
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com?transport=invalid", "anyuser", "anypassword",
|
||||||
|
"Wrong value specified in STUN/TURN uri: 'turn:hostname.com?transport=invalid'. Unique valid arguments after '?' are '?transport=tcp' or '?transport=udp"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com?transport=", "anyuser", "anypassword",
|
||||||
|
"Wrong value specified in STUN/TURN uri: 'turn:hostname.com?transport='. Unique valid arguments after '?' are '?transport=tcp' or '?transport=udp"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com?=", "anyuser", "anypassword",
|
||||||
|
"Wrong value specified in STUN/TURN uri: 'turn:hostname.com?='. Unique valid arguments after '?' are '?transport=tcp' or '?transport=udp"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com?", "anyuser", "anypassword",
|
||||||
|
"Wrong value specified in STUN/TURN uri: 'turn:hostname.com?'. Unique valid arguments after '?' are '?transport=tcp' or '?transport=udp"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"?", "anyuser", "anypassword",
|
||||||
|
"Not a valid TURN/STUN uri provided. No colons found in: '?'"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Transport can not be defined in STUN
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com?transport=tcp", null, null,
|
||||||
|
"STUN uri can't have any '?' query param"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com?transport=udp", null, null,
|
||||||
|
"STUN uri can't have any '?' query param"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Stun can not have credentials defined
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com", "username", "credential",
|
||||||
|
"Credentials can not be defined while using stun."
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com", "username", "credential",
|
||||||
|
"Credentials can not be defined while using stun."
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com", "username", null,
|
||||||
|
"Credentials can not be defined while using stun."
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"stun:hostname.com", null, "credential",
|
||||||
|
"Credentials can not be defined while using stun."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Turn must have credentials
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com", null, null,
|
||||||
|
"Credentials must be defined while using turn"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com", "username", null,
|
||||||
|
"Credentials must be defined while using turn"
|
||||||
|
);
|
||||||
|
notValidIceServerTest(
|
||||||
|
"turn:hostname.com", null, "credential",
|
||||||
|
"Credentials must be defined while using turn"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("IceServerProperty exceptions tests")
|
||||||
|
public void iceServerPropertiesValidTest() {
|
||||||
|
// Stun and stuns
|
||||||
|
validIceServerTest("stun:hostname.com", null, null);
|
||||||
|
validIceServerTest("stuns:hostname.com", null, null);
|
||||||
|
|
||||||
|
// Turn and turns
|
||||||
|
validIceServerTest("turn:hostname.com", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:hostname.com", "anyuser", "credential");
|
||||||
|
|
||||||
|
// Test IPv4/IPv6/hostname and with/without port
|
||||||
|
validIceServerTest("stun:1.2.3.4:1234", null, null);
|
||||||
|
validIceServerTest("stun:[1:2:3:4:5:6:7:8]:4321", null, null);
|
||||||
|
validIceServerTest("stun:hostname.com:9999", null, null);
|
||||||
|
validIceServerTest("stun:1.2.3.4", null, null);
|
||||||
|
validIceServerTest("stun:[1:2:3:4:5:6:7:8]", null, null);
|
||||||
|
validIceServerTest("stuns:1.2.3.4:1234", null, null);
|
||||||
|
validIceServerTest("stuns:[1:2:3:4:5:6:7:8]:4321", null, null);
|
||||||
|
validIceServerTest("stuns:hostname.com:9999", null, null);
|
||||||
|
validIceServerTest("stuns:1.2.3.4", null, null);
|
||||||
|
validIceServerTest("stuns:[1:2:3:4:5:6:7:8]", null, null);
|
||||||
|
validIceServerTest("turn:1.2.3.4:1234", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:[1:2:3:4:5:6:7:8]:4321", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:hostname.com:9999", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:1.2.3.4", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:[1:2:3:4:5:6:7:8]", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:1.2.3.4:1234", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:[1:2:3:4:5:6:7:8]:4321", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:hostname.com:9999", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:1.2.3.4", "anyuser", "credential");
|
||||||
|
validIceServerTest("turns:[1:2:3:4:5:6:7:8]", "anyuser", "credential");
|
||||||
|
|
||||||
|
// Test valid ?transport=tcp or ?transport=udp
|
||||||
|
validIceServerTest("turn:hostname.com:1234?transport=tcp", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:hostname.com?transport=udp", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:1.2.3.4:1234?transport=tcp", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:1.2.3.4?transport=udp", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:[1:2:3:4:5:6:7:8]:4321?transport=udp", "anyuser", "credential");
|
||||||
|
validIceServerTest("turn:[1:2:3:4:5:6:7:8]?transport=udp", "anyuser", "credential");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validIceServerTest(String url, String username, String credential) {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
IceServerProperties.Builder iceServerPropertiesBuilder = new IceServerProperties.Builder().url(url);
|
||||||
|
if (username != null) {
|
||||||
|
iceServerPropertiesBuilder.username(username);
|
||||||
|
}
|
||||||
|
if (credential != null) {
|
||||||
|
iceServerPropertiesBuilder.credential(credential);
|
||||||
|
}
|
||||||
|
IceServerProperties iceServerProperties = iceServerPropertiesBuilder.build();
|
||||||
|
assertEquals(url, iceServerProperties.getUrl());
|
||||||
|
if (username != null) {
|
||||||
|
assertEquals(username, iceServerProperties.getUsername());
|
||||||
|
}
|
||||||
|
if (credential != null) {
|
||||||
|
assertEquals(credential, iceServerProperties.getCredential());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notValidIceServerTest(String url, String username, String credential, String expectedMessage) {
|
||||||
|
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
IceServerProperties.Builder iceServerPropertiesBuilder = new IceServerProperties.Builder().url(url);
|
||||||
|
if (username != null) {
|
||||||
|
iceServerPropertiesBuilder.username(username);
|
||||||
|
}
|
||||||
|
if (credential != null) {
|
||||||
|
iceServerPropertiesBuilder.credential(credential);
|
||||||
|
}
|
||||||
|
iceServerPropertiesBuilder.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
String actualMessage = exception.getMessage();
|
||||||
|
assertEquals(actualMessage, expectedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue