コード例 #1
0
ファイル: test_algorithms.py プロジェクト: federicobond/pyjwt
    def test_rsa_verify_should_return_true_for_test_vector(self):
        """
        This test verifies that RSA PKCS v1.5 verification works with a known
        good signature and key.

        Reference: https://tools.ietf.org/html/rfc7520#section-4.1
        """
        signing_input = ensure_bytes(
            'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb'
            'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb'
            '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS'
            'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU'
            'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4'
        )

        signature = base64url_decode(ensure_bytes(
            'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZop'
            'dHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJ'
            'K3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4'
            'QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic'
            '1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogor'
            'ee7vjbU5y18kDquDg'
        ))

        algo = RSAAlgorithm(RSAAlgorithm.SHA256)
        key = algo.prepare_key(load_rsa_pub_key())

        result = algo.verify(signing_input, key, signature)
        assert result
コード例 #2
0
ファイル: test_algorithms.py プロジェクト: thinkmonkeys/pyjwt
    def test_rsa_jwk_private_key_with_other_primes_is_invalid(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path('jwk_rsa_key.json'), 'r') as keyfile:
            with pytest.raises(InvalidKeyError):
                keydata = json.loads(keyfile.read())
                keydata['oth'] = []

                algo.from_jwk(json.dumps(keydata))
コード例 #3
0
    def test_rsa_jwk_private_key_with_missing_values_is_invalid(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path("jwk_rsa_key.json"), "r") as keyfile:
            with pytest.raises(InvalidKeyError):
                keydata = json.loads(keyfile.read())
                del keydata["p"]

                algo.from_jwk(json.dumps(keydata))
コード例 #4
0
    def test_rsa_private_key_to_jwk_works_with_from_jwk(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path('testkey_rsa'), 'r') as rsa_key:
            orig_key = algo.prepare_key(force_unicode(rsa_key.read()))

        parsed_key = algo.from_jwk(algo.to_jwk(orig_key))
        assert parsed_key.private_numbers() == orig_key.private_numbers()
        assert parsed_key.private_numbers().public_numbers == orig_key.private_numbers().public_numbers
コード例 #5
0
ファイル: test_algorithms.py プロジェクト: xupefei/pyjwt
    def test_rsa_to_jwk_returns_correct_values_for_private_key(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path("testkey_rsa.priv")) as keyfile:
            priv_key = algo.prepare_key(keyfile.read())

        key = algo.to_jwk(priv_key)

        expected = {
            "key_ops": ["sign"],
            "kty": "RSA",
            "e": "AQAB",
            "n": (
                "1HgzBfJv2cOjQryCwe8NEelriOTNFWKZUivevUrRhlqcmZJdCvuCJRr-xCN-"
                "OmO8qwgJJR98feNujxVg-J9Ls3_UOA4HcF9nYH6aqVXELAE8Hk_ALvxi96ms"
                "1DDuAvQGaYZ-lANxlvxeQFOZSbjkz_9mh8aLeGKwqJLp3p-OhUBQpwvAUAPg"
                "82-OUtgTW3nSljjeFr14B8qAneGSc_wl0ni--1SRZUXFSovzcqQOkla3W27r"
                "rLfrD6LXgj_TsDs4vD1PnIm1zcVenKT7TfYI17bsG_O_Wecwz2Nl19pL7gDo"
                "sNruF3ogJWNq1Lyn_ijPQnkPLpZHyhvuiycYcI3DiQ"
            ),
            "d": (
                "rfbs8AWdB1RkLJRlC51LukrAvYl5UfU1TE6XRa4o-DTg2-03OXLNEMyVpMr"
                "a47weEnu14StypzC8qXL7vxXOyd30SSFTffLfleaTg-qxgMZSDw-Fb_M-pU"
                "HMPMEDYG-lgGma4l4fd1yTX2ATtoUo9BVOQgWS1LMZqi0ASEOkUfzlBgL04"
                "UoaLhPSuDdLygdlDzgruVPnec0t1uOEObmrcWIkhwU2CGQzeLtuzX6OVgPh"
                "k7xcnjbDurTTVpWH0R0gbZ5ukmQ2P-YuCX8T9iWNMGjPNSkb7h02s2Oe9ZR"
                "zP007xQ0VF-Z7xyLuxk6ASmoX1S39ujSbk2WF0eXNPRgFwQ"
            ),
            "q": (
                "47hlW2f1ARuWYJf9Dl6MieXjdj2dGx9PL2UH0unVzJYInd56nqXNPrQrc5k"
                "ZU65KApC9n9oKUwIxuqwAAbh8oGNEQDqnuTj-powCkdC6bwA8KH1Y-wotpq"
                "_GSjxkNzjWRm2GArJSzZc6Fb8EuObOrAavKJ285-zMPCEfus1WZG0"
            ),
            "p": (
                "7tr0z929Lp4OHIRJjIKM_rDrWMPtRgnV-51pgWsN6qdpDzns_PgFwrHcoyY"
                "sWIO-4yCdVWPxFOgEZ8xXTM_uwOe4VEmdZhw55Tx7axYZtmZYZbO_RIP4CG"
                "mlJlOFTiYnxpr-2Cx6kIeQmd-hf7fA3tL018aEzwYMbFMcnAGnEg0"
            ),
            "qi": (
                "djo95mB0LVYikNPa-NgyDwLotLqrueb9IviMmn6zKHCwiOXReqXDX9slB8"
                "RA15uv56bmN04O__NyVFcgJ2ef169GZHiRFIgIy0Pl8LYkMhCYKKhyqM7g"
                "xN-SqGqDTKDC22j00S7jcvCaa1qadn1qbdfukZ4NXv7E2d_LO0Y2Kkc"
            ),
            "dp": (
                "tgZ2-tJpEdWxu1m1EzeKa644LHVjpTRptk7H0LDc8i6SieADEuWQvkb9df"
                "fpY6tDFaQNQr3fQ6dtdAztmsP7l1b_ynwvT1nDZUcqZvl4ruBgDWFmKbjI"
                "lOCt0v9jX6MEPP5xqBx9axdkw18BnGtUuHrbzHSlUX-yh_rumpVH1SE"
            ),
            "dq": (
                "xxCIuhD0YlWFbUcwFgGdBWcLIm_WCMGj7SB6aGu1VDTLr4Wu10TFWM0TNu"
                "hc9YPker2gpj5qzAmdAzwcfWSSvXpJTYR43jfulBTMoj8-2o3wCM0anclW"
                "AuKhin-kc4mh9ssDXRQZwlMymZP0QtaxUDw_nlfVrUCZgO7L1_ZsUTk"
            ),
        }
        assert json.loads(key) == expected
コード例 #6
0
    def _verify_token(self, request, forced_refresh=False):
        authorization_header = request.headers['Authorization']
        token = authorization_header[7:]
        authorization_scheme = authorization_header[:6]
        token_headers = jwt.get_unverified_header(token)

        # Get valid signing keys
        if self.cache_certs:
            valid_certificates = self._get_stored_certificates(forced_refresh=forced_refresh)
        else:
            valid_certificates = self._get_remote_certificates()

        # 1. The token was sent in the HTTP Authorization header with 'Bearer' scheme
        if authorization_scheme != "Bearer":
            self.logger.warning('The token was not sent in the http authorisation header with the Bearer scheme.')
            return False

        # 2. The token is valid JSON that conforms to the JWT standard (see references)
        # 4. The token contains an audience claim with a value equivalent to your bot's Microsoft App ID.
        # 5. The token has not yet expired. Industry-standard clock-skew is 5 minutes.
        # 6. The token has a valid cryptographic signature with a key listed in the OpenId keys document retrieved in step 1, above.
        decoded_jwt = None
        for dict_key in valid_certificates['keys']:
            if dict_key['kid'] == token_headers['kid']:
                key = json.dumps(dict_key)

                algo = RSAAlgorithm('SHA256')
                public_key = algo.from_jwk(key)

                try:
                    decoded_jwt = jwt.decode(token, public_key, algorithms=['RS256'], audience=self.app_client_id)
                except jwt.exceptions.InvalidTokenError as e:
                    self.logger.warning('{}'.format(e))

        if decoded_jwt is None:
            if self.cache_certs and not forced_refresh:
                # Force cache refresh
                self.logger.warning('Forcing cache refresh as no valid certificate was found.')
                self._get_remote_certificates()
                return self._verify_token(request, forced_refresh=True)

            self.logger.warning('No valid certificate was found to verify JWT')
            return False

        if decoded_jwt is None:
            return False

        # 3. The token contains an issuer claim with value of https://api.botframework.com
        if decoded_jwt['iss'] != 'https://api.botframework.com':
            self.logger.warning('The token issuer claim had the incorrect value of {}'.format(decoded_jwt['iss']))
            return False

        self.logger.info('Token was validated - {}'.format(json.dumps(decoded_jwt)))
        return decoded_jwt
コード例 #7
0
def generate_signed_data(payload, private_pem: str) -> str:
    """Generates signature for payload.

    :param payload: The payload to sign.
    :type payload: str|dict
    :param private_pem: The private key used for signing.
    :type private_pem: str
    :return: The signature.
    :rtype: str
    """
    payload_string = get_signature_payload(payload)
    alg_obj = RSAAlgorithm(RSAAlgorithm.SHA256)
    key = alg_obj.prepare_key(private_pem)
    return alg_obj.sign(payload_string.encode('utf-8'), key)
コード例 #8
0
def get_oidc_configuration(app):

    OIDC_ISSUER_URL_BY_PROVIDER = {
        'azure': 'https://sts.windows.net/{}/'.format(app.config['AZURE_TENANT']),
        'gitlab': app.config['GITLAB_URL'],
        'google': 'https://accounts.google.com',
        'keycloak': '{}/auth/realms/{}'.format(app.config['KEYCLOAK_URL'], app.config['KEYCLOAK_REALM'])
    }

    issuer_url = OIDC_ISSUER_URL_BY_PROVIDER.get(app.config['AUTH_PROVIDER']) or app.config['OIDC_ISSUER_URL']
    if not issuer_url:
        raise ApiError('Must define Issuer URL (OIDC_ISSUER_URL) in server configuration to use OpenID Connect.', 503)
    discovery_doc_url = issuer_url.strip('/') + '/.well-known/openid-configuration'

    r = requests.get(discovery_doc_url)
    config = r.json()

    if config['issuer'] != issuer_url:
        raise ApiError('Issuer Claim does not match Issuer URL used to retrieve OpenID configuration', 503)

    jwks_uri = config['jwks_uri']
    r = requests.get(jwks_uri)
    keys = {k['kid']: RSAAlgorithm.from_jwk(json.dumps(k)) for k in r.json()['keys']}

    return config, keys
コード例 #9
0
ファイル: oidc.py プロジェクト: guardian/alerta
def get_oidc_configuration(app):

    OIDC_ISSUER_URL_BY_PROVIDER = {
        'azure': 'https://sts.windows.net/{}/'.format(app.config['AZURE_TENANT']),
        'gitlab': app.config['GITLAB_URL'],
        'google': 'https://accounts.google.com',
        'keycloak': '{}/auth/realms/{}'.format(app.config['KEYCLOAK_URL'], app.config['KEYCLOAK_REALM'])
    }

    issuer_url = OIDC_ISSUER_URL_BY_PROVIDER.get(app.config['AUTH_PROVIDER']) or app.config['OIDC_ISSUER_URL']
    if not issuer_url:
        raise ApiError('Must define Issuer URL (OIDC_ISSUER_URL) in server configuration to use OpenID Connect.', 503)
    discovery_doc_url = issuer_url.strip('/') + '/.well-known/openid-configuration'

    try:
        r = requests.get(discovery_doc_url)
        config = r.json()
    except Exception as e:
        raise ApiError('Could not get OpenID configuration from well known URL: {}'.format(str(e)), 503)

    if config['issuer'] != issuer_url:
        raise ApiError('Issuer Claim does not match Issuer URL used to retrieve OpenID configuration', 503)

    if app.config['OIDC_VERIFY_TOKEN']:
        try:
            jwks_uri = config['jwks_uri']
            r = requests.get(jwks_uri)
            keys = {k['kid']: RSAAlgorithm.from_jwk(json.dumps(k)) for k in r.json()['keys']}
        except Exception as e:
            raise ApiError('Could not get OpenID JWT Key Set from JWKS URL: {}'.format(str(e)), 503)
    else:
        keys = {}

    return config, keys
コード例 #10
0
def validate_signed_data(payload, signature: str, public_pem: str) -> bool:
    """Validates a signature for given payload.

    :param payload: The payload to validate.
    :type payload: str|dict
    :param signature: The signature to validate.
    :type signature: str
    :param public_pem: The public key used for validating.
    :type public_pem: str
    :return: True if signature valid, False otherwise.
    :rtype: bool
    """
    payload_string = get_signature_payload(payload)
    alg_obj = RSAAlgorithm(RSAAlgorithm.SHA256)
    key = alg_obj.prepare_key(public_pem)
    return alg_obj.verify(payload_string.encode('utf-8'), key, signature)
コード例 #11
0
    def decorated(*args, **kwargs):
        token = get_token_auth_header(request)
        with urllib.request.urlopen(os.getenv('AUTH0_BASE_URL') + "/.well-known/jwks.json") as url:
            jwks = json.loads(url.read().decode())
        unverified_header = jwt.get_unverified_header(token)
        rsa_key = {}
        for key in jwks["keys"]:
            if key["kid"] == unverified_header["kid"]:
                rsa_key = RSAAlgorithm.from_jwk(json.dumps(key))
        if rsa_key:
            try:
                payload = jwt.decode(
                    token,
                    rsa_key,
                    algorithms=ALGORITHMS,
                    audience=os.getenv('AUTH0_WEB_API_AUDIENCE'),
                    issuer=os.getenv('AUTH0_BASE_URL') + "/"
                )
            except jwt.ExpiredSignatureError:
                raise CoreAuthError({"code": "token_expired",
                                     "description": "token is expired"}, 401)
            except jwt.MissingRequiredClaimError:
                raise CoreAuthError({"code": "invalid_claims",
                                     "description":
                                         "incorrect claims,"
                                         "please check the audience and issuer"}, 401)
            except Exception as e:
                raise CoreAuthError({"code": "invalid_header",
                                     "description": str(e)}, 401)

            _request_ctx_stack.top.current_user = payload
            return f(*args, **kwargs)
        raise CoreAuthError({"code": "invalid_header",
                             "description": "Unable to find appropriate key"}, 401)
コード例 #12
0
    def get_current_user(self):
        if isinstance(self, UI):
            return True

        if sickbeard.WEB_USERNAME and sickbeard.WEB_PASSWORD:
            # Authenticate using jwt for CF Access
            # NOTE: Setting a username and password is STILL required to protect poorly configured tunnels or firewalls
            if sickbeard.CF_AUTH_DOMAIN and sickbeard.CF_POLICY_AUD and has_cryptography:
                CERTS_URL = "{}/cdn-cgi/access/certs".format(
                    sickbeard.CF_AUTH_DOMAIN)
                if 'CF_Authorization' in self.request.cookies:
                    jwk_set = helpers.getURL(CERTS_URL, returns='json')
                    for key_dict in jwk_set['keys']:
                        public_key = jwt_algorithms_RSAAlgorithm.from_jwk(
                            json.dumps(key_dict))
                        if jwt.decode(self.request.cookies['CF_Authorization'],
                                      key=public_key,
                                      audience=sickbeard.CF_POLICY_AUD):
                            return True

            # Basic Auth at a minimum
            auth_header = self.request.headers.get('Authorization')
            if auth_header and auth_header.startswith('Basic '):
                auth_decoded = base64.decodestring(auth_header[6:])
                username, password = auth_decoded.split(':', 2)
                if username == sickbeard.WEB_USERNAME and password == sickbeard.WEB_PASSWORD:
                    return True
                return False

            # Logged into UI?
            return self.get_secure_cookie('sickchill_user')
        else:
            # Local network
            return helpers.is_ip_private(self.request.remote_ip)
コード例 #13
0
def _get_rsa_key(token):
    """
    Get rsa key(public key) from token
    Details https://jwt.io/

    :param str token: Id/Access token
    :return: token public key after validation with RSAAlgorithm
    """

    try:
        unverified_header = jwt.get_unverified_header(token)
    except jwt.DecodeError as exc:
        raise AuthError(
            {
                'code': 'invalid_header',
                'message': f'Invalid header. {str(exc)}'
            }, 401)
    if unverified_header['alg'] == 'HS256':
        raise AuthError(
            {
                'code': 'invalid_header',
                'message':
                'Invalid header. Use an RS256 signed JWT Access Token'
            }, 401)

    jwk_keys = _json_web_keys()
    jwk_data = jwk_keys.get(unverified_header['kid'])

    if jwk_data:
        return RSAAlgorithm.from_jwk(jwk_data)

    return None
コード例 #14
0
def decode_jwt(encoded_token):
    """
    Returns the decoded token from an encoded one. This does all the checks
    to insure that the decoded token is valid before returning it.
    """
    audience = current_app.config['JWT_AUDIENCE']
    required_scopes = current_app.config['JWT_REQUIRED_SCOPES']
    header = jwt.get_unverified_header(encoded_token)
    kid = header["kid"]
    keys = get_jwks()["keys"]
    keys = {key["kid"]: key for key in keys}
    if kid not in keys:
        msg = "No key matching kid: {} found".format(kid)
        raise NoKeyMatchingKidFound(msg)

    public_key = RSAAlgorithm.from_jwk(json.dumps(keys[kid]))

    decoded = jwt.decode(encoded_token,
                         key=public_key,
                         algorithms=['RS256'],
                         audience=audience)

    if len(required_scopes) > 0:
        if "scopes" not in decoded:
            msg = "Missing required scopes: {}".format(
                pformat(required_scopes))
            raise MissingRequiredScopeError(msg)
        else:
            scopes = decoded["scopes"]
            for required_scope in required_scopes:
                if required_scope not in scopes:
                    msg = "Missing required scope: {}".format(
                        pformat(required_scope))
                    raise MissingRequiredScopeError(msg)
    return decoded
コード例 #15
0
ファイル: api_auth.py プロジェクト: schatten/ThreatExchange
def _get_public_keys():
    response = requests.get(KEYS_URL)
    key_list = json.loads(response.text).get("keys", [])
    return {
        key["kid"]: RSAAlgorithm.from_jwk(json.dumps(key))
        for key in key_list
    }
コード例 #16
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        # Force auth state so that we can store the tokens in the user dict
        self.enable_auth_state = True

        if not self.oidc_issuer:
            raise Exception('No OIDC issuer url provided')

        self.log.info('Configuring OIDC from %s' % self.oidc_issuer)

        try:
            with request.urlopen('%s/.well-known/openid-configuration' % self.oidc_issuer) as response:
                data = json.loads(response.read())

                if not set(['authorization_endpoint', 'token_endpoint', 'userinfo_endpoint', 'end_session_endpoint']).issubset(data.keys()):
                    raise Exception('Unable to retrieve OIDC necessary values')

                self.authorize_url = data['authorization_endpoint']
                self.token_url = data['token_endpoint']
                self.userdata_url = data['userinfo_endpoint']
                self.end_session_url = data['end_session_endpoint']

                if self.config.check_signature :
                    jwks_uri = data['jwks_uri']
                    with request.urlopen(jwks_uri) as jkws_response:
                        jwk_data = json.loads(jkws_response.read())
                        self.public_key = RSAAlgorithm(RSAAlgorithm.SHA256).from_jwk(jwk_data['keys'][0])
                        self.log.info('aquired public key from %s' % jwks_uri)

        except HTTPError:
            self.log.error("Failure to retrieve the openid configuration")
            raise
