def parse_cookie(name, seed, kaka): """Parses and verifies a cookie value :param seed: A seed used for the HMAC signature :param kaka: The cookie :return: A tuple consisting of (payload, timestamp) """ if not kaka: return None cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name) if morsel: parts = morsel.value.split("|") if len(parts) != 3: return None # verify the cookie signature sig = cookie_signature(seed, parts[0].encode("utf-8"), parts[1].encode("utf-8")) if sig != parts[2]: raise InvalidCookieSign() try: return parts[0].strip(), parts[1] except KeyError: return None else: return None
def make_cookie(name, load, seed, expire=0, domain="", path="", timestamp=""): """ Create and return a cookie :param name: Cookie name :param load: Cookie load :param seed: A seed for the HMAC function :param expire: Number of minutes before this cookie goes stale :param domain: The domain of the cookie :param path: The path specification for the cookie :param timestamp: A time stamp :return: A tuple to be added to headers """ cookie = SimpleCookie() if not timestamp: timestamp = str(int(time.time())) signature = cookie_signature(seed, load.encode("utf-8"), timestamp.encode("utf-8")) cookie[name] = "|".join([load, timestamp, signature]) if path: cookie[name]["path"] = path if domain: cookie[name]["domain"] = domain if expire: cookie[name]["expires"] = _expiration(expire, "%a, %d-%b-%Y %H:%M:%S GMT") return tuple(cookie.output().split(": ", 1))
def cookie_parts(name, kaka): cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def set_cookie(name, _, *args): cookie = SimpleCookie() cookie[name] = base64.b64encode(":".join(args)) cookie[name]['path'] = "/" cookie[name]["expires"] = _expiration(5) # 5 minutes from now logger.debug("Cookie expires: %s", cookie[name]["expires"]) return tuple(cookie.output().split(": ", 1))
def parse_cookie(name, seed, kaka): """Parses and verifies a cookie value :param seed: A seed used for the HMAC signature :param kaka: The cookie :return: A tuple consisting of (payload, timestamp) """ if not kaka: return None if isinstance(seed, text_type): seed = seed.encode("utf-8") cookie_obj = SimpleCookie(text_type(kaka)) morsel = cookie_obj.get(name) if morsel: parts = morsel.value.split("|") if len(parts) != 3: return None # verify the cookie signature sig = cookie_signature(seed, parts[0].encode("utf-8"), parts[1].encode("utf-8")) if sig != parts[2]: raise InvalidCookieSign() try: return parts[0].strip(), parts[1] except KeyError: return None else: return None
def cookie_parts(name, kaka): cookie_obj = SimpleCookie(text_type(kaka)) morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def parse_cookie(name, seed, kaka): """Parses and verifies a cookie value :param seed: A seed used for the HMAC signature :param kaka: The cookie :return: A tuple consisting of (payload, timestamp) """ if not kaka: return None cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name) if morsel: parts = morsel.value.split("|") if len(parts) != 3: return None # verify the cookie signature sig = cookie_signature(seed, parts[0], parts[1]) if sig != parts[2]: raise SAMLError("Invalid cookie signature") try: return parts[0].strip(), parts[1] except KeyError: return None else: return None
def set_cookie(self, user): uid = rndstr(32) self.uid2user[uid] = user cookie = SimpleCookie() cookie[self.cookie_name] = uid cookie[self.cookie_name]['path'] = "/" cookie[self.cookie_name]["expires"] = _expiration(480) logger.debug("Cookie expires: %s", cookie[self.cookie_name]["expires"]) return cookie.output().encode("UTF-8").split(": ", 1)
def delete_cookie(self, environ): cookie = environ.get("HTTP_COOKIE", '') logger.debug("delete cookie: %s", cookie) if cookie: _name = self.cookie_name cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(_name, None) cookie = SimpleCookie() cookie[_name] = "" cookie[_name]['path'] = "/" logger.debug("Expire: %s", morsel) cookie[_name]["expires"] = _expiration("now") return cookie.output().split(": ", 1) return None
def get_user(self, environ): cookie = environ.get("HTTP_COOKIE", '') logger.debug("Cookie: %s" % cookie) if cookie: cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(self.cookie_name, None) if morsel: try: return self.uid2user[morsel.value] except KeyError: return None else: logger.debug("No %s cookie", self.cookie_name) return None
def get_user(self, environ): cookie = environ.get("HTTP_COOKIE", '') cookie = cookie.decode("UTF-8") logger.debug("Cookie: %s", cookie) if cookie: cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(self.cookie_name, None) if morsel: try: return self.uid2user[morsel.value] except KeyError: return None else: logger.debug("No %s cookie", self.cookie_name) return None
def _assert_cookies_expired(self, http_headers): cookies_string = ";".join( [c[1] for c in http_headers if c[0] == "Set-Cookie"]) all_cookies = SimpleCookie() try: cookies_string = cookies_string.decode() except (AttributeError, UnicodeDecodeError): pass all_cookies.load(cookies_string) now = datetime.datetime.utcnow() # for c in [self.provider.cookie_name, self.provider.session_cookie_name]: dt = datetime.datetime.strptime(all_cookies[c]["expires"], "%a, %d-%b-%Y %H:%M:%S GMT") assert dt < now # make sure the cookies have expired to be cleared
def construct_message(self): _kwargs = {'request': self.conv.events.last_item(EV_REQUEST)} _kwargs.update(self.msg_args) _kwargs.update(self.op_args) _op = self.conv.entity _cookie = self.conv.events.last_item('Cookie') try: set_cookie(_op.server.cookiejar, SimpleCookie(_cookie)) except CookieError as err: logger.error(err) else: _kwargs['cookie'] = _op.server._cookies() resp = _op.authorization_endpoint(**_kwargs) return resp
def test_set_cookie(): cookiejar = FileCookieJar() _cookie = {"value_0": "v_0", "value_1": "v_1", "value_2": "v_2"} c = SimpleCookie(_cookie) domain_0 = ".test_domain" domain_1 = "test_domain" max_age = "09 Feb 1994 22:23:32 GMT" expires = http2time(max_age) path = "test/path" c["value_0"]["max-age"] = max_age c["value_0"]["domain"] = domain_0 c["value_0"]["path"] = path c["value_1"]["domain"] = domain_1 util.set_cookie(cookiejar, c) cookies = cookiejar._cookies c_0 = cookies[domain_0][path]["value_0"] c_1 = cookies[domain_1][""]["value_1"] c_2 = cookies[""][""]["value_2"] assert not (c_2.domain_specified and c_2.path_specified) assert c_1.domain_specified and not c_1.domain_initial_dot and not c_1.path_specified assert c_0.domain_specified and c_0.domain_initial_dot and c_0.path_specified assert c_0.expires == expires assert c_0.domain == domain_0 assert c_0.name == "value_0" assert c_0.path == path assert c_0.value == "v_0" assert not c_1.expires assert c_1.domain == domain_1 assert c_1.name == "value_1" assert c_1.path == "" assert c_1.value == "v_1" assert not c_2.expires assert c_2.domain == "" assert c_2.name == "value_2" assert c_2.path == "" assert c_2.value == "v_2"
def delete_cookie(environ, name): kaka = environ.get("HTTP_COOKIE", '') logger.debug("delete KAKA: %s", kaka) if kaka: cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name, None) cookie = SimpleCookie() cookie[name] = "" cookie[name]['path'] = "/" logger.debug("Expire: %s", morsel) cookie[name]["expires"] = _expiration("dawn") return tuple(cookie.output().split(": ", 1)) return None
def delete_cookie(self, environ): cookie = environ.get("HTTP_COOKIE", '') logger.debug("delete cookie: %s" % cookie) if cookie: _name = self.cookie_name cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(_name, None) cookie = SimpleCookie() cookie[_name] = "" cookie[_name]['path'] = "/" logger.debug("Expire: %s" % morsel) cookie[_name]["expires"] = _expiration("now") return cookie.output().split(": ", 1) return None
def info_from_cookie(kaka): logger.debug("KAKA: %s", kaka) if kaka: cookie_obj = SimpleCookie() if PY3: import builtins cookie_obj.load(builtins.str(kaka)) else: cookie_obj.load(str(kaka)) morsel = cookie_obj.get("idpauthn", None) if morsel: try: key, ref = base64.b64decode(morsel.value).split(":") return IDP.cache.uid2user[key], ref except (KeyError, TypeError): return None, None else: logger.debug("No idpauthn cookie") return None, None
def construct_message(self): _kwargs = {'request': self.conv.events.last_item(EV_REQUEST)} _kwargs.update(self.msg_args) _kwargs.update(self.op_args) _op = self.conv.entity try: _cookie = self.conv.events.last_item('Cookie') except NoSuchEvent: pass else: try: set_cookie(_op.server.cookiejar, SimpleCookie(_cookie)) except CookieError as err: logger.error(err) else: _kwargs['cookie'] = _op.server._cookies() resp = _op.authorization_endpoint(**_kwargs) if isinstance(resp, SeeOther): save_response(self.conv.events, resp, oic.message.AuthorizationResponse, oic.message.AuthorizationErrorResponse) return resp
def test_cookie_dealer_with_path(self): class DomServer(): def __init__(self): self.symkey = b"0123456789012345" self.cookie_path = "/oidc" cookie_dealer = CookieDealer(DomServer()) cookie_value = "Something to pass along" cookie_typ = "sso" cookie_name = "Foobar" kaka = cookie_dealer.create_cookie(cookie_value, cookie_typ, cookie_name) C = SimpleCookie() if PY2: # the backported SimpleCookie wants py3 str C.load(newstr(kaka[1])) else: C.load(kaka[1]) assert C[cookie_name]["path"] == "/oidc"
def make_cookie(name, load, seed, expire=0, domain="", path="", timestamp="", enc_key=None): """ Create and return a cookie The cookie is secured against tampering. If you only provide a `seed`, a HMAC gets added to the cookies value and this is checked, when the cookie is parsed again. If you provide both `seed` and `enc_key`, the cookie gets protected by using AEAD encryption. This provides both a MAC over the whole cookie and encrypts the `load` in a single step. The `seed` and `enc_key` parameters should be byte strings of at least 16 bytes length each. Those are used as cryptographic keys. :param name: Cookie name :type name: text :param load: Cookie load :type load: text :param seed: A seed key for the HMAC function :type seed: byte string :param expire: Number of minutes before this cookie goes stale :type expire: int :param domain: The domain of the cookie :param path: The path specification for the cookie :param timestamp: A time stamp :type timestamp: text :param enc_key: The key to use for cookie encryption. :type enc_key: byte string :return: A tuple to be added to headers """ cookie = SimpleCookie() if not timestamp: timestamp = str(int(time.time())) bytes_load = load.encode("utf-8") bytes_timestamp = timestamp.encode("utf-8") if enc_key: # Make sure the key is 256-bit long, for AES-128-SIV # # This should go away once we push the keysize requirements up # to the top level APIs. key = _make_hashed_key((enc_key, seed)) # Random 128-Bit IV iv = os.urandom(16) crypt = AEAD(key, iv) # timestamp does not need to be encrypted, just MAC'ed, # so we add it to 'Associated Data' only. crypt.add_associated_data(bytes_timestamp) ciphertext, tag = crypt.encrypt_and_tag(bytes_load) cookie_payload = [bytes_timestamp, base64.b64encode(iv), base64.b64encode(ciphertext), base64.b64encode(tag)] else: cookie_payload = [ bytes_load, bytes_timestamp, cookie_signature(seed, load, timestamp).encode('utf-8')] cookie[name] = (b"|".join(cookie_payload)).decode('utf-8') if path: cookie[name]["path"] = path if domain: cookie[name]["domain"] = domain if expire: cookie[name]["expires"] = _expiration(expire, "%a, %d-%b-%Y %H:%M:%S GMT") return tuple(cookie.output().split(": ", 1))
def make_cookie(name, load, seed, expire=0, domain="", path="", timestamp="", enc_key=None): """ Create and return a cookie The cookie is secured against tampering. If you only provide a `seed`, a HMAC gets added to the cookies value and this is checked, when the cookie is parsed again. If you provide both `seed` and `enc_key`, the cookie gets protected by using AEAD encryption. This provides both a MAC over the whole cookie and encrypts the `load` in a single step. The `seed` and `enc_key` parameters should be byte strings of at least 16 bytes length each. Those are used as cryptographic keys. :param name: Cookie name :type name: text :param load: Cookie load :type load: text :param seed: A seed key for the HMAC function :type seed: byte string :param expire: Number of minutes before this cookie goes stale :type expire: int :param domain: The domain of the cookie :param path: The path specification for the cookie :param timestamp: A time stamp :type timestamp: text :param enc_key: The key to use for cookie encryption. :type enc_key: byte string :return: A tuple to be added to headers """ cookie = SimpleCookie() if not timestamp: timestamp = str(int(time.time())) bytes_load = load.encode("utf-8") bytes_timestamp = timestamp.encode("utf-8") if enc_key: # Make sure the key is 256-bit long, for AES-128-SIV # # This should go away once we push the keysize requirements up # to the top level APIs. key = _make_hashed_key((enc_key, seed)) # Random 128-Bit IV iv = os.urandom(16) crypt = AEAD(key, iv) # timestamp does not need to be encrypted, just MAC'ed, # so we add it to 'Associated Data' only. crypt.add_associated_data(bytes_timestamp) ciphertext, tag = crypt.encrypt_and_tag(bytes_load) cookie_payload = [ bytes_timestamp, base64.b64encode(iv), base64.b64encode(ciphertext), base64.b64encode(tag) ] else: cookie_payload = [ bytes_load, bytes_timestamp, cookie_signature(seed, load, timestamp).encode('utf-8') ] cookie[name] = (b"|".join(cookie_payload)).decode('utf-8') if path: cookie[name]["path"] = path if domain: cookie[name]["domain"] = domain if expire: cookie[name]["expires"] = _expiration(expire, "%a, %d-%b-%Y %H:%M:%S GMT") return tuple(cookie.output().split(": ", 1))
def _complete_authz(self, user, areq, sid, **kwargs): _log_debug = logger.debug _log_debug("- in authenticated() -") # Do the authorization try: permission = self.authz(user, client_id=areq['client_id']) self.sdb.update(sid, "permission", permission) except Exception: raise _log_debug("response type: %s" % areq["response_type"]) if self.sdb.is_revoked(sid): return self._error(error="access_denied", descr="Token is revoked") try: info = self.create_authn_response(areq, sid) except UnSupported as err: return self._error_response(*err.args) if isinstance(info, Response): return info else: aresp, fragment_enc = info try: redirect_uri = self.get_redirect_uri(areq) except (RedirectURIError, ParameterError) as err: return BadRequest("%s" % err) # Must not use HTTP unless implicit grant type and native application info = self.aresp_check(aresp, areq) if isinstance(info, Response): return info headers = [] try: _kaka = kwargs["cookie"] except KeyError: pass else: if _kaka: if isinstance(_kaka, dict): for name, val in _kaka.items(): _c = SimpleCookie() _c[name] = val _x = _c.output() if PY2: _x = str(_x) headers.append(tuple(_x.split(": ", 1))) else: if PY2: _kaka = newstr(_kaka) _c = SimpleCookie() _c.load(_kaka) for x in _c.output().split('\r\n'): if PY2: x = str(x) headers.append(tuple(x.split(": ", 1))) if self.cookie_name not in _kaka: # Don't overwrite header = self.cookie_func(user, typ="sso", ttl=self.sso_ttl) if header: headers.append(header) else: header = self.cookie_func(user, typ="sso", ttl=self.sso_ttl) if header: headers.append(header) # Now about the response_mode. Should not be set if it's obvious # from the response_type. Knows about 'query', 'fragment' and # 'form_post'. if "response_mode" in areq: try: resp = self.response_mode(areq, fragment_enc, aresp=aresp, redirect_uri=redirect_uri, headers=headers) except InvalidRequest as err: return self._error("invalid_request", err) else: if resp is not None: return resp return aresp, headers, redirect_uri, fragment_enc
def _complete_authz(self, user, areq, sid, **kwargs): _log_debug = logger.debug _log_debug("- in authenticated() -") # Do the authorization try: permission = self.authz(user, client_id=areq['client_id']) self.sdb.update(sid, "permission", permission) except Exception: raise _log_debug("response type: %s" % areq["response_type"]) if self.sdb.is_revoked(sid): return error(error="access_denied", descr="Token is revoked") try: info = self.create_authn_response(areq, sid) except UnSupported as err: return error_response(*err.args) if isinstance(info, Response): return info else: aresp, fragment_enc = info try: redirect_uri = self.get_redirect_uri(areq) except (RedirectURIError, ParameterError) as err: return BadRequest("%s" % err) # Must not use HTTP unless implicit grant type and native application info = self.aresp_check(aresp, areq) if isinstance(info, Response): return info headers = [] try: _kaka = kwargs["cookie"] except KeyError: pass else: if _kaka: if isinstance(_kaka, dict): for name, val in _kaka.items(): _c = SimpleCookie() _c[name] = val _x = _c.output() if PY2: _x = str(_x) headers.append(tuple(_x.split(": ", 1))) else: if PY2: _kaka = newstr(_kaka) _c = SimpleCookie() _c.load(_kaka) for x in _c.output().split('\r\n'): if PY2: x = str(x) headers.append(tuple(x.split(": ", 1))) if self.cookie_name not in _kaka: # Don't overwrite header = self.cookie_func(user, typ="sso", ttl=self.sso_ttl) if header: headers.append(header) else: header = self.cookie_func(user, typ="sso", ttl=self.sso_ttl) if header: headers.append(header) # Now about the response_mode. Should not be set if it's obvious # from the response_type. Knows about 'query', 'fragment' and # 'form_post'. if "response_mode" in areq: try: resp = self.response_mode(areq, fragment_enc, aresp=aresp, redirect_uri=redirect_uri, headers=headers) except InvalidRequest as err: return error("invalid_request", err) else: if resp is not None: return resp return aresp, headers, redirect_uri, fragment_enc