【山大智云开发日志】seafdav分析(9)

2021SC@SDUSC

http_authenticator.py。是用于HTTP基本和摘要认证的WSGI中间件。

用法:从http_authenticator导入httpauthentication

WSGIApp = HTTPAuthenticator(ProtectedWSGIApp, domain_controller, accept_basic,

accept_digest default_to_digest)

ProtectedWSGIApp是需要身份验证访问的应用程序

Domain_controller是满足特定要求的域控制器对象

Accept_basic是一个布尔值,指示是否使用基本身份验证方案(默认= True)

Accept_digest是一个布尔值,指示是否使用摘要身份验证方案(default = True)

Default_to_digest是一个布尔值。如果为True,则未经身份验证的请求将发送需要验证的摘要响应,否则为未验证。请求将发送基本的认证要求响应(默认= True)

HTTPAuthenticator将把以下经过验证的信息放入

环境字典:

[" wsgidav.auth包围。Realm "] =域名

[" wsgidav.auth包围。user_name "] = user_name

[" wsgidav.auth包围。角色"]= (可选)

[" wsgidav.auth包围。权限"]= (可选)

HTTP基本和摘要身份验证方案基于以下内容概念:

每个请求的相对URI都可以解析到一个域进行身份验证,

例如:

/fac_eng/courses/ee5903/timetable.pdf ->可能会解决领域“工程通用”

/fac_eng/examsolns/ee5903/thisyearssolns.pdf ->可能会解决“工程讲师”领域

/med_sci/courses/m500/surgery.htm ->可能会解决到领域“医学科学一般”

每个领域都有一组user_name和密码对允许访问资源。

域控制器将此信息提供给HTTPAuthenticator。这允许开发人员编写他们自己的域控制器,

例如,与自己的用户数据库接口。对于简单的应用程序,提供了一个SimpleDomainController,它将执行在单个域名(用于显示)和user_name(键)的单个字典中和密码(值)字符串对

用法:

从wsgidav.dc,simple_dc进入SimpleDomainController

users = dict(({'John Smith': 'YouNeverGuessMe', 'Dan Brown': 'DontGuessMeEither'})

realm = '示例领域'

domain_controller = SimpleDomainController(用户,领域)

域控制器必须提供中描述的方法

' ' wsgidav.interfaces.domaincontrollerinterface ' ' (interface_)

.. / domaincontrollerinterface.py _interface:接口

这里的environ变量是WSGI 'environ'字典。它被传递给域控制器的所有方法作为开发人员传递信息的手段,从以前的中间件或服务器配置(如果需要)。

改文件主要是使域控制器,和HTTP身份验证两个部分。HTTP身份验证已经在上面详细描述了。

域控制器主要代码。


def make_domain_controller(wsgidav_app, config):
    dc = config.get("http_authenticator", {}).get("domain_controller")
    org_dc = dc
    if dc is True or not dc:
        # True or null:
        dc = SimpleDomainController
    elif compat.is_basestring(dc):
        # If a plain string is passed, try to import it as class
        dc = dynamic_import_class(dc)

    if inspect.isclass(dc):
        # If a class is passed, instantiate that
        dc = dc(wsgidav_app, config)
    else:
        raise RuntimeError(
            "Could not resolve domain controller class (got {})".format(org_dc)
        )
    # print("make_domain_controller", dc)
    return dc

def compute_digest_response是在http身份验证中起到重要作用的函数。其主要负责计算消化散列。A1 (HA1)部分的计算委托直流接口法进行“digest_auth_user()”。

参数:

realm(str):

user_name (str):

method(str): WebDAV请求方法

uri (str):

Nonce (str):服务器生成的Nonce值

Cnonce (str):客户端生成的Cnonce值

Qop (str):防护质量

Nc (str) (number), nonce计数器由客户端递增

返回:MD5哈希字符串,如果用户被域控制器拒绝,则为False

代码

 def compute_digest_response(
        self, realm, user_name, method, uri, nonce, cnonce, qop, nc, environ
    ):

        def md5h(data):
            return md5(compat.to_bytes(data)).hexdigest()

        def md5kd(secret, data):
            return md5h(secret + ":" + data)

        A1 = self.domain_controller.digest_auth_user(realm, user_name, environ)
        if not A1:
            return False

        A2 = method + ":" + uri

        if qop:
            res = md5kd(
                A1, nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + md5h(A2)
            )
        else:
            res = md5kd(A1, nonce + ":" + md5h(A2))

        return res

lock_manager.py。实现提供锁定功能的‘LockManager’对象。

LockManager需要一个LockStorage对象来实现持久性。在lock_storage模块中定义了两个替代的锁存储类:wsgidav.lock_storage.LockStorageDict和wsgidav.lock_storage.LockStorageShelve。

锁数据模型是一个包含以下字段的字典:

root:资源URL。

 principal:创建锁的经过身份验证的用户名。

type:必须是“写”。

 scope:必须是“共享的”或“独占的”。

depth:必须是“0”或“无穷大”。

owner:标识所有者的字符串。

timeout:距离锁定过期还有几秒。这个值传递给create()和refresh()

expire:转换的持久性超时:expire = time() + timeout。

token:自动生成的唯一标记。

文件中名为LockManager的类是核心部分。其主要负责使用自定义存储层实现锁定功能。

函数acquire负责检查权限并获取锁。成功返回新的锁字典。如果出现错误,引发带有嵌入式DAVErrorCondition的DAVError。

代码

def acquire(self,url,lock_type,lock_scope,lock_depth,lock_owner,timeout,principal,token_list,):
       url = normalize_lock_root(url)
        self._lock.acquire_write()
        try:
            # Raises DAVError on conflict:
            self._check_lock_permission(
                url, lock_type, lock_scope, lock_depth, token_list, principal
            )
            return self._generate_lock(
                principal, lock_type, lock_scope, lock_depth, lock_owner, url, timeout
            )
        finally:
            self._lock.release()

函数get_lock,返回lock_dict,如果没有找到或无效,返回None。副作用:如果锁过期,它将被清除并返回None。关键:将被返回的锁属性名称,而不是一个字典。

    def get_lock(self, token, key=None):
        assert key in (
            None,
            "type",
            "scope",
            "depth",
            "owner",
            "root",
            "timeout",
            "principal",
            "token",
        )
        lock = self.storage.get(token)
        if key is None or lock is None:
            return lock
        return lock[key]

函数get_indirect_url_lock_list,返回一个有效的lockdict列表,该列表直接或间接地保护。如果给定一个主体,则只返回该主体拥有的锁。副作用:此路径的锁过期,所有父路径都会被清除。

    def get_indirect_url_lock_list(self, url, principal=None):
        """Return a list of valid lockDicts, that protect <path> directly or indirectly.

        If a principal is given, only locks owned by this principal are returned.
        Side effect: expired locks for this path and all parents are purged.
        """
        url = normalize_lock_root(url)
        lockList = []
        u = url
        while u:
            lock_list = self.storage.get_lock_list(
                u, include_root=True, include_children=False, token_only=False
            )
            for lock in lock_list:
                if u != url and lock["depth"] != "infinity":
                    continue  # We only consider parents with Depth: infinity
                # TODO: handle shared locks in some way?
                #                if (lock["scope"] == "shared" and lock_scope == "shared"
                #                   and principal != lock["principal"]):
                # continue  # Only compatible with shared locks by other users
                if principal is None or principal == lock["principal"]:
                    lockList.append(lock)
            u = util.get_uri_parent(u)
        return lockList

函数_check_lock_permission检查,如果可以锁定,否则将引发错误。如果锁定会创建冲突,则会引发DAVError(HTTP_LOCKED)。嵌入的DAVErrorCondition包含冲突资源。

代码

    def _check_lock_permission(
        self, url, lock_type, lock_scope, lock_depth, token_list, principal
    ):
        errcond = DAVErrorCondition(PRECONDITION_CODE_LockConflict)

        self._lock.acquire_read()
        try:
            # Check url and all parents for conflicting locks
            u = url
            while u:
                lock_list = self.get_url_lock_list(u)
                for lock in lock_list:
                    _logger.debug(
                        "    check parent {}, {}".format(u, lock_string(lock))
                    )
                    if u != url and lock["depth"] != "infinity":
                        # We only consider parents with Depth: infinity
                        continue
                    elif lock["scope"] == "shared" and lock_scope == "shared":
                        # Only compatible with shared locks (even by same
                        # principal)
                        continue
                    # Lock conflict
                    _logger.debug(
                        " -> DENIED due to locked parent {}".format(lock_string(lock))
                    )
                    errcond.add_href(lock["root"])
                u = util.get_uri_parent(u)

            if lock_depth == "infinity":
                # Check child URLs for conflicting locks
                child_ocks = self.storage.get_lock_list(
                    url, include_root=False, include_children=True, token_only=False
                )

                for lock in child_ocks:
                    assert util.is_child_uri(url, lock["root"])
                    #                    if util.is_child_uri(url, lock["root"]):
                    _logger.debug(
                        " -> DENIED due to locked child {}".format(lock_string(lock))
                    )
                    errcond.add_href(lock["root"])
        finally:
            self._lock.release()

        # If there were conflicts, raise HTTP_LOCKED for <url>, and pass
        # conflicting resource with 'no-conflicting-lock' precondition
        if len(errcond.hrefs) > 0:
            raise DAVError(HTTP_LOCKED, err_condition=errcond)
        return

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值