コード例 #17
0
ファイル: __init__.py プロジェクト: tiagocborg/django-cognito
 def _get_public_key(self, token):
     try:
         headers = jwt.get_unverified_header(token)
     except jwt.DecodeError as exc:
         raise TokenError(str(exc))
     jwk_data = self._json_web_keys().get(headers["kid"])
     return RSAAlgorithm.from_jwk(jwk_data)
コード例 #18
0
    def _get_keys(self):
        """Assemble a list of valid signing public keys we use to verify the token"""

        decoded_keys = {}

        # We have a test key loaded
        if settings.KEYCLOAK['RS256_KEY'] is not None:
            decoded_keys['imported'] = settings.KEYCLOAK['RS256_KEY']

        if not settings.KEYCLOAK['DOWNLOAD_CERTS']:
            return decoded_keys

        # TODO cache the keys for some amount of time (in the db, perhaps)

        # Download a key directly from Keycloak
        response = requests.get(settings.KEYCLOAK['CERTS_URL'], timeout=5)

        if not response:
            raise RuntimeError('keys not available from {}'.format(
                settings.KEYCLOAK['CERTS_URL']))

        keys = response.json()
        decoded_keys = {}

        for key in keys['keys']:
            print('key: {}'.format(key))
            if key['alg'] in ['RS256', 'RS384', 'RS512']:
                decoded_keys[key['kid']] = RSAAlgorithm.from_jwk(
                    json.dumps(key)).public_bytes(
                        format=serialization.PublicFormat.SubjectPublicKeyInfo,
                        encoding=serialization.Encoding.PEM).decode('utf-8')

        return decoded_keys
コード例 #19
0
def get_keycloak_public_key_and_algorithm(token_kid):
    """
    Get Keycloak public key and token signing algorithm
    :param token_kid: Token kid
    :return: Algorithm and public_key pair
    """
    handle = f'{keycloak_config.get("oidc_server_url")}/protocol/openid-connect/certs'
    log.info(f'Getting public key for the kid={token_kid} from the keycloak...')
    r = requests.get(handle, verify=http_config.get('verify_cert'))
    if not r.ok:
        error = "Could not get certificates from Keycloak. " \
                "Reason: [{}]: {}".format(r.status_code, r.text)
        logger.error(error)
        raise ValueError(error)
    try:
        json_response = r.json()
    except Exception:
        error = "Could not retrieve the public key. " \
                "Got unexpected response: '{}'".format(r.text)
        logging.error(error)
        raise ValueError(error)
    try:
        matching_key = next((item for item in json_response.get('keys') if item['kid'] == token_kid), None)
        if matching_key is None:
            error = "No public key found for kid {}".format(token_kid)
            logger.error(error)
            raise ValueError(error)
        matching_key_json = json.dumps(matching_key)
        public_key = RSAAlgorithm.from_jwk(matching_key_json)
    except Exception as e:
        error = f'Invalid public key!. Reason: {e}'
        logger.error(error)
        raise ValueError(error)
    logger.info(f'The public key for the kid={token_kid} has been fetched.')
    return matching_key.get('alg'), public_key
コード例 #20
0
ファイル: authorization.py プロジェクト: thehyve/Fractalis
def retrieve_keycloak_public_key_and_algorithm(token_kid: str, oidc_server_url: str) -> (str, str):
    """ Retrieve the public key for the token from keycloak
    :param token_kid: The user token
    :param oidc_server_url:  Url of the server to authorize with
    :return: keycloak public key and algorithm
    """
    handle = f'{oidc_server_url}/certs'
    logger.info(f'Getting public key for the kid={token_kid} from the keycloak...')
    r = requests.get(handle)
    if r.status_code != 200:
        error = "Could not get certificates from the keycloak. " \
                "Reason: [{}]: {}".format(r.status_code, r.text)
        logger.error(error)
        raise ValueError(error)
    try:
        json_response = r.json()
    except Exception:
        error = "Could not retrieve the public key. " \
                 "Got unexpected response: '{}'".format(r.text)
        logger.error(error)
        raise ValueError(error)
    try:
        matching_key = next((item for item in json_response.get('keys') if item['kid'] == token_kid), None)
        matching_key_json = json.dumps(matching_key)
        public_key = RSAAlgorithm.from_jwk(matching_key_json)
    except Exception as e:
        error = f'Invalid public key!. Reason: {e}'
        logger.error(error)
        raise ValueError(error)
    logger.info(f'The public key for the kid={token_kid} has been fetched.')
    return matching_key.get('alg'), public_key
コード例 #21
0
    def verify_and_decode_id_token(self, id_token: str) -> Optional[dict]:
        """
        Verifies that the received ID Token was signed and sent by the
        Authorization Server and that the client is one of the audiences
        of the key. If ID Token is valid returns a dict containing the tokens
        decoded information.
        """
        unverified_header = jwt.get_unverified_header(id_token)

        # Get public key thumbprint
        kid = unverified_header.get("kid")
        jwks = self._retrieve_jwks_related_to_kid(kid)

        if jwks:
            alg = unverified_header.get("alg")
            public_key = RSAAlgorithm.from_jwk(json.dumps(jwks))

            try:
                decoded_token = jwt.decode(id_token,
                                           public_key,
                                           audience=[self.client_id],
                                           algorithms=alg)

                if self.cache_nonces:
                    # Verify that the cached nonce is present and that
                    # the provider the nonce was initiated for, is the same
                    # provider returning it
                    server = cache.get(decoded_token.get("nonce"))
                    if self.auth_server != server:
                        return None

                return decoded_token
            except Exception as e:
                raise e
        return None
