Exemplo n.º 1
0
    def _send_request(self, path, data):
        """
        Sends request to the FURS Server and decodes response.

        :param path: (string) Server path
        :param data: (dict) Data to be sent
        :return: (dict) Received response

        :raises:
            ConnectionTimedOutException: If connection timed out
            ConnectionException: If FURS responded with status code different than 200
            FURSException: If server responded with error
        """
        try:
            response = self.connector.post(path=path, json=data)

            if response.status_code == codes.ok:
                # TODO - we should verify server signature!
                server_response = jws.get_unverified_claims(response.json()['token'])

                return self._check_for_errors(server_response)
            else:
                raise ConnectionException(code=response.status_code,
                                          message=response.text)

        except Timeout as e:
            raise ConnectionTimedOutException(e)
Exemplo n.º 2
0
def get_unverified_claims(token):
    """Returns the decoded claims without verification of any kind.

    Args:
        token (str): A signed JWT to decode the headers from.

    Returns:
        dict: The dict representation of the token claims.

    Raises:
        JWTError: If there is an exception decoding the token.
    """
    try:
        claims = jws.get_unverified_claims(token)
    except:
        raise JWTError('Error decoding token claims.')

    try:
        claims = json.loads(claims.decode('utf-8'))
    except ValueError as e:
        raise JWTError('Invalid claims string: %s' % e)

    if not isinstance(claims, Mapping):
        raise JWTError('Invalid claims string: must be a json object')

    return claims
Exemplo n.º 3
0
def get_unverified_claims(token):
    """Returns the decoded claims without verification of any kind.

    Args:
        token (str): A signed JWT to decode the headers from.

    Returns:
        dict: The dict representation of the token claims.

    Raises:
        JWTError: If there is an exception decoding the token.
    """
    try:
        claims = jws.get_unverified_claims(token)
    except Exception:
        raise JWTError('Error decoding token claims.')

    try:
        claims = json.loads(claims.decode('utf-8'))
    except ValueError as e:
        raise JWTError('Invalid claims string: %s' % e)

    if not isinstance(claims, Mapping):
        raise JWTError('Invalid claims string: must be a json object')

    return claims
def _decode_vc(jws_raw, key_resolver):
    # before we can verify the vc, we first need to resolve the key
    # the key ID is stored in the header
    # Per the health cards IG,
    ## "Issuers SHALL publish keys as JSON Web Key Sets (see RFC7517), available at <<iss value from Signed JWT>> + .well-known/jwks.json"
    # therefore, we need decode the claims to get the iss value in order to resolve the key
    # The claims are compressed via Deflate, so decompress the data
    # then, extract the iss claim to get access to the base URL, use that to resolve key with id = kid
    # then, verify the jws
    unverified_headers = jws.get_unverified_headers(jws_raw)

    # we expect data to be zipped, so deflate the data
    if unverified_headers.get('zip') == 'DEF':
        unverfied_claims_zip = jws.get_unverified_claims(jws_raw)
        raw_data = inflate(unverfied_claims_zip)
        data = json.loads(raw_data)
    else:
        raise Exception('Expecting payload to be compressed')

    iss = data['iss']
    kid = unverified_headers['kid']

    key = key_resolver(iss, kid, 'ES256')

    verified_jws = jws.verify(jws_raw, key, algorithms='ES256')
    payload = json.loads(inflate(verified_jws))
    return payload
Exemplo n.º 5
0
    def _send_request(self, path, data):
        """
        Sends request to the FURS Server and decodes response.

        :param path: (string) Server path
        :param data: (dict) Data to be sent
        :return: (dict) Received response

        :raises:
            ConnectionTimedOutException: If connection timed out
            ConnectionException: If FURS responded with status code different than 200
            FURSException: If server responded with error
        """
        try:
            response = self.connector.post(path=path, json=data)

            if response.status_code == codes.ok:
                # TODO - we should verify server signature!
                server_response = json.loads(
                    jws.get_unverified_claims(response.json()['token']))
                return self._check_for_errors(server_response)
            else:
                raise ConnectionException(code=response.status_code,
                                          message=response.text)

        except Timeout as e:
            raise ConnectionTimedOutException(e)
Exemplo n.º 6
0
def _extract_token_body() -> dict:
    if getattr(flask.g, "token_body", None):
        return flask.g.token_body

    token = _http._get_token(flask.request.headers)
    if not token:
        return {}

    try:
        return json.loads(jws.get_unverified_claims(token=token))
    except exceptions.JOSEError:
        return {}
Exemplo n.º 7
0
def validate_signatures(body):
    att_stmts = []
    if isinstance(body, list):
        for s in body:
            if 'attachments' in s:
                att_stmts.append(s)
    elif 'attachments' in body:
        att_stmts.append(body)
    if att_stmts:
        # find if any of those statements with attachments have a signed statement
        signed_stmts = [(s, a) for s in att_stmts
                        for a in s.get('attachments', None) if a['usageType']
                        == "http://adlnet.gov/expapi/attachments/signature"]
        for ss in signed_stmts:
            sha2_key = ss[1]['sha2']
            signature = att_cache.get(sha2_key)
            algorithm = jws.get_unverified_headers(signature).get('alg', None)
            x5c = jws.get_unverified_headers(signature).get('x5c', None)
            jws_payload = jws.get_unverified_claims(signature)
            body_payload = ss[0]
            # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it
            # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec
            # only has SHOULD - need to look into. If x.509 is necessary then if no x5c header is found this should fail
            if x5c:
                verified = False
                try:
                    verified = jws.verify(signature, cert_to_key(x5c[0]),
                                          algorithm)
                except Exception, e:
                    att_cache.delete(sha2_key)
                    raise BadRequest("The JWS is not valid: %s" % e.message)
                else:
                    if not verified:
                        att_cache.delete(sha2_key)
                        raise BadRequest(
                            "The JWS is not valid - could not verify signature"
                        )
                    # Compare statements
                    if not compare_payloads(jws_payload, body_payload):
                        att_cache.delete(sha2_key)
                        raise BadRequest(
                            "The JWS is not valid - payload and body statements do not match"
                        )
            else:
                # Compare statements
                if not compare_payloads(jws_payload, body_payload):
                    att_cache.delete(sha2_key)
                    raise BadRequest(
                        "The JWS is not valid - payload and body statements do not match"
                    )
Exemplo n.º 8
0
 def _try_decode(self, openid_credentials: dict) -> dict:
     id_token = openid_credentials["id_token"]
     # "access_token" must only be provided if claim is provided, else "jwt.decode" throws...
     if b"at_hash" in jws.get_unverified_claims(id_token):
         access_token = openid_credentials["access_token"]
     else:
         access_token = None
     header = jws.get_unverified_header(id_token)
     verified_id_token = jwt.decode(
         id_token,
         self._jwk_pkey.key(header["kid"]),
         issuer=self._issuer,
         access_token=access_token,
         audience=self._client_id,
     )
     return verified_id_token
Exemplo n.º 9
0
def _decode_with_cert(token, key, hint=None):
    kid = key.get('kid', None)
    tokenkid = None
    pubcert = None
    jwtson = None

    tokendecode = jjws.get_unverified_claims(token)
    tokenkid = jjws.get_unverified_header(token).get("kid")

    if (tokenkid and kid) and (kid == tokenkid):
        try:
            jwtson = jjwt.decode(token,
                                 key,
                                 algorithms='RS256',
                                 options={'verify_aud': False})
            return jwtson
        except Exception as e:
            print("kid in token: Cannot be introspected in JWKS %s" % e)
Exemplo n.º 10
0
def get_unverified_claims(token):
    """Returns the decoded claims without verification of any kind.

    Args:
        token (str): A signed JWT to decode the headers from.

    Returns:
        dict: The dict representation of the token claims.

    Raises:
        JWTError: If there is an exception decoding the token.
    """
    try:
        claims = jws.get_unverified_claims(token)
    except:
        raise JWTError('Error decoding token claims.')

    return claims
Exemplo n.º 11
0
def get_unverified_claims(token):
    """Returns the decoded claims without verification of any kind.

    Args:
        token (str): A signed JWT to decode the headers from.

    Returns:
        dict: The dict representation of the token claims.

    Raises:
        JWTError: If there is an exception decoding the token.
    """
    try:
        claims = jws.get_unverified_claims(token)
    except:
        raise JWTError('Error decoding token claims.')

    return claims
Exemplo n.º 12
0
def validate_signatures(body):
    att_stmts = []
    if isinstance(body, list):
        for s in body:
            if 'attachments' in s:
                att_stmts.append(s)
    elif 'attachments' in body:
        att_stmts.append(body)
    if att_stmts:
        # find if any of those statements with attachments have a signed statement
        signed_stmts = [(s,a) for s in att_stmts for a in s.get('attachments', None) if a['usageType'] == "http://adlnet.gov/expapi/attachments/signature"]
        for ss in signed_stmts:
            sha2_key = ss[1]['sha2']
            signature = att_cache.get(sha2_key)
            algorithm = jws.get_unverified_headers(signature).get('alg', None)
            x5c = jws.get_unverified_headers(signature).get('x5c', None)
            jws_payload = jws.get_unverified_claims(signature)
            body_payload = ss[0]
            # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it
            # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec
            # only has SHOULD - need to look into. If x.509 is necessary then if no x5c header is found this should fail
            if x5c:
                verified = False
                try:
                    verified = jws.verify(signature, cert_to_key(x5c[0]), algorithm)
                except Exception, e:
                    att_cache.delete(sha2_key)
                    raise BadRequest("The JWS is not valid: %s" % e.message)
                else:
                    if not verified:
                        att_cache.delete(sha2_key)
                        raise BadRequest("The JWS is not valid - could not verify signature")                
                    # Compare statements
                    if not compare_payloads(jws_payload, body_payload):
                        att_cache.delete(sha2_key)
                        raise BadRequest("The JWS is not valid - payload and body statements do not match")                    
            else:
                # Compare statements
                if not compare_payloads(jws_payload, body_payload):
                    att_cache.delete(sha2_key)
                    raise BadRequest("The JWS is not valid - payload and body statements do not match")    
Exemplo n.º 13
0
def validate_signature(tup, part):
    sha2_key = tup[1][0]
    signature = get_part_payload(part)
    algorithm = jws.get_unverified_headers(signature).get('alg', None)
    if not algorithm:
        raise BadRequest(
            "No signing algorithm found for JWS signature")
    if algorithm != 'RS256' and algorithm != 'RS384' and algorithm != 'RS512':
        raise BadRequest(
            "JWS signature must be calculated with SHA-256, SHA-384 or" \
            "SHA-512 algorithms")
    x5c = jws.get_unverified_headers(signature).get('x5c', None)
    jws_payload = jws.get_unverified_claims(signature)
    body_payload = tup[0]
    # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it
    # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec
    # only has SHOULD - need to look into. If x.509 is necessary then
    # if no x5c header is found this should fail
    if x5c:
        verified = False
        try:
            verified = jws.verify(
                signature, cert_to_key(x5c[0]), algorithm)
        except Exception as e:
            raise BadRequest("The JWS is not valid: %s" % e.message)
        else:
            if not verified:
                raise BadRequest(
                    "The JWS is not valid - could not verify signature")
            # Compare statements
            if not compare_payloads(jws_payload, body_payload, sha2_key):
                raise BadRequest(
                    "The JWS is not valid - payload and body statements do not match")
    else:
        # Compare statements
        if not compare_payloads(jws_payload, body_payload, sha2_key):
            raise BadRequest(
                "The JWS is not valid - payload and body statements do not match")
Exemplo n.º 14
0
def validate_signature(tup, part):
    sha2_key = tup[1][0]
    signature = get_part_payload(part)
    algorithm = jws.get_unverified_headers(signature).get('alg', None)
    if not algorithm:
        raise BadRequest("No signing algorithm found for JWS signature")
    if algorithm != 'RS256' and algorithm != 'RS384' and algorithm != 'RS512':
        raise BadRequest(
            "JWS signature must be calculated with SHA-256, SHA-384 or" \
            "SHA-512 algorithms")
    x5c = jws.get_unverified_headers(signature).get('x5c', None)
    jws_payload = jws.get_unverified_claims(signature)
    body_payload = tup[0]
    # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it
    # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec
    # only has SHOULD - need to look into. If x.509 is necessary then
    # if no x5c header is found this should fail
    if x5c:
        verified = False
        try:
            verified = jws.verify(signature, cert_to_key(x5c[0]), algorithm)
        except Exception as e:
            raise BadRequest("The JWS is not valid: %s" % e.message)
        else:
            if not verified:
                raise BadRequest(
                    "The JWS is not valid - could not verify signature")
            # Compare statements
            if not compare_payloads(jws_payload, body_payload, sha2_key):
                raise BadRequest(
                    "The JWS is not valid - payload and body statements do not match"
                )
    else:
        # Compare statements
        if not compare_payloads(jws_payload, body_payload, sha2_key):
            raise BadRequest(
                "The JWS is not valid - payload and body statements do not match"
            )
Exemplo n.º 15
0
def process_jws_input(state, task_meta, **options):
    try:
        data = task_meta['data']
    except KeyError:
        raise TaskPrerequisitesError()

    node_json = jws.get_unverified_claims(data).decode('utf-8')
    node_data = json.loads(node_json)
    node_id = task_meta.get('node_id', node_data.get('id'))

    actions = [
        add_task(INTAKE_JSON, data=node_json, node_id=node_id),
        add_task(VERIFY_JWS,
                 node_id=node_id,
                 data=data,
                 prerequisites=SIGNING_KEY_FETCHED)
    ]
    if node_id:
        actions.append(set_validation_subject(node_id))
    return task_result(
        True,
        "Processed JWS-signed data and queued signature verification task",
        actions)