async def _validate_token(self, jwt_token: str, channel_id: str) -> ClaimsIdentity: headers = jwt.get_unverified_header(jwt_token) # Update the signing tokens from the last refresh key_id = headers.get("kid", None) metadata = await self.open_id_metadata.get(key_id) if key_id and metadata.endorsements: if not EndorsementsValidator.validate(channel_id, metadata.endorsements): raise Exception("Could not validate endorsement key") if headers.get("alg", None) not in self.validation_parameters.algorithms: raise Exception("Token signing algorithm not in allowed list") options = { "verify_aud": False, "verify_exp": not self.validation_parameters.ignore_expiration, } decoded_payload = jwt.decode(jwt_token, metadata.public_key, options=options) claims = ClaimsIdentity(decoded_payload, True) return claims
async def test_sign_in_tampered_token( repositories: Repositories, approved_up_user: User, approved_up_user_email_address: str, approved_up_user_password: str, ): user_sign_in_request = UserSignInRequest( email_address=approved_up_user_email_address, password=approved_up_user_password) response = await sign_in_user(user_sign_in_request) token = f"Bearer {response.token}" await get_all_feeds(authorization=token) with pytest.raises(HTTPException) as http_exception: await get_all_feeds(authorization=f"s-{token}") assert http_exception.value.status_code == 401 # construct some other token. decoded = jwt.get_unverified_header(response.token) other_users_token = jwt.encode( { "name": decoded.get("name"), "user_id": decoded.get("user_id"), "exp": datetime.utcnow() + timedelta(days=7), }, f"wrong-{AppConfig.token_secret_key()}", algorithm="HS256", ) with pytest.raises(HTTPException) as http_exception: await get_all_feeds(authorization=other_users_token) assert http_exception.value.status_code == 401
def verify_cognito_kid(jwt_value): """ Verifies that the kid in the access_token header matches a well-known kid in Cognito :param jwt_value: :return: """ try: jwt_kid = jwt.get_unverified_header(jwt_value).get('kid') except jwt.exceptions.DecodeError: raise exceptions.AuthenticationFailed({ 'error': 'invalid_jwt' }) if jwt_kid is None: raise exceptions.AuthenticationFailed({ 'error': 'kid_required' }) jwk_path = os.path.join(settings.BASE_DIR, 'account', 'resources', 'jwks.json') if not os.path.isfile(jwk_path): capture_message("jwks_missing: jwks.json does not exist. run get_all_jwks", level="error") raise exceptions.AuthenticationFailed({ 'error': 'jwks_missing' }) with open(jwk_path) as f: keys = json.loads(f.read())['keys'] keys = [key['kid'] for key in keys] if not jwt_kid in keys: capture_message("invalid_kid: make sure JWKs retrieved (get_all_jwks)", level="error") raise exceptions.AuthenticationFailed({ 'error': 'invalid_kid' })
def test_keys_with_key_id(monkeypatch, user, call_auth_endpoint, rsa_keys): monkeypatch.setattr(api_settings, "JWT_PRIVATE_KEY", {"rsa1": rsa_keys["secret"]["rsa1"]}) monkeypatch.setattr(api_settings, "JWT_PUBLIC_KEY", rsa_keys["public"]) secret_key = OrderedDict([("hash1", "one"), ("hash2", "two")]) monkeypatch.setattr(api_settings, "JWT_SECRET_KEY", secret_key) for kid, algo in { "hash1": ["HS256", "RS256"], "rsa1": ["RS256", "HS256"] }.items(): monkeypatch.setattr(api_settings, "JWT_ALGORITHM", algo) response = call_auth_endpoint("username", "password") token = response.json()["token"] # check needs to succeed no matter which algo is first algo = [algo[1], algo[0]] monkeypatch.setattr(api_settings, "JWT_ALGORITHM", algo) payload = JSONWebTokenAuthentication.jwt_decode_token(token) hdr = get_unverified_header(token) assert hdr["kid"] == kid assert response.status_code == status.HTTP_200_OK assert payload["user_id"] == user.id assert payload["username"] == user.get_username()
def decode_jwt(token: str, audience: typing.List[str]) -> typing.Optional[typing.Mapping]: """ Verify and decode the JWT from the request. :param token: the Authorization header in the request. :param audience: the expected audience for the JWT :return: Decoded and verified token info. """ try: unverified_token = jwt.decode(token, verify=False) except jwt.DecodeError: raise AuthenticationException('Failed to decode token.') assert_authorized_issuer(unverified_token) issuer = unverified_token['iss'] public_keys = get_public_keys(issuer) try: token_header = jwt.get_unverified_header(token) verified_token_info = jwt.decode( token, key=public_keys[token_header["kid"]], issuer=issuer, audience=audience, algorithms=allowed_algorithms, ) except jwt.PyJWTError as ex: # type: ignore raise AuthenticationException('Authorization token is invalid') from ex return verified_token_info
def authenticate(encoded_token: str) -> Mapping[str, Any]: """ Authenticate the token. Upon successful authentication, the decoded token is returned. Otherwise, an exception is thrown. :param encoded_token: The encoded token in string form :return: The verified token :raises PyJWTError: if there's an issue decoding the token :raises Exception: if there's some other issue """ unverified_token = jwt.decode(encoded_token, verify=False) unverified_headers = jwt.get_unverified_header(encoded_token) jti = unverified_token.get("jti", "UNKNOWN") logger.debug(f"Authenticating token with jti: {jti}") if current_app.config["NO_VERIFY"] is True: logger.debug(f"Skipping Verification of the token with jti: {jti}") return unverified_token issuer_url = unverified_token["iss"] if issuer_url not in current_app.config["ISSUERS"]: raise InvalidIssuerError(f"Unauthorized Issuer: {issuer_url}") issuer = current_app.config["ISSUERS"][issuer_url] # This can throw an InvalidIssuerError as well, # though it may be a server-side issue key = get_key_as_pem(issuer_url, unverified_headers["kid"]) return jwt.decode( encoded_token, key, algorithm=ALGORITHM, audience=issuer["audience"], options=current_app.config.get("JWT_VERIFICATION_OPTIONS"), )
def _authenticate(self, request: Request): """Authenticate a request """ token = self._get_token_from_headers(request) if token is None: token = self._get_token_from_qs(request) if token is None: return None # Check if this is a JWT token, and if it has the expected key ID try: header = jwt.get_unverified_header(token) if self.key_id and self.key_id != header.get('kid'): return None except jwt.PyJWTError: return None # We got a JWT token, now let's decode and verify it try: return jwt.decode(token, key=self._get_verification_key(), algorithms=self.algorithm, leeway=self.leeway) except jwt.PyJWTError as e: raise Unauthorized( 'Expired or otherwise invalid JWT token ({})'.format(str(e)))
async def auth_middleware(request, handler): request.user = None try: token = request.headers.get('authorization', None).split(' ')[1] unverified_header = jwt.get_unverified_header(token) except: return await handler(request) rsa_key = await validate_header(unverified_header) if rsa_key: try: payload = jwt.decode( token, jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(rsa_key)), algorithms=[JWT_ALGORITHM], audience=API_AUDIENCE, issuer=f"https://{AUTH0_DOMAIN}/", ) except jwt.ExpiredSignatureError: return web.json_response({'message': 'token is expired'}, status=401) except (jwt.InvalidAudienceError, jwt.InvalidIssuerError): return web.json_response( { 'message': 'Incorrect claims, please check the audience and issuer' }, status=401) except Exception: return web.json_response( {'message': 'Unable to parse authentication token.'}, status=401) request.user = payload return await handler(request)
def jwt_bruteforce( self, wordlist: str, b64_encode: bool = False, algorithm: list = ["HS256"] ): """Brute force JWT token secret This method will use the provided wordlist to try and bruteforce the verification. Args: wordlist (str): Required. Path to a wordlist b64_encode (bool, optional): Encoded the words in base64. Defaults to False. algorithm (list, optional): Array of valid algorithms. Defaults to ["HS256"]. Returns: Chepy: The Chepy object. """ with open(pathlib.Path(wordlist).expanduser().absolute()) as words: for word in words: try: word = word.strip() if b64_encode: # pragma: no cover word = base64.b64encode(word) j = jwt.decode(self._convert_to_str(), word, algorithms=algorithm) self.state = { "paylod": j, "header": jwt.get_unverified_header(self._convert_to_str()), "secret": word, } return self except jwt.InvalidSignatureError: continue else: # pragma: no cover return self
def decode_jwt(jwt_token, provider): """ :param jwt_token: :param provider: :return: """ provider_config = current_app.config['LTI_TOOL_CONFIG'].get_iss_config( provider) jwks_url = provider_config['key_set_url'] jwks = requests.get(jwks_url).json() public_keys = {} for jwk in jwks['keys']: kid = jwk['kid'] public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk( json.dumps(jwk)) kid = jwt.get_unverified_header(jwt_token)['kid'] key = public_keys[kid] jwt_payload = jwt.decode(jwt_token, key=key, audience=provider_config['client_id'], algorithms=['RS256']) return jwt_payload
def validate_iap_jwt(base_url, iap_jwt): """Validate a JWT passed to your application by Identity-Aware Proxy. Args: base_url: The URL from the incoming request, minus any path, query, etc. For instance: "https://example.com:8443" or "https://example.appspot.com" . iap_jwt: The contents of the X-Goog-Authenticated-User-JWT header. Returns: (user_id, user_email, error_str). """ try: key_id = jwt.get_unverified_header(iap_jwt).get('kid') if not key_id: return (None, None, '**ERROR: no key ID**') key = get_iap_key(key_id) decoded_jwt = jwt.decode( iap_jwt, key, algorithms=['ES256'], audience=base_url) return (decoded_jwt['sub'], decoded_jwt['email'], '') except (jwt.exceptions.InvalidTokenError, requests.exceptions.RequestException) as e: return (None, None, '**ERROR: JWT validation error {}**'.format(e))
def validate_cognito_id_token( token: str, region: str, user_pool_id: str, client_id: str, ) -> dict: header = jwt.get_unverified_header(token) keys = get_jwt_keys(region, user_pool_id) # convert to {kid: key} map, instead of [{kid: kid, ...}, ...] list keys = { key['kid']: key for key in keys['keys'] } key = keys[header['kid']] # may raise public_key = import_jwk(key) token = jwt.decode( token, key=public_key, algorithms=['RS256'], audience=client_id, ) return token
def decode_token(self, token, use): kid = jwt.get_unverified_header(token).get('kid') jwt_set = [x for x in self.cognito_jwt_set.get('keys') if x.get('kid') == kid][0] n_str, e_str = jwt_set.get('n'), jwt_set.get('e') # signature verification included if use == 'access': decoded = jwt.decode(token, key=_public_key(n_str, e_str)) elif use == 'id': decoded = jwt.decode( token, key=_public_key(n_str, e_str), audience=app.config.get('COGNITO_CLIENT_ID')) else: raise exception.AuthError('unknown token_use:{}'.format(use)) if decoded.get('iss') != 'https://cognito-idp.{}.amazonaws.com/{}' \ .format(self.cognito_region, self.cognito_user_pool_id): raise exception.AuthError('token invalid. bad iss.') if decoded.get('token_use') != use: raise exception.AuthError( 'token invalid. bad token_use. expected {}'.format(use)) if datetime.datetime.fromtimestamp(decoded.get('exp'), pytz.utc) \ < datetime.datetime.now(pytz.utc): raise exception.AuthError('token invalid. expired.') return decoded
def verify_jwt_token(jwt_token, expected_issuer, expected_audience, algorithms, public_certs_url): # https://developers.cloudflare.com/access/setting-up-access/validate-jwt-tokens/ # https://cloud.google.com/iap/docs/signed-headers-howto # Loop through the keys since we can't pass the key set to the decoder keys = get_public_keys(public_certs_url) key_id = jwt.get_unverified_header(jwt_token).get('kid', '') if key_id and isinstance(keys, dict): keys = [keys.get(key_id)] valid_token = False payload = None for key in keys: try: # decode returns the claims which has the email if you need it payload = jwt.decode(jwt_token, key=key, audience=expected_audience, algorithms=algorithms) issuer = payload['iss'] if issuer != expected_issuer: raise Exception('Wrong issuer: {}'.format(issuer)) valid_token = True break except Exception as e: logging.exception(e) return payload, valid_token
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)
def visit_value(self, key: str, value: str): if value in self._visited_values: return self._log_visit(value, name=key) key = key.lower() if key == "appid": log.info(f"App ID {value}") elif key == "muid": log.info(f"MUID {value}") values = value.split(" ") for val in values: try: token = jwt.get_unverified_header(val) log.info(f"JWT token {token}") except: pass # # g UserAuthentication 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1...' # DEBUG:visitors:Visiting FedAuth '77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGlu...' # DEBUG:visitors:Visiting FedAuth1 'UkN6OHVuNlBnaGRudzB3a2RqLzJ1U1JvcTUyZVkx...' # DEBUG:visitors:Visiting FedAuth2 'cml0eUNvbnRleHRUb2tlbj4=' # DEBUG:visitors:Visiting HostAuthentication 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1...'
def decode_user_jwt_token_hs256(self): user_info = '' signing_algo = '' try: signing_algo = jwt.get_unverified_header(self.payload)['alg'] except: return False try: if signing_algo.upper() == 'RS256': user_info = jwt.decode(self.payload, self.__get_pub_key__(), algorithm='RS256') elif signing_algo.upper() == 'HS256': user_info = jwt.decode(self.payload, self.__get_fake_pub_key__(), algorithm='HS256') else: return False except: return False if user_info['group'] == 'Supervillains': return True else: False
def authorize(self, request, uid=None): token = self._get_raw_token(request) issuer_info = self._get_issuer_info() unverified_headers = jwt.get_unverified_header(token) key_id = unverified_headers.get('kid', None) if key_id is None: raise UnauthorizedException("Missing key id in token") jwks_uri = issuer_info.get('jwks_uri') if jwks_uri is None: raise UnauthorizedException("Missing JWKS URI in config") key, algo = self._get_signing_key(jwks_uri, key_id) try: claims = jwt.decode(token, key, algorithms=algo, issuer=issuer_info['issuer'], audience=self.config['audience']) except Exception as e: raise UnauthorizedException('Invalid access token: %s' % e) if token['preferred_username'] == self.config.get( 'admin_username', 'admin'): return 'admin' if uid and uid == claims['preferred_username']: return uid if uid and uid != claims['preferred_username']: raise UnauthorizedException("Only the admin ") raise UnauthorizedException('unauthorized')
def oauth(token): jsonurl = urlopen("https://" + app.config['AUTH0_DOMAIN'] + "/.well-known/jwks.json") jwks = json.loads(jsonurl.read()) unverified_header = jwt.get_unverified_header(token) rsa_key = {} for key in jwks["keys"]: if key["kid"] == unverified_header["kid"]: rsa_key = { "kty": key["kty"], "kid": key["kid"], "use": key["use"], "n": key["n"], "e": key["e"] } if rsa_key: try: payload = jose_jwt.decode(token, rsa_key, algorithms=["RS256"], audience=app.config['AUTH0_AUDIENCE'], issuer='https://' + app.config['AUTH0_DOMAIN'] + '/') except Exception as exp: traceback.print_exc() raise AuthException( payload={'info': 'Sessão expirada ou é inválida'}) from exp return payload['email']
def getJWTTokens(): jsonData = request.get_json() if jsonData and 'safetynet' in jsonData and 'device_id' in jsonData and 'timestamp' in jsonData: jwt_body = jsonData['safetynet'] x5c = jwtStandalone.get_unverified_header(jwt_body)['x5c'][0] certificate = x509.load_der_x509_certificate( base64.b64decode(x5c), default_backend()) if "CN=attest.android.com" not in certificate.subject.rfc4514_string(): return "Attestation failed!", 403 jwt_decoded = jwtStandalone.decode( jwt_body, key=certificate.public_key(), algorithm='HS256') if jwt_decoded and 'nonce' in jwt_decoded: if not check_password_hash(base64.b64decode(jwt_decoded['nonce']).decode('utf-8'), jsonData['timestamp']+jsonData['device_id']): return "Error with nonce!", 403 if jwt_decoded and 'ctsProfileMatch' in jwt_decoded and 'basicIntegrity' in jwt_decoded: if jwt_decoded['ctsProfileMatch'] or jwt_decoded['basicIntegrity']: expires = datetime.timedelta(days=30) jwt_keys = { 'access_token': create_access_token(identity=jsonData['device_id']), 'refresh_token': create_refresh_token(identity=jsonData['device_id'], expires_delta=expires) } return jsonify(jwt_keys) else: return "Attestation failed!", 403 else: return "Invalid attestation response", 403 return "Missing body parts!", 403
def from_jwt(cls, jwt, key=''): """ Decode a JWT string into a Jwt object :param str jwt: JWT string :param Optional[str] key: key used to verify JWT signature, if not provided then validation is skipped. :raises JwtDecodeError if decoding JWT fails for any reason. :return: A DecodedJwt object containing the jwt information. """ verify = True if key else False try: headers = jwt_lib.get_unverified_header(jwt) alg = headers.get('alg') if alg != cls.ALGORITHM: raise ValueError(f"Incorrect decoding algorithm {alg}, " f"expecting {cls.ALGORITHM}.") payload = jwt_lib.decode(jwt, key, algorithms=[cls.ALGORITHM], options={ 'verify_signature': verify, 'verify_exp': True, 'verify_nbf': True, }) except Exception as e: raise JwtDecodeError(getattr(e, 'message', str(e))) return cls._from_jwt(headers, payload, key)
def decode_token(encoded_token, csrf_value=None): """ Returns the decoded token (python dict) from an encoded JWT. This does all the checks to insure that the decoded token is valid before returning it. :param encoded_token: The encoded JWT to decode into a python dict. :param csrf_value: Expected CSRF double submit value (optional) """ jwt_manager = _get_jwt_manager() unverified_claims = jwt.decode( encoded_token, verify=False, algorithms=config.algorithm ) unverified_headers = jwt.get_unverified_header(encoded_token) # Attempt to call callback with both claims and headers, but fallback to just claims # for backwards compatibility try: secret = jwt_manager._decode_key_callback(unverified_claims, unverified_headers) except TypeError: msg = ( "The single-argument (unverified_claims) form of decode_key_callback ", "is deprecated. Update your code to use the two-argument form ", "(unverified_claims, unverified_headers)." ) warn(msg, DeprecationWarning) secret = jwt_manager._decode_key_callback(unverified_claims) return decode_jwt( encoded_token=encoded_token, secret=secret, algorithm=config.algorithm, identity_claim_key=config.identity_claim_key, user_claims_key=config.user_claims_key, csrf_value=csrf_value, audience=config.audience, leeway=config.leeway )
def verify_jwt_token(jwt_token, expected_issuer, expected_audience, algorithms, public_certs_url): # https://developers.cloudflare.com/access/setting-up-access/validate-jwt-tokens/ # https://cloud.google.com/iap/docs/signed-headers-howto # Loop through the keys since we can't pass the key set to the decoder keys = get_public_keys(public_certs_url) key_id = jwt.get_unverified_header(jwt_token).get('kid', '') if key_id and isinstance(keys, dict): keys = [keys.get(key_id)] valid_token = False payload = None for key in keys: try: # decode returns the claims which has the email if you need it payload = jwt.decode( jwt_token, key=key, audience=expected_audience, algorithms=algorithms ) issuer = payload['iss'] if issuer != expected_issuer: raise Exception('Wrong issuer: {}'.format(issuer)) valid_token = True break except Exception as e: logging.exception(e) return payload, valid_token
def verify_jwt(token: str) -> typing.Optional[typing.Mapping]: try: unverified_token = jwt.decode(token, verify=False) except jwt.DecodeError: logger.info(f"Failed to decode JWT: {token}", exc_info=True) raise DSSException(401, 'Unauthorized', 'Failed to decode token.') assert_authorized_issuer(unverified_token) issuer = unverified_token['iss'] public_keys = get_public_keys(issuer) try: token_header = jwt.get_unverified_header(token) verified_tok = jwt.decode( token, key=public_keys[token_header["kid"]], issuer=issuer, audience=Config.get_audience(), algorithms=allowed_algorithms, ) logger.info("""{"valid": true, "token": %s}""", json.dumps(verified_tok)) except jwt.PyJWTError as ex: # type: ignore logger.info("""{"valid": false, "token": %s}""", json.dumps(unverified_token), exc_info=True) raise DSSException(401, 'Unauthorized', 'Authorization token is invalid') from ex return verified_tok
def _signer_kid(encoded_jwt, allow_none=False): headers = get_unverified_header(encoded_jwt) kid = headers.get('kid', None) if not kid and not allow_none: abort(400) return kid
def get_payload(encoded): failed = False print(encoded) try: print(jwt.get_unverified_header(encoded)) decoded_jwt = jwt.decode(encoded, options={"verify_signature": False}, algorithms=["RS256"]) keys_returned = decoded_jwt.keys() except jwt.exceptions.DecodeError as e: print("Decode failed.", e) decoded_jwt = None failed = True if not failed: if "appId" not in keys_returned: print("Error: encoded JWT data does not contain appId key.") if "activationRefId" not in keys_returned: print( "Error: encoded JWT data does not contain activationRefId key." ) if "expiresIn" not in keys_returned: print("Error: encoded JWT data does not contain expiresIn key") try: expiration_time = datetime.fromtimestamp(decoded_jwt["expiresIn"] / 1000) except: print("Error: encoded JWT expiration time invalid.") if expiration_time < datetime.now(): print(f"Error: the JWT expired on {expiration_time}") elif debug: print(f"Note: JWT token will expire {expiration_time}") return decoded_jwt
def verify_token(token): public_key = current_app.config.get("QUICKPOLL_PUBLIC_KEY") algorithm = current_app.config.get("QUICKPOLL_ALGORITHM", "RS512") if not public_key: return False try: data = jwt.decode(token, public_key, algorithm=algorithm) except jwt.InvalidTokenError: try: print(jwt.get_unverified_header(token)) print(jwt.decode(token, verify=False)) except jwt.InvalidTokenError: print("Unable to decode JWT") return False try: return User( id=data["id"], username=data.get("username"), roles=data.get("roles", []) ) except KeyError: return False
def get_jwt_info(self): if has_jwt is False: self.error_message = "PyJWT not installed, please add PyJWT to requirements.txt add deploy saas again" return False if has_crypto is False: self.error_message = ( "cryptography not installed, please add PyJWT to requirements.txt add " "deploy saas again") return False if not self.raw_content: self.error_message = "X_BKAPI_JWT not in http header or it is empty, please called API through API Gateway" return False try: self.headers = jwt.get_unverified_header(self.raw_content) self.payload = jwt.decode(self.raw_content, settings.APIGW_PUBLIC_KEY, issuer='APIGW') self.is_valid = True except jwt_exceptions.InvalidKeyError: self.error_message = "APIGW_PUBLIC_KEY error" except jwt_exceptions.DecodeError: self.error_message = "Invalid X_BKAPI_JWT, wrong format or value" except jwt_exceptions.ExpiredSignatureError: self.error_message = "Invalid X_BKAPI_JWT, which is expired" except jwt_exceptions.InvalidIssuerError: self.error_message = "Invalid X_BKAPI_JWT, which is not from API Gateway" except Exception as error: LOG.exception('decode jwt fail') self.error_message = error.message
def validate_request(self, req, config): headers = req.headers if "Authorization" not in headers: return False, "Must provide authorization header.", None id_token = headers["Authorization"] try: kid = jwt.get_unverified_header(id_token)['kid'] except: return False, "Could not retrieve kid from ID token.", None try: public_key = self.get_key(kid) except: return False, "Failed to retrieve public key.", None if public_key is None: return False, "Unable to find matching public key.", None try: token_data = jwt.decode( id_token, public_key, algorithms='RS256', audience=config.client_id, ) except: return False, "ID Token is invalid.", None try: now = time.time() exp = token_data['exp'] if now > exp: return False, "Token is expired.", None nbf = token_data['nbf'] if now < nbf: return False, "Token nbf check failed.", None except: return False, "Token timestamps are invalid.", None return True, None, token_data
def verify_login(self, token): """ This function is called for each Flask route. This is to ensure that user's login is verified for each web page. To avoid multiple calls to Keycloak's introspect endpoint, this function performs manual token validation """ # Make request to keycloak's jwks endpoint, which returns the Json web key set jwk_uri = '{0}/auth/realms/{1}/protocol/openid-connect/certs'.format( base_uri, realm) jwks = requests.get(jwk_uri).json() public_keys = {} # Sort all the returned jwk into dictionary keyed with their KID. In this case, we are returned with a single key for jwk in jwks['keys']: kid = jwk['kid'] public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk( json.dumps(jwk)) # Get the Kid from access token - it tells which key was used to sign the token kid = jwt.get_unverified_header(token)['kid'] # Use the same key to verify signature key = public_keys[kid] # The jwt decode throws an exception if it fails to verify signature. Catch the exception and authenticate user before serving the request. try: jwt_decode = jwt.decode(token, key=key, audience='{}'.format(realm)) print(jwt_decode) verify_user = jwt_decode['preferred_username'] print(verify_user) return True, verify_user except: return False, verify_user
def decode(self, token: str) -> Dict[str, Any]: """ Args: token: The jwt token to decode Returns: the decoded token """ public_keys = {} unverified_header = jwt.get_unverified_header(token) for jwk in self._key["keys"]: if jwk["kid"] == unverified_header["kid"]: kid = jwk["kid"] public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk( json.dumps(jwk)) rsa_key = public_keys[kid] if rsa_key: try: return jwt.decode( token, rsa_key, algorithms=["RS256"], options={"verify_aud": False}, ) except jwt.ExpiredSignatureError: raise LumAppsJwtTokenExpiredError("Token is expired.") except LumAppsJWTClaimsError: raise LumAppsJwtInvalidClaimError( "Incorrect claims, please check the audience and issuer." ) except Exception as e: raise LumAppsJwtCustomError(e) raise LumAppsJwtHeaderError("Unable to find appropriate key.")
def decode_token(token): """Return user dict from given token. If incorrect token or user is inputted, it returns None. """ # firstly get public u_id from header try: u_id = jwt.get_unverified_header(token).get('u_id') except DecodeError: return None # next, get the hidden session_secret try: stored_secret = jwt.decode(token, JWT_SECRET, algorithms=['HS256']).get('session_secret') except DecodeError: # if it fails to decode token, return none return None # find user with session secret focus_user = None for user in data.return_users(): if (user.get('session_secret') == stored_secret and user.get('u_id') == u_id): # if user is correct and matches the session focus_user = user break # if u_id and session_secret match, return user # if no user is found, it also returns None return focus_user
def oauth2_callback(): state = json.loads(base64.b64decode(request.args["state"])) token_endpoint = get_openid_config( os.environ["OPENID_PROVIDER"])["token_endpoint"] res = requests.post( token_endpoint, dict(code=request.args["code"], client_id=os.environ["OAUTH2_CLIENT_ID"], client_secret=os.environ["OAUTH2_CLIENT_SECRET"], redirect_uri=get_redirect_uri(), grant_type="authorization_code")) token_header = jwt.get_unverified_header(res.json()["id_token"]) tok = jwt.decode(res.json()["id_token"], key=get_public_key(token_header["kid"]), audience=os.environ["OAUTH2_CLIENT_ID"]) assert tok["email_verified"] credentials = sts.assume_role(RoleArn=os.environ["ASSUME_ROLE_ARN"], RoleSessionName=tok["email"])["Credentials"] del credentials["Expiration"] cookie = base64.b64encode(json.dumps(credentials).encode()).decode() cookie_header = "elk_auth={}; Path=/; Max-Age=3600; Secure; HttpOnly".format( cookie) response = make_response("", 302) response.headers['Location'] = state["nav_origin"] response.headers['Set-Cookie'] = cookie_header return response
def storeToken(token, request, conf): """ Save the important parts of the token in session storage. Returns the corresponding SessionInfo object. If we can't return the object for any reason, we remove the Auth0 information from the session and expire the cookie. """ try: session = request.SESSION # get the key id from the jwt header key_id = jwt.get_unverified_header(token)['kid'] key = Auth0._getKey(key_id, conf) if not key: log.warn('Invalid jwt kid (key id) - not setting session info') Auth0.removeToken(request) return None payload = jwt.decode(token, key, verify=True, algorithms=['RS256'], audience=conf['audience'], issuer=conf['tenant']) # Make sure we have an auth0 conf conf = conf or getAuth0Conf() if not conf: log.warn('Incomplete Auth0 config in GlobalConfig - not using Auth0 login') Auth0.removeToken(request) return None # Verify that the tenant is in our whitelist. # + The tenantkey is used to lookup the tenant from the jwt. tenantkey = conf.get('tenantkey', 'https://dev.zing.ninja/tenant') tenant = payload.get(tenantkey, None) # ie: "https://dev.zing.ninja/tenant": "alphacorp", in jwt if not tenant: log.warn('No auth0 tenant specified in jwt for tenantkey: {}'.format(tenantkey)) Auth0.removeToken(request) return None # + Get the whitelist from global.conf and verify that it's in the list. whitelist = conf.get('whitelist', []) if not tenant in whitelist: log.warn('Tenant {} is invalid. Not in whitelist: {}'.format(tenant, whitelist)) Auth0.removeToken(request) return None emailkey = conf.get('emailkey', 'https://dev.zing.ninja/email') email = payload.get(emailkey, None) sessionInfo = session.setdefault(Auth0.session_key, SessionInfo()) # use the email as the userid, if defined, otherwise fall back to parsing the sub field. if email: sessionInfo.userid = email else: sessionInfo.userid = payload['sub'].encode('utf8').split('|')[-1] sessionInfo.expiration = payload['exp'] sessionInfo.roles = Auth0.getRoleAssignments(payload.get('https://zenoss.com/roles', [])) return sessionInfo except Exception as ex: log.debug('Error storing jwt token: {}'.format(ex.message)) Auth0.removeToken(request) return None
def assertJwtsEqual(self, jwt, key, expected_payload=None, expected_headers=None): expected_headers = expected_headers or {} expected_payload = expected_payload or {} decoded_payload = jwt_lib.decode(jwt, key, verify=False) decoded_headers = jwt_lib.get_unverified_header(jwt) self.assertEqual(expected_headers, decoded_headers) self.assertEqual(expected_payload, decoded_payload)
def parsing_token(self,raw_jwttoken): raw_jwttoken = unquote(raw_jwttoken) token = JWTToken() try: token.headers = jwt.get_unverified_header(raw_jwttoken) token.body = jwt.decode(raw_jwttoken, verify=False) token.algo = token.headers['alg'] except: pass return token
def get_header(jwt_string): """ Return all of the headers in the given JWT. :return the headers as a dictionary """ try: return jwt.get_unverified_header(jwt_string) except jwt.InvalidTokenError as e: log.debug("", exc_info=1) raise ValidationError("Unable to decode token: %s" % e)
def get_header(jwt_string): """ Return all of the headers in the given JWT. :return the headers as a dictionary """ try: return jwt.get_unverified_header(jwt_string) except jwt.InvalidTokenError as e: if log.isEnabledFor(logging.DEBUG): log.exception('') raise ValidationError('Unable to decode token: %s' % e)
def _validate_iap_jwt(iap_jwt, expected_audience): try: key_id = jwt.get_unverified_header(iap_jwt).get('kid') if not key_id: return (None, None, '**ERROR: no key ID**') key = get_iap_key(key_id) decoded_jwt = jwt.decode( iap_jwt, key, algorithms=['ES256'], audience=expected_audience) return (decoded_jwt['sub'], decoded_jwt['email'], '') except (jwt.exceptions.InvalidTokenError, requests.exceptions.RequestException) as e: return (None, None, '**ERROR: JWT validation error {}**'.format(e))
def _check_headers(self, token): header_data, payload_data, signature_data = token.split('.', maxsplit=2) try: headers = self._base64_decode(header_data) if not headers: raise InvalidTokenException("Missing Headers") self._check_for_duplicates(headers) except UnicodeDecodeError: raise InvalidTokenException("Corrupted Header") except ValueError as e: raise InvalidTokenException(repr(e)) header = jwt.get_unverified_header(token) self._check_header_values(header)
def ValidateIapJwt(iap_jwt, expected_audience): """Validates an IAP JWT.""" try: key_id = jwt.get_unverified_header(iap_jwt).get("kid") if not key_id: raise IAPValidationFailedError("No key ID") key = GetIapKey(key_id) decoded_jwt = jwt.decode( iap_jwt, key, algorithms=["ES256"], audience=expected_audience) return (decoded_jwt["sub"], decoded_jwt["email"]) except (jwt.exceptions.InvalidTokenError, requests.exceptions.RequestException) as e: raise IAPValidationFailedError(e)
def decode_jwt_token(token): unverified_header = jwt.get_unverified_header(token) unverified_claims = jwt.decode(token, verify=False) if unverified_header.get(claims.KEY_ID): unverified_key_id = six.text_type(unverified_header.get(claims.KEY_ID)) else: unverified_key_id = None if claims.ISSUER not in unverified_claims: raise MissingRequiredClaimError(claims.ISSUER) unverified_issuer = six.text_type(unverified_claims[claims.ISSUER]) if api_settings.ACCEPTED_ISSUERS is not None and unverified_issuer not in api_settings.ACCEPTED_ISSUERS: raise InvalidIssuerError('Invalid issuer') public_key, key_id = get_public_key_and_key_id(issuer=unverified_issuer, key_id=unverified_key_id) options = { 'verify_exp': api_settings.VERIFY_EXPIRATION, 'verify_aud': True, 'verify_iss': True, } payload = jwt.decode( jwt=token, key=public_key, verify=api_settings.VERIFY_SIGNATURE, algorithms=api_settings.DECODE_ALGORITHMS or [api_settings.ENCODE_ALGORITHM], options=options, leeway=api_settings.EXPIRATION_LEEWAY, audience=api_settings.IDENTITY, issuer=unverified_issuer, ) if payload.get(claims.TOKEN) not in (claims.TOKEN_SESSION, claims.TOKEN_AUTHORIZATION): raise InvalidTokenError('Unknown token type') if payload.get(claims.ISSUER) != api_settings.IDENTITY and payload.get(claims.TOKEN) != claims.TOKEN_AUTHORIZATION: raise InvalidTokenError('Only authorization tokens are accepted from other issuers') if not payload.get(claims.SESSION_ID): raise MissingRequiredClaimError('Session ID is missing.') if not payload.get(claims.USER_ID): raise MissingRequiredClaimError('User ID is missing.') return payload
def verify_auth_token(request): """Verifies the JWT auth token in the request. If no token is found or if the token is invalid, returns None. Otherwise, it returns a dictionary containing the JWT claims. """ if 'Authorization' not in request.headers: return None # Auth header is in format 'Bearer {jwt}'. request_jwt = request.headers['Authorization'].split(' ').pop() # Determine which certificate was used to sign the JWT. header = jwt.get_unverified_header(request_jwt) kid = header['kid'] certificates = get_firebase_certificates() try: certificate = certificates[kid] except KeyError: logging.warning('JWT signed with unkown kid {}'.format(header['kid'])) return None # Get the public key from the certificate. This is used to verify the # JWT signature. public_key = extract_public_key_from_certificate(certificate) # [START decrypt_token] try: claims = jwt.decode( request_jwt, public_key, algorithms=['RS256'], audience=os.environ['FIREBASE_PROJECT_ID'], issuer='https://securetoken.google.com/{}'.format( os.environ['FIREBASE_PROJECT_ID'])) except jwt.exceptions.InvalidTokenError as e: logging.warning('JWT verification failed: {}'.format(e)) return None # [END decrypt_token] return claims
def auth_token(self, token): header = jwt.get_unverified_header(token) kid = header.get('kid') if not kid: raise Exception("The JWT token not include KID") if int(time.time()) >= self.cert_expire: try: yield self.request_cert() except Exception as e: raise Exception("Requires JWT public certificate failure, {}".format(str(e))) try: cert_obj = load_pem_x509_certificate(self.public_cert.get(kid).encode('utf-8'), default_backend()) public_key = cert_obj.public_key() payload = jwt.decode(token, public_key, audience=self.PROJECT_ID, algorithms=['RS256'], verify=True) except Exception as e: raise Exception("Verify JWT token failure, {}".format(str(e))) raise gen.Return({'user_id': payload['user_id'], 'token': token, 'expire': payload['exp'], "ext": payload})
def get_public_key_for_jwt(encoded_jwt, url): """Get public key for JWT in order to verify the signature. The keys get cached in order to limit the amount of network round trips. Args: encoded_jwt: Base64 encoded JWT. url: URL where keys can be fetched. Raises: JwTKeyError if keys cannot be fetched. Returns: Key as string. """ # Get the Key ID from the JWT header. key_id = jwt.get_unverified_header(encoded_jwt).get('kid') if not key_id: raise JwtKeyError('Missing key ID field in token header') key_cache = get_public_key_for_jwt.key_cache key = key_cache.get(key_id) if key: return key # Re-fetch the key file. keys_json = _fetch_public_keys(url) if 'keys' in keys_json: _new_keys_dict = {} for key_dict in keys_json['keys']: public_key = jwt.algorithms.RSAAlgorithm.from_jwk( json.dumps(key_dict)) _new_keys_dict[key_dict['kid']] = public_key key_cache = _new_keys_dict else: key_cache = keys_json get_public_key_for_jwt.key_cache = key_cache key = key_cache.get(key_id) if not key: raise JwtKeyError('IAP public key {!r} not found'.format(key_id)) return key
def from_jwt(cls, jwt, key=''): """ Decode a JWT string into a Jwt object :param str jwt: JWT string :param Optional[str] key: key used to verify JWT signature, if not provided then validation is skipped. :raises JwtDecodeError if decoding JWT fails for any reason. :return: A DecodedJwt object containing the jwt information. """ verify = True if key else False try: payload = jwt_lib.decode(bytes(jwt), key, options={ 'verify_signature': verify, 'verify_exp': True, 'verify_nbf': True, }) headers = jwt_lib.get_unverified_header(jwt) except Exception as e: raise JwtDecodeError(getattr(e, 'message', str(e))) return cls._from_jwt(headers, payload, key)
def _get_key_id_from_jwt_header(a_jwt): """ returns the key identifier from a jwt header. """ header = jwt.get_unverified_header(a_jwt) return KeyIdentifier(header['kid'])
def test_token_should_contain_correct_headers(): token = create_jwt_token("key", "client_id") headers = jwt.get_unverified_header(token) assert headers['typ'] == 'JWT' assert headers['alg'] == 'HS256'
def openid(): oidc_configuration, jwt_key_set = get_oidc_configuration(current_app) token_endpoint = oidc_configuration['token_endpoint'] userinfo_endpoint = oidc_configuration['userinfo_endpoint'] data = { 'grant_type': 'authorization_code', 'code': request.json['code'], 'redirect_uri': request.json['redirectUri'], 'client_id': request.json['clientId'], 'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'], } r = requests.post(token_endpoint, data) token = r.json() try: if current_app.config['OIDC_VERIFY_TOKEN']: jwt_header = jwt.get_unverified_header(token['id_token']) public_key = jwt_key_set[jwt_header['kid']] id_token = jwt.decode( token['id_token'], key=public_key, algorithms=jwt_header['alg'] ) else: id_token = jwt.decode( token['id_token'], verify=False ) except Exception: current_app.logger.warning('No ID token in OpenID Connect token response.') id_token = {} try: headers = {'Authorization': '{} {}'.format(token.get('token_type', 'Bearer'), token['access_token'])} r = requests.get(userinfo_endpoint, headers=headers) userinfo = r.json() except Exception: raise ApiError('No access token in OpenID Connect token response.') subject = userinfo['sub'] name = userinfo.get('name') or id_token.get('name') nickname = userinfo.get('nickname') email = userinfo.get('email') or id_token.get('email') email_verified = userinfo.get('email_verified', id_token.get('email_verified', bool(email))) picture = userinfo.get('picture') or id_token.get('picture') role_claim = current_app.config['OIDC_ROLE_CLAIM'] group_claim = current_app.config['OIDC_GROUP_CLAIM'] custom_claims = { role_claim: userinfo.get(role_claim) or id_token.get(role_claim, []), group_claim: userinfo.get(group_claim) or id_token.get(group_claim, []), } login = userinfo.get('preferred_username', nickname or email) if not login: raise ApiError("Must support one of the following OpenID claims: 'preferred_username', 'nickname' or 'email'", 400) user = User.find_by_id(id=subject) if not user: user = User(id=subject, name=name, login=login, password='', email=email, roles=[], text='', email_verified=email_verified) user.create() else: user.update(login=login, email=email) roles = custom_claims[role_claim] or user.roles groups = custom_claims[group_claim] if user.status != 'active': raise ApiError('User {} is not active'.format(login), 403) if not_authorized('ALLOWED_OIDC_ROLES', roles) and not_authorized('ALLOWED_EMAIL_DOMAINS', groups=[user.domain]): raise ApiError('User {} is not authorized'.format(login), 403) user.update_last_login() scopes = Permission.lookup(login, roles) customers = get_customers(login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='openid-login', message='user login via OpenID Connect', user=login, customers=customers, scopes=scopes, resource_id=subject, type='user', request=request) token = create_token(user_id=subject, name=name, login=login, provider='openid', customers=customers, scopes=scopes, email=email, email_verified=email_verified, picture=picture, **custom_claims) return jsonify(token=token.tokenize)