コード例 #22
0
    def _oauth_validation(cls):
        issuer = config.get('connect_token_issuer')
        cert_url = config.get('connect_token_cert')
        if request.httprequest.method == 'GET':
            mode = 'read'
        if request.httprequest.method == 'POST':
            mode = 'write'

        # Get public certificate of issuer for token validation
        try:
            token_data = request.httprequest.headers.get('Authorization')
            access_token = token_data.split()[1]
            _logger.info("Received access token: %s", access_token)
            cert = requests.get(cert_url)
            key_json = simplejson.dumps(cert.json()['keys'][0])
        except ValueError:
            # If any error occurs during token and certificate retrieval,
            # we put a wrong certificate, and jwt library will fail
            # to decrypt the token, leading to unauthorized error.
            key_json = {}

        public_key = RSAAlgorithm.from_jwk(key_json)
        jwt_decoded = jwt.decode(access_token,
                                 key=public_key,
                                 algorithms=['RS256'],
                                 audience=issuer + '/resources',
                                 issuer=issuer)
        # validation
        # is scope read or write in scopes ?
        scope = jwt_decoded.get('scope')
        if scope and mode not in scope:
            raise Unauthorized()
        client_id = jwt_decoded.get('client_id') or jwt_decoded.get('ClientID')
        _logger.info("TOKEN CLIENT IS -----------------> " + client_id)
        return client_id
コード例 #23
0
def test_authenticate_jwt():
    jwt_token = """eyJhbGciOiJSUzI1NiIsImtpZCI6IjJlM2VlYjc2ODM2YWViNjBjMzA2MzNkYjM3ZGU4ZDgwOWE4MTE0YzciLCJ0eXAiOiJKV1QifQ.eyJiYW5zIjpbXSwiY2xpZW50X2lkIjoiZTdkZTkyMjZkZjRkNDAxYmJhNDRkMjQzZTkzNzgyMDQiLCJjb3VudHJ5IjoiR2xvYmFsIiwiZGlzcGxheV9uYW1lIjoiU3VwZXJ1c2VyIiwiZXhwIjoxNTgyODAwNTUxLCJpYXQiOjE1ODI3ODYxNTEsImpmbGdzIjoxLCJuYW1lc3BhY2UiOiJ2ZXJzdXNldmlsIiwicGVybWlzc2lvbnMiOltdLCJyb2xlcyI6WyJkMzJiMzM1NGRjOTg0ZjQ2YmJlMjk5ZDcwZDJlY2M3NCJdLCJzY29wZSI6ImFjY291bnQgY29tbWVyY2Ugc29jaWFsIHB1Ymxpc2hpbmcgYW5hbHl0aWNzIiwic3ViIjoiYjkzY2JlYWNhMGQwNGJiZGIxZWIxNjBjZWY4OGE0ZWIifQ.mAR7QCsp2VqSconomgNwse_aYek3T1XKmaRKGVGU0VRQYp_-wDodrA35yypswwbtjX9qhRfsK28E9lhMf9C8UAf5lLG8p0lpejFpuPJAlKe0h6g_n3iylBWZronpa0_KxF0KCHh3DZERXMUXA7Jm8GWAIerrBX6tAj1PXw4EYQ_Cm9x-Issj8hffNPcvPrH61pdvQItIgx_lA8wDgyaGZvpFmHSzjKtWkZHpvBVRh5NZzJE-8FrLYdgwipJ6wKLF6kVA8rhqSMxqC9YfuwQ58GYSyS4jFw_LQyOe_d-RKDJS-0-pphsfd8rvqGROhhmImZEo9Pr1unOYT4MgEdW28w"""

    jwks  = """{
      "keys": [
        {
          "kty": "RSA",
          "use": "sig",
          "kid": "2e3eeb76836aeb60c30633db37de8d809a8114c7",
          "n": "uEvSt8ecPmI8-8_z9K5F1IzSeBze9OvR-y9U1AqUX6vncMZjJWQti05VbXUk8-UsJUI-5OkBxJ8XYy_8PIUArsTC-naoer7_XM7gvdWH_y20Vbwibbpy7ONhgACZOaeA0iUXyuKu7f5L78gyY7AedY7JJ5shvgMBeR8HJKbVSBq1H4fJqGIjPss6k5C62shiKrMbpm4q1Tg8o8tmCWm7CyyUbiUggzJusKAqc7ZccsSLRkTF5G3fN4nzBP4rwthYf2aSOVNC4Lcnqx7QsEQvpauVdR0rRuiB8ERyikWjGSVMXoZ-1YxaAUkKHtz1J4jMtNvOJa6Qw_UMbiAVhrz0Gw",
          "e": "AQAB"
        }
      ]
    }"""

    jwks = json.loads(jwks)
    jwk_key = json.dumps(jwks['keys'][0])
    public_key = RSAAlgorithm.from_jwk(jwk_key)

    permission_rule_json = """{
        "accelbytetesting": ["rolesidaccelbytetesting", "adminrolesidaccelbytetesting", "accelbyteadminrole"],
        "samplegame": ["rolesidsamplegame", "accelbyteadminrole"],
        "public": ["*"],
        "accelbyte": ["accelbyteadminrole"],
        "versusevil": ["d32b3354dc984f46bbe299d70d2ecc74"]
    }"""

    allowed, decoded = jwt.authenticate_jwt(public_key, jwt_token, permission_rule_json, verify_exp=False)

    result = {'bans': [], 'client_id': 'e7de9226df4d401bba44d243e9378204', 'country': 'Global', 'display_name': 'Superuser', 'exp': 1582800551, 'iat': 1582786151, 'jflgs': 1, 'namespace': 'versusevil', 'permissions': [], 'roles': ['d32b3354dc984f46bbe299d70d2ecc74'], 'scope': 'account commerce social publishing analytics', 'sub': 'b93cbeaca0d04bbdb1eb160cef88a4eb'}
    print(allowed, decoded)

    assert result == decoded
