2021SC@SDUSC
上一次博客的结尾简略的引出了decorator.py和middleware.py的一些内容,这次详细分析一下这个文件是做什么用的,以及seahub-extra文件夹下其余的文件。详细代码见github-seahub-extra
1.decorator.py
本身是一个用户登录测试模块,并解决重定向循环问题的替换身份验证修饰符。
2.middleware.py CAS认证中间件
实现管理页面上的CAS身份验证,并在使用之前对系统进行检测是否已经安装本中间件,如果未安装,会给出相应的错误提示。
def process_request(self, request):
error = ("The Django CAS middleware requires authentication "
"middleware to be installed. Edit your MIDDLEWARE_CLASSES "
"setting to insert 'django.contrib.auth.middleware."
"AuthenticationMiddleware'.")
assert hasattr(request, 'user'), error
对管理页面的未经身份验证的请求转发到CAS登录URL,以及对django.contri.auth.views.login和注销的调用。
函数声明如下,上一篇博客已经将方法体给出,这里不再重新给出。
def process_view(self, request, view_func, view_args, view_kwargs):
models.py主要负责代理分发会话凭证,和清楚会话凭证。
对session内格式进行设置。
class Meta:
unique_together = ('session_key', 'user')
session_key = models.CharField(max_length=255, blank=True, null=True)
user = LowerCaseCharField(max_length=255, db_index=True)
pgtiou = models.CharField(max_length=255, null=True, blank=True)
pgt = models.CharField(max_length=255, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
清除已删除的Session,首先通过SessionStore获取session,对于未经过认证的用户会话进行删除。
def clean_deleted_sessions(cls):
for pgt in cls.objects.all():
session = SessionStore(session_key=pgt.session_key)
user = get_user_from_session(session)
if django.VERSION[0] < 2:
if not user.is_authenticated:
pgt.delete()
else:
if not user.is_authenticated:
pgt.delete()
由于我们的request
应该是当前的HttpRequest对象service
,代表我们要检索服务凭证的字符串。该函数返回代理凭证,如果失败或引发ProxyError
def retrieve_pt(cls, request, service)
下面是尝试获取到用户信息和session_key,失败则表名这是一个无效的凭据。
try:
pgt = cls.objects.get(user=request.user.username,
session_key=request.session.session_key).pgt
except cls.DoesNotExist:
raise ProxyError(
"INVALID_TICKET",
"No proxy ticket found for this HttpRequest object"
)
对于CAS认证错误和其它错误,这里实现了统一将其替换成代理错误。即抓取到CASError和一般Exception,在提示的时候使用的ProxyError。
client = get_cas_client(service_url=service, request=request)
try:
return client.get_proxy_ticket(pgt)
except CASError as error:
raise ProxyError(*error.args)
except Exception as e:
raise ProxyError(e)
signal.py主要对几个服务signals进行监听,包括登录认证时和登出时:
cas_user_authenticated = dispatch.Signal(
providing_args=['user', 'created', 'attributes', 'ticket', 'service', 'request'],
)
cas_user_logout = dispatch.Signal(
providing_args=['user', 'session', 'ticket'],
)
utils.py实现了一个工具函数,下面列举一下函数名。
def get_protocol(request)
def get_redirect_url(request)
def get_service_url(request, redirect_to=None)
def get_cas_client(service_url=None, request=None)
def get_user_from_session(session)
获取请求用的协议,默认为HTTP和安全请求下的HTTPS协议
def get_protocol(request)
重定向到引用页面,如果未设置引用,则重定向到预定义的CAS_REDIRECT_URL页面
def get_redirect_url(request)
为CAS生成应用程序Django服务URL
get_service_url(request, redirect_to=None)
根据CAS_*settigs初始化CASClient
get_cas_client(service_url=None, request=None)
这是返回值,包括服务地址,CAS版本,服务器地址,用户名以及代理的callback等
return CASClient(
service_url=service_url,
version=django_settings.CAS_VERSION,
server_url=server_url,
verify_ssl_certificate=django_settings.CAS_SERVER_CERT_VERIFY,
extra_login_params=django_settings.CAS_EXTRA_LOGIN_PARAMS,
renew=django_settings.CAS_RENEW,
username_attribute=django_settings.CAS_USERNAME_ATTRIBUTE,
proxy_callback=django_settings.CAS_PROXY_CALLBACK
)
最后就是从会话中获取用户信息,如果获取会话密钥key失败,则无法获取到用户id,所以相当于获取到了一个匿名用户。
def get_user_from_session(session):
try:
user_id = session[SESSION_KEY]
backend_path = session[BACKEND_SESSION_KEY]
backend = load_backend(backend_path)
return backend.get_user(user_id) or AnonymousUser()
except KeyError:
return AnonymousUser()
views.py —— CAS login/logout replacement views,就是登录和登出对应页面的替换。
在登录时,cas认证过程:
第一步,用户请求A服务url
第二步,A服务判断url是否要走cas认证过滤器,需要走,则请求cas server并附加回调地址,如:cas server?service=A服务url
第三步,cas认证失败,A服务获取到返回信息,走cas认证失败重定向,正常重定向到cas server登陆页
第四步,在cas server登陆页输入用户名密码,验证成功回调A服务url,并附加A服务url?ticket=asdsadasdasda
第五步,A服务校验有ticket,则再次调用cas server的校验服务,cas server?serviceValidate=asdsadasdasda
第六步,cas返回校验结果,如果有效,则返回用户信息
第七步,A服务获取到用户信息,生成登陆凭证,并重定向到认证成功配置页面url
循环
def login(request, next_page=None, required=False)
则是通过解析会话请求,检查是否有指定的url如果有则转到,如果没有则重定向到请求页面。
简而言之,登录对应的服务视图是通过检查会话请求,检查会话凭证,确定重定向的页面进行返回。
登出首先尝试查找与注销信号的当前会话匹配的凭证,然后就是特别重要的一环,即清除当前会话ProxyGrantingTicket和SessionTicket,最后重定向到指定的登出页面。
对于山大统一认证的接口,传给后端传的是rsa密文,账号长度ul,密码长度pl,加上一个隐藏参数lt,另外还有无关紧要的参数,在山大智云登录的时候需要跳转到山东大学统一认证界面,成功则重定向到seafile的服务主页,其通过会话信息解析出用户id,用户名等数据,然后通过seafile服务器将该用户对应的数据信息进行返回,用户则成功进入自己的私有云系统。 那么如果认证失败,则还是停留在认证页面。
代码中还有KRB5认证,详细代码见github-seahub-extra-krb5_auth
在 Kerberos 认证中,最主要的问题是如何证明「你是你」的问题,如当一个 Client 去访问 Server 服务器上的某服务时,Server 如何判断 Client 是否有权限来访问自己主机上的服务,同时保证在这个过程中的通讯内容即使被拦截或篡改也不影响通讯的安全性,这正是 Kerberos 解决的问题
图解:
结合上一次的博客,我们这一次分析完了登录认证系统,下一次博客将去重点分析登录之后的一些服务。