Implement initial flow (#2)

This commit is contained in:
Christiaan Goossens
2024-12-24 21:38:57 +01:00
committed by GitHub
parent 1c8c7ed14a
commit 8ba494c49c
15 changed files with 883 additions and 1805 deletions

View File

@@ -0,0 +1,49 @@
from aiohttp import web
from homeassistant.components.http import HomeAssistantView
import logging
from ..oidc_client import OIDCClient
from ..provider import OpenIDAuthProvider
PATH = "/auth/oidc/callback"
_LOGGER = logging.getLogger(__name__)
class OIDCCallbackView(HomeAssistantView):
"""OIDC Plugin Callback View."""
requires_auth = False
url = PATH
name = "auth:oidc:callback"
def __init__(
self, oidc_client: OIDCClient, oidc_provider: OpenIDAuthProvider
) -> None:
self.oidc_client = oidc_client
self.oidc_provider = oidc_provider
async def get(self, request: web.Request) -> web.Response:
"""Receive response."""
_LOGGER.debug("Callback view accessed")
params = request.rel_url.query
code = params.get("code")
state = params.get("state")
base_uri = str(request.url).split('/auth', 2)[0]
if not (code and state):
return web.Response(
headers={"content-type": "text/html"},
text="<h1>Error</h1><p>Missing code or state parameter</p>",
)
user_details = await self.oidc_client.complete_token_flow(base_uri, code, state)
if user_details is None:
return web.Response(
headers={"content-type": "text/html"},
text="<h1>Error</h1><p>Failed to get user details, see console.</p>",
)
code = await self.oidc_provider.save_user_info(user_details)
return web.HTTPFound(base_uri + "/auth/oidc/finish?code=" + code)

View File

@@ -0,0 +1,24 @@
from aiohttp import web
from homeassistant.components.http import HomeAssistantView
import logging
PATH = "/auth/oidc/finish"
_LOGGER = logging.getLogger(__name__)
class OIDCFinishView(HomeAssistantView):
"""OIDC Plugin Finish View."""
requires_auth = False
url = PATH
name = "auth:oidc:finish"
async def get(self, request: web.Request) -> web.Response:
"""Receive response."""
code = request.query.get("code", "FAIL")
return web.Response(
headers={"content-type": "text/html"},
text=f"<h1>Done!</h1><p>Your code is: <b>{code}</b></p><p>Please return to the Home Assistant login screen (or your mobile app) and fill in this code into the single login field. It should be visible if you select 'Login with OpenID Connect (SSO)'.</p>",
)

View File

@@ -0,0 +1,46 @@
from aiohttp import web
from homeassistant.components.http import HomeAssistantView
import logging
from ..oidc_client import OIDCClient
PATH = "/auth/oidc/redirect"
_LOGGER = logging.getLogger(__name__)
class OIDCRedirectView(HomeAssistantView):
"""OIDC Plugin Redirect View."""
requires_auth = False
url = PATH
name = "auth:oidc:redirect"
def __init__(
self, oidc_client: OIDCClient
) -> None:
self.oidc_client = oidc_client
async def get(self, request: web.Request) -> web.Response:
"""Receive response."""
_LOGGER.debug("Redirect view accessed")
base_uri = str(request.url).split('/auth', 2)[0]
_LOGGER.debug("Base URI: %s", base_uri)
auth_url = await self.oidc_client.get_authorization_url(base_uri)
_LOGGER.debug("Auth URL: %s", auth_url)
if auth_url:
return web.HTTPFound(auth_url)
else:
return web.Response(
headers={"content-type": "text/html"},
text="<h1>Plugin is misconfigured, discovery could not be obtained</h1>",
)
async def post(self, request: web.Request) -> web.Response:
"""POST"""
_LOGGER.debug("Redirect POST view accessed")
return await self.get(request)

View File

@@ -0,0 +1,24 @@
from aiohttp import web
from homeassistant.components.http import HomeAssistantView
import logging
PATH = "/auth/oidc/welcome"
_LOGGER = logging.getLogger(__name__)
class OIDCWelcomeView(HomeAssistantView):
"""OIDC Plugin Welcome View."""
requires_auth = False
url = PATH
name = "auth:oidc:welcome"
async def get(self, request: web.Request) -> web.Response:
"""Receive response."""
_LOGGER.debug("Welcome view accessed")
return web.Response(
headers={"content-type": "text/html"},
text="<h1>OIDC Login (beta)</h1><p><a href='/auth/oidc/redirect'>Login with OIDC</a></p>",
)