mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-15 01:32:57 -07:00
Add Plex OAuth to login page
This commit is contained in:
parent
b49e500221
commit
3bd1b03faf
4 changed files with 273 additions and 63 deletions
|
@ -19,7 +19,6 @@
|
|||
# Session tool to be loaded.
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import re
|
||||
from urllib import quote, unquote
|
||||
|
||||
import cherrypy
|
||||
|
@ -37,17 +36,27 @@ JWT_ALGORITHM = 'HS256'
|
|||
JWT_COOKIE_NAME = 'tautulli_token_'
|
||||
|
||||
|
||||
def user_login(username=None, password=None):
|
||||
if not username or not password:
|
||||
return None
|
||||
def user_login(username=None, password=None, token=None):
|
||||
user_token = None
|
||||
user_id = None
|
||||
|
||||
# Try to login to Plex.tv to check if the user has a vaild account
|
||||
plex_tv = PlexTV(username=username, password=password)
|
||||
plex_user = plex_tv.get_token()
|
||||
if plex_user:
|
||||
user_token = plex_user['auth_token']
|
||||
user_id = plex_user['user_id']
|
||||
if username and password:
|
||||
plex_tv = PlexTV(username=username, password=password)
|
||||
plex_user = plex_tv.get_token()
|
||||
if plex_user:
|
||||
user_token = plex_user['auth_token']
|
||||
user_id = plex_user['user_id']
|
||||
elif token:
|
||||
plex_tv = PlexTV(token=token)
|
||||
plex_user = plex_tv.get_plex_account_details()
|
||||
if plex_user:
|
||||
user_token = token
|
||||
user_id = plex_user['user_id']
|
||||
else:
|
||||
return None
|
||||
|
||||
if user_token and user_id:
|
||||
# Try to retrieve the user from the database.
|
||||
# Also make sure guest access is enabled for the user and the user is not deleted.
|
||||
user_data = Users()
|
||||
|
@ -57,7 +66,7 @@ def user_login(username=None, password=None):
|
|||
return None
|
||||
elif plexpy.CONFIG.HTTP_PLEX_ADMIN and user_details['is_admin']:
|
||||
# Plex admin login
|
||||
return 'admin'
|
||||
return user_details, 'admin'
|
||||
elif not user_details['allow_guest'] or user_details['deleted_user']:
|
||||
# Guest access is disabled or the user is deleted.
|
||||
return None
|
||||
|
@ -75,49 +84,64 @@ def user_login(username=None, password=None):
|
|||
# Register the new user / update the access tokens.
|
||||
monitor_db = MonitorDatabase()
|
||||
try:
|
||||
logger.debug(u"Tautulli WebAuth :: Regestering tokens for user '%s' in the database." % username)
|
||||
result = monitor_db.action('UPDATE users SET user_token = ?, server_token = ? WHERE user_id = ?',
|
||||
[user_token, server_token, user_id])
|
||||
logger.debug(u"Tautulli WebAuth :: Regestering tokens for user '%s' in the database."
|
||||
% user_details['username'])
|
||||
result = monitor_db.action('UPDATE users SET server_token = ? WHERE user_id = ?',
|
||||
[server_token, user_details['user_id']])
|
||||
|
||||
if result:
|
||||
# Refresh the users list to make sure we have all the correct permissions.
|
||||
refresh_users()
|
||||
# Successful login
|
||||
return 'guest'
|
||||
return user_details, 'guest'
|
||||
else:
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database." % username)
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database."
|
||||
% user_details['username'])
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database: %s." % (username, e))
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database: %s."
|
||||
% (user_details['username'], e))
|
||||
return None
|
||||
else:
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv server token for user '%s'." % username)
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv server token for user '%s'."
|
||||
% user_details['username'])
|
||||
return None
|
||||
else:
|
||||
elif username:
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for user '%s'." % username)
|
||||
return None
|
||||
|
||||
return None
|
||||
elif token:
|
||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for Plex OAuth.")
|
||||
return None
|
||||
|
||||
|
||||
def check_credentials(username, password, admin_login='0'):
|
||||
def check_credentials(username=None, password=None, token=None, admin_login='0'):
|
||||
"""Verifies credentials for username and password.
|
||||
Returns True and the user group on success or False and no user group"""
|
||||
|
||||
if plexpy.CONFIG.HTTP_PASSWORD:
|
||||
if plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||
username == plexpy.CONFIG.HTTP_USERNAME and check_hash(password, plexpy.CONFIG.HTTP_PASSWORD):
|
||||
return True, 'tautulli admin'
|
||||
elif not plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||
username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
||||
return True, 'tautulli admin'
|
||||
if username and password:
|
||||
if plexpy.CONFIG.HTTP_PASSWORD:
|
||||
user_details = {'user_id': None, 'username': username}
|
||||
|
||||
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
||||
plex_login = user_login(username, password)
|
||||
if plex_login is not None:
|
||||
return True, plex_login
|
||||
if plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||
username == plexpy.CONFIG.HTTP_USERNAME and check_hash(password, plexpy.CONFIG.HTTP_PASSWORD):
|
||||
return True, user_details, 'admin'
|
||||
elif not plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||
username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
||||
return True, user_details, 'admin'
|
||||
|
||||
return False, None
|
||||
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
||||
plex_login = user_login(username=username, password=password)
|
||||
if plex_login is not None:
|
||||
return True, plex_login[0], plex_login[1]
|
||||
|
||||
elif token:
|
||||
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
||||
plex_login = user_login(token=token)
|
||||
if plex_login is not None:
|
||||
return True, plex_login[0], plex_login[1]
|
||||
|
||||
return False, None, None
|
||||
|
||||
|
||||
def check_jwt_token():
|
||||
|
@ -279,41 +303,33 @@ class AuthController(object):
|
|||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def signin(self, username=None, password=None, remember_me='0', admin_login='0', *args, **kwargs):
|
||||
def signin(self, username=None, password=None, token=None, remember_me='0', admin_login='0', *args, **kwargs):
|
||||
if cherrypy.request.method != 'POST':
|
||||
cherrypy.response.status = 405
|
||||
return {'status': 'error', 'message': 'Sign in using POST.'}
|
||||
|
||||
error_message = {'status': 'error', 'message': 'Incorrect username or password.'}
|
||||
error_message = {'status': 'error', 'message': 'Invalid credentials.'}
|
||||
|
||||
valid_login, user_group = check_credentials(username, password, admin_login)
|
||||
valid_login, user_details, user_group = check_credentials(username=username,
|
||||
password=password,
|
||||
token=token,
|
||||
admin_login=admin_login)
|
||||
|
||||
if valid_login:
|
||||
if user_group == 'tautulli admin':
|
||||
user_group = 'admin'
|
||||
user_id = None
|
||||
else:
|
||||
if re.match(r"[^@]+@[^@]+\.[^@]+", username):
|
||||
user_details = Users().get_details(email=username)
|
||||
else:
|
||||
user_details = Users().get_details(user=username)
|
||||
|
||||
user_id = user_details['user_id']
|
||||
|
||||
time_delta = timedelta(days=30) if remember_me == '1' else timedelta(minutes=60)
|
||||
expiry = datetime.utcnow() + time_delta
|
||||
|
||||
payload = {
|
||||
'user_id': user_id,
|
||||
'user': username,
|
||||
'user_id': user_details['user_id'],
|
||||
'user': user_details['username'],
|
||||
'user_group': user_group,
|
||||
'exp': expiry
|
||||
}
|
||||
|
||||
jwt_token = jwt.encode(payload, plexpy.CONFIG.JWT_SECRET, algorithm=JWT_ALGORITHM)
|
||||
|
||||
self.on_login(username=username,
|
||||
user_id=user_id,
|
||||
self.on_login(username=user_details['username'],
|
||||
user_id=user_details['user_id'],
|
||||
user_group=user_group,
|
||||
success=1)
|
||||
|
||||
|
@ -326,14 +342,36 @@ class AuthController(object):
|
|||
cherrypy.response.status = 200
|
||||
return {'status': 'success', 'token': jwt_token.decode('utf-8'), 'uuid': plexpy.CONFIG.PMS_UUID}
|
||||
|
||||
elif admin_login == '1':
|
||||
elif admin_login == '1' and username:
|
||||
self.on_login(username=username)
|
||||
logger.debug(u"Tautulli WebAuth :: Invalid admin login attempt from '%s'." % username)
|
||||
cherrypy.response.status = 401
|
||||
return error_message
|
||||
|
||||
else:
|
||||
elif username:
|
||||
self.on_login(username=username)
|
||||
logger.debug(u"Tautulli WebAuth :: Invalid login attempt from '%s'." % username)
|
||||
logger.debug(u"Tautulli WebAuth :: Invalid user login attempt from '%s'." % username)
|
||||
cherrypy.response.status = 401
|
||||
return error_message
|
||||
|
||||
elif token:
|
||||
logger.debug(u"Tautulli WebAuth :: Invalid Plex OAuth login attempt.")
|
||||
cherrypy.response.status = 401
|
||||
return error_message
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def get_plex_oauth_url(self, *args, **kwargs):
|
||||
pin = PlexTV().get_pin()
|
||||
oauth_url = 'https://app.plex.tv/auth/#!?clientID={}&code={}'.format(
|
||||
plexpy.CONFIG.PMS_UUID, pin['code'])
|
||||
return {'pin': pin['id'], 'url': oauth_url}
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def pin(self, pin=None, *args, **kwargs):
|
||||
pin = PlexTV().get_pin(pin=pin)
|
||||
if pin['token']:
|
||||
return {'result': 'success', 'token': pin['token']}
|
||||
else:
|
||||
return {'result': 'polling'}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue