mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-10 23:42:37 -07:00
Store JWT token in database
This commit is contained in:
parent
6c34e2cb22
commit
da1c342971
3 changed files with 63 additions and 10 deletions
|
@ -723,7 +723,8 @@ def dbcheck():
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS user_login (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
'CREATE TABLE IF NOT EXISTS user_login (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||||
'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, '
|
'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, '
|
||||||
'ip_address TEXT, host TEXT, user_agent TEXT, success INTEGER DEFAULT 1)'
|
'ip_address TEXT, host TEXT, user_agent TEXT, success INTEGER DEFAULT 1,'
|
||||||
|
'expiry TEXT, jwt_token TEXT)'
|
||||||
)
|
)
|
||||||
|
|
||||||
# notifiers table :: This table keeps record of the notification agent settings
|
# notifiers table :: This table keeps record of the notification agent settings
|
||||||
|
@ -2300,6 +2301,18 @@ def dbcheck():
|
||||||
'ALTER TABLE user_login ADD COLUMN success INTEGER DEFAULT 1'
|
'ALTER TABLE user_login ADD COLUMN success INTEGER DEFAULT 1'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade user_login table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT expiry FROM user_login')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug("Altering database. Updating database table user_login.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE user_login ADD COLUMN expiry TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE user_login ADD COLUMN jwt_token TEXT'
|
||||||
|
)
|
||||||
|
|
||||||
# Rename notifiers in the database
|
# Rename notifiers in the database
|
||||||
result = c_db.execute('SELECT agent_label FROM notifiers '
|
result = c_db.execute('SELECT agent_label FROM notifiers '
|
||||||
'WHERE agent_label = "XBMC" OR agent_label = "OSX Notify"').fetchone()
|
'WHERE agent_label = "XBMC" OR agent_label = "OSX Notify"').fetchone()
|
||||||
|
|
|
@ -849,11 +849,15 @@ class Users(object):
|
||||||
|
|
||||||
return filters_list
|
return filters_list
|
||||||
|
|
||||||
def set_user_login(self, user_id=None, user=None, user_group=None, ip_address=None, host=None, user_agent=None, success=0):
|
def set_user_login(self, user_id=None, user=None, user_group=None, ip_address=None, host=None,
|
||||||
|
user_agent=None, success=0, expiry=None, jwt_token=None):
|
||||||
|
|
||||||
if user_id is None or str(user_id).isdigit():
|
if user_id is None or str(user_id).isdigit():
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
if expiry is not None:
|
||||||
|
expiry = helpers.datetime_to_iso(expiry)
|
||||||
|
|
||||||
keys = {'timestamp': helpers.timestamp(),
|
keys = {'timestamp': helpers.timestamp(),
|
||||||
'user_id': user_id}
|
'user_id': user_id}
|
||||||
|
|
||||||
|
@ -862,13 +866,29 @@ class Users(object):
|
||||||
'ip_address': ip_address,
|
'ip_address': ip_address,
|
||||||
'host': host,
|
'host': host,
|
||||||
'user_agent': user_agent,
|
'user_agent': user_agent,
|
||||||
'success': success}
|
'success': success,
|
||||||
|
'expiry': expiry,
|
||||||
|
'jwt_token': jwt_token}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values)
|
monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn("Tautulli Users :: Unable to execute database query for set_login_log: %s." % e)
|
logger.warn("Tautulli Users :: Unable to execute database query for set_login_log: %s." % e)
|
||||||
|
|
||||||
|
def get_user_login(self, jwt_token):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
result = monitor_db.select_single('SELECT * FROM user_login '
|
||||||
|
'WHERE jwt_token = ?',
|
||||||
|
[jwt_token])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def clear_user_login_token(self, jwt_token):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
result = monitor_db.select_single('UPDATE user_login SET jwt_token = NULL '
|
||||||
|
'WHERE jwt_token = ?',
|
||||||
|
[jwt_token])
|
||||||
|
return result
|
||||||
|
|
||||||
def get_datatables_user_login(self, user_id=None, kwargs=None):
|
def get_datatables_user_login(self, user_id=None, kwargs=None):
|
||||||
default_return = {'recordsFiltered': 0,
|
default_return = {'recordsFiltered': 0,
|
||||||
'recordsTotal': 0,
|
'recordsTotal': 0,
|
||||||
|
|
|
@ -148,18 +148,28 @@ def check_credentials(username=None, password=None, token=None, admin_login='0',
|
||||||
return False, None, None
|
return False, None, None
|
||||||
|
|
||||||
|
|
||||||
def check_jwt_token():
|
def get_jwt_token():
|
||||||
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
||||||
jwt_token = cherrypy.request.cookie.get(jwt_cookie)
|
jwt_token = cherrypy.request.cookie.get(jwt_cookie)
|
||||||
|
|
||||||
|
if jwt_token:
|
||||||
|
return jwt_token.value
|
||||||
|
|
||||||
|
|
||||||
|
def check_jwt_token():
|
||||||
|
jwt_token = get_jwt_token()
|
||||||
|
|
||||||
if jwt_token:
|
if jwt_token:
|
||||||
try:
|
try:
|
||||||
payload = jwt.decode(
|
payload = jwt.decode(
|
||||||
jwt_token.value, plexpy.CONFIG.JWT_SECRET, leeway=timedelta(seconds=10), algorithms=[JWT_ALGORITHM]
|
jwt_token, plexpy.CONFIG.JWT_SECRET, leeway=timedelta(seconds=10), algorithms=[JWT_ALGORITHM]
|
||||||
)
|
)
|
||||||
except (jwt.DecodeError, jwt.ExpiredSignatureError):
|
except (jwt.DecodeError, jwt.ExpiredSignatureError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if not Users().get_user_login(jwt_token=jwt_token):
|
||||||
|
return None
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,7 +285,8 @@ class AuthController(object):
|
||||||
return
|
return
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
|
|
||||||
def on_login(self, username=None, user_id=None, user_group=None, success=False, oauth=False):
|
def on_login(self, username=None, user_id=None, user_group=None, success=False, oauth=False,
|
||||||
|
expiry=None, jwt_token=None):
|
||||||
"""Called on successful login"""
|
"""Called on successful login"""
|
||||||
|
|
||||||
# Save login to the database
|
# Save login to the database
|
||||||
|
@ -289,15 +300,21 @@ class AuthController(object):
|
||||||
ip_address=ip_address,
|
ip_address=ip_address,
|
||||||
host=host,
|
host=host,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
success=success)
|
success=success,
|
||||||
|
expiry=expiry,
|
||||||
|
jwt_token=jwt_token)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
use_oauth = 'Plex OAuth' if oauth else 'form'
|
use_oauth = 'Plex OAuth' if oauth else 'form'
|
||||||
logger.debug("Tautulli WebAuth :: %s user '%s' logged into Tautulli using %s login."
|
logger.debug("Tautulli WebAuth :: %s user '%s' logged into Tautulli using %s login."
|
||||||
% (user_group.capitalize(), username, use_oauth))
|
% (user_group.capitalize(), username, use_oauth))
|
||||||
|
|
||||||
def on_logout(self, username, user_group):
|
def on_logout(self, username, user_group, jwt_token=None):
|
||||||
"""Called on logout"""
|
"""Called on logout"""
|
||||||
|
jwt_token = get_jwt_token()
|
||||||
|
if jwt_token:
|
||||||
|
Users().clear_user_login_token(jwt_token=jwt_token)
|
||||||
|
|
||||||
logger.debug("Tautulli WebAuth :: %s user '%s' logged out of Tautulli." % (user_group.capitalize(), username))
|
logger.debug("Tautulli WebAuth :: %s user '%s' logged out of Tautulli." % (user_group.capitalize(), username))
|
||||||
|
|
||||||
def get_loginform(self, redirect_uri=''):
|
def get_loginform(self, redirect_uri=''):
|
||||||
|
@ -320,7 +337,8 @@ class AuthController(object):
|
||||||
|
|
||||||
payload = check_jwt_token()
|
payload = check_jwt_token()
|
||||||
if payload:
|
if payload:
|
||||||
self.on_logout(payload['user'], payload['user_group'])
|
self.on_logout(username=payload['user'],
|
||||||
|
user_group=payload['user_group'])
|
||||||
|
|
||||||
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
||||||
cherrypy.response.cookie[jwt_cookie] = ''
|
cherrypy.response.cookie[jwt_cookie] = ''
|
||||||
|
@ -380,7 +398,9 @@ class AuthController(object):
|
||||||
user_id=user_details['user_id'],
|
user_id=user_details['user_id'],
|
||||||
user_group=user_group,
|
user_group=user_group,
|
||||||
success=True,
|
success=True,
|
||||||
oauth=bool(token))
|
oauth=bool(token),
|
||||||
|
expiry=expiry,
|
||||||
|
jwt_token=jwt_token)
|
||||||
|
|
||||||
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
jwt_cookie = str(JWT_COOKIE_NAME + plexpy.CONFIG.PMS_UUID)
|
||||||
cherrypy.response.cookie[jwt_cookie] = jwt_token
|
cherrypy.response.cookie[jwt_cookie] = jwt_token
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue