Git Product home page Git Product logo

flask-security's People

Contributors

abendebury avatar abulte avatar ademaro avatar almavizca avatar apahomov avatar chrishaines avatar dependabot[bot] avatar eskil avatar gissimo avatar ingokl avatar inoreneroni avatar ioparaskev avatar jamesonjlee avatar jinblack avatar jirikuncar avatar jonafato avatar joshpurvis avatar jwag956 avatar jxltom avatar kishi85 avatar kuba-lilz avatar lnielsen avatar mattupstate avatar nfvs avatar nickretallack avatar rochacbruno avatar sr-verde avatar taavie avatar tescalada avatar tillerburr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flask-security's Issues

Disable access on user deactivated

Today - if a user is deactivated, existing session and API tokens still work. They shouldn't.

We might be able to piggy back on the idea of a generation/change count in the user model.
Tokens and sessions would be tied to a particular generation/count - on password change or deactivate - we would reject the token/session (since the gen/count wouldn't match)
This would also potentially solve the API token password hash every time

Authtokens are slow

This has caused more folks to abandon flask-security that anything.

pallets-eco/flask-security-3.0#731

cross posted:
https://stackoverflow.com/questions/47157092/slow-flask-response-when-using-flask-security

The issue is that FS is using default hashing per-request to verify that the data in the auth token corresponds to the stored user password.

This seems totally wrong - auth tokens shouldn't be invalidated just because someone changes their password

Also - while the UserMixin has a method for get_auth_token - it doesnt easily allow overriding verifying auth_token - so it is almost impossible to do one's on thing.

Tokens are already signed - that should be enough.

Add doc around best practice

Things like how to generate secret keys - that MUST set flask's SECRET_KEY, good signing algorithms, password encryption etc....

sqlalchemy - pool_pre_ping=True

Look into using passlib for totp secrets

The new 2FA code has a hardwired random secret generator that is used in generating totp_secrets - that doesn't seem secure nor configurable - look into using passlib.totp module

Confirmation token can be reused

The confirmation token can be used again, even if user already confirmed. Using the token actually logs in the user - so this is a potential security issue.

This is discussed in #54 (upstream #662)

Not clear the any security implications - but requiring the user to relogin after confirmation is a nice option.

U2F/WebAuthn support

This is just a U2F/WebAuthn support tracking issue for discussion and etc.

I'd love to implement this but I don't yet have time and any U2F hardware, maybe someone else has thought about implementing this?

SPA/json and CSRF

There are few threads on folks using token authentication to get around difficulty with CSRF and sessions.
Today, flask-security doesn't really support a way for non-template/form UIs to get CSRF token access.

While tokens appear to solve some issues it isn't that secure since today at least, flask and flask-security still create a session and still sets a session cookie.

POST request on /logout should be allowed (at the very least)

Flask-Security should at the very least accept POST requests on the /logout endpoint.
My reasoning being:

  • Some browsers are starting to prefetch links on a website, which can lead to an accidental logout of the user. (As this guy has already found out.)
  • GET request technically shouldn't perform an action on the server side (can we agree that logging a user out is an action?), therefore I feel POST is more correct here.

In my case, I already have a form in the nav, that sends a post request to the /logout endpoint with the submit button, and it's styled to look exactly as any other item on the navbar. Sure, It's not effortless, but I think the work's kinda worth it.

confusion on unauthorized versus unauthenticated.

Today, FS only as a single callback: _security._unauthorized_callback
which is used in both the 'not authenticated' @auth_required case as well as the
unauthorized case @role_required.
The first should return a 401 ,
the second a 403 (Forbidden).

Probably the easiest backward compatible thing is to introduce a new unauthenticated_callback and if that is set - call it.

Also - only FlaskLogin's unauthorized handler does all the appropriate things to redirect to a login view - FS's just returns some lame html....

Work better with Flask-Admin

Flask-Admin has a writeup about how to work with Flask-Security - it is old and we now have a base template. However, we should make it REALLY easy and not require to copy all the FS templates to get it to work well.
Then, do a PR for Flask-Admin to get our integration in their docs.

cache system for apikey not working

Hello @jwag956 ,

the newly added feature of caching apikeys seems to not work in your fork.
Only the Default Flask security dict is used and configuration from my project's config.py file is not used as Flask-Security does.

I don't know what are the differences between the two projects on this topic but I cannot execute the code of my PR as the option to use cache is not set properly.

2FA - naming improvements

The original 2FA PR was done a while ago - and some things have changed, and the naming conventions in the code aren't very consistent. Since this will require some minor backwards incompatibilities, getting them in before the initial release seems prudent:

  1. The templates currently don't use the (new) base template structure. This should be a trivial change.
  2. UserModel - the proposal is to unify all two factor external (and most internal) naming as 'tf_xxx'. To that end - change 'primary_method' to 'tf_primary_method'. Change 'phone_number' to 'tf_phone_number' and change 'totp_secret' to 'tf_totp_secret'.

A few templates and code refer to 'change_method' - but in fact this really is about changing the two factor profile (like phone number, etc). And some, like 'two_factor_change_method_password_confirmation` are just plain silly long names.

Proposal:

  1. change two_factor_change_method.html to tf_setup.html
  2. change two_factor_change_method_password_confirmation.html to tf_confirm.html
  3. change two_factor_verify_code.html to tf_verify.html
  4. make similar changes to internal method names.

leave configuration variables as is - SECURITY_TWO_FACTOR_xxx

Register view returns auth_token when it shouldn't

Need some additional testing/verification - but it appears that after a successful registration, the JSON response always returns an auth_token. That will avoid the normal login form validation that checks for confirmation.?

Potential breaking changes

Possible 4.0 ideas

  • add username to register form/template (this might actually be backwards compat). Not for 4.0
  • drop py 2.7 support
  • Drop token cache (now that we have uniquifier)
  • add authentication_token set to get_security_payload rather than hard wiring it. - Bad Idea!
  • convert TFA re-validate to new 'fresh' model.
  • Remove dependency on Flask-Mail
  • Remove authtoken based on password (require fs_uniquifier)
  • Remove get_user

Can't get translations to work

Trying here where I might have more chance with an undead fork.

I'm using flask_babelex in my app and the app translation itself works fine, but the flask-security part stays in english.

def create_app():
...
    babel = Babel(app)  # noqa: F841
...
    security = Security(  # noqa: F841
        app, user_datastore, register_form=ExtendedRegisterForm, confirm_register_form=ExtendedRegisterForm
    )
...
    @babel.localeselector
    def get_locale():
        # if a user is logged in, use the locale from the user settings
        identity = getattr(g, "identity", None)
        if identity is not None and identity.id:
            return identity.user.locale
        # otherwise try to guess the language from the user accept
        # header the browser transmits.  We support fr/en in this
        # example.  The best match wins.
        print(f"Best locale choosed: {request.accept_languages.best_match(AVAILABLE_LOCALES)}")
        return request.accept_languages.best_match(AVAILABLE_LOCALES)

    @babel.timezoneselector
    def get_timezone():
        identity = getattr(g, "identity", None)
        if identity is not None and identity.id:
            return identity.user.timezone

My get_locale returns "fr" as my browser have been set in french, but flask-security form labels and error messages stays in english.

An example is my register form, which have an extra field "username", that field gets translated, the others from flask-security doesn't.

Any ideas on how I can try to debug that ?

More infos : my form is render by render_form from greyli/bootstrap-flask but since every other parts of the forms, except flask-security works, I don't know if that can be the issue, I do remember seeing issues about translations upstream but nothing seemed to help here.

`Required` class change causes issues when migrating

I think people would appreciate if the changes to the Required class from flask_security.forms could be somehow be listed as a breaking change, removed in general (if people should use wtf's DataRequired instead) or marked deprecated. Right now using Required() on a form field causes a generic error like this which is not ideal:

  File "~/Project/.venv/lib/python3.7/site-packages/flask_security/forms.py", line 76, in __init__
    self._original_message = kwargs["message"]
KeyError: 'message'

Add real DB tests to CI

For CI - maybe add testing against real DB: postgres, mongo, mysql?

we have a lot of configs - 3 ORMs 3 DBs just for RDBMS - and mongo...

2FA - tf_totp_secret will be regenerated after submission

Hi,
Thank for continuing the development!

Each time a user is successfully submitting the second factor, the function "two_factor_token_validation" generates a new "tf_totp_secret" via "complete_two_factor_process".

This means, it is only possible to login once because the user does not know the newly generated "tf_totp_secret" afterwards.

This bug was introduced with the following commit c8d7adb

Black Formatting

Now that this package is starting to go more towards a black style, would you be opposed to blackening the entire package? There is a plugin for pytest to use black formatting: https://github.com/shopkeep/pytest-black. This doesn't work with Python 2, which would mean that the Python 2 support would have to be dropped. Not sure your feelings about that since Python 2 is not going to be supported as of 1/1/2020 (https://pythonclock.org/).

Help required with setting up dev environment; please foresee contributing guidelines

Hi,

I want to add a little feature to the library (redirect after sending the passwordless login info), but I'm having troubles setting up a dev and test environment.

I've cloned the repo in a virtualenv and ran pip install -e .[tests] (I had to ask around on IRC about how to find a way to install and setup the test dependencies).

When running the tests with python setup.py test I'm getting

1 failed, 66 passed, 690 skipped, 12 warnings

The failure is always the same (also when running a specific test):

================================================================== ERRORS ==================================================================
_________________________________________________ ERROR at setup of test_custom_change_url _________________________________________________

request = <SubRequest 'app' for <Function test_custom_change_url>>

    @pytest.fixture()
    def app(request):
        app = Flask(__name__)
        app.response_class = Response
        app.debug = True
        app.config['SECRET_KEY'] = 'secret'
        app.config['TESTING'] = True
        app.config['LOGIN_DISABLED'] = False
        app.config['WTF_CSRF_ENABLED'] = False
        app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

        app.config['SECURITY_PASSWORD_SALT'] = 'salty'

        for opt in ['changeable', 'recoverable', 'registerable',
                    'trackable', 'passwordless', 'confirmable']:
            app.config['SECURITY_' + opt.upper()] = opt in request.keywords

        if 'settings' in request.keywords:
>           for key, value in request.keywords['settings'].kwargs.items():
E           AttributeError: 'bool' object has no attribute 'kwargs'

tests\conftest.py:58: AttributeError

I guess docs on how to contribute would be very helpful, not only for me but also to make it easier for future contributors.

Postgres UUID columns not working?

Hi,

Thank for continuing development of Flask-Security: appreciated :-)

I tried to use Flask-Security-Too as a 'drop in' replacement. Forms, templates etc. work, but I think I am running into a problem with postgres UUID fields.

User model:

from sqlalchemy.dialects.postgresql import UUID

class User(db.Model, UserMixin):
    __tablename__ = 'user'
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
    email = Column(String(255), unique=True)
    first_name = Column(String(255), index=True)
    last_name = Column(String(255), index=True)
    username = Column(String(255), unique=True)
    password = Column(String(255))
    active = Column(Boolean())
    created_at = Column(DateTime, default=datetime.datetime.utcnow)
    confirmed_at = Column(DateTime())
    roles = relationship('Role', secondary='roles_users', backref=backref('users', lazy='dynamic'))

Console:
sqlalchemy.exc.DataError: (psycopg2.DataError) invalid input syntax for uuid: "[email protected]"

Looks as it doesn't see the UUID pk field correctly?

Configuration:
https://github.com/acidjunk/improviser/blob/flask-security-too/improviser/main.py

Travis CI:
https://travis-ci.com/acidjunk/improviser/jobs/222120290

Or do I miss some new configuration stuff, somewhere?

2FA - enable per-user 2FA

Today, it is all or nothing - enable ability to have normal login and opt-in per user for 2FA.

It would be great if this could address storing things like totp_secret etc on the session.

Password Hash Cache not working as expected

Hi there. I seem to be in the minority, but the password caching mechanism does not work out of the box for me (#91 seems to imply that it will work for some folks). I'm just using flask's built in dev server flask run

The main issue seems to be obvious: The cache is being stored in a werkzeug Local(), which (for me) gets wiped after every request. Thus the cache is working, in a sense, but it gets cleared after every request. This feels correct because the Locals() interface acts as a guard between accidentally sharing data across threads, where what I want is actually a shared cache between all threads. I want all my requests to be fast (and share their cache between all requests).

I fixed this by simply replacing the Locals() call with a globally instantiated call to the TTLCache (see below). I'll probably end up throwing this into Redis (so that I can share caches across like 20 workers).

I've found the password verification to be a substantial bottleneck in my app where polling requests take at a minimum 700ms just to verify the hash (ugh) on every single auth-token request, which really starts to bog everything down if you're trying to stack requests or poll relatively quickly (like every couple seconds). If you've got a handful of requests across a handful of clients, forget about it. Thus I'm very interested in this feature, and a clean implementation that works for me.

So... am I doing something different from everyone else or do I have different requirements?

Before:

local_cache = Local()

# ...
def _request_loader(request):
    # ...
    use_cache = cv("USE_VERIFY_PASSWORD_CACHE")

    if not user:
        return _security.login_manager.anonymous_user()
    if use_cache:
        cache = getattr(local_cache, "verify_hash_cache", None)
        if cache is None: # its ALWAYS None!
            cache = VerifyHashCache()
            local_cache.verify_hash_cache = cache
        if cache.has_verify_hash_cache(user):
            return user
        if verify_hash(data[1], user.password):
            cache.set_cache(user)
            return user
    else:
        if verify_hash(data[1], user.password):
            return user

After:

#local_cache = Local()
verifyCache = None

# ...
def _request_loader(request):
   # ...

    use_cache = cv("USE_VERIFY_PASSWORD_CACHE")

    if not user:
        return _security.login_manager.anonymous_user()
    if use_cache:
        global verifyCache
        if (verifyCache is None):
            verifyCache = VerifyHashCache()
        if verifyCache.has_verify_hash_cache(user):
            return user
        if verify_hash(data[1], user.password):
            verifyCache.set_cache(user)
            return user
    else:
        if verify_hash(data[1], user.password):
            return user

    return _security.login_manager.anonymous_user()

Interestingly, this only partially fails on my production setup with gunicorn. But it only works if I refresh the page (and thus do couple of requests back to back). I assume that this is because gunicorn will maybe re-use the thread for requests from the same client within a window (or maybe Chrome is pipelining the http requests over a single socket). However, if I just let it poll every few seconds it consistently misses the cache (presumably because gunicorn is resetting the thread).

I'm curious what setup everyone else is using where this "just works" for them?

Add signer config

itsdangerous allows for many signing algorithms - currently it defaults to SHA1 - which is considered 'broken'. _get_serializer should take new config parameters that allows apps to change this.

Improve 2FA views

The new 2FA code has some issues with views:

  1. doesn't allow overriding names

  2. default names don't conform to stds (underscores)

  3. we should allow BOTH regular AND 2FA logins if an application wants to support them - also make sure it is easy to REQUIRE 2FA.

  4. also - add missing context processor initialization in core.py.

@baurt

Jinja2 exception on adding new fields to register

Thanks for taking over the maintenance of Flask-Security!

I tried extending the registration form but I am getting the following error:

  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 2328, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 2314, in wsgi_app
    response = self.handle_exception(e)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 1760, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/_compat.py", line 36, in reraise
    raise value
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 2311, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 1834, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 1737, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/_compat.py", line 36, in reraise
    raise value
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 1832, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/app.py", line 1818, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask_security/decorators.py", line 254, in wrapper
    return f(*args, **kwargs)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask_security/views.py", line 185, in register
    **_ctx("register")
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask_security/core.py", line 728, in render_template
    return render_template(*args, **kwargs)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/templating.py", line 135, in render_template
    context, ctx.app)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/flask/templating.py", line 117, in _render
    rv = template.render(context)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/jinja2/environment.py", line 1008, in render
    return self.environment.handle_exception(exc_info, True)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/jinja2/environment.py", line 780, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/jinja2/_compat.py", line 37, in reraise
    raise value.with_traceback(tb)
  File "/home/user/dev/templates/security/register_user.html", line 1, in top-level template code
    {% extends "white-base.html" %}
  File "/home/user/dev/templates/white-base.html", line 78, in top-level template code
    {% block content %}
  File "/home/user/dev/templates/security/register_user.html", line 82, in block "content"
    {{ render_field_with_errors(register_user_form.first_name,placeholder="First Name",class="input-form-field form-control",spellcheck="false") }}
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/jinja2/runtime.py", line 579, in _invoke
    rv = self._func(*arguments)
  File "/home/user/dev/templates/security/_macros.html", line 2, in template
    {% if field.errors %}
  File "/home/user/virtualenv/dev/3.5/lib/python3.5/site-packages/jinja2/environment.py", line 430, in getattr
    return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'flask_security.forms.ConfirmRegisterForm object' has no attribute 'first_name'

I'm not sure what the issue is as I've made an extended registration form and called it too.
security = Security(app, user_datastore, register_form=ExtendedRegisterForm)

I've seen this issue in the original repo however I'm not sure if it is related or what the fix is.

Any help would be appreciated.

JSON responses and LazyStrings

Turns out that if we get a validation error (which are LazyStrings) and are requesting a JSON response, we get a 500 Json encoding error since LazyString isn't json serializable.

Amazingly this wasn't caught in unit tests, because the unit test code actually overrode the JSONEncoder and handles LazyStrings.
sigh.

Use want_json for responses

We know have the concept of want_json() which will look at the Accept header - use that for ALL responses instead of request.is_json().

This will fix strange things like having to send in an empty body in order to get a json response.

Add get_user_info endpoint

Today, there is no way to get information about what the session cookie represents.
This info is returned on login and other APIs - but for UIs, after hitting 'refresh' it is useful to be able to query current status - is a user logged in? what is user id/name/email etc.

No module named 'flask_security.models'

I am using Python 3.6.8 in the virtual environment created whilst following the Quick Start. Same thing happens with Python 3.5.3.

This error comes up immediately when attempting to run the app.

Traceback (most recent call last): File "appme.py", line 4, in <module> from flask_security.models import fsqla ModuleNotFoundError: No module named 'flask_security.models'

The appme.py file is copied verbatim from the Quick Start.

TLS client-cert authentication built-in?

Given that client certificates are commonly regarded as the best method of verifying if the user is authorized or not it would be really nice if Flask-Security could allow such logins with less setup required.

It's also worth mentioning that client certificates are something that quite a lot of countries provide to their citizens (for ex. Estonia, Latvia, Belgium, Finland) and is very commonly used in at least Estonia so there'd definitely be a relatively large user-base for such integration.

I myself implemented it by reusing Flask-Dance's OAuth link schema and providing a few endpoints to accept client-certificates. It would be much easier if common web-server configuration examples and etc. were provided and the endpoints with necessary checks existed.

3.2.0 Release

I am ready to push 3.2.0 - Tyler - it would be great if you could try 3.2.0rc4 in your application to make sure nothing obvious broke.

I'd like to push this in the next few days....

Thanks!

Enabling pool pre-ping by default

Since Flask-SqlAlchemy 2.4.0 it's easy to enable SQL pool pre-pinging that should increase reliability of any services using Flask-Security, it would be a good default in majority of cases. What do you think?

This is how I and some others have done it:

    self.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
        "pool_pre_ping": True,
    }

Add get_api_token endpoint (oauth2?)

Today - an auth_token is returned on login and some other endpoints.
This isn't ideal - UIs shouldn't normally need this - they should use sessions. It is an unnecessary security hole to send the auth_token to a browser if they don't need it.

Furthermore - options such as TTL should be specifiable as part of an API (not to exceed global configurations).

Upon thinking about this - considering moving away from current token mechanism completely and implementing the first pieces of oauth2 (client credential and password grant), along with using JWT to represent the access token.

Custom User backend

I'm currently trying to get multi-email, better audit logs and password history support into the original Flask-Security but that has proven non-trivial. Are there any plans to make it easier in this fork or even integrate the functionality?

Just that people reading this would understand the feature request better:

  • I'm working on multi-email support because some people want to log in with multiple e-mails or log in with one and get emails to another, the current db model is unsuitable for that.
  • Password history support is nice to be able to remind people that they've changed passwords or to enforce no password reuse when compromise is detected.
  • Audit logs are somewhat self-explanatory - to track changes made to accounts and logins so people know what's going on with their logins and to provide warnings if needed. The current rudimentary configuration option and data model is just terribly unsuitable for that.

Issue with http_auth_required and Flask-Restplus

I am having issues with the way an unauthenticated request is handled in conjunction with flask-restplus.

Given the following example code

@api.route('/users/<id>', endpoint='user')
class UserAPI(Resource):
    @http_auth_required
    @permissions_accepted('user_read', 'user_read_all')
    @api.marshal_with(user_get)
    @api.response(200, "Success")
    def get(self, id):
        user = do_something_to_get_user()
        return user

When I do a GET request on this endpoint I get the following stacktrace (for example by doing this: curl -X GET "http://localhost:5000/api/v1/users/1" -H "accept: application/json"):

[2019-08-16 17:08:27,192] ERROR in app: Exception on /api/v1/users/1 [GET]
Traceback (most recent call last):
  File "/home/mkoek/prog/taskmanager/venv/taskmanager/lib/python3.6/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/mkoek/prog/taskmanager/venv/taskmanager/lib/python3.6/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/mkoek/prog/taskmanager/venv/taskmanager/lib/python3.6/site-packages/flask_restplus/api.py", line 330, in wrapper
    return self.make_response(data, code, headers=headers)
  File "/home/mkoek/prog/taskmanager/venv/taskmanager/lib/python3.6/site-packages/flask_restplus/api.py", line 351, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "/home/mkoek/prog/taskmanager/venv/taskmanager/lib/python3.6/site-packages/flask_restplus/representations.py", line 25, in output_json
    dumped = dumps(data, **settings) + "\n"
  File "/usr/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.6/json/encoder.py", line 201, in encode
    chunks = list(chunks)
  File "/usr/lib/python3.6/json/encoder.py", line 437, in _iterencode
    o = _default(o)
  File "/usr/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'Response' is not JSON serializable

I think what we see is happening here is, that _security._render_json (at https://github.com/jwag956/flask-security/blob/master/flask_security/decorators.py#L75) returns the following tuple down the decorator line, in this case it is this:
(<Response 81 bytes [200 OK]>, 401, {'WWW-Authenticate': 'Basic realm="Taskmanager Login Required"'})
In the case the accept: application/json is set, flask-restplus expects either a Response object or a sequence that should be serialized to json. In this case it received a sequence with a response object in it and got confused ;)

I think in this case (the want_json path) it is good idea to just pass a Response object back with the correct body, headers and response code. This gives the least chances of breakage when this extension is used together with other flask extensions.

Also when having a look inside _security._render_json -> views.default_render_json (at https://github.com/jwag956/flask-security/blob/master/flask_security/views.py#L130)

  • You cannot pass the status code to jsonify (at least in recent versions) of Flask in the way you do right now.
  • The user argument is not used. Is this reserved for future plans?

I am preparing a pull request, but I wanted to make sure to be on the page on beforehand. Is it OK if I implement in default_render_json to only return a Response object or maybe create a specific method for the want_json case? Should a 401 response have an empty body or should there be a message saying that it was an unauthenticated request?

Add ability to use different login methods

First of all, awesome of you @jwag956 to take this library into your hands! I hope I'll be able to contribute meaningfully to it.

I'm using passwordless login in one of my projects, but I've been having issues with email deliverability. I'd like to be able to add username/password login too, but currently there's only one method allowed per app (based on the config settings). So the ability to set multiple login methods would be helpful in my case.

I understand this suggestion might be a difficult one to implement, so please don't see this as an "I need this asap"-thing. I just wanted to log it here because I'm probably not the only one with this suggestion and open up the discussion.

Form validation Errors not being translated

Please see: pallets-eco/flask-security-3.0#801

turns out that our validators have a similar issue with form labels - they are evaluated too early (at import time). validators actually have state - self.message - that is shared among all instances of a form (or in our case - the entire app in the case of 'email_required').
These messages need to be lazy_strings so that they are evaluated in the context of the request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.