Example #1
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    def _raise_unauthorized():
        raise JsonError(401, description='Unauthorized')

    token = request.headers.get('Authorization')
    if token is None:
        _raise_unauthorized()

    token = token.split()
    if len(token) != 2:
        _raise_unauthorized()

    name, assertion = token
    if name.lower() != 'browser-id':
        resp = JsonError(401, description='Unsupported')
        resp.www_authenticate = ('Browser-ID', {})
        raise resp

    try:
        verifier = get_verifier()
        assertion = verifier.verify(assertion)
    except BrowserIDError:
        _raise_unauthorized()

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    request.validated['assertion'] = assertion
Example #2
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browserid':
        resp = _unauthorized(description='Unsupported')
        resp.www_authenticate = ('BrowserID', {})
        raise resp

    try:
        verifier = get_verifier()
        with metrics_timer('tokenserver.assertion.verify', request):
            assertion = verifier.verify(assertion)
    except browserid.errors.Error as e:
        # Convert CamelCase to under_scores for reporting.
        error_type = e.__class__.__name__
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()
        request.metrics['token.assertion.verify_failure'] = 1
        request.metrics['token.assertion.%s' % error_type] = 1
        # Log a full traceback for errors that are not a simple
        # "your assertion was bad and we dont trust it".
        if not isinstance(e, browserid.errors.TrustError):
            logger.exception("Unexpected verification error")
        # Report an appropriate error code.
        if isinstance(e, browserid.errors.ConnectionError):
            raise json_error(503, description="Resource is not available")
        if isinstance(e, browserid.errors.ExpiredSignatureError):
            raise _unauthorized("invalid-timestamp")
        raise _unauthorized("invalid-credentials")

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    request.metrics['token.assertion.verify_success'] = 1
    request.validated['assertion'] = assertion

    # Include a unique FxA identifier in the logs, but obfuscate
    # it for privacy purposes.
    id_key = request.registry.settings.get("fxa.metrics_uid_secret_key")
    if id_key:
        email = request.validated['assertion']['email']
        request.metrics['uid'] = fxa_metrics_uid(email, id_key)
Example #3
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    metlog = request.registry['metlog']

    def _unauthorized():
        return json_error(401, description='Unauthorized')

    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browser-id':
        resp = json_error(401, description='Unsupported')
        resp.www_authenticate = ('Browser-ID', {})
        raise resp

    def _handle_exception(error_type):
        # convert CamelCase to camel_case
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()

        metlog.incr('token.assertion.verify_failure')
        metlog.incr('token.assertion.%s' % error_type)
        if error_type == "connection_error":
            raise json_error(503, description="Resource is not available")
        else:
            raise _unauthorized()

    try:
        verifier = get_verifier()
        assertion = verifier.verify(assertion)
    except ClientCatchedError as e:
        _handle_exception(e.error_type)
    except BrowserIDError as e:
        _handle_exception(e.__class__.__name__)

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    metlog.incr('token.assertion.verify_success')
    request.validated['assertion'] = assertion
Example #4
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    metlog = request.registry['metlog']

    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browserid':
        resp = _unauthorized(description='Unsupported')
        resp.www_authenticate = ('BrowserID', {})
        raise resp

    def _handle_exception(error_type):
        # convert CamelCase to camel_case
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()

        metlog.incr('token.assertion.verify_failure')
        metlog.incr('token.assertion.%s' % error_type)
        if error_type == "connection_error":
            raise json_error(503, description="Resource is not available")
        if error_type == "expired_signature_error":
            raise _unauthorized("invalid-timestamp")
        else:
            raise _unauthorized("invalid-credentials")

    try:
        verifier = get_verifier()
        with time_backend_operation(request, 'assertion.verify'):
            assertion = verifier.verify(assertion)
    except ClientCatchedError as e:
        _handle_exception(e.error_type)
    except BrowserIDError as e:
        _handle_exception(e.__class__.__name__)

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    metlog.incr('token.assertion.verify_success')
    request.validated['assertion'] = assertion
    def mock_verifier(self, response=None, exc=None):
        def mock_verify_method(assertion):
            if exc is not None:
                raise exc
            if response is not None:
                return response
            return {"status": "okay", "email": get_assertion_info(assertion)["principal"]["email"]}

        verifier = get_verifier(self.config.registry)
        orig_verify_method = verifier.__dict__.get("verify", None)
        verifier.__dict__["verify"] = mock_verify_method
        try:
            yield None
        finally:
            if orig_verify_method is None:
                del verifier.__dict__["verify"]
            else:
                verifier.__dict__["verify"] = orig_verify_method
Example #6
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browserid':
        resp = _unauthorized(description='Unsupported')
        resp.www_authenticate = ('BrowserID', {})
        raise resp

    def _handle_exception(error_type):
        # convert CamelCase to camel_case
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()

        request.metrics['token.assertion.verify_failure'] = 1
        request.metrics['token.assertion.%s' % error_type] = 1
        if error_type == "connection_error":
            raise json_error(503, description="Resource is not available")
        if error_type == "expired_signature_error":
            raise _unauthorized("invalid-timestamp")
        else:
            raise _unauthorized("invalid-credentials")

    try:
        verifier = get_verifier()
        with metrics_timer('tokenserver.assertion.verify', request):
            assertion = verifier.verify(assertion)
    except BrowserIDError as e:
        _handle_exception(e.__class__.__name__)

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    request.metrics['token.assertion.verify_success'] = 1
    request.validated['assertion'] = assertion
