Beispiel #1
0
    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
Beispiel #2
0
    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)
Beispiel #4
0
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
Beispiel #6
0
 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
Beispiel #7
0
    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
Beispiel #8
0
    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