Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom authentication method for Flask-Security

I'm using flask security to authenticate users. I've made sure the authentication works properly with the http_auth_required decorator - the user is being validated against the userstore (an SQLAlchemyUserDatastore in my case), and all is well.

I would like now to use my own authentication method (I'll be using a custom LDAP validation system), while still taking advantage of the things Flask-Security is giving me (things like current_user). I wrote a custom decorator that looks like this:

def authenticate_with_ldap(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if not request.authorization:
            return unauthorized_user_handler()
        user = user_datastore.get_user(request.authorization.username)
        if not user or not authenticate_with_ldap(user.email, user.password):
            return unauthorized_user_handler()
        return func(*args, **kwargs)
    return wrapper

However, when I look at the http_auth_required decorator I see that it uses a private function called _check_http_auth that is doing some stuff that I can't do on my own without accessing private members, like setting the user to the top of the request context stack and sending signals. The code looks like this:

def _check_http_auth():
    auth = request.authorization or BasicAuth(username=None, password=None)
    user = _security.datastore.find_user(email=auth.username)

    if user and utils.verify_and_update_password(auth.password, user):
        _security.datastore.commit()
        app = current_app._get_current_object()
        _request_ctx_stack.top.user = user
        identity_changed.send(app, identity=Identity(user.id))
        return True

    return False

So my question is: what is the correct way to have a custom authentication method, while still utilizing Flask-Security to its fullest?

like image 837
mcouthon Avatar asked Nov 09 '22 09:11

mcouthon


1 Answers

You can accomplish this with a quick monkey patch. Not ideal, but I'm not sure what else you can do until the Flask-Security team writes in a more elegant way to handle this.

import flask_security

def verify_and_update_password_custom(password, user):
    return user.verify_password(password)    

flask_security.forms.verify_and_update_password = verify_and_update_password_custom

I'm not sure if it is used anywhere else. The above works for my own purposes. If it does get called elsewhere, you would just need to monkeypatch it into place wherever that is.

like image 69
melchoir55 Avatar answered Nov 15 '22 04:11

melchoir55