Example #7
0
 def mock_verifier(self, response=None, exc=None):
     def mock_verify_method(assertion):
         if exc is not None:
             raise exc
         if response is not None:
             return response
         return {
             "status": "okay",
             "email": get_assertion_info(assertion)["principal"]["email"],
         }
     verifier = get_verifier(self.config.registry)
     orig_verify_method = verifier.__dict__.get("verify", None)
     verifier.__dict__["verify"] = mock_verify_method
     try:
         yield None
     finally:
         if orig_verify_method is None:
             del verifier.__dict__["verify"]
         else:
             verifier.__dict__["verify"] = orig_verify_method
Example #8
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browserid':
        resp = _unauthorized(description='Unsupported')
        resp.www_authenticate = ('BrowserID', {})
        raise resp

    try:
        verifier = get_verifier()
        with metrics_timer('tokenserver.assertion.verify', request):
            assertion = verifier.verify(assertion)
    except browserid.errors.Error as e:
        # Convert CamelCase to under_scores for reporting.
        error_type = e.__class__.__name__
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()
        request.metrics['token.assertion.verify_failure'] = 1
        request.metrics['token.assertion.%s' % error_type] = 1
        # Log a full traceback for errors that are not a simple
        # "your assertion was bad and we dont trust it".
        if not isinstance(e, browserid.errors.TrustError):
            logger.exception("Unexpected verification error")
        # Report an appropriate error code.
        if isinstance(e, browserid.errors.ConnectionError):
            raise json_error(503, description="Resource is not available")
        if isinstance(e, browserid.errors.ExpiredSignatureError):
            raise _unauthorized("invalid-timestamp")
        raise _unauthorized("invalid-credentials")

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    request.metrics['token.assertion.verify_success'] = 1
    request.validated['assertion'] = assertion

    id_key = request.registry.settings.get("fxa.metrics_uid_secret_key")
    if id_key is None:
        id_key = 'insecure'
    email = assertion['email']
    fxa_uid_full = fxa_metrics_hash(email, id_key)
    # "legacy" key used by heka active_counts.lua
    request.metrics['uid'] = fxa_uid_full
    request.metrics['email'] = email

    # "new" keys use shorter values
    fxa_uid = fxa_uid_full[:32]
    request.validated['fxa_uid'] = fxa_uid
    request.metrics['fxa_uid'] = fxa_uid

    try:
        device = assertion['idpClaims']['fxa-deviceId']
        if device is None:
            device = 'none'
    except KeyError:
        device = 'none'
    device_id = fxa_metrics_hash(fxa_uid + device, id_key)[:32]
    request.validated['device_id'] = device_id
    request.metrics['device_id'] = device_id
Example #9
0
def valid_assertion(request):
    """Validate that the assertion given in the request is correct.

    If not, add errors in the response so that the client can know what
    happened.
    """
    token = request.headers.get('Authorization')
    if token is None:
        raise _unauthorized()

    token = token.split()
    if len(token) != 2:
        raise _unauthorized()

    name, assertion = token
    if name.lower() != 'browserid':
        resp = _unauthorized(description='Unsupported')
        resp.www_authenticate = ('BrowserID', {})
        raise resp

    try:
        verifier = get_verifier()
        with metrics_timer('tokenserver.assertion.verify', request):
            assertion = verifier.verify(assertion)
    except browserid.errors.Error as e:
        # Convert CamelCase to under_scores for reporting.
        error_type = e.__class__.__name__
        error_type = re.sub('(?<=.)([A-Z])', r'_\1', error_type).lower()
        request.metrics['token.assertion.verify_failure'] = 1
        request.metrics['token.assertion.%s' % error_type] = 1
        # Log a full traceback for errors that are not a simple
        # "your assertion was bad and we dont trust it".
        if not isinstance(e, browserid.errors.TrustError):
            logger.exception("Unexpected verification error")
        # Report an appropriate error code.
        if isinstance(e, browserid.errors.ConnectionError):
            raise json_error(503, description="Resource is not available")
        if isinstance(e, browserid.errors.ExpiredSignatureError):
            raise _unauthorized("invalid-timestamp")
        raise _unauthorized("invalid-credentials")

    # FxA sign-in confirmation introduced the notion of unverified tokens.
    # The default value is True to preserve backwards compatibility.
    try:
        tokenVerified = assertion['idpClaims']['fxa-tokenVerified']
    except KeyError:
        tokenVerified = True
    if not tokenVerified:
        raise _unauthorized("invalid-credentials")

    # everything sounds good, add the assertion to the list of validated fields
    # and continue
    request.metrics['token.assertion.verify_success'] = 1
    request.validated['assertion'] = assertion

    id_key = request.registry.settings.get("fxa.metrics_uid_secret_key")
    if id_key is None:
        id_key = 'insecure'
    email = assertion['email']
    fxa_uid_full = fxa_metrics_hash(email, id_key)
    # "legacy" key used by heka active_counts.lua
    request.metrics['uid'] = fxa_uid_full
    request.metrics['email'] = email

    # "new" keys use shorter values
    fxa_uid = fxa_uid_full[:32]
    request.validated['fxa_uid'] = fxa_uid
    request.metrics['fxa_uid'] = fxa_uid

    try:
        device = assertion['idpClaims']['fxa-deviceId']
        if device is None:
            device = 'none'
    except KeyError:
        device = 'none'
    device_id = fxa_metrics_hash(fxa_uid + device, id_key)[:32]
    request.validated['device_id'] = device_id
    request.metrics['device_id'] = device_id