我使用龙卷风5.1.1实现了SAML身份验证单一登录
简而言之,SAML要求进行多次重定向,大致如下: 第1步-浏览器在/ sp_sso url(服务提供商单点登录)上启动,该URL重定向到标识提供者授权上的saml sso url
步骤2-身份颁发机构检查请求,如果决定批准登录,则将请求作为POST请求重定向到原始服务,作为断言客户端响应(称为/ sp_acs),其中用户详细信息位于编码在帖子正文中。
第3步-在/ sp_acs url中,检查正文,检索用户数据并创建服务会话-那时,请求再次被重定向,但是这次是到登录页面,我们称之为/ home
在我的情况下,/ home是一个静态页面,龙卷风服务不提供该页面(nginx会拦截它并为UX提供服务)。
重定向实际上可以正常工作,浏览器加载/ home URL,并且用户体验从那时起一直没有问题。
但是,我确实在日志中看到以下错误,并且对我来说,我可以找出原因,并确定这确实是一个问题。
[E 181204 16:56:11 web:1670] Uncaught exception POST /sp_acs (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:3000', method='POST', uri='/sp_acs', version='HTTP/1.0', remote_ip='127.0.0.1')
Traceback (most recent call last):
File "/home/erez/amicus/wf/svc-amicus-authentication/env/lib/python3.6/site-packages/tornado/web.py", line 1590, in _execute
result = method(*self.path_args, **self.path_kwargs)
TypeError: 'NoneType' object is not callable
这是/ sp_acs后处理程序中的最后代码:
def post(self):
logger.info("at acs")
auth=None
try:
auth = init_saml_auth(self.request)
auth.process_response()
if auth.get_errors():
logger.error(str(auth.get_errors()))
return self.set_status(400,",".join(auth.get_errors()))
if not auth.is_authenticated():
logger.error("authentication failed " + str(auth))
return self.set_status(403, "Not Authenticated")
logger.info(str({'samlUserdata': auth.get_attributes(),
'samlNameId': auth.get_nameid(),
'samlSessionIndex': auth.get_session_index()}))
user_uid = auth.get_attributes()['uid'][0]
login_response = ... # some application logic
logger.info('login_response: '+str(login_response))
if login_response:
rdr = self.request.protocol + '://' + self.request.host + LANDING_PAGE
self.redirect(rdr,status=303)
else:
self.redirect(LOGIN_ERROR_PAGE,status=303)
except Exception as e:
logger.exception("acs error "+str(auth))
raise e
我正在使用OneLogin作为SAML协议解析器,由于它最初是围绕烧瓶构建的,因此经过了稍微修改后可以与Tornado一起使用。它运行良好,我将SimplSAML用作SAML测试工具...(https://hub.docker.com/r/kristophjunge/test-saml-idp/)
编辑
这是init_saml_auth()的作用:
def init_saml_auth(request):
def prepare_tornado_request(request):
result = {
'https': 'on' if request.protocol == 'https' else 'off',
'http_host': tornado.httputil.split_host_and_port(request.host)[0],
'script_name': request.path,
'server_port': tornado.httputil.split_host_and_port(request.host)[1],
'get_data': request.arguments,
'post_data': request.arguments,
'query_string': request.query
}
return result
auth = OneLogin_Saml2_Auth(prepare_tornado_request(request), custom_base_path=SAML_PATH)
return auth