def middleware(endpoint): logger.info('got new request to frontegg: method = %s, path = %s', request.method, request.path) o = urlparse(request.base_url) response = self.proxy_request(request, method=request.method, path=request.path, host=o.hostname, params=request.args, body=request.data, cookies=request.cookies, headers=dict(request.headers)) logger.info( 'got response from frontegg: status_code = %s, path = %s, traceId = %s', response.status_code, request.path, response.headers.get('frontegg-trace-id')) flask_response = make_response(response.content, response.status_code, response.headers) for cookieKey in response.cookies.keys(): flask_response.headers.add_header( 'set-cookie', response.cookies.get(cookieKey).OutputString()) return flask_response
def authentication_middleware(request: Request): try: __frontegg.frontegg.decode_jwt(request.headers.get('Authorization')) logger.info('JWT token verified') return None except Exception as e: logger.debug('could not verify JWT token, ' + str(e), ) raise UnauthenticatedException()
def context_provider(request: Request): try: user = __frontegg.frontegg.decode_jwt( request.headers.get('Authorization')) logger.info('decoded entity') return FronteggContext(user.get('sub'), user.get('tenantId')) except: return FronteggContext('user-id', 'tenant-id')
def context_provider(request: Request): try: user = __frontegg.frontegg.decode_jwt( request.headers.get('Authorization')) logger.debug('get user from JWT' + str(user)) return FronteggContext(user.get('sub'), user.get('tenantId')) except Exception as e: logger.debug('could not get user from JWT, ' + str(e)) logger.info('will send default tenant-id and user-id') return FronteggContext('user-id', 'tenant-id')
def decode_jwt(self, authorization_header, verify: typing.Optional[bool] = True): if not authorization_header: raise InvalidTokenError('Authorization headers is missing') logger.debug('found authorization header: ' + str(authorization_header)) jwt_token = authorization_header.replace('Bearer ', '') public_key = self.get_public_key() logger.debug('got public key' + str(public_key)) decoded = self.__get_jwt_data(jwt_token, verify, public_key) logger.info('jwt was decoded successfully') logger.debug('JWT value - ' + str(decoded)) return decoded
def decorated_function(*args, **kwargs): # Initially valid_permissions = True valid_roles = True try: decoded = __frontegg.frontegg.decode_jwt(request.headers.get('Authorization')) g.user = decoded # Validate roles if role_keys is not None: logger.info('will check if entity has one of required roles') valid_roles = any( role in decoded['roles'] for role in role_keys) if permission_keys is not None: logger.info('will check if entity has one of required permissions') valid_permissions = any( permission in decoded['permissions'] for permission in permission_keys) except Exception as e: logger.debug('something went wrong while validating roles and permissions, ' + str(e)) abort(401) if not valid_permissions or not valid_roles: logger.info('entity does not have required role and permissions') abort(403) return logger.info('entity passed authentication middleware') return f(*args, **kwargs)
def get_public_key(self) -> str: if self.__publicKey: return self.__publicKey logger.info('could not find public key locally, will fetch public key') reties = 0 while reties < 10: try: self.__publicKey = self.fetch_public_key() return self.__publicKey except Exception as e: reties = reties + 1 logger.error( 'could not get public key from frontegg, retry number - ' + str(reties) + ', ' + str(e)) logger.error('failed to get public key in all retries')
def func_with_retries(*args, **kwargs): _tries = 0 while _tries < total_tries: try: return f(*args, **kwargs) except Exception as e: if _tries == 0: logger.info((action or f'function "{f.__name__}"') + f' failed on first try, {e}') if +_tries >= total_tries - 1: logger.info( (action or f'function "{f.__name__}"') + f' failed on the last retry attempt ({total_tries}), {e}' ) raise e _tries += 1 if retry_delay > 0: sleep(retry_delay)
def middleware(endpoint): logger.info('got new request to frontegg: method = %s, path = %s', request.method, request.path) o = urlparse(request.base_url) response = self.proxy_request(request, method=request.method, path=request.path, host=o.hostname, params=request.args, body=request.data, cookies=request.cookies, headers=dict(request.headers)) logger.info( 'got response from frontegg: status_code = %s, path = %s', response.status_code, request.path) return make_response(response.content, response.status_code, response.headers)
def refresh_vendor_token(self) -> None: body = {'clientId': self.client_id, 'secret': self.api_key} logger.info('will refresh vendor token') auth_url = frontegg_urls.authentication_service['authenticate_vendor'] auth_response = self.vendor_session_request.post(auth_url, json=body) auth_response.raise_for_status() logger.info('got new vendor token from frontegg') response_body = auth_response.json() self.__access_token = response_body['token'] self.__access_token_expiration = arrow.utcnow().shift( seconds=response_body['expiresIn'] * 0.8) self.vendor_session_request.headers.update( {'x-access-token': self.__access_token}) logger.info('new vendor token was set successfully')
def proxy_request(self, request, method: str, path: str, host: str, params: dict, body: typing.Optional[any], cookies: typing.Optional[dict] = None, headers: typing.Optional[dict] = {}): if not request: raise Exception('request is required') if not method: raise Exception('method is required') if not path: raise Exception('path is required') path_without_frontegg = path.replace( '/' + self.middleware_prefix, '', 1).replace(self.middleware_prefix, '', 1) logger.info('removed path prefix before sending to frontegg, new path - %s', path_without_frontegg) public_route = self.is_public_route( path_without_frontegg, params, method) logger.info('route is %s public route', '' if public_route else 'not') if self.authentication_middleware is not None and not public_route: try: logger.info('will validate user authentication') self.authentication_middleware(request) except HttpException as response: logger.info('failed to authorize entity') return response except Exception as e: logger.info('something went wrong, could not run authentication middleware') logger.debug('auth middleware error - %s', str(e)) return HttpException('Something went wrong', 500) url = urljoin(frontegg_urls.base_url, path_without_frontegg) headers = self.clean_request_headers(headers, host) headers = self.set_context(headers, request) logger.info('adjusted headers before proxying request to frontegg') logger.debug('new headers - %s', str(headers)) if self.should_refresh_vendor_token: logger.info('refresh vendor token is required, will refresh token') self.refresh_vendor_token() logger.info('will proxy request to frontegg') logger.debug('request data: method=%s, url=%s,cookies=%s, body=%s, params=%s, headers=%s', method, url, str(cookies), str(body), str(params), str(headers)) response = self.vendor_session_request.request( method, url, headers=headers, cookies=cookies, data=body, params=params ) logger.info('got response from frontegg') response.headers = self.clean_response_headers(response.headers) response.cookies = self.get_cookies(response.headers) return response