openvidu-server: token management refactoring

pull/391/head
pabloFuente 2020-01-31 14:59:46 +01:00
parent e663680b48
commit 35d8490180
7 changed files with 69 additions and 82 deletions

View File

@ -27,6 +27,9 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@ -42,9 +45,12 @@ import io.openvidu.server.recording.service.RecordingManager;
public class Session implements SessionInterface {
private static final Logger log = LoggerFactory.getLogger(Session.class);
protected OpenviduConfig openviduConfig;
protected RecordingManager recordingManager;
protected ConcurrentMap<String, Token> tokens = new ConcurrentHashMap<>();
protected final ConcurrentMap<String, Participant> participants = new ConcurrentHashMap<>();
protected String sessionId;
protected SessionProperties sessionProperties;
@ -72,6 +78,7 @@ public class Session implements SessionInterface {
this.sessionProperties = previousSession.getSessionProperties();
this.openviduConfig = previousSession.openviduConfig;
this.recordingManager = previousSession.recordingManager;
this.tokens = previousSession.tokens;
}
public Session(String sessionId, SessionProperties sessionProperties, OpenviduConfig openviduConfig,
@ -132,6 +139,24 @@ public class Session implements SessionInterface {
this.activePublishers.decrementAndGet();
}
public void storeToken(Token token) {
this.tokens.put(token.getToken(), token);
}
public boolean isTokenValid(String token) {
return this.tokens.containsKey(token);
}
public Token consumeToken(String token) {
Token tokenObj = this.tokens.remove(token);
showTokens("Token consumed");
return tokenObj;
}
public void showTokens(String preMessage) {
log.info("{} { Session: {} | Tokens: {} }", preMessage, this.sessionId, this.tokens.keySet().toString());
}
public boolean isClosed() {
return closed;
}

View File

@ -89,7 +89,6 @@ public abstract class SessionManager {
protected ConcurrentMap<String, ConcurrentLinkedQueue<CDREventRecording>> sessionidAccumulatedRecordings = new ConcurrentHashMap<>();
protected ConcurrentMap<String, Boolean> insecureUsers = new ConcurrentHashMap<>();
public ConcurrentMap<String, ConcurrentHashMap<String, Token>> sessionidTokenTokenobj = new ConcurrentHashMap<>();
public abstract void joinRoom(Participant participant, String sessionId, Integer transactionId);
@ -281,51 +280,29 @@ public abstract class SessionManager {
final String sessionId = sessionNotActive.getSessionId();
this.sessionsNotActive.put(sessionId, sessionNotActive);
this.initializeCollections(sessionId);
showTokens();
return sessionNotActive;
}
public String newToken(String sessionId, OpenViduRole role, String serverMetadata,
public String newToken(Session session, OpenViduRole role, String serverMetadata,
KurentoTokenOptions kurentoTokenOptions) throws OpenViduException {
Map<String, Token> tokenMap = this.sessionidTokenTokenobj.get(sessionId);
if (tokenMap != null) {
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
log.error("Data invalid format");
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
}
Token token = tokenGenerator.generateToken(sessionId, role, serverMetadata, kurentoTokenOptions);
tokenMap.putIfAbsent(token.getToken(), token);
showTokens();
return token.getToken();
} else {
log.error("sessionId [" + sessionId + "] was not found (race condition error)");
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "sessionId [" + sessionId + "] not found");
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
log.error("Data invalid format");
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
}
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), role, serverMetadata,
kurentoTokenOptions);
session.storeToken(tokenObj);
session.showTokens("Token created");
return tokenObj.getToken();
}
public boolean isTokenValidInSession(String token, String sessionId, String participanPrivatetId,
String serverMetadata) {
if (!this.isInsecureParticipant(participanPrivatetId)) {
if (this.sessionidTokenTokenobj.get(sessionId) != null) {
return this.sessionidTokenTokenobj.get(sessionId).containsKey(token);
} else {
return false;
}
} else {
this.initializeCollections(sessionId);
this.sessionidTokenTokenobj.get(sessionId).putIfAbsent(token,
new Token(token, OpenViduRole.PUBLISHER, serverMetadata,
this.coturnCredentialsService.isCoturnAvailable()
? this.coturnCredentialsService.createUser()
: null,
null));
return true;
}
public Token newTokenForInsecureUser(Session session, String token, String serverMetadata) {
Token tokenObj = new Token(token, OpenViduRole.PUBLISHER, serverMetadata != null ? serverMetadata : "",
this.coturnCredentialsService.isCoturnAvailable() ? this.coturnCredentialsService.createUser() : null,
null);
session.storeToken(tokenObj);
session.showTokens("Token created for insecure user");
return tokenObj;
}
public boolean isPublisherInSession(String sessionId, Participant participant) {
@ -416,23 +393,6 @@ public abstract class SessionManager {
}
}
public Token consumeToken(String sessionId, String participantPrivateId, String token) {
if (this.sessionidTokenTokenobj.get(sessionId) != null) {
Token t = this.sessionidTokenTokenobj.get(sessionId).remove(token);
if (t != null) {
return t;
} else {
throw new OpenViduException(Code.TOKEN_CANNOT_BE_CREATED_ERROR_CODE, sessionId);
}
} else {
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, sessionId);
}
}
public void showTokens() {
log.info("<SESSIONID, TOKENS>: {}", this.sessionidTokenTokenobj.toString());
}
/**
* Closes all resources. This method has been annotated with the @PreDestroy
* directive (javax.annotation package) so that it will be automatically called
@ -531,13 +491,11 @@ public abstract class SessionManager {
sessionidParticipantpublicidParticipant.remove(sessionId);
sessionidFinalUsers.remove(sessionId);
sessionidAccumulatedRecordings.remove(sessionId);
sessionidTokenTokenobj.remove(sessionId);
}
private void initializeCollections(String sessionId) {
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
this.sessionidFinalUsers.putIfAbsent(sessionId, new ConcurrentHashMap<>());
this.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>());
if (this.openviduConfig.isRecordingModuleEnabled()) {
this.sessionidAccumulatedRecordings.putIfAbsent(sessionId, new ConcurrentLinkedQueue<>());
}

View File

@ -138,6 +138,8 @@ public class KurentoSession extends Session {
public boolean close(EndReason reason) {
if (!closed) {
this.tokens.clear();
for (Participant participant : participants.values()) {
((KurentoParticipant) participant).releaseAllFilters();
((KurentoParticipant) participant).close(reason, true, 0);

View File

@ -170,9 +170,6 @@ public class KurentoSessionManager extends SessionManager {
this.coturnCredentialsService.deleteUser(p.getToken().getTurnCredentials().getUsername());
}
if (sessionidTokenTokenobj.get(sessionId) != null) {
sessionidTokenTokenobj.get(sessionId).remove(p.getToken().getToken());
}
boolean stillParticipant = false;
for (Session s : sessions.values()) {
if (s.getParticipantByPrivateId(p.getParticipantPrivateId()) != null) {
@ -185,8 +182,6 @@ public class KurentoSessionManager extends SessionManager {
}
}
showTokens();
// Close Session if no more participants
Set<Participant> remainingParticipants = null;
@ -222,7 +217,6 @@ public class KurentoSessionManager extends SessionManager {
log.info("No more participants in session '{}', removing it and closing it", sessionId);
this.closeSessionAndEmptyCollections(session, reason, true);
sessionClosedByLastParticipant = true;
showTokens();
} finally {
session.closingLock.writeLock().unlock();
}
@ -909,10 +903,9 @@ public class KurentoSessionManager extends SessionManager {
this.newInsecureParticipant(rtspConnectionId);
String token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
+ RandomStringUtils.randomAlphanumeric(15);
Token tokenObj = null;
if (this.isTokenValidInSession(token, sessionId, rtspConnectionId, serverMetadata)) {
tokenObj = this.consumeToken(sessionId, rtspConnectionId, token);
}
this.newTokenForInsecureUser(session, token, serverMetadata);
final Token tokenObj = session.consumeToken(token);
Participant ipcamParticipant = this.newIpcamParticipant(sessionId, rtspConnectionId, tokenObj, location,
mediaOptions.getTypeOfVideo());

View File

@ -494,7 +494,6 @@ public class RecordingManager {
log.info("Closing session {} after automatic stop of recording {}", session.getSessionId(),
recordingId);
sessionManager.closeSessionAndEmptyCollections(session, EndReason.automaticStop, true);
sessionManager.showTokens();
} else {
// There are users connected, but no one is publishing
session.closingLock.writeLock().unlock(); // We don't need the lock if session's not closing
@ -536,7 +535,6 @@ public class RecordingManager {
"Ongoing recording of session {} was explicetly stopped within timeout for automatic recording stop. Closing session",
session.getSessionId());
sessionManager.closeSessionAndEmptyCollections(session, reason, false);
sessionManager.showTokens();
}
return cancelled;
} finally {

View File

@ -21,6 +21,7 @@ import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
@ -165,6 +166,8 @@ public class SessionRestController {
}
Session sessionNotActive = sessionManager.storeSessionNotActive(sessionId, sessionProperties);
log.info("New session {} initialized {}", sessionId, this.sessionManager.getSessionsWithNotActive().stream()
.map(Session::getSessionId).collect(Collectors.toList()).toString());
JsonObject responseJson = new JsonObject();
responseJson.addProperty("id", sessionNotActive.getSessionId());
responseJson.addProperty("createdAt", sessionNotActive.getStartTime());
@ -364,7 +367,7 @@ public class SessionRestController {
// While closing a session tokens can't be generated
if (session.closingLock.readLock().tryLock()) {
try {
String token = sessionManager.newToken(sessionId, role, metadata, kurentoTokenOptions);
String token = sessionManager.newToken(session, role, metadata, kurentoTokenOptions);
JsonObject responseJson = new JsonObject();
responseJson.addProperty("id", token);

View File

@ -176,6 +176,13 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
String platform = getStringParam(request, ProtocolElements.JOINROOM_PLATFORM_PARAM);
String participantPrivatetId = rpcConnection.getParticipantPrivateId();
final io.openvidu.server.core.Session session = sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
log.error("ERROR: Session {} not found", sessionId);
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE,
"Unable to join session. Session " + sessionId + " cannot be found");
}
InetAddress remoteAddress = null;
GeoLocation location = null;
Object obj = rpcConnection.getSession().getAttributes().get("remoteAddress");
@ -234,24 +241,25 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
sessionManager.newInsecureParticipant(participantPrivatetId);
token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
+ RandomStringUtils.randomAlphanumeric(15);
sessionManager.newTokenForInsecureUser(session, token, null);
if (recorder) {
generateRecorderParticipant = true;
}
}
if (sessionManager.isTokenValidInSession(token, sessionId, participantPrivatetId, "")) {
Token tokenObj = session.consumeToken(token);
if (tokenObj != null) {
String clientMetadata = getStringParam(request, ProtocolElements.JOINROOM_METADATA_PARAM);
if (sessionManager.formatChecker.isServerMetadataFormatCorrect(clientMetadata)) {
Token tokenObj = sessionManager.consumeToken(sessionId, participantPrivatetId, token);
Participant participant;
io.openvidu.server.core.Session session = sessionManager.getSessionWithNotActive(sessionId);
// While closing a session users can't join
if (session.closingLock.readLock().tryLock()) {
if (session.isClosed()) {
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE,
"Unable to join the session. Session " + sessionId + " is closed");
}
try {
Participant participant;
if (generateRecorderParticipant) {
participant = sessionManager.newRecorderParticipant(sessionId, participantPrivatetId,
tokenObj, clientMetadata);
@ -276,13 +284,13 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
}
} else {
log.error("ERROR: Metadata format set in client-side is incorrect");
throw new OpenViduException(Code.USER_METADATA_FORMAT_INVALID_ERROR_CODE,
"Unable to join room. The metadata received from the client-side has an invalid format");
throw new OpenViduException(Code.USER_METADATA_FORMAT_INVALID_ERROR_CODE, "Unable to join session "
+ sessionId + ". The metadata received from the client-side has an invalid format");
}
} else {
log.error("ERROR: sessionId or token not valid");
log.error("ERROR: token not valid");
throw new OpenViduException(Code.USER_UNAUTHORIZED_ERROR_CODE,
"Unable to join room. The user is not authorized");
"Unable to join session " + sessionId + ". Token " + token + "is not valid");
}
}