Skip to content

Commit

Permalink
Merge pull request #7 from photos-network/feature/oauth
Browse files Browse the repository at this point in the history
add first draft of oauth/indieauth
  • Loading branch information
thebino committed Jan 25, 2021
2 parents 83501a2 + d42908e commit 99a50c9
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 2 deletions.
1 change: 1 addition & 0 deletions core/addons/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ async def post(self, core: ApplicationCore, request: web.Request) -> web.Respons

_LOGGER.warning(f"request: {original_filename}")

# TODO: get storage directory for user
path = os.path.join(f"./data/users/{user}/", original_filename)
if os.path.exists(path):
# TODO: handle filename already exists
Expand Down
104 changes: 104 additions & 0 deletions core/authentication/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""Initialization of authentication."""
import json
import logging
import secrets

import aiohttp_jinja2
from aiohttp import web
from authlib.oauth2 import AuthorizationServer, ClientAuthentication, OAuth2Request

from core.webserver.request import ComplexEncoder
from core.webserver.status import HTTP_OK
from core.webserver.type import APPLICATION_JSON

_LOGGER = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)


class Auth(AuthorizationServer):
def __init__(self, application):
self.app = application

self.app.router.add_post(
path="/login", handler=self.login_handler2, name="auth:login2"
)
self.app.router.add_get(
path="/oauth/authorize",
handler=self.authorization_handler,
name="auth:authorize",
)
self.app.router.add_post(
path="/oauth/authorize",
handler=self.authorization_handler2,
name="auth:authorize2",
)
self.app.router.add_post(
path="/oauth/access_token",
handler=self.access_handler,
name="auth:access_token",
)

async def login_handler2(self, request):
_LOGGER.warning("POST /login")
response_type = "code"
client_id = "ABCDEF123"
redirect_uri = request.host
scope = "user public_photos"
state = secrets.token_hex(16)

raise web.HTTPFound(
location=f"http://127.0.0.1:9090/oauth/authorize?response_type={response_type}&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}"
)

@aiohttp_jinja2.template("tmpl.jinja2")
async def authorization_handler(self, request):
"""Endpoint where the user get its authorization."""
_LOGGER.warning("GET /oauth/access_token")
_LOGGER.warning(f"request: {request.host}")

response_type = request.query.get("response_type")
client_id = request.query.get("client_id")
redirect_uri = request.query.get("redirect_uri")
scope = request.query.get("scope")
state = request.query.get("state")

_LOGGER.warning(f"a: {response_type}")
_LOGGER.warning(f"b: {client_id}")
_LOGGER.warning(f"c: {redirect_uri}")
_LOGGER.warning(f"d: {scope}")
_LOGGER.warning(f"e: {state}")

_LOGGER.warning(f"request: {request.query_string}")
# _LOGGER.warning(f"request: {request.__dict__}")

return {"redirect_uri": redirect_uri}

async def authorization_handler2(self, request):
_LOGGER.warning("POST /oauth/access_token")
data = await request.post()
return web.Response()

async def access_handler(self, request):
"""Endpoint to request an access token."""
_LOGGER.warning("GET /oauth/access_token")

success = True
if success:
msg = {
"access_token": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"scope": "create",
}
response = web.Response(
body=json.dumps(msg, cls=ComplexEncoder, allow_nan=False).encode(
"UTF-8"
),
content_type=APPLICATION_JSON,
status=HTTP_OK,
)
response.enable_compression()
return response
else:
return web.Response()
14 changes: 13 additions & 1 deletion core/webserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
from ipaddress import ip_address
from typing import TYPE_CHECKING

import aiohttp_jinja2
import jinja2
from aiohttp import hdrs, web
from aiohttp.web_exceptions import HTTPForbidden, HTTPUnauthorized
from aiohttp.web_middlewares import middleware

from .. import const
from ..authentication import Auth
from .request import KEY_AUTHENTICATED, KEY_USER_ID, RequestView # noqa: F401

if TYPE_CHECKING:
Expand All @@ -29,6 +32,14 @@ def __init__(self, core: "ApplicationCore"):
self.app = web.Application(middlewares=[], client_max_size=MAX_CLIENT_SIZE)
self.runner = web.AppRunner(self.app)

# init jinja2 template engine
aiohttp_jinja2.setup(
self.app, loader=jinja2.FileSystemLoader("core/webserver/templates")
)

# init auth
self.auth = Auth(self.app)

self.app.middlewares.append(self.ban_middleware)
self.app.middlewares.append(self.auth_middleware)
self.app.middlewares.append(self.headers_middleware)
Expand Down Expand Up @@ -160,5 +171,6 @@ async def auth_middleware(self, request: web.Request, handler):
async def headers_middleware(self, request: web.Request, handler):
"""Add a server header to all responses."""
response = await handler(request)
response.headers["Server"] = f"Photos.network/{const.CORE_VERSION}"
if response is not None:
response.headers["Server"] = f"Photos.network/{const.CORE_VERSION}"
return response
19 changes: 19 additions & 0 deletions core/webserver/templates/tmpl.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<body style="background: #888888">
Do you wish to authorize the app <b>Frontend</b> to access your Photos.network?<br />
<br />
This application will be able to:<br />
<ul>
<li>Access all photos you own</li>
<li>Edit tags and meta data of your photos</li>
<li>Upload new photos to your storage</li>
</ul>
<br />
<br /><a href="{{ redirect_uri }}" type="submit">Sign In</a>
<br /><a href="#" type="submit">Cancel</a>
<br />
This application will not be able to:
<ul>
<li>See your password</li>
</ul>
<br />
You can revoke access to any application at any time from your Photos.network settings.
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
aiohttp>=3.7.0
aiohttp_cors==0.7.0
aiohttp-jinja2>=1.4.2
jinja2>=2.11.2
authlib>=0.15.3
astral==1.10.1
async_timeout==3.0.1
attrs==19.3.0
Expand All @@ -8,7 +11,6 @@ certifi>=2020.6.20
ciso8601==2.1.3
httpx==0.16.1
importlib-metadata==1.6.0;python_version<'3.8'
jinja2>=2.11.2
PyJWT==1.7.1
cryptography==3.2
pip>=8.0.3
Expand Down

0 comments on commit 99a50c9

Please sign in to comment.