You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					324 lines
				
				12 KiB
			
		
		
			
		
	
	
					324 lines
				
				12 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								# -*- coding: utf-8 -*-
							 | 
						||
| 
								 | 
							
								r"""
							 | 
						||
| 
								 | 
							
								    werkzeug.contrib.securecookie
							 | 
						||
| 
								 | 
							
								    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This module implements a cookie that is not alterable from the client
							 | 
						||
| 
								 | 
							
								    because it adds a checksum the server checks for.  You can use it as
							 | 
						||
| 
								 | 
							
								    session replacement if all you have is a user id or something to mark
							 | 
						||
| 
								 | 
							
								    a logged in user.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Keep in mind that the data is still readable from the client as a
							 | 
						||
| 
								 | 
							
								    normal cookie is.  However you don't have to store and flush the
							 | 
						||
| 
								 | 
							
								    sessions you have at the server.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Example usage:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from werkzeug.contrib.securecookie import SecureCookie
							 | 
						||
| 
								 | 
							
								    >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Dumping into a string so that one can store it in a cookie:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> value = x.serialize()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Loading from that string again:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> x = SecureCookie.unserialize(value, "deadbeef")
							 | 
						||
| 
								 | 
							
								    >>> x["baz"]
							 | 
						||
| 
								 | 
							
								    (1, 2, 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    If someone modifies the cookie and the checksum is wrong the unserialize
							 | 
						||
| 
								 | 
							
								    method will fail silently and return a new empty `SecureCookie` object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Keep in mind that the values will be visible in the cookie so do not
							 | 
						||
| 
								 | 
							
								    store data in a cookie you don't want the user to see.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Application Integration
							 | 
						||
| 
								 | 
							
								    =======================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    If you are using the werkzeug request objects you could integrate the
							 | 
						||
| 
								 | 
							
								    secure cookie into your application like this::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        from werkzeug.utils import cached_property
							 | 
						||
| 
								 | 
							
								        from werkzeug.wrappers import BaseRequest
							 | 
						||
| 
								 | 
							
								        from werkzeug.contrib.securecookie import SecureCookie
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # don't use this key but a different one; you could just use
							 | 
						||
| 
								 | 
							
								        # os.urandom(20) to get something random
							 | 
						||
| 
								 | 
							
								        SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class Request(BaseRequest):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            @cached_property
							 | 
						||
| 
								 | 
							
								            def client_session(self):
							 | 
						||
| 
								 | 
							
								                data = self.cookies.get('session_data')
							 | 
						||
| 
								 | 
							
								                if not data:
							 | 
						||
| 
								 | 
							
								                    return SecureCookie(secret_key=SECRET_KEY)
							 | 
						||
| 
								 | 
							
								                return SecureCookie.unserialize(data, SECRET_KEY)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def application(environ, start_response):
							 | 
						||
| 
								 | 
							
								            request = Request(environ)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # get a response object here
							 | 
						||
| 
								 | 
							
								            response = ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if request.client_session.should_save:
							 | 
						||
| 
								 | 
							
								                session_data = request.client_session.serialize()
							 | 
						||
| 
								 | 
							
								                response.set_cookie('session_data', session_data,
							 | 
						||
| 
								 | 
							
								                                    httponly=True)
							 | 
						||
| 
								 | 
							
								            return response(environ, start_response)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    A less verbose integration can be achieved by using shorthand methods::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class Request(BaseRequest):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            @cached_property
							 | 
						||
| 
								 | 
							
								            def client_session(self):
							 | 
						||
| 
								 | 
							
								                return SecureCookie.load_cookie(self, secret_key=COOKIE_SECRET)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def application(environ, start_response):
							 | 
						||
| 
								 | 
							
								            request = Request(environ)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # get a response object here
							 | 
						||
| 
								 | 
							
								            response = ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            request.client_session.save_cookie(response)
							 | 
						||
| 
								 | 
							
								            return response(environ, start_response)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
							 | 
						||
| 
								 | 
							
								    :license: BSD, see LICENSE for more details.
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								import pickle
							 | 
						||
| 
								 | 
							
								import base64
							 | 
						||
| 
								 | 
							
								from hmac import new as hmac
							 | 
						||
| 
								 | 
							
								from time import time
							 | 
						||
| 
								 | 
							
								from hashlib import sha1 as _default_hash
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from werkzeug._compat import iteritems, text_type, to_bytes
							 | 
						||
| 
								 | 
							
								from werkzeug.urls import url_quote_plus, url_unquote_plus
							 | 
						||
| 
								 | 
							
								from werkzeug._internal import _date_to_unix
							 | 
						||
| 
								 | 
							
								from werkzeug.contrib.sessions import ModificationTrackingDict
							 | 
						||
| 
								 | 
							
								from werkzeug.security import safe_str_cmp
							 | 
						||
| 
								 | 
							
								from werkzeug._compat import to_native
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class UnquoteError(Exception):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Internal exception used to signal failures on quoting."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SecureCookie(ModificationTrackingDict):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Represents a secure cookie.  You can subclass this class and provide
							 | 
						||
| 
								 | 
							
								    an alternative mac method.  The import thing is that the mac method
							 | 
						||
| 
								 | 
							
								    is a function with a similar interface to the hashlib.  Required
							 | 
						||
| 
								 | 
							
								    methods are update() and digest().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Example usage:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
							 | 
						||
| 
								 | 
							
								    >>> x["foo"]
							 | 
						||
| 
								 | 
							
								    42
							 | 
						||
| 
								 | 
							
								    >>> x["baz"]
							 | 
						||
| 
								 | 
							
								    (1, 2, 3)
							 | 
						||
| 
								 | 
							
								    >>> x["blafasel"] = 23
							 | 
						||
| 
								 | 
							
								    >>> x.should_save
							 | 
						||
| 
								 | 
							
								    True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param data: the initial data.  Either a dict, list of tuples or `None`.
							 | 
						||
| 
								 | 
							
								    :param secret_key: the secret key.  If not set `None` or not specified
							 | 
						||
| 
								 | 
							
								                       it has to be set before :meth:`serialize` is called.
							 | 
						||
| 
								 | 
							
								    :param new: The initial value of the `new` flag.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #: The hash method to use.  This has to be a module with a new function
							 | 
						||
| 
								 | 
							
								    #: or a function that creates a hashlib object.  Such as `hashlib.md5`
							 | 
						||
| 
								 | 
							
								    #: Subclasses can override this attribute.  The default hash is sha1.
							 | 
						||
| 
								 | 
							
								    #: Make sure to wrap this in staticmethod() if you store an arbitrary
							 | 
						||
| 
								 | 
							
								    #: function there such as hashlib.sha1 which  might be implemented
							 | 
						||
| 
								 | 
							
								    #: as a function.
							 | 
						||
| 
								 | 
							
								    hash_method = staticmethod(_default_hash)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #: the module used for serialization.  Unless overriden by subclasses
							 | 
						||
| 
								 | 
							
								    #: the standard pickle module is used.
							 | 
						||
| 
								 | 
							
								    serialization_method = pickle
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #: if the contents should be base64 quoted.  This can be disabled if the
							 | 
						||
| 
								 | 
							
								    #: serialization process returns cookie safe strings only.
							 | 
						||
| 
								 | 
							
								    quote_base64 = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, data=None, secret_key=None, new=True):
							 | 
						||
| 
								 | 
							
								        ModificationTrackingDict.__init__(self, data or ())
							 | 
						||
| 
								 | 
							
								        # explicitly convert it into a bytestring because python 2.6
							 | 
						||
| 
								 | 
							
								        # no longer performs an implicit string conversion on hmac
							 | 
						||
| 
								 | 
							
								        if secret_key is not None:
							 | 
						||
| 
								 | 
							
								            secret_key = to_bytes(secret_key, 'utf-8')
							 | 
						||
| 
								 | 
							
								        self.secret_key = secret_key
							 | 
						||
| 
								 | 
							
								        self.new = new
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return '<%s %s%s>' % (
							 | 
						||
| 
								 | 
							
								            self.__class__.__name__,
							 | 
						||
| 
								 | 
							
								            dict.__repr__(self),
							 | 
						||
| 
								 | 
							
								            self.should_save and '*' or ''
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def should_save(self):
							 | 
						||
| 
								 | 
							
								        """True if the session should be saved.  By default this is only true
							 | 
						||
