mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: token management refactoring
parent
e663680b48
commit
35d8490180
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
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<>());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue