jumpserver/apps/common/auth/signature.py

113 lines
3.9 KiB
Python
Raw Normal View History

Dev beta (#3048) * [Update] 统一url地址 * [Update] 修改api * [Update] 使用规范的签名 * [Update] 修改url * [Update] 修改swagger * [Update] 添加serializer class避免报错 * [Update] 修改token * [Update] 支持api key * [Update] 支持生成api key * [Update] 修改api重定向 * [Update] 修改翻译 * [Update] 添加说明文档 * [Update] 修复浏览器关闭后session不失效的问题 * [Update] 修改一些内容 * [Update] 修改 jms脚本 * [Update] 修改重定向 * [Update] 修改搜索trim * [Update] 修改搜索trim * [Update] 添加sys log * [Bugfix] 修改登陆错误 * [Update] 优化User操作private_token的接口 (#3091) * [Update] 优化User操作private_token的接口 * [Update] 优化User操作private_token的接口 2 * [Bugfix] 解决授权了一个节点,当移动节点后,被移动的节点下的资产会放到未分组节点下的问题 * [Update] 升级jquery * [Update] 默认使用page * [Update] 修改使用Orgmodel view set * [Update] 支持 nv的硬盘 https://github.com/jumpserver/jumpserver/issues/1804 * [UPdate] 解决命令执行宽度问题 * [Update] 优化节点 * [Update] 修改nodes过多时创建比较麻烦 * [Update] 修改导入 * [Update] 节点获取更新 * [Update] 修改nodes * [Update] nodes显示full value * [Update] 统一使用nodes select2 函数 * [Update] 修改磁盘大小小数 * [Update] 修改 Node service * [Update] 优化授权节点 * [Update] 修改 node permission * [Update] 修改asset permission * [Stash] * [Update] 修改node assets api * [Update] 修改tree service,支持资产数量 * [Update] 修改暂时完成 * [Update] 修改一些bug
2019-08-21 12:27:21 +00:00
from rest_framework import authentication
from rest_framework import exceptions
from httpsig import HeaderVerifier, utils
"""
Reusing failure exceptions serves several purposes:
1. Lack of useful information regarding the failure inhibits attackers
from learning about valid keyIDs or other forms of information leakage.
Using the same actual object for any failure makes preventing such
leakage through mistakenly-distinct error messages less likely.
2. In an API scenario, the object is created once and raised many times
rather than generated on every failure, which could lead to higher loads
or memory usage in high-volume attack scenarios.
"""
FAILED = exceptions.AuthenticationFailed('Invalid signature.')
class SignatureAuthentication(authentication.BaseAuthentication):
"""
DRF authentication class for HTTP Signature support.
You must subclass this class in your own project and implement the
`fetch_user_data(self, keyId, algorithm)` method, returning a tuple of
the User object and a bytes object containing the user's secret. Note
that key_id and algorithm are DIRTY as they are supplied by the client
and so must be verified in your subclass!
You may set the following class properties in your subclass to configure
authentication for your particular use case:
:param www_authenticate_realm: Default: "api"
:param required_headers: Default: ["(request-target)", "date"]
"""
www_authenticate_realm = "api"
required_headers = ["(request-target)", "date"]
def fetch_user_data(self, key_id, algorithm=None):
"""Returns a tuple (User, secret) or (None, None)."""
Dev beta (#3048) * [Update] 统一url地址 * [Update] 修改api * [Update] 使用规范的签名 * [Update] 修改url * [Update] 修改swagger * [Update] 添加serializer class避免报错 * [Update] 修改token * [Update] 支持api key * [Update] 支持生成api key * [Update] 修改api重定向 * [Update] 修改翻译 * [Update] 添加说明文档 * [Update] 修复浏览器关闭后session不失效的问题 * [Update] 修改一些内容 * [Update] 修改 jms脚本 * [Update] 修改重定向 * [Update] 修改搜索trim * [Update] 修改搜索trim * [Update] 添加sys log * [Bugfix] 修改登陆错误 * [Update] 优化User操作private_token的接口 (#3091) * [Update] 优化User操作private_token的接口 * [Update] 优化User操作private_token的接口 2 * [Bugfix] 解决授权了一个节点,当移动节点后,被移动的节点下的资产会放到未分组节点下的问题 * [Update] 升级jquery * [Update] 默认使用page * [Update] 修改使用Orgmodel view set * [Update] 支持 nv的硬盘 https://github.com/jumpserver/jumpserver/issues/1804 * [UPdate] 解决命令执行宽度问题 * [Update] 优化节点 * [Update] 修改nodes过多时创建比较麻烦 * [Update] 修改导入 * [Update] 节点获取更新 * [Update] 修改nodes * [Update] nodes显示full value * [Update] 统一使用nodes select2 函数 * [Update] 修改磁盘大小小数 * [Update] 修改 Node service * [Update] 优化授权节点 * [Update] 修改 node permission * [Update] 修改asset permission * [Stash] * [Update] 修改node assets api * [Update] 修改tree service,支持资产数量 * [Update] 修改暂时完成 * [Update] 修改一些bug
2019-08-21 12:27:21 +00:00
raise NotImplementedError()
def authenticate_header(self, request):
"""
DRF sends this for unauthenticated responses if we're the primary
authenticator.
"""
h = " ".join(self.required_headers)
return 'Signature realm="%s",headers="%s"' % (
self.www_authenticate_realm, h)
def authenticate(self, request):
"""
Perform the actual authentication.
Note that the exception raised is always the same. This is so that we
don't leak information about in/valid keyIds and other such useful
things.
"""
auth_header = authentication.get_authorization_header(request)
if not auth_header or len(auth_header) == 0:
return None
method, fields = utils.parse_authorization_header(auth_header)
# Ignore foreign Authorization headers.
if method.lower() != 'signature':
return None
# Verify basic header structure.
if len(fields) == 0:
raise FAILED
# Ensure all required fields were included.
if len({"keyid", "algorithm", "signature"} - set(fields.keys())) > 0:
raise FAILED
# Fetch the secret associated with the keyid
user, secret = self.fetch_user_data(
fields["keyid"],
algorithm=fields["algorithm"]
)
if not (user and secret):
raise FAILED
# Gather all request headers and translate them as stated in the Django docs:
# https://docs.djangoproject.com/en/1.6/ref/request-response/#django.http.HttpRequest.META
headers = {}
for key in request.META.keys():
if key.startswith("HTTP_") or \
key in ("CONTENT_TYPE", "CONTENT_LENGTH"):
header = key[5:].lower().replace('_', '-')
headers[header] = request.META[key]
# Verify headers
hs = HeaderVerifier(
headers,
secret,
required_headers=self.required_headers,
method=request.method.lower(),
path=request.get_full_path()
)
# All of that just to get to this.
if not hs.verify():
raise FAILED
return user, fields["keyid"]