| 
								 | 
							
								        for :attr:`modified` cookies, not :attr:`new`.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self.modified
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def quote(cls, value):
							 | 
						||
| 
								 | 
							
								        """Quote the value for the cookie.  This can be any object supported
							 | 
						||
| 
								 | 
							
								        by :attr:`serialization_method`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param value: the value to quote.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if cls.serialization_method is not None:
							 | 
						||
| 
								 | 
							
								            value = cls.serialization_method.dumps(value)
							 | 
						||
| 
								 | 
							
								        if cls.quote_base64:
							 | 
						||
| 
								 | 
							
								            value = b''.join(base64.b64encode(value).splitlines()).strip()
							 | 
						||
| 
								 | 
							
								        return value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def unquote(cls, value):
							 | 
						||
| 
								 | 
							
								        """Unquote the value for the cookie.  If unquoting does not work a
							 | 
						||
| 
								 | 
							
								        :exc:`UnquoteError` is raised.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param value: the value to unquote.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            if cls.quote_base64:
							 | 
						||
| 
								 | 
							
								                value = base64.b64decode(value)
							 | 
						||
| 
								 | 
							
								            if cls.serialization_method is not None:
							 | 
						||
| 
								 | 
							
								                value = cls.serialization_method.loads(value)
							 | 
						||
