Mic*_*ter 4 python authentication cookies session cherrypy
我有一个需要身份验证的CherryPy Web应用程序.我有一个HTTP基本身份验证工作,其配置如下所示:
app_config = {
'/' : {
'tools.sessions.on': True,
'tools.sessions.name': 'zknsrv',
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'zknsrv',
'tools.auth_basic.checkpassword': checkpassword,
}
}
Run Code Online (Sandbox Code Playgroud)
HTTP auth在这一点上很有用.例如,这将为我提供我在内部定义的成功登录消息AuthTest
:
curl http://realuser:realpass@localhost/AuthTest/
Run Code Online (Sandbox Code Playgroud)
自会话开始以来,我可以保存cookie并检查CherryPy设置的cookie:
curl --cookie-jar cookie.jar http://realuser:realpass@localhost/AuthTest/
Run Code Online (Sandbox Code Playgroud)
该cookie.jar
文件最终将如下所示:
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.
localhost FALSE / FALSE 1348640978 zknsrv 821aaad0ba34fd51f77b2452c7ae3c182237deb3
Run Code Online (Sandbox Code Playgroud)
但是,401 Not Authorized
如果我在没有用户名和密码的情况下提供此会话ID ,我将收到HTTP 失败,如下所示:
curl --cookie 'zknsrv=821aaad0ba34fd51f77b2452c7ae3c182237deb3' http://localhost/AuthTest
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
非常感谢您的帮助.
所以,简单的答案是,你可以这样做,但你必须编写自己的CherryPy工具(一before_handler
),你必须不能够在CherryPy的配置(也就是,你不应该做任何事情一样基本身份验证tools.auth.on
或tools.auth.basic...
等) -你必须自己处理HTTP基本身份验证.原因是内置的基本身份验证功能显然非常原始.如果您通过启用基本身份验证来保护某些内容,就像我上面所做的那样,它将在检查会话之前进行身份验证检查,并且您的cookie将不执行任何操作.
幸运的是,即使CherryPy无法同时执行这两种操作,您仍然可以使用其内置的会话代码.您仍然需要编写自己的代码来处理基本身份验证部分,但总的来说这并不是很糟糕,使用会话代码是一个很大的胜利,因为编写自定义会话管理器是将安全漏洞引入Web应用程序的好方法.
我最终能够从CherryPy wiki上的一个页面中获取很多东西,称为简单身份验证和访问限制助手.该代码使用CP会话,但它不使用Basic Auth,而是使用具有提交的登录表单的特殊页面?username=USERNAME&password=PASSWORD
.我所做的基本上只是将提供的check_auth
功能从使用特殊登录页面改为使用HTTP身份验证头.
通常,您需要一个可以添加为CherryPy工具的功能 - 特别是a before_handler
.(在原始代码中,调用了此函数check_auth()
,但我将其重命名为protect()
.)此函数首先尝试查看cookie是否包含(有效)会话ID,如果失败,则会尝试查看是否存在HTTP身份验证信息在标题中.
然后,您需要一种方法来要求对给定页面进行身份验证; 我这样做require()
,加上一些条件,只是返回的callables True
.就我而言,这些条件是zkn_admin()
和user_is()
功能; 如果你有更复杂的需求,你可能也想看看member_of()
,any_of()
和all_of()
从原来的代码.
如果您这样做,您已经有了登录的方法 - 您只需将有效的会话cookie或HTTPBA凭证提交给您使用@require()
装饰器保护的任何URL .您现在需要的只是一种注销方式.
(原始代码有一个AuthController
包含login()
和的类logout()
,你可以AuthController
通过放入auth = AuthController()
CherryPy根类来使用HTTP文档树中的整个对象,并使用例如http://example.com/的URL来访问它.auth/login和http://example.com/auth/logout.我的代码不使用authcontroller对象,只是一些函数.)
user_verify()
和user_is_admin()
debugprint()
只在设置DEBUG
变量时打印输出的函数,为了清楚起见,我将这些调用留在了里面.cherrypy.tools.WHATEVER
(见最后一行); 我zkauth
根据应用程序的名称调用它.但请注意不要调用它auth
,或任何其他内置工具的名称.cherrypy.tools.WHATEVER
,您必须在CherryPy配置中启用.import base64
import re
import cherrypy
SESSION_KEY = '_zkn_username'
def protect(*args, **kwargs):
debugprint("Inside protect()...")
authenticated = False
conditions = cherrypy.request.config.get('auth.require', None)
debugprint("conditions: {}".format(conditions))
if conditions is not None:
# A condition is just a callable that returns true or false
try:
# TODO: I'm not sure if this is actually checking for a valid session?
# or if just any data here would work?
this_session = cherrypy.session[SESSION_KEY]
# check if there is an active session
# sessions are turned on so we just have to know if there is
# something inside of cherrypy.session[SESSION_KEY]:
cherrypy.session.regenerate()
# I can't actually tell if I need to do this myself or what
email = cherrypy.request.login = cherrypy.session[SESSION_KEY]
authenticated = True
debugprint("Authenticated with session: {}, for user: {}".format(
this_session, email))
except KeyError:
# If the session isn't set, it either wasn't present or wasn't valid.
# Now check if the request includes HTTPBA?
# FFR The auth header looks like: "AUTHORIZATION: Basic <base64shit>"
# TODO: cherrypy has got to handle this for me, right?
authheader = cherrypy.request.headers.get('AUTHORIZATION')
debugprint("Authheader: {}".format(authheader))
if authheader:
#b64data = re.sub("Basic ", "", cherrypy.request.headers.get('AUTHORIZATION'))
# TODO: what happens if you get an auth header that doesn't use basic auth?
b64data = re.sub("Basic ", "", authheader)
decodeddata = base64.b64decode(b64data.encode("ASCII"))
# TODO: test how this handles ':' characters in username/passphrase.
email,passphrase = decodeddata.decode().split(":", 1)
if user_verify(email, passphrase):
cherrypy.session.regenerate()
# This line of code is discussed in doc/sessions-and-auth.markdown
cherrypy.session[SESSION_KEY] = cherrypy.request.login = email
authenticated = True
else:
debugprint ("Attempted to log in with HTTBA username {} but failed.".format(
email))
else:
debugprint ("Auth header was not present.")
except:
debugprint ("Client has no valid session and did not provide HTTPBA credentials.")
debugprint ("TODO: ensure that if I have a failure inside the 'except KeyError'"
+ " section above, it doesn't get to this section... I'd want to"
+ " show a different error message if that happened.")
if authenticated:
for condition in conditions:
if not condition():
debugprint ("Authentication succeeded but authorization failed.")
raise cherrypy.HTTPError("403 Forbidden")
else:
raise cherrypy.HTTPError("401 Unauthorized")
cherrypy.tools.zkauth = cherrypy.Tool('before_handler', protect)
def require(*conditions):
"""A decorator that appends conditions to the auth.require config
variable."""
def decorate(f):
if not hasattr(f, '_cp_config'):
f._cp_config = dict()
if 'auth.require' not in f._cp_config:
f._cp_config['auth.require'] = []
f._cp_config['auth.require'].extend(conditions)
return f
return decorate
#### CONDITIONS
#
# Conditions are callables that return True
# if the user fulfills the conditions they define, False otherwise
#
# They can access the current user as cherrypy.request.login
# TODO: test this function with cookies, I want to make sure that cherrypy.request.login is
# set properly so that this function can use it.
def zkn_admin():
return lambda: user_is_admin(cherrypy.request.login)
def user_is(reqd_email):
return lambda: reqd_email == cherrypy.request.login
#### END CONDITIONS
def logout():
email = cherrypy.session.get(SESSION_KEY, None)
cherrypy.session[SESSION_KEY] = cherrypy.request.login = None
return "Logout successful"
Run Code Online (Sandbox Code Playgroud)
现在,您只需cherrypy.tools.WHATEVER
在CherryPy配置中启用内置会话和您自己的会话.再次,注意不要启用cherrypy.tools.auth
.我的配置最终看起来像这样:
config_root = {
'/' : {
'tools.zkauth.on': True,
'tools.sessions.on': True,
'tools.sessions.name': 'zknsrv',
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4026 次 |
最近记录: |