diff --git a/server/Auth.js b/server/Auth.js index 4f1ee3c5d..8425532ec 100644 --- a/server/Auth.js +++ b/server/Auth.js @@ -47,6 +47,7 @@ class Auth { async authMiddleware(req, res, next) { var token = null + var proxyAccount = this.getProxyAccount(req.headers) // If using a get request, the token can be passed as a query string if (req.method === 'GET' && req.query && req.query.token) { @@ -56,13 +57,7 @@ class Auth { token = authHeader && authHeader.split(' ')[1] } - let proxyUsername = null - if (Database.serverSettings.proxyAuthEnabled) { - const uHeader = Database.serverSettings.proxyAuthUsernameHeader.toLowerCase() - proxyUsername = uHeader ? req.headers[uHeader] : null - } - - if (token == null && proxyUsername == null) { + if (token == null && !(proxyAccount && proxyAccount['username'])) { Logger.error('Api called without a token and no proxy auth provided', req.path) return res.sendStatus(401) } @@ -76,11 +71,8 @@ class Auth { } user.isFromProxy = false - } else if (proxyUsername) { - const eHeader = Database.serverSettings.proxyAuthEmailHeader.toLowerCase() - const proxyEmail = eHeader ? req.headers[eHeader] : null - - user = await this.getProxyUser(proxyUsername, proxyEmail) + } else if (proxyAccount) { + user = await this.getProxyUser(proxyAccount) if (!user) { Logger.error('Cannot get user from proxy headers', proxyUsername) return res.sendStatus(401) @@ -121,8 +113,20 @@ class Auth { return jwt.sign(payload, Database.serverSettings.tokenSecret) } - authenticateUser(token) { - return this.verifyToken(token) + async authenticateUser(token, headers) { + const tokenUser = token ? await this.verifyToken(token) : null + if (tokenUser) return tokenUser + + const proxyAccount = this.getProxyAccount(headers) + if (proxyAccount && proxyAccount.username) { + const proxyUser = await this.getProxyUser(proxyAccount) + if (proxyUser) { + proxyUser.isFromProxy = true; + return proxyUser; + } + } + + return null } verifyToken(token) { @@ -143,19 +147,28 @@ class Auth { }) } - async getProxyUser(username, email) { - const user = await Database.userModel.getUserByUsername(username) - if (user) { - return user - } + getProxyAccount(headers) { + if (!Database.serverSettings.proxyAuthEnabled) return null - if (!email) { - return null - } + const uHeader = Database.serverSettings.proxyAuthUsernameHeader.toLowerCase() + const eHeader = Database.serverSettings.proxyAuthEmailHeader.toLowerCase() - const account = { - username, - email, + return { + username: uHeader ? headers[uHeader] : null, + email: eHeader ? headers[eHeader] : null, + } + } + + async getProxyUser(account) { + const user = await Database.userModel.getUserByUsername(account.username) + if (user) return user; + + // we need an email to create accounts + if (!account.email) return null; + + // add some fields for proxy users + account = { + ...account, type: 'user', isActive: true, } diff --git a/server/SocketAuthority.js b/server/SocketAuthority.js index 86f94d3d8..cc9f48895 100644 --- a/server/SocketAuthority.js +++ b/server/SocketAuthority.js @@ -36,8 +36,8 @@ class SocketAuthority { /** * Emits event to all authorized clients - * @param {string} evt - * @param {any} data + * @param {string} evt + * @param {any} data * @param {Function} [filter] optional filter function to only send event to specific users */ emitter(evt, data, filter = null) { @@ -147,7 +147,7 @@ class SocketAuthority { // When setting up a socket connection the user needs to be associated with a socket id // for this the client will send a 'auth' event that includes the users API token async authenticateSocket(socket, token) { - const user = await this.Server.auth.authenticateUser(token) + const user = await this.Server.auth.authenticateUser(token, socket.handshake.headers) if (!user) { Logger.error('Cannot validate socket - invalid token') return socket.emit('invalid_token') @@ -169,7 +169,7 @@ class SocketAuthority { return } - Logger.debug(`[SocketAuthority] User Online ${client.user.username}`) + Logger.debug(`[SocketAuthority] User Online ${client.user.username} (FromProxy: ${user.isFromProxy})`) this.adminEmitter('user_online', client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions)) @@ -212,4 +212,4 @@ class SocketAuthority { this.Server.cancelLibraryScan(id) } } -module.exports = new SocketAuthority() \ No newline at end of file +module.exports = new SocketAuthority()