seafdav/wsgidav/dc/domain_controller.py
2024-02-22 11:16:29 +08:00

123 lines
4.2 KiB
Python

import os
import posixpath
import ccnet
from pysearpc import SearpcError
from wsgidav.dc.seaf_utils import CCNET_CONF_DIR, SEAFILE_CENTRAL_CONF_DIR, multi_tenancy_enabled
from wsgidav.dc import seahub_db
import wsgidav.util as util
from wsgidav.dc.base_dc import BaseDomainController
# basic_auth_user, get_domain_realm, require_authentication
_logger = util.get_module_logger(__name__)
# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 32
import base64
PADDING = '{'
# An encrypted block size must be a multiple of 16
pad = lambda s: s + (16 - len(s) % 16) * PADDING
# encrypt with AES, encode with base64
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
class SeafileDomainController(BaseDomainController):
def __init__(self, wsgidav_app, config):
self.ccnet_threaded_rpc = ccnet.CcnetThreadedRpcClient(posixpath.join(CCNET_CONF_DIR, 'ccnet-rpc.sock'))
self.session_cls = seahub_db.init_db_session_class()
def __repr__(self):
return self.__class__.__name__
def supports_http_digest_auth(self):
# We have access to a plaintext password (or stored hash)
return True
def get_domain_realm(self, inputURL, environ):
return "Seafile Authentication"
def require_authentication(self, realmname, envrion):
return True
def isRealmUser(self, realmname, username, environ):
return True
def getRealmUserPassword(self, realmname, username, environ):
"""
Not applicable to seafile.
"""
return ""
def basic_auth_user(self, realmname, username, password, environ):
if "'" in username:
return False
try:
ccnet_email = None
session = None
if self.session_cls:
session = self.session_cls()
user = self.ccnet_threaded_rpc.get_emailuser(username)
if user:
ccnet_email = user.email
else:
if session:
profile_profile = Base.classes.profile_profile
q = session.query(profile_profile.user).filter(profile_profile.contact_email==username)
res = q.first()
if res:
ccnet_email = res[0]
if not ccnet_email:
_logger.warning('User %s doesn\'t exist', username)
if session:
session.close()
return False
if self.ccnet_threaded_rpc.validate_emailuser(ccnet_email, password) != 0:
if not session:
return False
else:
from Crypto.Cipher import AES
import seahub_settings
secret = seahub_settings.SECRET_KEY[:BLOCK_SIZE]
cipher = AES.new(secret, AES.MODE_ECB)
encoded_str = 'aes$' + EncodeAES(cipher, password)
options_useroptions = Base.classes.options_useroptions
q = session.query(options_useroptions.email)
q = q.filter(options_useroptions.email==ccnet_email,
options_useroptions.option_val==encoded_str)
res = q.first()
if not res:
session.close()
return False
if session:
session.close()
username = ccnet_email
except Exception as e:
_logger.warning('Failed to login: %s', e)
return False
try:
user = self.ccnet_threaded_rpc.get_emailuser_with_import(username)
if user.role == 'guest':
environ['seafile.is_guest'] = True
else:
environ['seafile.is_guest'] = False
except Exception as e:
_logger.exception('get_emailuser')
if multi_tenancy_enabled():
try:
orgs = self.ccnet_threaded_rpc.get_orgs_by_user(username)
if orgs:
environ['seafile.org_id'] = orgs[0].org_id
except Exception as e:
_logger.exception('get_orgs_by_user')
pass
environ["http_authenticator.username"] = username
return True