Skip to content
/ kvmd Public

Commit 8eaa176

Browse files
committed
WIP: OAuth: unbreak, get it to work
1 parent 815ffc5 commit 8eaa176

File tree

3 files changed

+36
-19
lines changed

3 files changed

+36
-19
lines changed

kvmd/apps/kvmd/api/auth.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from aiohttp.web import Request
2626
from aiohttp.web import Response
27-
from aiohttp.web_exceptions import HTTPNotFound, HTTPFound, HTTPUnauthorized
27+
from aiohttp.web_exceptions import HTTPNotFound, HTTPFound, HTTPUnauthorized, HTTPBadRequest
2828

2929
from ....htserver import UnauthorizedError
3030
from ....htserver import ForbiddenError
@@ -41,6 +41,8 @@
4141

4242
from ..auth import AuthManager
4343

44+
from ....logging import get_logger
45+
4446

4547
# =====
4648
_COOKIE_AUTH_TOKEN = "auth_token"
@@ -139,7 +141,7 @@ async def __logout_handler(self, req: Request) -> Response:
139141
async def __check_handler(self, _: Request) -> Response:
140142
return make_json_response()
141143

142-
@exposed_http("GET", "/auth/oauth/providers", auth_required=False)
144+
@exposed_http("GET", "/auth/oauth/providers", auth_required=False, allow_usc=False)
143145
async def __oauth_providers(self, request: Request) -> Response:
144146
"""
145147
Return a json containing the available Providers with short_name and long_name and if oauth is enabled
@@ -153,7 +155,7 @@ async def __oauth_providers(self, request: Request) -> Response:
153155
response.update({'enabled': True, 'providers': self.__auth_manager.oauth_manager.get_providers()})
154156
return make_json_response(response)
155157

156-
@exposed_http("GET", "/auth/oauth/login/{provider}", auth_required=False)
158+
@exposed_http("GET", "/auth/oauth/login/{provider}", auth_required=False, allow_usc=False)
157159
async def __oauth(self, request: Request) -> None:
158160
"""
159161
Creates the redirect to the Provider specified in the URL. Checks if the provider is valid.
@@ -162,12 +164,13 @@ async def __oauth(self, request: Request) -> None:
162164
@return: redirect to provider
163165
"""
164166
if self.__auth_manager.oauth_manager is None:
165-
return
167+
raise HTTPBadRequest(reason="Auth disabled")
168+
166169
provider = format(request.match_info['provider'])
167170
if not self.__auth_manager.oauth_manager.valid_provider(provider):
168171
raise HTTPNotFound(reason="Unknown provider %s" % provider)
169172

170-
redirect_url = request.url.with_path(f"/api/auth/oauth/callback/{provider}/").with_scheme('https')
173+
redirect_url = request.url.with_path(f"/api/auth/oauth/callback/{provider}").with_scheme("https")
171174
oauth_cookie = request.cookies.get(_COOKIE_OAUTH_SESSION, "")
172175

173176
is_valid_session = await self.__auth_manager.oauth_manager.is_valid_session(provider, oauth_cookie)
@@ -186,7 +189,7 @@ async def __oauth(self, request: Request) -> None:
186189
# 302 redirect to provider:
187190
raise response
188191

189-
@exposed_http("GET", "/auth/oauth/callback/{provider}", auth_required=False)
192+
@exposed_http("GET", "/auth/oauth/callback/{provider}", auth_required=False, allow_usc=False)
190193
async def __callback(self, request: Request) -> Response:
191194
"""
192195
After successful login on the side of the provider, the user gets redirected here. If everything is correct,
@@ -195,7 +198,7 @@ async def __callback(self, request: Request) -> Response:
195198
@return:
196199
"""
197200
if self.__auth_manager.oauth_manager is None:
198-
return make_json_response()
201+
raise HTTPBadRequest(reason="Auth disabled")
199202

200203
if not request.match_info['provider']:
201204
raise HTTPUnauthorized(reason="Provider is missing")
@@ -210,19 +213,25 @@ async def __callback(self, request: Request) -> Response:
210213
if not self.__auth_manager.oauth_manager.is_redirect_from_provider(provider=provider, request_query=dict(request.query)):
211214
raise HTTPUnauthorized(reason="Authorization Code is missing")
212215

213-
redirect_url = request.url.with_query("").with_path(f"/api/auth/oauth/callback/{provider}").with_scheme('https')
216+
redirect_url = request.url.with_path(f"/api/auth/oauth/callback/{provider}").with_scheme("https")
214217
user = await self.__auth_manager.oauth_manager.get_user_info(
215218
provider=provider,
216219
oauth_session=oauth_session,
217220
request_query=dict(request.query),
218221
redirect_url=redirect_url
219222
)
223+
if not user:
224+
raise ForbiddenError()
220225

221-
if self.__auth_manager.is_auth_enabled():
222-
token = await self.__auth_manager.login_oauth(
223-
user=valid_user(user)
224-
)
225-
if token:
226-
return make_json_response(set_cookies={_COOKIE_AUTH_TOKEN: token})
226+
token = await self.__auth_manager.login_oauth(
227+
user=valid_user(user)
228+
)
229+
get_logger().info(f"OAUTH CALLBACK: {token=}")
230+
if not token:
227231
raise ForbiddenError()
228-
return make_json_response()
232+
233+
response = HTTPFound(
234+
request.url.with_path("").with_scheme("https")
235+
)
236+
response.set_cookie(name=_COOKIE_AUTH_TOKEN, value=token, samesite="Lax", httponly=True)
237+
return response

kvmd/apps/kvmd/auth.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,15 @@ async def login_oauth(self, user: str) -> (str | None):
197197
assert self.__enabled
198198
assert self.oauth_manager
199199
token = self.__make_new_token()
200-
self.__tokens[token] = user
201-
202-
get_logger().info("Logged in user with OAuth %r", user)
200+
session = _Session(
201+
user=user,
202+
expire_ts=self.__make_expire_ts(0),
203+
)
204+
self.__sessions[token] = session
205+
get_logger(0).info("Logged in via OAuth (user %r); expire=%s, sessions_now=%d",
206+
session.user,
207+
self.__format_expire_ts(session.expire_ts),
208+
self.__get_sessions_number(session.user))
203209
return token
204210

205211
def __make_new_token(self) -> str:

kvmd/plugins/auth/oauth2.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
from ...yamlconf import Option
3535
from . import OAuthService, OAuthException
3636

37+
from ...logging import get_logger
38+
3739

3840
class Plugin(OAuthService): # pylint: disable=too-many-instance-attributes
3941
def __init__( # pylint: disable=too-many-arguments
@@ -156,7 +158,7 @@ async def get_user_info(
156158
try:
157159
async with session.get(self.__user_info_url, headers=headers) as response:
158160
user_info = await response.json()
159-
return user_info[self.__username_attribute]
161+
return user_info.get(self.__username_attribute, "_oauth_user_")
160162
except aiohttp.ClientConnectorError as error:
161163
raise OAuthException(message="could not connect to provider! error message: %s" % str(error))
162164

0 commit comments

Comments
 (0)