Beispiel #1
0
 def verify(self, assertion, audience=None):
     data = super(LocalBrowserIdVerifier, self).verify(assertion, audience)
     if self.allowed_issuers is not None:
         issuer = data.get('issuer')
         if issuer not in self.allowed_issuers:
             raise InvalidIssuerError("Issuer not allowed: %s" % (issuer,))
     return data
    def _fetch(self,
               hostname,
               requests,
               well_known_url=None,
               side_effect=None,
               response_text='',
               status_code=200):
        response = Mock()
        response.text = response_text
        response.status_code = status_code
        requests.request.side_effect = side_effect
        requests.request.return_value = response

        kwargs = {}
        if well_known_url is not None:
            kwargs['well_known_url'] = well_known_url

        supportdoc = fetch_support_document(hostname, **kwargs)

        try:
            key = supportdoc['public-key']
        except KeyError:
            raise InvalidIssuerError('Host %r has malformed public key '
                                     'document' % hostname)

        return key
Beispiel #3
0
class RemoteVerifier(object):
    implements(IBrowserIdVerifier)

    def __init__(self,
                 audiences=None,
                 trusted_issuers=None,
                 allowed_issuers=None,
                 verifier_url=None):
        # Since we don't parse the assertion locally, we cannot support
        # list- or pattern-based audience strings.
        if audiences is not None:
            assert isinstance(audiences, basestring)
        self.audiences = audiences
        if isinstance(trusted_issuers, basestring):
            trusted_issuers = trusted_issuers.split()
        self.trusted_issuers = trusted_issuers
        if isinstance(allowed_issuers, basestring):
            allowed_issuers = allowed_issuers.split()
        self.allowed_issuers = allowed_issuers
        if verifier_url is None:
            verifier_url = "https://verifier.accounts.firefox.com/v2"
        self.verifier_url = verifier_url
        self.session = requests.Session()
        self.session.verify = True

    def verify(self, assertion, audience=None):
        if audience is None:
            audience = self.audiences

        body = {'assertion': assertion, 'audience': audience}
        if self.trusted_issuers is not None:
            body['trustedIssuers'] = self.trusted_issuers
        headers = {'content-type': 'application/json'}
        try:
            response = self.session.post(self.verifier_url,
                                         data=json.dumps(body),
                                         headers=headers)
        except (socket.error, requests.RequestException), e:
            msg = "Failed to POST %s. Reason: %s" % (self.verifier_url, str(e))
            raise ConnectionError(msg)

        if response.status_code != 200:
            raise ConnectionError('server returned invalid response')
        try:
            data = json.loads(response.text)
        except ValueError:
            raise ConnectionError("server returned invalid response")

        if data.get('status') != "okay":
            reason = data.get('reason', 'unknown error')
            if "audience mismatch" in reason:
                raise AudienceMismatchError(data.get("audience"), audience)
            if "expired" in reason or "issued later than" in reason:
                raise ExpiredSignatureError(reason)
            raise InvalidSignatureError(reason)
        if self.allowed_issuers is not None:
            issuer = data.get('issuer')
            if issuer not in self.allowed_issuers:
                raise InvalidIssuerError("Issuer not allowed: %s" % (issuer, ))
        return data
def fetch_public_key(hostname, well_known_url=None):
    """Fetch the BrowserID public key for the given hostname.

    This function uses the well-known BrowserID meta-data file to extract
    the public key for the given hostname.
    """
    if well_known_url is None:
        well_known_url = WELL_KNOWN_URL

    hostname = "https://" + hostname
    # Try to find the public key.  If it can't be found then we
    # raise an InvalidIssuerError.  Any other connection-related
    # errors are passed back up to the caller.
    try:
        # Try to read the well-known browserid file to load the key.
        try:
            browserid_url = urljoin(hostname, well_known_url)
            browserid_data = urlread(browserid_url)
        except ConnectionError, e:
            if "404" not in str(e):
                raise
            # The well-known file was not found, try falling back to
            # just "/pk".  Not really a good idea, but that's currently
            # the only way to get browserid.org's public key.
            pubkey_url = urljoin(hostname, "/pk")
            key = urlread(urljoin(hostname, pubkey_url))
            try:
                key = json.loads(key)
            except ValueError:
                msg = "Host %r has malformed public key document"
                raise InvalidIssuerError(msg % (hostname, ))
        else:
