Skip to content

Commit

Permalink
Fix #88 importing config & Add Support for FastAPI 0.92.0 +
Browse files Browse the repository at this point in the history
* fixed issue preventing /import from /export config output. Added tests validating import/export apis

* Bumpted min supported pydbantc version & allowing >= version 0.0.22

* added event loop fixture

* calling include_router from EasyAuthAPIRouter init

* include routers is now a normal def & removed from on_event startup

* added self.include_routers to startup_tasks called by lifecycle startup

* using httpx AsyncClient & manually calling lifelcycle startup coroutine server.auth.startup_tasks

* converted client usage to AsyncClient

* removed action / role verification from api setup

* added logging to global_store_update ops

* quorum establishes leader, but not RPC secret

* reverted redundant include router statement

* fixed self.global_store_update references, key_path ENV is now optional allowing local path usage. Fixed manager_proxy cleanup within shutdown_auth_server method. RPC_SECRET is now set from auth_secret

* pinned max fastapi version

* pinned max fastapi version

* fixed lifecycle handling via LifespanManager

* added library ensuring lifespan usage in testing

* reverted client to non-async

* bumped pytest-asyncio, pytest verisons

* bumped uvicorn, allowed multipart, fastapi-mail bcrypt versions

* added event loop & AsyncClient Usage

* using async client

* added httpx

* passing fastapi app as sever along with test_client

* test_client, server returned as tuple

* adding pytest.ini

* added clean db & tables_setup() to auth_test_server fixture, post auth server setup

* added explicit logging for post config import checks

* reducing concurrent tests

* added testing flag to prevent rpc proxies from being created during testing

* added testing=True to prevent rpc proxy usage in testing

* modified order of building container used by client tests

* adjusted how post import data is validated

* added previously tested python versions 3.7+

* removed 3.10 testing for mysql due to lack of support

* converted .create into normal def, added middleware setup to __init__ tasks allowing latest release of FastAPI releases

* moved EasyAuthServer.create & EasyAuthAPIRouter.create outside of startup def as auth_server is now defined outside running event loop constraint

* updated with auth_test_server_and_clean_db fixture

* allowing latest fastapi release

* moved EasyAuthServer.create out of startup task

* Updated EasyAuthClient.create as normal def, to be used before event loop creation

* rpc_server attribute assigned from setup coroutine

* updated EasyAuthClient.create usage outside of startup task

* updated documentation with new EasyAuthServer / EasyAuthClient .create() usage outside of startup events

* updated fastapi versions allowed, & min pydbantic version

* updated min pydbantic

* moved EasyAuthServer.create outside of startup lifecycle

---------

Co-authored-by: Joshua (codemation)
  • Loading branch information
codemation authored Feb 21, 2023
1 parent 4d4a2f4 commit 89e958c
Show file tree
Hide file tree
Showing 20 changed files with 679 additions and 574 deletions.
31 changes: 16 additions & 15 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ jobs:
python-version: [3.7,3.8,3.9,3.10.8]
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-postgres -t joshjamison/easyauth:postgres .
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
Expand All @@ -59,6 +54,12 @@ jobs:
export KEY_NAME=test_key
export ENV=postgres
pytest tests/test_server_api.py -s
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-postgres -t joshjamison/easyauth:postgres .
- name: Test EasyAuth Client
run: |
export ENV=postgres
Expand All @@ -71,11 +72,6 @@ jobs:
python-version: [3.7,3.8,3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-mysql -t joshjamison/easyauth:mysql .
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
Expand All @@ -99,6 +95,11 @@ jobs:
echo "Sleeping to allow db to start"
sleep 30
pytest tests/test_server_api.py -s
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-mysql -t joshjamison/easyauth:mysql .
- name: Test EasyAuth Client
run: |
export ENV=mysql
Expand All @@ -111,11 +112,6 @@ jobs:
python-version: [3.7,3.8,3.9,3.10.8]
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-sqlite -t joshjamison/easyauth:sqlite .
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
Expand All @@ -135,6 +131,11 @@ jobs:
export KEY_NAME=test_key
export ENV=sqlite
pytest tests/test_server_api.py -s
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: build and run auth server image
run: |
docker build -f docker/test-docker/Dockerfile-sqlite -t joshjamison/easyauth:sqlite .
- name: Test EasyAuth - Client
run: |
export ENV=sqlite
Expand Down
86 changes: 41 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,14 @@ from easyauth.server import EasyAuthServer

server = FastAPI()

@server.on_event('startup')
async def startup():
server.auth = await EasyAuthServer.create(
server,
'/auth/token',
auth_secret='abcd1234',
admin_title='EasyAuth - Company',
admin_prefix='/admin',
env_from_file='server_env.json'
)
server.auth = EasyAuthServer.create(
server,
'/auth/token',
auth_secret='abcd1234',
admin_title='EasyAuth - Company',
admin_prefix='/admin',
env_from_file='server_env.json'
)

```

Expand All @@ -89,41 +87,39 @@ from easyauth import get_user

server = FastAPI()

@server.on_event('startup')
async def startup():
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default():
return f"I am default"

# grants access to only specified users
@server.auth.get('/', users=['jane'])
async def root():
return f"I am root"

# grants access to members of 'users' or 'admins' group.
@server.auth.get('/groups', groups=['users', 'admins'])
async def groups(user: str = get_user()):
return f"{user} is in groups"

# grants access to all members of 'users' group
# or a groups with role of 'basic' or advanced
@server.auth.get('/roles', roles=['basic', 'advanced'], groups=['users'])
async def roles():
return f"Roles and Groups"

# grants access to all members of groups with a roles granting 'BASIC_CREATE'
@server.auth.get('/actions', actions=['BASIC_CREATE'])
async def action():
return f"I am actions"
server.auth = EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default():
return f"I am default"

# grants access to only specified users
@server.auth.get('/', users=['jane'])
async def root():
return f"I am root"

# grants access to members of 'users' or 'admins' group.
@server.auth.get('/groups', groups=['users', 'admins'])
async def groups(user: str = get_user()):
return f"{user} is in groups"

# grants access to all members of 'users' group
# or a groups with role of 'basic' or advanced
@server.auth.get('/roles', roles=['basic', 'advanced'], groups=['users'])
async def roles():
return f"Roles and Groups"

# grants access to all members of groups with a roles granting 'BASIC_CREATE'
@server.auth.get('/actions', actions=['BASIC_CREATE'])
async def action():
return f"I am actions"
```

![](docs/images/login.png)
Expand Down
17 changes: 7 additions & 10 deletions docker/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@
if not ADMIN_PREFIX:
ADMIN_PREFIX = "/admin"


@server.on_event("startup")
async def startup():
server.auth = await EasyAuthServer.create(
server,
"/auth/token",
auth_secret=AUTH_SECRET,
admin_title=ADMIN_TITLE,
admin_prefix=ADMIN_PREFIX,
)
server.auth = EasyAuthServer.create(
server,
"/auth/token",
auth_secret=AUTH_SECRET,
admin_title=ADMIN_TITLE,
admin_prefix=ADMIN_PREFIX,
)
110 changes: 53 additions & 57 deletions docs/client_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,39 @@ from easyauth.client import EasyAuthClient

server = FastAPI()

@server.on_event('startup')
async def startup():
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default():
return f"I am default"

# grants access to only specified users
@server.auth.get('/', users=['jane'])
async def root():
return f"I am root"

# grants access to members of 'users' or 'admins' group.
@server.auth.get('/groups', groups=['users', 'admins'])
async def groups(user: get_user()):
return f"{user} is in groups"

# grants access to all members of 'users' group
# or a groups with role of 'basic' or advanced
@server.auth.get('/roles', roles=['basic', 'advanced'], groups=['users'])
async def roles():
return f"Roles and Groups"

# grants access to all members of groups with a roles granting 'BASIC_CREATE'
@server.auth.get('/actions', actions=['BASIC_CREATE'])
async def action():
return f"I am actions"
server.auth = EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default():
return f"I am default"

# grants access to only specified users
@server.auth.get('/', users=['jane'])
async def root():
return f"I am root"

# grants access to members of 'users' or 'admins' group.
@server.auth.get('/groups', groups=['users', 'admins'])
async def groups(user: get_user()):
return f"{user} is in groups"

# grants access to all members of 'users' group
# or a groups with role of 'basic' or advanced
@server.auth.get('/roles', roles=['basic', 'advanced'], groups=['users'])
async def roles():
return f"Roles and Groups"

# grants access to all members of groups with a roles granting 'BASIC_CREATE'
@server.auth.get('/actions', actions=['BASIC_CREATE'])
async def action():
return f"I am actions"
```
!!! NOTE "default_permissions, if unspecified"
{'groups': ['administrators']}
Expand All @@ -65,20 +63,18 @@ from easyauth.client import EasyAuthClient

server = FastAPI(openapi_url="/groups/openapi.json")

@server.on_event('startup')
async def startup():
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# import sub modules
from .finance import finance
from .hr import hr
from .marketing import marketing
server.auth = EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# import sub modules
from .finance import finance
from .hr import hr
from .marketing import marketing
```

```python
Expand Down Expand Up @@ -202,12 +198,12 @@ def custom_activation_page():
The default `/login` and 401 redirect path can be overloaded by setting the `default_login_path` on `EasyAuthClient.create()`.

```python
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']},
default_login_path='/v1/internal/login'
)
server.auth = EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']},
default_login_path='/v1/internal/login'
)
```
26 changes: 12 additions & 14 deletions docs/rbac.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,16 @@ from easyauth import get_user

server = FastAPI()

@server.on_event('startup')
async def startup():
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default(user: str = get_user()):
return f"{user} is accessing default endpoint"
server.auth = await EasyAuthClient.create(
server,
token_server='0.0.0.0',
token_server_port=8090,
auth_secret='abcd1234',
default_permissions={'groups': ['users']}
)

# grants access to users matching default_permissions
@server.auth.get('/default')
async def default(user: str = get_user()):
return f"{user} is accessing default endpoint"
```
Loading

0 comments on commit 89e958c

Please sign in to comment.