コード例 #24
0
 def _find(self, key_id: str):
     if not self.keys:
         return None
     key = next(x for x in self.keys if x["kid"] == key_id)
     public_key = RSAAlgorithm.from_jwk(json.dumps(key))
     endorsements = key.get("endorsements", [])
     return _OpenIdConfig(public_key, endorsements)
コード例 #25
0
ファイル: jwt.py プロジェクト: saravanpa-aot/sbc-auth
    async def authenticate(self, request):  # pylint: disable=arguments-renamed
        """Authenticate the token."""
        if 'Authorization' not in request.headers:
            return None

        auth = request.headers['Authorization']
        token = self.get_token_from_header(authorization=auth,
                                           prefix=self.prefix)

        if self.jwt_oidc_test_mode:
            # in test mode, use a publick key to decode token directly.
            try:
                payload = jwt.decode(str.encode(token),
                                     self.jwt_oidc_test_public_key_pem,
                                     algorithms=self.algorithm)
            except jwt.InvalidTokenError as e:
                raise AuthenticationError(str(e))
        else:
            #  in production mod, get the public key from jwks_url
            try:
                unverified_header = jwt.get_unverified_header(token)
            except jwt.PyJWTError:
                raise AuthenticationError(
                    'Invalid header: Use an RS256 signed JWT Access Token')
            if unverified_header['alg'] == 'HS256':
                raise AuthenticationError(
                    'Invalid header: Use an RS256 signed JWT Access Token')
            if 'kid' not in unverified_header:
                raise AuthenticationError(
                    'Invalid header: No KID in token header')

            rsa_key = self.get_rsa_key(self.get_jwks(),
                                       unverified_header['kid'])

            if not rsa_key and self.caching_enabled:
                # Could be key rotation, invalidate the cache and try again
                self.cache.delete('jwks')
                rsa_key = self.get_rsa_key(self.get_jwks(),
                                           unverified_header['kid'])

            if not rsa_key:
                raise AuthenticationError(
                    'invalid_header: Unable to find jwks key referenced in token'
                )

            public_key = RSAAlgorithm.from_jwk(json.dumps(rsa_key))

            try:
                payload = jwt.decode(token,
                                     public_key,
                                     algorithms=self.algorithm,
                                     audience=self.audience)
            except jwt.InvalidTokenError as e:
                raise AuthenticationError(str(e))

        return AuthCredentials(['authenticated'
                                ]), JWTUser(username=payload['username'],
                                            token=token,
                                            payload=payload)
コード例 #26
0
 def jwt_key_to_pem(self, key_json_dict):
     """
     Builds a PEM formatted key string from a JWT public key dict.
     """
     pub_key = RSAAlgorithm.from_jwk(json.dumps(key_json_dict))
     return pub_key.public_bytes(
         encoding=serialization.Encoding.PEM,
         format=serialization.PublicFormat.SubjectPublicKeyInfo)
