from base64 import urlsafe_b64encode, b64decode from collections import namedtuple import logging import re
import six
from .base import Resource from .util import (calculate_mac,
strings_match,
utc_now,
validate_header_attr) from .exc import (CredentialsLookupError,
InvalidBewit,
MacMismatch,
TokenExpired)
log = logging.getLogger(__name__)
def get_bewit(resource): """
Returns a bewit identifier for the resource as a string.
:param resource:
Resource to generate a bewit for
:type resource: `mohawk.base.Resource` """ if resource.method != 'GET': raise ValueError('bewits can only be generated for GET requests') if resource.nonce != '': raise ValueError('bewits must use an empty nonce')
mac = calculate_mac( 'bewit',
resource, None,
)
if isinstance(mac, six.binary_type):
mac = mac.decode('ascii')
# b64encode works only with bytes in python3, but all of our parameters are # in unicode, so we need to encode them. The cleanest way to do this that # works in both python 2 and 3 is to use string formatting to get a # unicode string, and then explicitly encode it to bytes.
inner_bewit = u"{id}\\{exp}\\{mac}\\{ext}".format(
id=resource.credentials['id'],
exp=resource.timestamp,
mac=mac,
ext=ext,
)
inner_bewit_bytes = inner_bewit.encode('ascii')
bewit_bytes = urlsafe_b64encode(inner_bewit_bytes) # Now decode the resulting bytes back to a unicode string return bewit_bytes.decode('ascii')
bewittuple = namedtuple('bewittuple', 'id expiration mac ext')
def parse_bewit(bewit): """
Returns a `bewittuple` representing the parts of an encoded bewit string.
This has the following named attributes:
(id, expiration, mac, ext)
:param bewit:
A base64 encoded bewit string
:type bewit: str """
decoded_bewit = b64decode(bewit).decode('ascii')
bewit_parts = decoded_bewit.split("\\") if len(bewit_parts) != 4: raise InvalidBewit('Expected 4 parts to bewit: %s' % decoded_bewit) return bewittuple(*bewit_parts)
def strip_bewit(url): """
Strips the bewit parameter out of a url.
Returns (encoded_bewit, stripped_url)
Raises InvalidBewit if no bewit found.
:param url:
The url containing a bewit parameter
:type url: str """
m = re.search('[?&]bewit=([^&]+)', url) ifnot m: raise InvalidBewit('no bewit data found')
bewit = m.group(1)
stripped_url = url[:m.start()] + url[m.end():] return bewit, stripped_url
def check_bewit(url, credential_lookup, now=None): """
Validates the given bewit.
Returns Trueif the resource has a valid bewit parameter attached, or raises a subclass of HawkFail otherwise.
:param credential_lookup:
Callable to look up the credentials dict by sender ID.
The credentials dict must have the keys:
``id``, ``key``, and ``algorithm``.
See :ref:`receiving-request` for an example.
:type credential_lookup: callable
:param now=None:
Unix epoch time for the current time to determine if bewit has expired. IfNone, then the current time as given by utc_now() is used.
:type now=None: integer """
raw_bewit, stripped_url = strip_bewit(url)
bewit = parse_bewit(raw_bewit) try:
credentials = credential_lookup(bewit.id) except LookupError: raise CredentialsLookupError('Could not find credentials for ID {0}'
.format(bewit.id))
res = Resource(url=stripped_url,
method='GET',
credentials=credentials,
timestamp=bewit.expiration,
nonce='',
ext=bewit.ext,
)
mac = calculate_mac('bewit', res, None)
mac = mac.decode('ascii')
ifnot strings_match(mac, bewit.mac): raise MacMismatch('bewit with mac {bewit_mac} did not match expected mac {expected_mac}'
.format(bewit_mac=bewit.mac,
expected_mac=mac))
# Check that the timestamp isn't expired if now isNone: # TODO: Add offset/skew
now = utc_now() if int(bewit.expiration) < now: # TODO: Refactor TokenExpired to handle this better raise TokenExpired('bewit with UTC timestamp {ts} has expired; ' 'it was compared to {now}'
.format(ts=bewit.expiration, now=now),
localtime_in_seconds=now,
www_authenticate=''
)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.