def fetch_public_key(url, *args):
    """Fetch the public key from the given URL."""
    # Try to find the public key.  If it can't be found then we
    # raise an InvalidIssuerError.  Any other connection-related
    # errors are passed back up to the caller.
    response = _get(url)
    if response.status_code == 200:
        try:
            try:
                key = parse_jwt(response.text).payload['jwk'][0]
            except ValueError:
                key = json.loads(response.text)['jwk'][0]
        except (ValueError, KeyError):
            raise InvalidIssuerError('Host %r has malformed public key '
                                     'document' % url)
    else:
        raise InvalidIssuerError('Can not retrieve key from "%s"' % url)

    return key
Beispiel #6
0
    def get_key(self, hostname):
        """Get the public key for verifying assertions from the given host."""
        supportdoc = self.get_support_document(hostname)
        try:
            key = supportdoc['public-key']
        except KeyError:
            raise InvalidIssuerError(
                    "Host %r doesn't provide a public key" % hostname)

        return key
Beispiel #7
0
def fetch_support_document(hostname, well_known_url=None, verify=None):
    """Fetch the BrowserID well-known file for the given hostname.

    This function fetches and parses the well-known BrowserID meta-data file.

    :param verify: verify the certificate when requesting ssl resources
    """
    if well_known_url is None:
        well_known_url = WELL_KNOWN_URL

    hostname = 'https://%s' % hostname

    # Try to find the support document.  If it can't be found then we
    # raise an InvalidIssuerError.  Any other connection-related
    # errors are passed back up to the caller.
    response = netutils.get(urljoin(hostname, well_known_url), verify=verify)
    if response.status_code == 200:
        try:
            data = json.loads(response.text)
        except ValueError:
            raise InvalidIssuerError('Host %r has malformed BrowserID '
                                     'support document' % hostname)
    else:
        # The well-known file was not found, try falling back to
        # just "/pk".
        response = netutils.get(urljoin(hostname, '/pk'), verify=verify)
        if response.status_code == 200:
            try:
                key = json.loads(response.text)
            except ValueError:
                raise InvalidIssuerError('Host %r has malformed BrowserID '
                                         'metadata document' % hostname)

            data = {"public-key": key}
        else:
            raise InvalidIssuerError('Host %r does not declare support for '
                                     'BrowserID' % hostname)

    return data
    def verify(self, assertion, audience=None):
        if audience is None:
            audience = self.audiences

        body = {'assertion': assertion, 'audience': audience}
        if self.trusted_issuers is not None:
            body['trustedIssuers'] = self.trusted_issuers
        headers = {'content-type': 'application/json'}
        try:
            response = self.session.post(self.verifier_url,
                                         data=json.dumps(body),
                                         headers=headers,
                                         timeout=self.timeout)
        except (socket.error, requests.RequestException) as e:
            msg = "Failed to POST %s. Reason: %s" % (self.verifier_url, str(e))
            raise ConnectionError(msg)

        if response.status_code != 200:
            raise ConnectionError('server returned invalid response code')
        try:
            data = json.loads(response.text)
        except ValueError:
            raise ConnectionError("server returned invalid response body")

        if data.get('status') != "okay":
            reason = data.get('reason', 'unknown error')
            if "audience mismatch" in reason:
                raise AudienceMismatchError(data.get("audience"), audience)
            if "expired" in reason or "issued later than" in reason:
                raise ExpiredSignatureError(reason)
            raise InvalidSignatureError(reason)
        if self.allowed_issuers is not None:
            issuer = data.get('issuer')
            if issuer not in self.allowed_issuers:
                raise InvalidIssuerError("Issuer not allowed: %s" % (issuer,))
        return data
            # the only way to get browserid.org's public key.
            pubkey_url = urljoin(hostname, "/pk")
            key = urlread(urljoin(hostname, pubkey_url))
            try:
                key = json.loads(key)
            except ValueError:
                msg = "Host %r has malformed public key document"
                raise InvalidIssuerError(msg % (hostname, ))
        else:
            # The well-known file was found, it must contain the key
            # data as part of its JSON response.
            try:
                key = json.loads(browserid_data)["public-key"]
            except (ValueError, KeyError):
                msg = "Host %r has malformed BrowserID metadata document"
                raise InvalidIssuerError(msg % (hostname, ))
        return key
    except ConnectionError, e:
        if "404" not in str(e):
            raise
        msg = "Host %r does not declare support for BrowserID" % (hostname, )
        raise InvalidIssuerError(msg)


def urlread(url, data=None):
    """Read the given URL, return response as a string."""
    # Anything that goes wrong inside this function will
    # be re-raised as an instance of ConnectionError.
    try:
        resp = secure_urlopen(url, data)
        try: