Giter VIP home page Giter VIP logo

aiohttp-security's People

Contributors

alanc10n avatar alefteris avatar alex-eri avatar alexpantyukhin avatar asvetlov avatar bmwant avatar dependabot-preview[bot] avatar dependabot[bot] avatar dfee avatar dreamsorcerer avatar enabokov avatar gyermolenko avatar hzlmn avatar imgbot[bot] avatar jchacking avatar jettify avatar litwisha avatar lysyloren avatar oleksandr-kuzmenko avatar pelson avatar pwntester avatar pyup-bot avatar skorpeo avatar thijstriemstra 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

aiohttp-security's Issues

Old version in PyPi

You have different versions of this package in PyPi and git with the same number of version

Is this production-ready?

Hello. Simple question about your package: is his production-ready?

I mean, I would like to start new project with aiohttp, but aiohttp-security is official aio-libs package and hasn't basic examples and google results to solve newbie questions (I'm newbie on aiohttp, using Django all time). And your package looks very good, have more useful examples than aiohttp-security ๐Ÿ‘

Authorize decorator

I am currently using aiohttp_security for our new server.
I think it would be nice to include decorator in aiohttp_security api.
This is method signature I currently have.

@aiohttp_security.authorize(required=True, redirect_url=None, permission=None)
def handler(request):
    return web.Response(body=b'OK')

Can I create pull request?

Replace API functions

Problem

