fix the path given by the set-cookie header

This commit is contained in:
Damien Churchill 2011-05-03 19:05:04 +01:00
parent 138b8ae314
commit d362a6ceba
2 changed files with 61 additions and 58 deletions

View File

@ -71,11 +71,11 @@ def get_session_id(session_id):
""" """
if not session_id: if not session_id:
return None return None
try: try:
checksum = int(session_id[-4:]) checksum = int(session_id[-4:])
session_id = session_id[:-4] session_id = session_id[:-4]
if checksum == make_checksum(session_id): if checksum == make_checksum(session_id):
return session_id return session_id
return None return None
@ -93,32 +93,32 @@ class Auth(JSONComponent):
""" """
The component that implements authentification into the JSON interface. The component that implements authentification into the JSON interface.
""" """
def __init__(self): def __init__(self):
super(Auth, self).__init__("Auth") super(Auth, self).__init__("Auth")
self.worker = LoopingCall(self._clean_sessions) self.worker = LoopingCall(self._clean_sessions)
self.worker.start(5) self.worker.start(5)
def _clean_sessions(self): def _clean_sessions(self):
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
session_ids = config["sessions"].keys() session_ids = config["sessions"].keys()
now = time.gmtime() now = time.gmtime()
for session_id in session_ids: for session_id in session_ids:
session = config["sessions"][session_id] session = config["sessions"][session_id]
if "expires" not in session: if "expires" not in session:
del config["sessions"][session_id] del config["sessions"][session_id]
continue continue
if time.gmtime(session["expires"]) < now: if time.gmtime(session["expires"]) < now:
del config["sessions"][session_id] del config["sessions"][session_id]
continue continue
def _create_session(self, request, login='admin'): def _create_session(self, request, login='admin'):
""" """
Creates a new session. Creates a new session.
:keyword login: the username of the user logging in, currently \ :keyword login: the username of the user logging in, currently \
only for future use currently. only for future use currently.
:type login: string :type login: string
@ -131,14 +131,13 @@ class Auth(JSONComponent):
session_id = m.hexdigest() session_id = m.hexdigest()
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
expires, expires_str = make_expires(config["session_timeout"]) expires, expires_str = make_expires(config["session_timeout"])
checksum = str(make_checksum(session_id)) checksum = str(make_checksum(session_id))
base = str(component.get("Web").get_config()["base"])
request.addCookie('_session_id', session_id + checksum, request.addCookie('_session_id', session_id + checksum,
path=base+"json", expires=expires_str) path=request.base+"json", expires=expires_str)
log.debug("Creating session for %s", login) log.debug("Creating session for %s", login)
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
@ -151,7 +150,7 @@ class Auth(JSONComponent):
"expires": expires "expires": expires
} }
return True return True
def check_password(self, password): def check_password(self, password):
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
if "pwd_md5" in config.config: if "pwd_md5" in config.config:
@ -165,14 +164,14 @@ class Auth(JSONComponent):
# the old passwords from the config file. # the old passwords from the config file.
self._change_password(password) self._change_password(password)
del config.config["pwd_md5"] del config.config["pwd_md5"]
# Remove the older password if there is now. # Remove the older password if there is now.
if "old_pwd_md5" in config.config: if "old_pwd_md5" in config.config:
del config.config["old_pwd_salt"] del config.config["old_pwd_salt"]
del config.config["old_pwd_md5"] del config.config["old_pwd_md5"]
return True return True
elif "old_pwd_md5" in config.config: elif "old_pwd_md5" in config.config:
# We are using the 1.1 webui auth method # We are using the 1.1 webui auth method
log.debug("Received a password via the 1.1 auth method") log.debug("Received a password via the 1.1 auth method")
@ -181,13 +180,13 @@ class Auth(JSONComponent):
m.update(decodestring(config["old_pwd_salt"])) m.update(decodestring(config["old_pwd_salt"]))
m.update(password) m.update(password)
if m.digest() == decodestring(config["old_pwd_md5"]): if m.digest() == decodestring(config["old_pwd_md5"]):
# We want to move the password over to sha1 and remove # We want to move the password over to sha1 and remove
# the old passwords from the config file. # the old passwords from the config file.
self._change_password(password) self._change_password(password)
del config.config["old_pwd_salt"] del config.config["old_pwd_salt"]
del config.config["old_pwd_md5"] del config.config["old_pwd_md5"]
return True return True
elif "pwd_sha1" in config.config: elif "pwd_sha1" in config.config:
@ -204,25 +203,25 @@ class Auth(JSONComponent):
# access. # access.
log.debug("Failed to detect the login method") log.debug("Failed to detect the login method")
return False return False
def check_request(self, request, method=None, level=None): def check_request(self, request, method=None, level=None):
""" """
Check to ensure that a request is authorised to call the specified Check to ensure that a request is authorised to call the specified
method of authentication level. method of authentication level.
:param request: The HTTP request in question :param request: The HTTP request in question
:type request: twisted.web.http.Request :type request: twisted.web.http.Request
:keyword method: Check the specified method :keyword method: Check the specified method
:type method: function :type method: function
:keyword level: Check the specified auth level :keyword level: Check the specified auth level
:type level: integer :type level: integer
:raises: Exception :raises: Exception
""" """
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
session_id = get_session_id(request.getCookie("_session_id")) session_id = get_session_id(request.getCookie("_session_id"))
if session_id not in config["sessions"]: if session_id not in config["sessions"]:
auth_level = AUTH_LEVEL_NONE auth_level = AUTH_LEVEL_NONE
session_id = None session_id = None
@ -233,34 +232,33 @@ class Auth(JSONComponent):
session["expires"] = expires session["expires"] = expires
_session_id = request.getCookie("_session_id") _session_id = request.getCookie("_session_id")
base = str(component.get("Web").get_config()["base"])
request.addCookie('_session_id', _session_id, request.addCookie('_session_id', _session_id,
path=base+"json", expires=expires_str) path=request.base+"json", expires=expires_str)
if method: if method:
if not hasattr(method, "_json_export"): if not hasattr(method, "_json_export"):
raise Exception("Not an exported method") raise Exception("Not an exported method")
method_level = getattr(method, "_json_auth_level") method_level = getattr(method, "_json_auth_level")
if method_level is None: if method_level is None:
raise Exception("Method has no auth level") raise Exception("Method has no auth level")
level = method_level level = method_level
if level is None: if level is None:
raise Exception("No level specified to check against") raise Exception("No level specified to check against")
request.auth_level = auth_level request.auth_level = auth_level
request.session_id = session_id request.session_id = session_id
if auth_level < level: if auth_level < level:
raise AuthError("Not authenticated") raise AuthError("Not authenticated")
def _change_password(self, new_password): def _change_password(self, new_password):
""" """
Change the password. This is to allow the UI to change/reset a Change the password. This is to allow the UI to change/reset a
password. password.
:param new_password: the password to change to :param new_password: the password to change to
:type new_password: string :type new_password: string
""" """
@ -272,12 +270,12 @@ class Auth(JSONComponent):
config["pwd_salt"] = salt config["pwd_salt"] = salt
config["pwd_sha1"] = s.hexdigest() config["pwd_sha1"] = s.hexdigest()
return True return True
@export @export
def change_password(self, old_password, new_password): def change_password(self, old_password, new_password):
""" """
Change the password. Change the password.
:param old_password: the current password :param old_password: the current password
:type old_password: string :type old_password: string
:param new_password: the password to change to :param new_password: the password to change to
@ -286,22 +284,22 @@ class Auth(JSONComponent):
if not self.check_password(old_password): if not self.check_password(old_password):
return False return False
return self._change_password(new_password) return self._change_password(new_password)
@export(AUTH_LEVEL_NONE) @export(AUTH_LEVEL_NONE)
def check_session(self, session_id=None): def check_session(self, session_id=None):
""" """
Check a session to see if it's still valid. Check a session to see if it's still valid.
:returns: True if the session is valid, False if not. :returns: True if the session is valid, False if not.
:rtype: booleon :rtype: booleon
""" """
return __request__.session_id is not None return __request__.session_id is not None
@export @export
def delete_session(self): def delete_session(self):
""" """
Removes a session. Removes a session.
:param session_id: the id for the session to remove :param session_id: the id for the session to remove
:type session_id: string :type session_id: string
""" """
@ -309,18 +307,18 @@ class Auth(JSONComponent):
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
del config["sessions"][__request__.session_id] del config["sessions"][__request__.session_id]
return True return True
@export(AUTH_LEVEL_NONE) @export(AUTH_LEVEL_NONE)
def login(self, password): def login(self, password):
""" """
Test a password to see if it's valid. Test a password to see if it's valid.
:param password: the password to test :param password: the password to test
:type password: string :type password: string
:returns: a session id or False :returns: a session id or False
:rtype: string or False :rtype: string or False
""" """
if self.check_password(password): if self.check_password(password):
return self._create_session(__request__) return self._create_session(__request__)
else: else:

View File

@ -518,13 +518,31 @@ class TopLevel(resource.Resource):
self.__scripts.remove(script) self.__scripts.remove(script)
self.__debug_scripts.remove(script) self.__debug_scripts.remove(script)
def getChild(self, path, request): def getChild(self, path, request):
if path == "": if path == "":
return self return self
else: else:
return resource.Resource.getChild(self, path, request) return resource.Resource.getChild(self, path, request)
def getChildWithDefault(self, path, request):
# Calculate the request base
header = request.getHeader('x-deluge-base')
base = header if header else component.get("DelugeWeb").base
# validate the base parameter
if not base:
base = '/'
if base[0] != '/':
base = '/' + base
if base[-1] != '/':
base += '/'
request.base = base.encode('idna')
return resource.Resource.getChildWithDefault(self, path, request)
def render(self, request): def render(self, request):
debug = False debug = False
if 'debug' in request.args: if 'debug' in request.args:
@ -555,25 +573,12 @@ class TopLevel(resource.Resource):
template = Template(filename=rpath("index.html")) template = Template(filename=rpath("index.html"))
request.setHeader("content-type", "text/html; charset=utf-8") request.setHeader("content-type", "text/html; charset=utf-8")
header = request.getHeader('x-deluge-base')
base = header if header else component.get("DelugeWeb").base
# validate the base parameter
if not base:
base = '/'
if base[0] != '/':
base = '/' + base
if base[-1] != '/':
base += '/'
web_config = component.get("Web").get_config() web_config = component.get("Web").get_config()
web_config["base"] = base web_config["base"] = request.base
config = dict([(key, web_config[key]) for key in UI_CONFIG_KEYS]) config = dict([(key, web_config[key]) for key in UI_CONFIG_KEYS])
js_config = common.json.dumps(config) js_config = common.json.dumps(config)
return template.render(scripts=scripts, stylesheets=self.stylesheets, return template.render(scripts=scripts, stylesheets=self.stylesheets,
debug=debug, base=base, js_config=js_config) debug=debug, base=request.base, js_config=js_config)
class ServerContextFactory: class ServerContextFactory: