mirror of
https://github.com/hexparrot/mineos
synced 2025-10-06 00:02:56 +02:00
mounts are no longer passed paths, instead the variables are used directly from the cherrypy.config localization removed as instance variable; referenced as cherrypy.config attribute instead sanitization added to misc.localization
131 lines
4.3 KiB
Python
131 lines
4.3 KiB
Python
# -*- encoding: UTF-8 -*-
|
|
#
|
|
# Form based authentication for CherryPy. Requires the
|
|
# Session tool to be loaded.
|
|
#
|
|
|
|
import cherrypy
|
|
|
|
SESSION_KEY = '_cp_username'
|
|
|
|
def check_credentials(username, password):
|
|
"""Verifies credentials for username and password.
|
|
Returns None on success or a string describing the error on failure"""
|
|
from spwd import getspnam
|
|
from crypt import crypt
|
|
|
|
try:
|
|
enc_pwd = getspnam(username)[1]
|
|
except KeyError:
|
|
raise OSError("user '%s' not found" % username)
|
|
else:
|
|
if enc_pwd in ['NP', '!', '', None]:
|
|
raise OSError("user '%s' has no password set" % username)
|
|
elif enc_pwd in ['LK', '*']:
|
|
raise OSError('account is locked')
|
|
elif enc_pwd == "!!":
|
|
raise OSError('password is expired')
|
|
|
|
if crypt(password, enc_pwd) == enc_pwd:
|
|
return True
|
|
else:
|
|
raise OSError('incorrect password')
|
|
|
|
def unix_authenticate(username, password):
|
|
"""Fallback authentication for BSD"""
|
|
from crypt import crypt
|
|
from pwd import getpwnam
|
|
|
|
cryptedpasswd = getpwnam(username)[1]
|
|
if cryptedpasswd:
|
|
if cryptedpasswd == 'x' or cryptedpasswd == '*':
|
|
raise NotImplementedError("Shadow passwords not supported")
|
|
return crypt(password, cryptedpasswd) == cryptedpasswd
|
|
else:
|
|
return False
|
|
|
|
def check_auth(*args, **kwargs):
|
|
"""A tool that looks in config for 'auth.require'. If found and it
|
|
is not None, a login is required and the entry is evaluated as a list of
|
|
conditions that the user must fulfill"""
|
|
conditions = cherrypy.request.config.get('auth.require', None)
|
|
if conditions is not None:
|
|
username = cherrypy.session.get(SESSION_KEY)
|
|
if username:
|
|
cherrypy.request.login = username
|
|
for condition in conditions:
|
|
# A condition is just a callable that returns true or false
|
|
if not condition():
|
|
raise cherrypy.HTTPRedirect("/auth/login")
|
|
else:
|
|
raise cherrypy.HTTPRedirect("/auth/login")
|
|
|
|
cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
|
|
|
|
def require(*conditions):
|
|
"""A decorator that appends conditions to the auth.require config
|
|
variable."""
|
|
def decorate(f):
|
|
if not hasattr(f, '_cp_config'):
|
|
f._cp_config = dict()
|
|
if 'auth.require' not in f._cp_config:
|
|
f._cp_config['auth.require'] = []
|
|
f._cp_config['auth.require'].extend(conditions)
|
|
return f
|
|
return decorate
|
|
|
|
# Controller to provide login and logout actions
|
|
|
|
class AuthController(object):
|
|
def __init__(self):
|
|
self.html_directory = cherrypy.config['misc.html_directory']
|
|
|
|
def on_login(self, username):
|
|
"""Called on successful login"""
|
|
|
|
def on_logout(self, username):
|
|
"""Called on logout"""
|
|
|
|
def get_loginform(self):
|
|
import os
|
|
from cherrypy.lib.static import serve_file
|
|
|
|
try:
|
|
return serve_file(os.path.join(self.html_directory,
|
|
'login_%s.html' % cherrypy.config['misc.localization']))
|
|
except cherrypy.NotFound:
|
|
return serve_file(os.path.join(self.html_directory,
|
|
'login_en.html'))
|
|
|
|
@cherrypy.expose
|
|
def login(self, username=None, password=None, hide=None, from_page='/'):
|
|
if not username or not password:
|
|
return self.get_loginform()
|
|
|
|
validated = False
|
|
try:
|
|
validated = check_credentials(username, password)
|
|
except OSError:
|
|
import pam
|
|
validated = pam.authenticate(username, password)
|
|
except ImportError:
|
|
validated = unix_authenticate(username, password)
|
|
finally:
|
|
if validated:
|
|
cherrypy.session.regenerate()
|
|
cherrypy.session[SESSION_KEY] = cherrypy.request.login = username
|
|
self.on_login(username)
|
|
raise cherrypy.HTTPRedirect("/")
|
|
else:
|
|
return self.get_loginform()
|
|
|
|
@cherrypy.expose
|
|
def logout(self):
|
|
sess = cherrypy.session
|
|
username = sess.get(SESSION_KEY, None)
|
|
sess[SESSION_KEY] = None
|
|
if username:
|
|
cherrypy.request.login = None
|
|
self.on_logout(username)
|
|
raise cherrypy.HTTPRedirect("/index")
|