The API functions don't support static typing well. For example:

  • If we want to allow other types for identity (e.g. #397), then we can't put types on these public API functions, as we wouldn't know what the correct type is.
  • The context parameter must be typed as Any and default to None to be compatible with the API. However, some implementations may require a specific type for context and won't accept a default (e.g. aiohttp-admin). There's no way to validate this with a type checker.

Solution

I'm thinking the best approach will be to remove the API functions (everything in api.py), and then use the IdentityPolicy and AuthorizationPolicy classes directly.

A few tweaks will need to be made, but this should make it much easier to subclass and implement these with precise types.

Most of these functions are just calling the methods anyway, so there's not really any extra complexity to just call the methods directly.

Forgetting all sessions for a certain identity

Hello,

Clearing the current session (e.g. on logout) is possible using forget. Is there also a way to clear all the other sessions of the same user/identity at the same time? (e.g. logging out a user in all browsers at once)

Thanks,
Victor

Writing extended data into session

Can you explain me something?

Method SessionIdentityPolicy.remember() has **kwargs as one of the parameters, but never use it to write data into user session dict. What's the point of this param?

For now in my project I have my own SessionPolicy implementation inherited from SessionIdentityPolicy, just in order to have a posibility of storing extended data in session (like different datetimes, uuids, IPs etc.).

So, my question is: was Session Policy designed to be self implemented by users or am I wrong and there is special way to write extra data into session?

simple_example_auth.py doesn't work properly

I tried running demo/simple_example_auth.py (without any changes). I accessed it through my web-browser, when I clicked Log_me_in it wouldn't login.
I still get the same output even after clicking login several times:

Hello, I'm Jack, I'm NOT logged in.

Log me in
Log me out

Check my permissions, when i'm logged in and logged out.
Can I listen?
Can I speak?

Which also makes /listen an unauthorized page.

has_permission decorator and aiohttp.web.View

Hello,

I would like use the has_permission decorator with aiohttp.web.View.

I update has_permission to check if parameters is an instance of aiohttp.web.View
#148

And I prototype a class decorator to set CRUD permission for each method.
#150

What do you think ?

Digest support for aiohttp through aiohttp-security?

Hi,

I would like to use aiohttp in a client for accessing a digest authenticated server. Do you have any suggestions on how i accomplish that? It's a requirement for us to use the Python 3.5 asyncio package.

We'd prefer if we were not forced to write the Digest implementation ourselves. If there is no other way, then we'd consider writing our own digest auth client.

Any and all suggestions are welcome.

response in methods needs?

Hello, friends.
Why response in forget and remember methods? I see it's need in cookies identity, but not for others.
Maybe add kwagrs params or set default none for it in api.py ?
I use session identity and pass response do nothing for me. Just not needed for it

Redis upgrade

We need to drop references to aioredis and migrate to redis.

"Basic" terminology is misleading

The docs say "basic auth example" (or similar), so people looking for HTTP Basic Auth will be confused because it means "basic (auth example)", not "(basic auth) example". (Human language is not associative...)

Alternate terms:
"simple"
"tutorial"
"baseline"
"example"
"basic usage"

I.e. it would be best to avoid the word combination "basic auth" in the docs, even if readers are not meant to parse it that way.

AbstractAuthorizationPolicy, passing in request

Because aiohttp discourages the use of global singletons and encourages that such values be stored within the application or request themselves, I've got a bit of trouble with the current implementations of AbstractAuthorizationPolicy.permits and AbstractAuthorizationPolicy.authorized_userid. Neither provide access to the request or application scope, which I need because I'm creating/storing within the application, on startup, a connection object to my database. When those functions are called, I need to be able to access my connector in order to validate the user and check their permissions.

I could submit a pull request with changes so that those function's would receive request as their first argument, but that would break compatibility with anyone who has implemented an AbstractAuthorizationPolicy.

Can we discuss this?

Thanks.

Issue with Authorization policy

Hi,

I'm trying to use aiohttp_security on my website, I'm testing the demo code with a custom Policy (as I don't have sql database)

below the code for my policy :

from aiohttp_session import setup as setup_session
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_security import setup as setup_security
from aiohttp_security import SessionIdentityPolicy
from aiohttp_security.abc import AbstractAuthorizationPolicy


class TestAuthorizationPolicy(AbstractAuthorizationPolicy):
    def __init__(self):
        pass

    def authorized_userid(self, identity):
        return identity

    def permits(self, identity, permission, context=None):
        return True


app = web.Application()
setup_session(app, EncryptedCookieStorage(key))
setup_security(app, SessionIdentityPolicy(), TestAuthorizationPolicy())


def user_role(role):
    '''
        Decorator that checks if a user has been authenticated and have the good role.
    '''
    def decorator(func):
        async def wrapper(*args, **kwargs):
            request = args[1]
            if not await permits(request, role):
                raise web.HTTPForbidden()
            return await func(*args, **kwargs)
        return wrapper
    return decorator

The stacktrace of the error :

======== Running on http://127.0.0.1:8500/ ========
(Press CTRL+C to quit)
Error handling request
Traceback (most recent call last):
  File "/home/olivier/Test/Test/venv/lib/python3.5/site-packages/aiohttp/server.py", line 261, in start
    yield from self.handle_request(message, payload)
  File "/home/olivier/Test/Test/venv/lib/python3.5/site-packages/aiohttp/web.py", line 88, in handle_request
    resp = yield from handler(request)
  File "/home/olivier/Test/Test/venv/lib/python3.5/site-packages/aiohttp_session/__init__.py", line 129, in middleware
    response = yield from handler(request)
  File "/home/olivier/Test/Test/test/web/handlers.py", line 79, in wrapper
    if not await permits(request, role):
  File "/home/olivier/Test/Test/venv/lib/python3.5/site-packages/aiohttp_security/api.py", line 73, in permits
    access = yield from autz_policy.permits(identity, permission, context)
TypeError: 'bool' object is not iterable

It seems that somewhere in your code you try to iterate over the boolean returned by permits method ... but I don't see where ?

Upload the latest version to Pypi

Hello,
can you upload the latest version to Pypi ?
The latest release on github is 0.1.1 (2016-10-22)
The latest release on Pypi is 0.1.0 (2016-01-18).
This simplifies our requirements.txt !
Thank you
F

cannot import name 'create_pool' from 'aioredis'

I try to launch demo/database_auth example but I get an error:

Traceback (most recent call last):
  File "demo/database_auth/main.py", line 9, in <module>
    from aioredis import create_pool
ImportError: cannot import name 'create_pool' from 'aioredis' (/home/flow/.local/lib/python3.8/site-packages/aioredis/__init__.py)

I've tried changing create_pool to create_redis_pool in the example code, like in aiohttp_demos, but it doesn't help. I've also tried versions 2.0.0 and 2.0.1 of aioredis and there was no use. I've even tried installing aioredis v 1.3.0 but RuntimeError("aioredis<2.0 is not supported") was raised.

System is Ubuntu 20.04 and python is 3.8.10

One weird moment for me is aioredis that is being installed in /home/flow/.local/lib/python3.8/site-packages/ though other libraries can be found in venv folder, e.g. /home/flow/aiohttp-security-master/venv/lib/python3.8/site-packages or /home/flow/aiohttp-security-master/venv/lib64/python3.8/site-packages...

SQLAlchemy upgrade

References to aiopg need to be removed and replaced with sqlalchemy 2.

Installing requirements-dev.txt is failed.

I was trying to run pip install -r requirements-dev.txt and there is the log:

Obtaining file:///D:/Work/github/aiohttp-security (from -r requirements-dev.txt
(line 1))
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "D:\Work\github\aiohttp-security\setup.py", line 22, in <module>
        version = re.findall(r"^__version__ = '([^']+)'$", fp.read(), re.M)[0]
    IndexError: list index out of range

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "D:\Work\github\aiohttp-security\setup.py", line 24, in <module>
        raise RuntimeError('Unable to determine version.')
    RuntimeError: Unable to determine version.

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in D:\Work\github\ai
ohttp-security\

pip version: 9.0.3
python version: 3.5.0
os: windows 7

Client security

In #183 it is said that aiohttp-security is used for server-side only, but can you provide some best-practices for login from a client?

I guess it is best to store the password in the database using pbkdf2_sha256 from passlib.hash. I think I have to trust SSL and send the password in plain because if someone manages to hijack the connection/manages a MITM-attack he can inject all kind of JavaScript that just invalidates every kind of Client-side security I can come up with.

Extend permission-checking methods to return additional information

Extend async def check_permission(request, permission, context=None) -> bool to return back additional information.

Method check_permission() calls method async def permits(...) -> bool declared in AuthPolicy and defined in user-defined policies that inherit AuthPolicy. We need to have a general and unified way to return back information from permits() (and thus check_permission()).

Use case:
check_permission is called on a bunch of permissions and the calling code wants to know which exactly permission check was failed.

Possible solutions:

  1. More narrow approach. In order to preserve backward compatibility, we could add method check_permissions() -> PermissionCheckResult (in addition to permits() -> bool) that returns a general dataclass (or json object) that will consolidate information on the permission check, for example:
T = TypeVar('T')

@dataclass
class PermissionCheckResult:
    success: bool
    missing: Set[T]

async def check_permissions(...) -> PermissionCheckResult:
    ...
  1. More general and more pythonic approach. Keep permits() -> bool, but allow it to raise a pre-defined exception for providing additional information:
class PermissionDeniedException(Exception):
    def __init__(self, missing_permissions):
        pass

Permission lists - Restrict route to multiple permission levels.

I will now begin work on a PR to add support for restricting routes to multiple permissions like this:

async def protected_page(self, request):
    await check_permission(request, ['protected', 'level1', 'level2'])
    response = web.Response(body=b'You are on protected page')
    return response

Discussion welcome.

Not clear usage of cookie storage

I would suggest updating docs to clarify that in order to use EncryptedCookieStorage one have to use SessionIdentityPolicy, and not CoookieIdentyPolicy (as it is not so intuitive).

I can make it in spare time.

Autorization Basic

Hey.
I propose to add middleware to the library.

middleware.py

import base64

from aiohttp import web
from aiohttp_security import authorized_userid, remember

async def check_credentials(db_engine, username, password):
    async with db_engine.acquire() as conn:
        where = and_(db.user.c.username == username,
                     db.user.c.is_active)
        query = db.user.select().where(where)
        ret = await conn.execute(query)
        user = await ret.fetchone()
        if user is not None:
            hash_ = user[2]
            return sha256_crypt.verify(password, hash_)
    return False


def middleware_factory():
    @web.middleware
    async def authorization_middleware(request, handler):
        username = await authorized_userid(request)
        if not username:
            if request.headers.get('Authorization', None):
                authorization = request.headers.get('Authorization').split(' ')
                basic = base64.b64decode(authorization[1]).decode('utf-8')
                username, password = basic.split(':')
                if await check_credentials(request.app['db'], username, password):
                    # await remember(request, web.HTTPFound(request.rel_url), username)
                    raise web.HTTPFound(request.rel_url)
                else:
                    raise web.HTTPForbidden()
        return await handler(request)
    return authorization_middleware

Tnx.

Why is identity forced to be string?

The module-level function, remember() asserts that the identity is a string:

    assert isinstance(identity, str), identity
    assert identity

Shouldn't that be the burden of the underlying implementation of an IdentityPolicy?

My use-case: I'm building a custom IdentityPolicy and associated AuthorizationPolicy that sends a JWT token back to the client with a custom header. In my user-session code I want to be able to do, e.g.:

   def login(request):
      # Get `username` and `password` from request data, validate, etc.
      username, password = ...
      # Using an underlying model, User, call a classmethod `login` which
      # validates the credentials and returns a user instance on success; None on failure
      user = User.login(username, password)
      if user is None:
         raise web.HTTPUnauthorized()
      # I have a valid, logged in user, json-ify the object and set header
      resp = web.json_response(user)
      remember(request, resp, user)  # <== BLOWS UP WITH ASSERTION ERROR
      return resp

The implementation of my policies expects a User instance in all places an identity is passed around. When creating the JWT the state of the user instance dictates the claims made. I want this logic in the IdentityPolicy not in the caller.

It seems to me that at the API level identities should be opaque and leave serialization/validation up to the underlying policy implementations.

Why is the "latest" release on github version 0.2.0?

Hi there,

I ran into some version issues where I assumed that the "latest" version on the github releases is correct, and corresponds to the latest version of the documentation, which is incorrect.

Could you please update the "latest" tag to point to v0.4.0?

Thank you!

Question: Timeouts with remember()

Hello,

Just wanted to ask, is there a way to apply a timeout to remember() (such that forget() is called after x seconds)? The only thing on timeouts I can see in the aiohttp docs is with ClientSession (and if that is the solution to be used with remember(), I'm not sure how to combine the two).

Thanks

Why has_permission decorator is being deprecated ?

Checking on the code, the decorator has_permission option is being deprecated in favor of check_permission which has no decorator option. Why?
My best guess is is that it should not be the responsibility of the package to implement such feature, but I could not find the documented reason.

remember() not working

I inserted some print()s to the api:

async def remember(self, request, response, identity, **kwargs):
        session = await get_session(request)
        session[self._session_key] = identity
        print(dict(session))
async def identify(self, request):
        session = await get_session(request)
        print(dict(session))
        return session.get(self._session_key)

Below are respective result:

{'AIOHTTP_SECURITY': 'username'}
{}

which mean the AIOHTTP_SECURITY session is gone before identify() is called. This seem to be a bug.

Demos don't follow best practices

The documentation is a little confusing, as it mentions that identity should not be something like a user ID or login. However, both demos appear to ignore this advice and it seems that userid == login == identity.

If trying to get started quickly by going through the demos, then it appears you would end up following bad practices.

Yum broken when RPM from this requirement with underscores.

Please never use underscores in python-packages names.

PEP-008 conatins

Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

We have a really problem. When our build system convert all dependencies to RPM (using FPM) yum is broken. We are can't use this package in our projects.

Non-SA MySQL Example (Inside)

I don't feel like forking and doing a PR. I made this mysql code to replace the SA code (I hate SA). You should add it as an example:

Edit: Nevermind. Regular contributors say they don't want code suggestions in issues.

online docs

It would be cool to be able to read the documentation online. Do you planning to upload it to readthedocs?

P.S. Can I help you with that?

Should identity be changed?

I am using this module to implement something like 'remember me'.
I understand that we should use a random string such as a uuid or hash as identity to make it unguessable for attackers. My question is is it fine to use a identity that is immutable for a specific user?
If so, what if the token is identity is leaked?
If not, when should it be changed?
Thanks in advance!

authorized_userid() method in AbstractAuthorizationPolicy required?

I was wondering if authorized_userid() method in AbstractAuthorizationPolicy is necessary.
It seems like it duplicates functionality of identity() in AbstractIdentityPolicy.

@asyncio.coroutine
@abc.abstractmethod
def authorized_userid(self, identity):
    """Retrieve authorized user id.
    Return the user_id of the user identified by the identity
    or 'None' if no user exists related to the identity.
    """
    pass

In demo code, it is used to get identities from database that are not disabled.

@asyncio.coroutine
def authorized_user_id(self, identity):
    with (yield from self.dbengine) as conn:
        where = [db.users.c.login == identity, not db.users.c.disabled]
        query = db.users.count().where(sa.and_(*where))
        ret = yield from conn.scalar(query)
        if ret:
            return identity
        else:
            return None

I believe this check can be done in identify() method in AbstractIdentityPolicy instead.

Deprecate has_permission and login_required in favor of new API

I'm thinking about opposite direction: deprecate and remove these decorators.

Please consider two snippets:

@has_permission('read')
async def handler(request):
    return web.Response()

and

async def handler(request):
    check_permission(request)
    return web.Response()

check_permission from second example works basically as existing has_perission decorator.
It raises HTTPForbidden if the user is not authorized.

The main advantage is debugging. In decorator approach basically there is no line to put a breakpoint for debugging permission checks for the handler. The decorator is executed before first handler's line. Setting a breakpoint to decorator itself leads to debugging all handlers with decorator applied, not the specific one.

Also, it solves the problem of class based views (and any other web handlers organization style). The check can be done in any place of code, it is pretty readable and straightforward.

Do you need help?

I would like to offer some help going through these PRs and issues. This package is really important to me.

Simple example from docs/example.rst not working

Example code in docs/example.rst is not working with current code. There are multiple issues with syntax and non-existent objects (like @protect decorator or DictionaryAuthorizationPolicy).

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.