def post(self): # get auth token auth_header = request.headers.get('Authorization') if auth_header: auth_token = auth_header.split(" ")[0] else: auth_token = '' if auth_token: resp = User.decode_auth_token(auth_token) if not isinstance(resp, str): # mark the token as blacklisted blacklist_token = BlacklistToken(token=auth_token) try: # insert the token db.session.add(blacklist_token) db.session.commit() response_object = { 'status': 'success', 'message': 'Successfully logged out.' } return make_response(jsonify(response_object)), 200 except Exception as e: response_object = {'status': 'fail', 'message': e} return make_response(jsonify(response_object)), 200 else: response_object = {'status': 'fail', 'message': resp} return make_response(jsonify(response_object)), 401 else: response_object = { 'status': 'fail', 'message': 'Provide a valid auth token.' } return make_response(jsonify(response_object)), 403
def test_decode_auth_token(self): user = User(username='******', email='*****@*****.**', password='******') auth_token = user.encode_auth_token(1) self.assertTrue(isinstance(auth_token, bytes)) self.assertTrue( User.decode_auth_token(auth_token.decode("utf-8")) == 1)
def decorator(*args, **kwargs): auth_token = request.headers.get("Authorization") if not auth_token: raise Unauthorized username = User.decode_auth_token(auth_token) user = User.findOne(username=username) if not user: raise Unauthorized() return f(username, *args, **kwargs)
def tfa_logic(user, tfa_token, ignore_tfa_requirement=False): if (user.is_TFA_required() or user.TFA_enabled) and not ignore_tfa_requirement: if not user.TFA_enabled: # Go down this path if user is yet to set up TFA tfa_url = user.tfa_url db.session.commit() response_object = { 'tfa_url': tfa_url, 'message': 'User must setup two factor authentication' } return response_object # Otherwise, check TFA if tfa_token is None: response_object = { 'tfa_failure': True, 'message': 'TFA token required, none supplied' } return response_object tfa_response = User.decode_auth_token(tfa_token, 'TFA') if isinstance(tfa_response, str): # User doesn't have valid TFA token response_object = {'tfa_failure': True, 'message': tfa_response} return response_object if tfa_response.get("token_type") != "TFA": # Ensure the TFA token was generated by encode_TFA_token response_object = { 'tfa_failure': True, 'message': 'Invalid TFA response' } return response_object if tfa_response.get("id") != user.id: # User doesn't has valid TFA token BUT it's not theirs response_object = { 'tfa_failure': True, 'message': 'Invalid User ID in TFA response' } return response_object return None
def test_get_file(self): register_res = self.client.post('/auth/register', data=json.dumps( dict(username="******", email='*****@*****.**', password='******')), content_type='application/json') data = json.loads(register_res.data.decode()) userid = User.decode_auth_token(data["auth_token"]) store_files(userid) doc_result = self.client.post('api/get_file', data=json.dumps(dict(docid=0, )), content_type="application/json", headers=dict(Authorization='Bearer ' + data["auth_token"])) print doc_result
def decorate_function(*args, **kws): auth_header = request.headers.get('Authorization') if auth_header: try: auth_token = auth_header.split(" ")[1] except IndexError: responseObject = { 'status': 'fail', 'message': 'Bearer token malformed.' } return make_response(jsonify(responseObject)), 401 else: responseObject = {'status': 'fail', 'message': 'please login'} return make_response(jsonify(responseObject)), 401 if auth_token: userid = User.decode_auth_token(auth_token) return f(userid, *args, **kws) else: responseObject = {'status': 'fail', 'message': 'no auth token'} return make_response(jsonify(responseObject)), 401
def post(self): # get the post data post_data = request.get_json() old_password = post_data.get('old_password') new_password = post_data.get('new_password') phone = proccess_phone_number(phone_number=post_data.get('phone'), region=post_data.get('region')) one_time_code = post_data.get('one_time_code') auth_header = request.headers.get('Authorization') # Check authorisation using a one time code if phone and one_time_code: card = phone[-6:] user = (User.query.filter_by(phone=phone).execution_options(show_all=True).first() or User.query.filter_by(public_serial_number=card).execution_options(show_all=True).first() ) if not user: response_object = { 'status': 'fail', 'message': 'User not found' } return make_response(jsonify(response_object)), 401 if user.is_activated: response_object = { 'status': 'fail', 'message': 'Account already activated' } return make_response(jsonify(response_object)), 401 if str(one_time_code) != user.one_time_code: response_object = { 'status': 'fail', 'message': 'One time code not valid' } return make_response(jsonify(response_object)), 401 user.hash_password(new_password) user.is_phone_verified = True user.is_activated = True user.one_time_code = None auth_token = user.encode_auth_token() response_object = create_user_response_object(user, auth_token, 'Successfully set pin') db.session.commit() return make_response(jsonify(response_object)), 200 # Check authorisation using regular auth elif auth_header and auth_header != 'null' and old_password: auth_token = auth_header.split(" ")[0] resp = User.decode_auth_token(auth_token) if isinstance(resp, str): response_object = { 'status': 'fail', 'message': 'Invalid auth token' } return make_response(jsonify(response_object)), 401 user = User.query.filter_by(id=resp.get('user_id')).execution_options(show_all=True).first() if not user: response_object = { 'status': 'fail', 'message': 'User not found' } return make_response(jsonify(response_object)), 401 if not user.verify_password(old_password): response_object = { 'status': 'fail', 'message': 'invalid password' } return make_response(jsonify(response_object)), 401 # Check authorisation using a reset token provided via email else: reset_password_token = post_data.get('reset_password_token') if not reset_password_token: response_object = { 'status': 'fail', 'message': 'Missing token.' } return make_response(jsonify(response_object)), 401 reset_password_token = reset_password_token.split(" ")[0] validity_check = User.decode_single_use_JWS(reset_password_token, 'R') if not validity_check['success']: response_object = { 'status': 'fail', 'message': validity_check['message'] } return make_response(jsonify(response_object)), 401 user = validity_check['user'] reuse_check = user.check_reset_token_already_used( reset_password_token) if not reuse_check: response_object = { 'status': 'fail', 'message': 'Token already used' } return make_response(jsonify(response_object)), 401 if not new_password or len(new_password) < 6: response_object = { 'status': 'fail', 'message': 'Password must be at least 6 characters long' } return make_response(jsonify(response_object)), 401 user.hash_password(new_password) user.delete_password_reset_tokens() db.session.commit() response_object = { 'status': 'success', 'message': 'Password changed, please log in' } return make_response(jsonify(response_object)), 200
def wrapper(*args, **kwargs): # ----- FIRST GET AUTH VALUES ----- # Query string auth needs to be explicity allowed for an endpoint since it can lead to security vulnerabilities # if used incorrectly by the client (for example credentials getting logged by website trackers). # We get credentials with it first, meaning any values will be overwritten by a present header auth if allow_query_string_auth: username = request.args.get('username', None) password = request.args.get('password', None) auth_token = request.args.get('auth_token', None) tfa_token = request.args.get('tfa_token', None) else: username = None password = None auth_token = None tfa_token = None # Next get basic auth, which we parse using flask's built-in process, if present overwriting query string values auth = request.authorization if auth and auth.type == 'basic': username = auth.username or username password = auth.password or password # Lastly, get any custom set Sempo auth headers, if present overwriting query string values auth_header = request.headers.get('Authorization') if auth_header: split_header = auth_header.split("|") auth_token = split_header[0] try: tfa_token = split_header[1] except IndexError: # Auth header does not contain a TFA token, try getting it from explicit header instead # (dev convenience) tfa_token = request.headers.get( 'TFA_Authorization') or tfa_token # ----- THEN ATTEMPT AUTHORIZATION ----- # If username as password attempt basic auth if username and password: # Make sure basic auth is allowed if len(allowed_basic_auth_types) == 0: response_object = {'message': 'basic auth not allowed'} return make_response(jsonify(response_object)), 401 # Try to find a matching password and auth type for the username, checking orgs first and then config # Check if username belongs to an org org = Organisation.query.filter_by( external_auth_username=username).first() if org: auth_type = 'external' required_password = org.external_auth_password # Otherwise, check if it is one of the allowed BASIC_AUTH_CREDENTIALS else: try: (required_password, auth_type ) = current_app.config['BASIC_AUTH_CREDENTIALS'][username] except KeyError: required_password = None auth_type = None g.auth_type = auth_type if required_password is None or required_password != password: response_object = { 'message': 'invalid basic auth username or password' } return make_response(jsonify(response_object)), 401 if (auth_type not in allowed_basic_auth_types) or (auth_type is None): response_object = { 'message': 'Basic Auth type is {}. Must be: {}'.format( auth_type, allowed_basic_auth_types) } return make_response(jsonify(response_object)), 401 g.active_organisation = org return f(*args, **kwargs) if auth_token: resp = User.decode_auth_token(auth_token) if not isinstance(resp, str): user = User.query.filter_by(id=resp['id']).execution_options( show_all=True).first() if not user: response_object = { 'status': 'fail', 'message': 'user not found' } return make_response(jsonify(response_object)), 401 if not user.is_activated: response_object = { 'status': 'fail', 'message': 'user not activated' } return make_response(jsonify(response_object)), 401 if user.is_disabled: response_object = { 'status': 'fail', 'message': 'user has been disabled' } return make_response(jsonify(response_object)), 401 tfa_response_object = tfa_logic(user, tfa_token, ignore_tfa_requirement) if tfa_response_object: return make_response(jsonify(tfa_response_object)), 401 if len(allowed_roles) > 0: held_roles = resp.get('roles', {}) if not AccessControl.has_suffient_role( held_roles, allowed_roles): response_object = { 'message': 'user does not have any of the allowed roles: ' + str(allowed_roles), } return make_response(jsonify(response_object)), 403 # ----- AUTH PASSED, DO FINAL SETUP ----- g.user = user g.member_organisations = [org.id for org in user.organisations] try: g.active_organisation = None # First try to set the active org from the query query_org = request.args.get('org', None) if query_org is not None: try: query_org = int(query_org) if query_org in g.member_organisations: g.active_organisation = Organisation.query.get( query_org) except ValueError: pass # Then get the fallback organisation if g.active_organisation is None: g.active_organisation = user.fallback_active_organisation( ) # Check for query_organisations as well. These are stored in g and used for operations which # are allowed to be run against multiple orgs. Submitted as a CSV # E.g. GET metrics, user list, transfer list should be gettable with ?query_organisations=1,2,3 query_organisations = request.args.get( 'query_organisations', None) if query_organisations: g.query_organisations = [] try: query_organisations = [ int(q) for q in query_organisations.split(',') ] if set(query_organisations).issubset( set(g.member_organisations)): g.query_organisations = query_organisations except ValueError: pass except NotImplementedError: g.active_organisation = None proxies = request.headers.getlist("X-Forwarded-For") check_ip(proxies, user, num_proxy=1) # updates the validated user last seen timestamp user.update_last_seen_ts() #This is the point where you've made it through ok and you can return the top method return f(*args, **kwargs) response_object = {'status': 'fail', 'message': resp} return make_response(jsonify(response_object)), 401 response_object = { 'status': 'fail', 'message': 'Provide a valid auth token.' } return make_response(jsonify(response_object)), 401