pull/701/head
cruizba 2022-02-25 10:47:07 +01:00
parent af5efc4de4
commit c15d6170da
3 changed files with 100 additions and 18 deletions

View File

@ -18,14 +18,19 @@
package io.openvidu.java.client;
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.validator.routines.DomainValidator;
import org.apache.commons.validator.routines.InetAddressValidator;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;
/**
* See
@ -89,6 +94,7 @@ public class IceServerProperties {
private String url;
private String username;
private String credential;
private String staticAuthSecret;
/**
* Set the url for the ICE Server you want to use.
@ -121,6 +127,23 @@ public class IceServerProperties {
return this;
}
/**
* Secret for TURN authentication based on:
* - https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
* - https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf
* This will generate credentials valid for 24 hours which is the recommended value
*/
public IceServerProperties.Builder staticAuthSecret(String staticAuthSecret) {
this.staticAuthSecret = staticAuthSecret;
return this;
}
public IceServerProperties.Builder clone() {
return new Builder().url(this.url)
.username(this.username)
.credential(this.credential)
.staticAuthSecret(this.staticAuthSecret);
}
/**
* Builder for {@link io.openvidu.java.client.RecordingProperties}
@ -137,6 +160,16 @@ public class IceServerProperties {
}
this.checkValidStunTurn(this.url);
if (this.url.startsWith("turn")) {
if (this.staticAuthSecret != null) {
if (this.username != null || this.credential != null) {
throw new IllegalArgumentException("You can't define username or credential if staticAuthSecret is defined");
}
try {
this.generateTURNCredentials();
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
}
}
if ((this.username == null || this.credential == null)) {
throw new IllegalArgumentException("Credentials must be defined while using turn");
}
@ -281,6 +314,35 @@ public class IceServerProperties {
this.checkHost(uri, host);
this.checkPort(uri, port);
}
private void generateTURNCredentials() throws NoSuchAlgorithmException, InvalidKeyException {
// 1. Generate random username
char[] ALPHANUMERIC =("abcdefghijklmnopqrstuvwxyzABCDEFGHIJK " +
"LMNOPQRSTUVWXYZ0123456789").toCharArray();
int MAX_LENGTH = 8;
StringBuilder randomUsername = new StringBuilder();
for(int i =0; i < MAX_LENGTH; i++) {
int index = new SecureRandom().nextInt(ALPHANUMERIC.length);
randomUsername.append(ALPHANUMERIC[index]);
}
// 2. Get unix timestamp adding 24 hours to define max credential valid time
String unixTimestamp = Long.toString((System.currentTimeMillis() / 1000) + 24*3600);
// 3. Generate TURN username
String username = unixTimestamp + ":" + randomUsername;
System.out.println(username);
// 4. Generate HMAC SHA-1 password
SecretKeySpec signingKey = new SecretKeySpec(staticAuthSecret.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
String credential = new String(Base64.encodeBase64(mac.doFinal(username.getBytes())));
// Set credentials in builder
this.username = username;
this.credential = credential;
}
}
}

View File

@ -225,7 +225,7 @@ public class OpenviduConfig {
private boolean webrtcSimulcast = false;
private List<IceServerProperties> webrtcIceServers;
private List<IceServerProperties.Builder> webrtcIceServersBuilders;
// Plain config properties getters
@ -293,8 +293,8 @@ public class OpenviduConfig {
return this.webrtcSimulcast;
}
public List<IceServerProperties> getWebrtcIceServers() {
return webrtcIceServers;
public List<IceServerProperties.Builder> getWebrtcIceServersBuilders() {
return webrtcIceServersBuilders;
}
public String getOpenViduRecordingPath() {
@ -640,7 +640,7 @@ public class OpenviduConfig {
checkCertificateType();
webrtcIceServers = loadWebrtcIceServers("OPENVIDU_WEBRTC_ICE_SERVERS");
webrtcIceServersBuilders = loadWebrtcIceServers("OPENVIDU_WEBRTC_ICE_SERVERS");
}
@ -1170,16 +1170,16 @@ public class OpenviduConfig {
}
}
private List<IceServerProperties> loadWebrtcIceServers(String property) {
private List<IceServerProperties.Builder> loadWebrtcIceServers(String property) {
String rawIceServers = asOptionalString(property);
List<IceServerProperties> webrtcIceServers = new ArrayList<>();
List<IceServerProperties.Builder> webrtcIceServers = new ArrayList<>();
if (rawIceServers == null || rawIceServers.isEmpty()) {
return webrtcIceServers;
}
List<String> arrayIceServers = asJsonStringsArray(property);
for (String iceServerString : arrayIceServers) {
try {
IceServerProperties iceServerProperties = readIceServer(property, iceServerString);
IceServerProperties.Builder iceServerProperties = readIceServer(property, iceServerString);
webrtcIceServers.add(iceServerProperties);
} catch (Exception e) {
addError(property, iceServerString + " is not a valid webrtc ice server: " + e.getMessage());
@ -1188,8 +1188,8 @@ public class OpenviduConfig {
return webrtcIceServers;
}
private IceServerProperties readIceServer(String property, String iceServerString) {
String url = null, username = null, credential = null;
private IceServerProperties.Builder readIceServer(String property, String iceServerString) {
String url = null, username = null, credential = null, staticAuthSecret = null;
String[] iceServerPropList = iceServerString.split(",");
for (String iceServerProp: iceServerPropList) {
if (iceServerProp.startsWith("url=")) {
@ -1198,13 +1198,29 @@ public class OpenviduConfig {
username = StringUtils.substringAfter(iceServerProp, "username=");
} else if (iceServerProp.startsWith("credential=")) {
credential = StringUtils.substringAfter(iceServerProp, "credential=");
} else if (iceServerProp.startsWith("staticAuthSecret=")) {
staticAuthSecret = StringUtils.substringAfter(iceServerProp, "staticAuthSecret=");
} else {
addError(property, "Wrong parameter: " + iceServerProp);
}
}
IceServerProperties iceServerProperties = new IceServerProperties.Builder()
.url(url).username(username).credential(credential).build();
return iceServerProperties;
IceServerProperties.Builder builder = new IceServerProperties.Builder().url(url);
IceServerProperties.Builder builderCheck = new IceServerProperties.Builder().url(url);
if (staticAuthSecret != null) {
builder.staticAuthSecret(staticAuthSecret);
builderCheck.staticAuthSecret(staticAuthSecret);
}
if (username != null) {
builder.username(username);
builderCheck.username(username);
}
if (credential != null) {
builder.credential(credential);
builderCheck.credential(credential);
}
// Validate config input
builderCheck.build();
return builder;
}
}

View File

@ -922,6 +922,9 @@ public class SessionRestController {
JsonObject customIceServerJson = customIceServersJsonArray.get(i).getAsJsonObject();
IceServerProperties.Builder iceServerPropertiesBuilder = new IceServerProperties.Builder();
iceServerPropertiesBuilder.url(customIceServerJson.get("url").getAsString());
if (customIceServerJson.has("staticAuthSecret")) {
iceServerPropertiesBuilder.staticAuthSecret(customIceServerJson.get("staticAuthSecret").getAsString());
}
if (customIceServerJson.has("username")) {
iceServerPropertiesBuilder.username(customIceServerJson.get("username").getAsString());
}
@ -934,10 +937,11 @@ public class SessionRestController {
} catch (Exception e) {
throw new Exception("Type error in some parameter of 'customIceServers': " + e.getMessage());
}
} else if(!openviduConfig.getWebrtcIceServers().isEmpty()){
} else if(!openviduConfig.getWebrtcIceServersBuilders().isEmpty()){
// If not defined in connection, check if defined in openvidu config
for (IceServerProperties iceServerProperties: openviduConfig.getWebrtcIceServers()) {
builder.addCustomIceServer(iceServerProperties);
for (IceServerProperties.Builder iceServerPropertiesBuilder: openviduConfig.getWebrtcIceServersBuilders()) {
IceServerProperties.Builder configIceBuilder = iceServerPropertiesBuilder.clone();
builder.addCustomIceServer(configIceBuilder.build());
}
}