コード例 #27
0
def get_oidc_configuration(app):

    OIDC_ISSUER_URL_BY_PROVIDER = {
        'azure':
        f"https://login.microsoftonline.com/{app.config['AZURE_TENANT']}/v2.0",
        'cognito':
        f"https://cognito-idp.{app.config['AWS_REGION']}.amazonaws.com/{app.config['COGNITO_USER_POOL_ID']}",
        'gitlab':
        app.config['GITLAB_URL'],
        'google':
        'https://accounts.google.com',
        'keycloak':
        f"{app.config['KEYCLOAK_URL']}/auth/realms/{app.config['KEYCLOAK_REALM']}"
    }

    issuer_url = OIDC_ISSUER_URL_BY_PROVIDER.get(
        app.config['AUTH_PROVIDER']) or app.config['OIDC_ISSUER_URL']
    if not issuer_url:
        raise ApiError(
            'Must define Issuer URL (OIDC_ISSUER_URL) in server configuration to use OpenID Connect.',
            503)
    discovery_doc_url = issuer_url.strip(
        '/') + '/.well-known/openid-configuration'

    try:
        r = requests.get(discovery_doc_url, timeout=2)
        config = r.json()
    except Exception as e:
        raise ApiError(
            f'Could not get OpenID configuration from well known URL: {str(e)}',
            503)

    if 'issuer' not in config:
        error = config.get('error') or config.get('message') or config
        raise ApiError(f'OpenID Connect issuer response invalid: {error}')

    if config['issuer'].format(
            tenantid=app.config['AZURE_TENANT']) != issuer_url:
        raise ApiError(
            'Issuer Claim does not match Issuer URL used to retrieve OpenID configuration',
            503)

    if app.config['OIDC_VERIFY_TOKEN']:
        try:
            jwks_uri = config['jwks_uri']
            r = requests.get(jwks_uri, timeout=2)
            keys = {
                k['kid']: RSAAlgorithm.from_jwk(json.dumps(k))
                for k in r.json()['keys']
            }
        except Exception as e:
            raise ApiError(
                f'Could not get OpenID JWT Key Set from JWKS URL: {str(e)}',
                503)
    else:
        keys = {}

    return config, keys
コード例 #28
0
 def _jwt_key_to_pem(self, key_json_dict):
     """
     Builds a PEM formatted key string from a JWT public key dict.
     """
     pub_key = RSAAlgorithm.from_jwk(json.dumps(key_json_dict))
     return pub_key.public_bytes(
         encoding=serialization.Encoding.PEM,
         format=serialization.PublicFormat.SubjectPublicKeyInfo
     )
コード例 #29
0
def get_latest_public_key(sso_url, realm):
    url = "%s/auth/realms/%s/.well-known/openid-configuration" % (sso_url,
                                                                  realm)
    jwks_uri = requests.get(url).json()["jwks_uri"]
    jwks = requests.get(jwks_uri).json()["keys"]
    return RSAAlgorithm.from_jwk(json.dumps(jwks[0])).public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
コード例 #30
0
ファイル: jwks.py プロジェクト: SelfHacked/jwt-auth
    def get_jwk(self, header: dict):
        """Get JWK matching the kid in the token."""
        # Cache the key set once retrieved.
        if not self._jwks:
            self._jwks = self._get_jwks()

        key = self._find_jwk(header)
        if key:
            return RSAAlgorithm.from_jwk(json.dumps(key))
コード例 #31
0
def create_jwt_token(private_key, payload):
    key = json.dumps(private_key)
    key_id = private_key['kid']

    secret = RSAAlgorithm.from_jwk(key)
    return jwt.encode(payload,
                      secret,
                      algorithm='RS256',
                      headers={'kid': key_id})
コード例 #32
0
    def test_rsa_verify_should_return_true_if_signature_valid(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        jwt_message = ensure_bytes('Hello World!')

        jwt_sig = base64.b64decode(ensure_bytes(
            'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp'
            '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl'
            '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix'
            'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX'
            'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA'
            'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA=='))

        with open(key_path('testkey_rsa.pub'), 'r') as keyfile:
            jwt_pub_key = algo.prepare_key(keyfile.read())

        result = algo.verify(jwt_message, jwt_pub_key, jwt_sig)
        self.assertTrue(result)
コード例 #33
0
def _create_jwt(payload, key_id=None):
    if key_id is None:
        key_id = JWK_PRIVATE_KEY["kid"]

    key = json.dumps(JWK_PRIVATE_KEY)
    secret = RSAAlgorithm.from_jwk(key)
    return jwt.encode(
        payload, secret, algorithm="RS256", headers={"kid": key_id, "alg": "RS256"}
    )
コード例 #34
0
ファイル: test_algorithms.py プロジェクト: federicobond/pyjwt
    def test_rsa_should_accept_pem_private_key_bytes(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path('testkey_rsa'), 'rb') as pem_key:
            algo.prepare_key(pem_key.read())
コード例 #35
0
    def test_rsa_should_accept_unicode_key(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path('testkey_rsa'), 'r') as rsa_key:
            algo.prepare_key(ensure_unicode(rsa_key.read()))
コード例 #36
0
    def test_rsa_should_parse_pem_public_key(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with open(key_path('testkey2_rsa.pub.pem'), 'r') as pem_key:
            algo.prepare_key(pem_key.read())
コード例 #37
0
    def test_rsa_should_reject_non_string_key(self):
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)

        with self.assertRaises(TypeError):
            algo.prepare_key(None)
コード例 #38
0
ファイル: __init__.py プロジェクト: jpadilla/pyjwt
 def load_rsa_pub_key():
     with open(os.path.join(BASE_PATH, 'jwk_rsa_pub.json'), 'r') as infile:
         return RSAAlgorithm.from_jwk(infile.read())