| 
								 | 
							
								            return value
							 | 
						||
| 
								 | 
							
								        except Exception:
							 | 
						||
| 
								 | 
							
								            # unfortunately pickle and other serialization modules can
							 | 
						||
| 
								 | 
							
								            # cause pretty every error here.  if we get one we catch it
							 | 
						||
| 
								 | 
							
								            # and convert it into an UnquoteError
							 | 
						||
| 
								 | 
							
								            raise UnquoteError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def serialize(self, expires=None):
							 | 
						||
| 
								 | 
							
								        """Serialize the secure cookie into a string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        If expires is provided, the session will be automatically invalidated
							 | 
						||
| 
								 | 
							
								        after expiration when you unseralize it. This provides better
							 | 
						||
| 
								 | 
							
								        protection against session cookie theft.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param expires: an optional expiration date for the cookie (a
							 | 
						||
| 
								 | 
							
								                        :class:`datetime.datetime` object)
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if self.secret_key is None:
							 | 
						||
| 
								 | 
							
								            raise RuntimeError('no secret key defined')
							 | 
						||
| 
								 | 
							
								        if expires:
							 | 
						||
| 
								 | 
							
								            self['_expires'] = _date_to_unix(expires)
							 | 
						||
| 
								 | 
							
								        result = []
							 | 
						||
| 
								 | 
							
								        mac = hmac(self.secret_key, None, self.hash_method)
							 | 
						||
| 
								 | 
							
								        for key, value in sorted(self.items()):
							 | 
						||
| 
								 | 
							
								            result.append(('%s=%s' % (
							 | 
						||
| 
								 | 
							
								                url_quote_plus(key),
							 | 
						||
| 
								 | 
							
								                self.quote(value).decode('ascii')
							 | 
						||
| 
								 | 
							
								            )).encode('ascii'))
							 | 
						||
| 
								 | 
							
								            mac.update(b'|' + result[-1])
							 | 
						||
| 
								 | 
							
								        return b'?'.join([
							 | 
						||
| 
								 | 
							
								            base64.b64encode(mac.digest()).strip(),
							 | 
						||
| 
								 | 
							
								            b'&'.join(result)
							 | 
						||
| 
								 | 
							
								        ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def unserialize(cls, string, secret_key):
							 | 
						||
| 
								 | 
							
								        """Load the secure cookie from a serialized string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param string: the cookie value to unserialize.
							 | 
						||
| 
								 | 
							
								        :param secret_key: the secret key used to serialize the cookie.
							 | 
						||
| 
								 | 
							
								        :return: a new :class:`SecureCookie`.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if isinstance(string, text_type):
							 | 
						||
| 
								 | 
							
								            string = string.encode('utf-8', 'replace')
							 | 
						||
| 
								 | 
							
								        if isinstance(secret_key, text_type):
							 | 
						||
| 
								 | 
							
								            secret_key = secret_key.encode('utf-8', 'replace')
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            base64_hash, data = string.split(b'?', 1)
							 | 
						||
| 
								 | 
							
								        except (ValueError, IndexError):
							 | 
						||
| 
								 | 
							
								            items = ()
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            items = {}
							 | 
						||
| 
								 | 
							
								            mac = hmac(secret_key, None, cls.hash_method)
							 | 
						||
| 
								 | 
							
								            for item in data.split(b'&'):
							 | 
						||
| 
								 | 
							
								                mac.update(b'|' + item)
							 | 
						||
