jellyfin-accounts/jellyfin_accounts/login.py

126 lines
3.9 KiB
Python
Raw Normal View History

2020-04-11 16:20:25 +02:00
#!/usr/bin/env python3
from flask_httpauth import HTTPBasicAuth
2020-06-21 21:29:53 +02:00
from itsdangerous import (
TimedJSONWebSignatureSerializer as Serializer,
BadSignature,
SignatureExpired,
)
2020-04-11 16:20:25 +02:00
from passlib.apps import custom_app_context as pwd_context
import uuid
from jellyfin_accounts import config, app, g
from jellyfin_accounts import auth_log as log
from jellyfin_accounts.jf_api import Jellyfin
from jellyfin_accounts.web_api import jf
2020-04-11 16:20:25 +02:00
2020-06-21 21:29:53 +02:00
auth_jf = Jellyfin(
config["jellyfin"]["server"],
config["jellyfin"]["client"],
config["jellyfin"]["version"],
config["jellyfin"]["device"],
config["jellyfin"]["device_id"] + "_authClient",
)
2020-06-21 21:29:53 +02:00
class Account:
def __init__(self, username=None, password=None):
2020-04-11 16:20:25 +02:00
self.username = username
if password is not None:
self.password_hash = pwd_context.hash(password)
self.id = str(uuid.uuid4())
self.jf = False
elif username is not None:
2020-06-21 21:29:53 +02:00
jf.authenticate(
config["jellyfin"]["username"], config["jellyfin"]["password"]
)
self.id = jf.getUsers(self.username, public=False)["Id"]
self.jf = True
2020-06-21 21:29:53 +02:00
2020-04-11 16:20:25 +02:00
def verify_password(self, password):
if not self.jf:
return pwd_context.verify(password, self.password_hash)
else:
try:
return auth_jf.authenticate(self.username, password)
except Jellyfin.AuthenticationError:
return False
2020-06-21 21:29:53 +02:00
2020-04-11 16:20:25 +02:00
def generate_token(self, expiration=1200):
2020-06-21 21:29:53 +02:00
s = Serializer(app.config["SECRET_KEY"], expires_in=expiration)
log.debug(self.id)
2020-06-21 21:29:53 +02:00
return s.dumps({"id": self.id})
2020-04-11 16:20:25 +02:00
@staticmethod
def verify_token(token, accounts):
2020-06-21 21:29:53 +02:00
log.debug(f"verifying token {token}")
s = Serializer(app.config["SECRET_KEY"])
2020-04-11 16:20:25 +02:00
try:
data = s.loads(token)
except SignatureExpired:
return None
except BadSignature:
return None
2020-06-21 21:29:53 +02:00
if config.getboolean("ui", "jellyfin_login"):
for account in accounts:
2020-06-21 21:29:53 +02:00
if data["id"] == accounts[account].id:
return account
else:
2020-06-21 21:29:53 +02:00
return accounts["adminAccount"]
2020-04-11 16:20:25 +02:00
auth = HTTPBasicAuth()
accounts = {}
2020-04-11 16:20:25 +02:00
2020-06-21 21:29:53 +02:00
if config.getboolean("ui", "jellyfin_login"):
log.debug("Using jellyfin for admin authentication")
else:
2020-06-21 21:29:53 +02:00
log.debug("Using configured login details for admin authentication")
accounts["adminAccount"] = Account(
config["ui"]["username"], config["ui"]["password"]
)
2020-04-11 16:20:25 +02:00
@auth.verify_password
def verify_password(username, password):
user = None
verified = False
2020-06-21 21:29:53 +02:00
log.debug("Verifying auth")
if config.getboolean("ui", "jellyfin_login"):
try:
jf_user = jf.getUsers(username, public=False)
2020-06-21 21:29:53 +02:00
id = jf_user["Id"]
user = accounts[id]
except KeyError:
2020-06-21 21:29:53 +02:00
if config.getboolean("ui", "admin_only"):
if jf_user["Policy"]["IsAdministrator"]:
user = Account(username)
accounts[id] = user
else:
2020-06-21 21:29:53 +02:00
log.debug(f"User {username} not admin.")
return False
else:
user = Account(username)
accounts[id] = user
except Jellyfin.UserNotFoundError:
user = Account().verify_token(username, accounts)
if user:
verified = True
if not user:
2020-06-21 21:29:53 +02:00
log.debug(f"User {username} not found on Jellyfin")
return False
else:
2020-06-21 21:29:53 +02:00
user = accounts["adminAccount"]
verified = Account().verify_token(username, accounts)
if not verified:
if username == user.username and user.verify_password(password):
g.user = user
2020-04-12 22:25:27 +02:00
log.debug("HTTPAuth Allowed")
2020-04-11 16:20:25 +02:00
return True
else:
2020-04-12 22:25:27 +02:00
log.debug("HTTPAuth Denied")
2020-04-11 16:20:25 +02:00
return False
g.user = user
2020-04-12 22:25:27 +02:00
log.debug("HTTPAuth Allowed")
2020-04-11 16:20:25 +02:00
return True