def _get_response_data(self, response, observable): expected_errors = { HTTPStatus.UNAUTHORIZED: lambda: AuthorizationError(), HTTPStatus.TOO_MANY_REQUESTS: lambda: AutofocusTooManyRequestsError(), HTTPStatus.CONFLICT: lambda: AuthorizationError(response.text) } if response.status_code == HTTPStatus.OK: return response.json() elif response.status_code >= 500: raise AutofocusServerError elif response.status_code == HTTPStatus.NOT_FOUND: # in some cases, when AutoFocus can't find observable, # it returns 404 if observable != self.health_test_observable: return {} else: raise AutofocusNotFoundError elif response.status_code in expected_errors: raise expected_errors[response.status_code]() else: raise TRFormattedError( HTTPStatus(response.status_code).phrase, f'Unexpected response from AutoFocus: {response.text}')
def _get(self, url): response = requests.get(url, headers=self.headers) if response.ok: return response.json() if response.status_code in POTENTIALLY_NOT_CRITICAL_ERRORS: if INVALID_TOKEN_MESSAGE in response.text: raise AuthorizationError(INVALID_TOKEN_MESSAGE) return [] elif response.status_code == HTTPStatus.UNAUTHORIZED: raise AuthorizationError(response.text) raise CriticalError(response)
def _request(self, path, method='GET', body=None, page=1, data_extractor=lambda r: r.json()): params = {'page': page} url = join_url(self.base_url, path) try: response = requests.request(method, url, headers=self.headers, json=body, params=params) except SSLError as error: raise SecurityTrailsSSLError(error) # catch wrong API key if response.status_code == HTTPStatus.FORBIDDEN: raise AuthorizationError(response.json().get('message') or response.text) if response.ok: return data_extractor(response) if response.status_code in NOT_CRITICAL_ERRORS: return {} raise CriticalSecurityTrailsResponseError(response)
def get_credentials(): expected_errors = { KeyError: WRONG_PAYLOAD_STRUCTURE, AssertionError: JWKS_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, MissingRequiredClaimError: WRONG_PAYLOAD_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, PyJWKClientError: KID_NOT_FOUND, URLError: WRONG_JWKS_HOST, HTTPError: WRONG_JWKS_HOST } try: token = get_auth_token() jwks_host = jwt.decode(token, options={ 'verify_signature': False }).get('jwks_host') assert jwks_host jwks_client = PyJWKClient(f'https://{jwks_host}/.well-known/jwks') signing_key = jwks_client.get_signing_key_from_jwt(token) aud = request.url_root payload = jwt.decode(token, signing_key.key, algorithms=['RS256'], audience=[aud.rstrip('/')]) current_app.config['SERVER_IP'] = payload['SERVER_IP'] set_ctr_entities_limit(payload) return payload['user'], payload['pass'] except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_jwt(): """ Get Authorization token and validate its signature against the application's secret key, . """ expected_errors = { KeyError: WRONG_PAYLOAD_STRUCTURE, AssertionError: JWK_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, TypeError: KID_NOT_FOUND } token = get_auth_token() try: jwks_payload = jwt.decode(token, options={'verify_signature': False}) assert 'jwks_host' in jwks_payload jwks_host = jwks_payload.get('jwks_host') key = get_public_key(jwks_host, token) aud = request.url_root payload = jwt.decode( token, key=key, algorithms=['RS256'], audience=[aud.rstrip('/')] ) set_ctr_entities_limit(payload) return payload except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def get_jwt() -> Union[dict, Exception]: """ Get authorization token and validate its signature against the public key from /.well-known/jwks endpoint """ jwt_payload_keys = { 'baseUrl', 'accessToken', 'clientToken', 'clientSecret' } expected_errors = { AssertionError: WRONG_PAYLOAD_STRUCTURE, KeyError: JWKS_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, TypeError: KID_NOT_FOUND } token = get_auth_token() try: jwks_host = jwt.decode( token, options={'verify_signature': False} )['jwks_host'] key = get_public_key(jwks_host, token) aud = request.url_root payload = jwt.decode( token, key=key, algorithms=['RS256'], audience=[aud.rstrip('/')] ) assert payload.keys() >= jwt_payload_keys return payload except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_response_data(response): expected_response_errors = { HTTPStatus.NOT_FOUND: AbuseNotFoundError, HTTPStatus.INTERNAL_SERVER_ERROR: AbuseInternalServerError, HTTPStatus.BAD_GATEWAY: AbuseUnavailableError, HTTPStatus.SERVICE_UNAVAILABLE: AbuseUnavailableError, HTTPStatus.GATEWAY_TIMEOUT: AbuseUnavailableError, 521: AbuseServerDownError } if response.ok: return response.text if 'DOCTYPE html' in response.text \ else response.json() else: if response.status_code in expected_response_errors: raise expected_response_errors[response.status_code] if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY: return {} if response.status_code == HTTPStatus.TOO_MANY_REQUESTS: raise AbuseTooManyRequestsError(response) if response.status_code == HTTPStatus.UNAUTHORIZED: raise AuthorizationError( message=response.json()['errors'][0]['detail']) else: raise AbuseUnexpectedResponseError(response)
def get_public_key(jwks_host, token): """ Get public key by requesting it from specified jwks host. """ expected_errors = ( ConnectionError, InvalidURL, JSONDecodeError, HTTPError, ) try: response = requests.get(f"https://{jwks_host}/.well-known/jwks") response.raise_for_status() jwks = response.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(token)['kid'] return public_keys.get(kid) except expected_errors: raise AuthorizationError(WRONG_JWKS_HOST)
def get_api_key(): """ Get authorization token and validate its signature against the public key from /.well-known/jwks endpoint """ expected_errors = { KeyError: WRONG_PAYLOAD_STRUCTURE, AssertionError: JWK_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, TypeError: KID_NOT_FOUND } token = get_auth_token() try: jwks_host = jwt.decode(token, options={ 'verify_signature': False }).get('jwks_host') assert jwks_host key = get_public_key(jwks_host, token) aud = request.url_root payload = jwt.decode(token, key=key, algorithms=['RS256'], audience=[aud.rstrip('/')]) return payload['key'] except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def _request_farsight(self, observable, action, number_of_days_to_filter=None, limit=None): path = self._path(observable['type']) time_filter = self._time_filter( number_of_days_to_filter) if number_of_days_to_filter else '' url = join_url(self.base_url, action, path, observable["value"], '?humantime=True&aggr=False', f'&limit={limit}' if limit else '', time_filter) try: response = requests.get(url, headers=self.headers) except SSLError as error: raise FarsightSSLError(error) if response.status_code == HTTPStatus.FORBIDDEN: raise AuthorizationError(response.text) if response.ok: return [json.loads(raw) for raw in response.iter_lines()] if response.status_code in NOT_CRITICAL_ERRORS: return [] raise CriticalFarsightResponseError(response)
def get_credentials(): """ Get authorization token and validate its signature against the public key from /.well-known/jwks endpoint """ jwt_payload_keys = {'application_id', 'tenant_id', 'client_secret'} expected_errors = { AssertionError: WRONG_PAYLOAD_STRUCTURE, KeyError: JWKS_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, TypeError: KID_NOT_FOUND } token = get_auth_token() try: jwks_host = jwt.decode(token, options={'verify_signature': False})['jwks_host'] key = get_public_key(jwks_host, token) aud = request.url_root payload = jwt.decode(token, key=key, algorithms=['RS256'], audience=[aud.rstrip('/')]) assert payload.keys() >= jwt_payload_keys set_ctr_entities_limit(payload) return payload except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def get_jwt(): """ Get Authorization token and validate its signature against the application's secret key. """ expected_errors = { KeyError: 'Wrong JWT payload structure', TypeError: '<SECRET_KEY> is missing', BadSignatureError: 'Failed to decode JWT with provided key', DecodeError: 'Wrong JWT structure' } token = get_auth_token() try: credentials = jwt.decode(token, current_app.config['SECRET_KEY']) client_id = credentials['client_id'] client_secret = credentials['client_secret'] tenant_id = credentials['tenant_id'] return { 'client_id': client_id, 'client_secret': client_secret, 'tenant_id': tenant_id } except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def get_auth_token() -> Union[str, Exception]: """Parse and validate incoming authorization header""" expected_errors = { KeyError: NO_AUTH_HEADER, AssertionError: WRONG_AUTH_TYPE } try: scheme, token = request.headers['Authorization'].split() assert scheme.lower() == 'bearer' return token except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_chronicle_http_client(account_info): """ Return an http client that is authorized with the given credentials using oauth2client or google-auth. """ try: credentials = service_account.Credentials.from_service_account_info( account_info, scopes=current_app.config['AUTH_SCOPES'] ) except ValueError as e: raise AuthorizationError(str(e)) return _auth.authorized_http(credentials)
def get_auth_token(): """ Parse the incoming request's Authorization Bearer JWT for some credentials. """ expected_errors = { KeyError: 'Authorization header is missing', AssertionError: 'Wrong authorization type' } try: scheme, token = request.headers['Authorization'].split() assert scheme.lower() == 'bearer' return token except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_jwt(): expected_errors = { KeyError: 'Wrong JWT payload structure', TypeError: '<SECRET_KEY> is missing', BadSignatureError: 'Failed to decode JWT with provided key', DecodeError: 'Wrong JWT structure' } token = get_auth_token() try: payload = jwt.decode(token, current_app.config['SECRET_KEY']) print(payload['key']) return payload['key'] except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def _get(self, endpoint, params): params.update(self.params) url = current_app.config['API_URL'].format(endpoint=endpoint) response = requests.get(url, headers=self.headers, params=params) if not response.ok: raise StandardHttpError(response) error = response.json().get('error') if error: if error in NOT_CRITICAL_ERRORS: return {} elif error in INVALID_API_KEY_MESSAGES: raise AuthorizationError(error) else: raise CriticalError(error) return response.json()
def get_auth_token(): """ Parse and validate incoming request Authorization header. NOTE. This function is just an example of how one can read and check anything before passing to an API endpoint, and thus it may be modified in any way, replaced by another function, or even removed from the module. """ expected_errors = { KeyError: 'Authorization header is missing', AssertionError: 'Wrong authorization type' } try: scheme, token = request.headers['Authorization'].split() assert scheme.lower() == 'bearer' return token except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_public_key(jwks_host, token): expected_errors = { ConnectionError: WRONG_JWKS_HOST, InvalidURL: WRONG_JWKS_HOST, } try: response = requests.get(f"https://{jwks_host}/.well-known/jwks") jwks = response.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(token)['kid'] return public_keys.get(kid) except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def get_response_data(response): expected_response_errors = { HTTPStatus.NOT_FOUND: SpycloudNotFoundError, HTTPStatus.INTERNAL_SERVER_ERROR: SpycloudInternalServerError, HTTPStatus.TOO_MANY_REQUESTS: SpycloudTooManyRequestsError } if response.ok: return response.json() else: if response.status_code in expected_response_errors: raise expected_response_errors[response.status_code] elif response.status_code == HTTPStatus.UNAUTHORIZED or \ response.status_code == HTTPStatus.FORBIDDEN: raise AuthorizationError(response.json()['message']) elif response.status_code == HTTPStatus.BAD_REQUEST: return {} else: raise SpycloudUnexpectedResponseError(response)
def _request(self, path, method='GET', params=None): url = urljoin(f'https://{self.base_url}', path) try: response = self.session.request(method, url, headers=self.headers, params=params) except SSLError as error: raise AkamaiSSLError(error) except ConnectionError: raise AkamaiConnectionError(self.base_url) if response.status_code == HTTPStatus.UNAUTHORIZED: raise AuthorizationError(response.json().get('detail') or response.text) if response.ok: return response.json() raise CriticalAkamaiResponseError(response)
def get_jwt(): """ Parse the incoming request's Authorization Bearer JWT for some credentials. Validate its signature against the application's secret key. NOTE. This function is just an example of how one can read and check anything before passing to an API endpoint, and thus it may be modified in any way, replaced by another function, or even removed from the module. """ expected_errors = { KeyError: 'Wrong JWT payload structure', TypeError: '<SECRET_KEY> is missing', BadSignatureError: 'Failed to decode JWT with provided key', DecodeError: 'Wrong JWT structure' } token = get_auth_token() try: return jwt.decode(token, current_app.config['SECRET_KEY'])['key'] except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
def _request_chronicle(self, path, observable, number_of_days_to_filter=None, page_size=None): time_filter = (self._time_filter(number_of_days_to_filter) if number_of_days_to_filter is not None else '') page_size_filter = ("&page_size=" + str(page_size) if page_size is not None else '') url = join_url( self.base_url, f'{path}?{self._artifact_filter(observable)}' f'{time_filter}' f'{page_size_filter}') try: response, body = self.client.request( url, 'GET', headers={ 'Content-Type': 'application/json', 'Accept': 'application/json', 'User-Agent': current_app.config['USER_AGENT'] }) except SSLCertVerificationError as error: raise ChronicleSSLError(error) except tuple(EXPECTED_AUTH_ERRORS) as error: raise AuthorizationError(EXPECTED_AUTH_ERRORS[error.__class__]) if response.status == HTTPStatus.OK: return json.loads(body) if response.status in NOT_CRITICAL_ERRORS: return {} raise UnexpectedChronicleResponseError(response, body)
def get_credentials(): """ Get authorization token and validate its signature against the public key from /.well-known/jwks endpoint. Extract and validate credentials. """ expected_errors = { KeyError: JWKS_HOST_MISSING, AssertionError: WRONG_PAYLOAD_STRUCTURE, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, TypeError: KID_NOT_FOUND } token = get_auth_token() try: jwks_host = jwt.decode( token, options={'verify_signature': False} )['jwks_host'] key = get_public_key(jwks_host, token) aud = request.url_root payload = jwt.decode( token, key=key, algorithms=['RS256'], audience=[aud.rstrip('/')] ) set_env_variable(payload, 'API_URL') set_env_variable(payload, 'PLATFORM_URL') set_env_variable(payload, 'CTR_ENTITIES_LIMIT') assert 'user' in payload assert 'pass' in payload return payload except tuple(expected_errors) as error: message = expected_errors[error.__class__] raise AuthorizationError(message)
def wraps(*args, **kwargs): try: return func(*args, **kwargs) except (UnicodeEncodeError, InvalidHeader): raise AuthorizationError(UNAUTHORIZED)