| 
								 | 
							
								                if b'=' not in item:
							 | 
						||
| 
								 | 
							
								                    items = None
							 | 
						||
| 
								 | 
							
								                    break
							 | 
						||
| 
								 | 
							
								                key, value = item.split(b'=', 1)
							 | 
						||
| 
								 | 
							
								                # try to make the key a string
							 | 
						||
| 
								 | 
							
								                key = url_unquote_plus(key.decode('ascii'))
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    key = to_native(key)
							 | 
						||
| 
								 | 
							
								                except UnicodeError:
							 | 
						||
| 
								 | 
							
								                    pass
							 | 
						||
| 
								 | 
							
								                items[key] = value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # no parsing error and the mac looks okay, we can now
							 | 
						||
| 
								 | 
							
								            # sercurely unpickle our cookie.
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                client_hash = base64.b64decode(base64_hash)
							 | 
						||
| 
								 | 
							
								            except TypeError:
							 | 
						||
| 
								 | 
							
								                items = client_hash = None
							 | 
						||
| 
								 | 
							
								            if items is not None and safe_str_cmp(client_hash, mac.digest()):
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    for key, value in iteritems(items):
							 | 
						||
| 
								 | 
							
								                        items[key] = cls.unquote(value)
							 | 
						||
| 
								 | 
							
								                except UnquoteError:
							 | 
						||
| 
								 | 
							
								                    items = ()
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    if '_expires' in items:
							 | 
						||
| 
								 | 
							
								                        if time() > items['_expires']:
							 | 
						||
| 
								 | 
							
								                            items = ()
							 | 
						||
| 
								 | 
							
								                        else:
							 | 
						||
| 
								 | 
							
								                            del items['_expires']
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                items = ()
							 | 
						||
| 
								 | 
							
								        return cls(items, secret_key, False)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def load_cookie(cls, request, key='session', secret_key=None):
							 | 
						||
| 
								 | 
							
								        """Loads a :class:`SecureCookie` from a cookie in request.  If the
							 | 
						||
| 
								 | 
							
								        cookie is not set, a new :class:`SecureCookie` instanced is
							 | 
						||
| 
								 | 
							
								        returned.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param request: a request object that has a `cookies` attribute
							 | 
						||
| 
								 | 
							
								                        which is a dict of all cookie values.
							 | 
						||
| 
								 | 
							
								        :param key: the name of the cookie.
							 | 
						||
| 
								 | 
							
								        :param secret_key: the secret key used to unquote the cookie.
							 | 
						||
| 
								 | 
							
								                           Always provide the value even though it has
							 | 
						||
| 
								 | 
							
								                           no default!
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        data = request.cookies.get(key)
							 | 
						||
| 
								 | 
							
								        if not data:
							 | 
						||
| 
								 | 
							
								            return cls(secret_key=secret_key)
							 | 
						||
| 
								 | 
							
								        return cls.unserialize(data, secret_key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def save_cookie(self, response, key='session', expires=None,
							 | 
						||
| 
								 | 
							
								                    session_expires=None, max_age=None, path='/', domain=None,
							 | 
						||
| 
								 | 
							
								                    secure=None, httponly=False, force=False):
							 | 
						||
| 
								 | 
							
								        """Saves the SecureCookie in a cookie on response object.  All
							 | 
						||
| 
								 | 
							
								        parameters that are not described here are forwarded directly
							 | 
						||
| 
								 | 
							
								        to :meth:`~BaseResponse.set_cookie`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param response: a response object that has a
							 | 
						||
| 
								 | 
							
								                         :meth:`~BaseResponse.set_cookie` method.
							 | 
						||
| 
								 | 
							
								        :param key: the name of the cookie.
							 | 
						||
| 
								 | 
							
								        :param session_expires: the expiration date of the secure cookie
							 | 
						||
| 
								 | 
							
								                                stored information.  If this is not provided
							 | 
						||
| 
								 | 
							
								                                the cookie `expires` date is used instead.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if force or self.should_save:
							 | 
						||
| 
								 | 
							
								            data = self.serialize(session_expires or expires)
							 | 
						||
| 
								 | 
							
								            response.set_cookie(key, data, expires=expires, max_age=max_age,
							 | 
						||
| 
								 | 
							
								                                path=path, domain=domain, secure=secure,
							 | 
						||
| 
								 | 
							
								                                httponly=httponly)
							 |