AccessTokens: Added support for temporary access tokens in the UserState message

This commit is contained in:
Robert Adam 2019-12-28 12:22:37 +01:00
parent 61ee9ddf6d
commit 1c38b53fdf
4 changed files with 76 additions and 0 deletions

View File

@ -213,6 +213,8 @@ message UserState {
optional bool priority_speaker = 18;
// True if the user is currently recording.
optional bool recording = 19;
// a list of temporary acces tokens to be respected when processing this request
repeated string temporary_access_tokens = 20;
}
// Relays information on the bans. The client may send the BanList message to

View File

@ -816,9 +816,20 @@ void ServerHandler::requestUserStats(unsigned int uiSession, bool statsOnly) {
}
void ServerHandler::joinChannel(unsigned int uiSession, unsigned int channel) {
static const QStringList EMPTY;
joinChannel(uiSession, channel, EMPTY);
}
void ServerHandler::joinChannel(unsigned int uiSession, unsigned int channel, const QStringList &temporaryAccessTokens) {
MumbleProto::UserState mpus;
mpus.set_session(uiSession);
mpus.set_channel_id(channel);
foreach(QString tmpToken, temporaryAccessTokens) {
mpus.add_temporary_access_tokens(tmpToken.toUtf8().constData());
}
sendMessage(mpus);
}

View File

@ -25,6 +25,7 @@
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QTimer>
#include <QtCore/QStringList>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QSslCipher>
#include <QtNetwork/QSslError>
@ -117,6 +118,7 @@ class ServerHandler : public QThread {
void requestUserStats(unsigned int uiSession, bool statsOnly);
void joinChannel(unsigned int uiSession, unsigned int channel);
void joinChannel(unsigned int uiSession, unsigned int channel, const QStringList &temporaryAccessTokens);
void createChannel(unsigned int parent_id, const QString &name, const QString &description, unsigned int position, bool temporary, unsigned int maxUsers);
void requestBanList();
void requestUserList();

View File

@ -77,6 +77,59 @@
sendMessage(uSource, mppd); \
}
/// A helper class for managing temporary access tokens
/// It will add the tokens in the comstructor and remove them again in the destructor effectively
/// turning the tokens into a scope-based property
class TemporaryAccessTokenHelper {
protected:
ServerUser *affectedUser;
QStringList qslTemporaryTokens;
Server *server;
public:
TemporaryAccessTokenHelper(ServerUser *affectedUser, const QStringList &tokens, Server *server) : affectedUser(affectedUser),
qslTemporaryTokens(tokens), server(server) {
// Add the temporary tokens
QMutableStringListIterator it(this->qslTemporaryTokens);
{
QMutexLocker qml(&server->qmCache);
while (it.hasNext()) {
QString token = it.next();
if (!this->affectedUser->qslAccessTokens.contains(token)) {
// Add token
this->affectedUser->qslAccessTokens << token;
} else {
// It appears, as if the user already has this token set -> it's not a temporary one or a duplicate
it.remove();
}
}
}
if (!this->qslTemporaryTokens.isEmpty()) {
// Clear the cache in order for tokens to take effect
server->clearACLCache(this->affectedUser);
}
}
~TemporaryAccessTokenHelper() {
if (!this->qslTemporaryTokens.isEmpty()) {
{
QMutexLocker qml(&server->qmCache);
// remove the temporary tokens
foreach(QString token, this->qslTemporaryTokens) {
this->affectedUser->qslAccessTokens.removeOne(token);
}
}
// Clear cache to actually get rid of the temporary tokens
server->clearACLCache(this->affectedUser);
}
}
};
void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg) {
if ((msg.tokens_size() > 0) || (uSource->sState == ServerUser::Authenticated)) {
QStringList qsl;
@ -501,6 +554,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
First check all permissions involved
*/
if ((pDstServerUser->iId == 0) && (uSource->iId != 0)) {
// Don't allow any action on the SuperUser except initiated directly by the SuperUser himself/herself
PERM_DENIED_TYPE(SuperUser);
return;
}
@ -516,6 +570,13 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
if (uSource == pDstServerUser) {
RATELIMIT(uSource);
}
// Handle potential temporary access tokens
QStringList temporaryAccessTokens;
for (int i=0; i < msg.temporary_access_tokens_size(); i++) {
temporaryAccessTokens << u8(msg.temporary_access_tokens(i));
}
TemporaryAccessTokenHelper tempTokenHelper(uSource, temporaryAccessTokens, this);
if (msg.has_channel_id()) {
Channel *c = qhChannels.value(msg.channel_id());