|
24 | 24 |
|
25 | 25 | from aiohttp.web import Request |
26 | 26 | from aiohttp.web import Response |
| 27 | +from aiohttp.web_exceptions import HTTPNotFound, HTTPFound, HTTPUnauthorized |
27 | 28 |
|
28 | 29 | from ....htserver import UnauthorizedError |
29 | 30 | from ....htserver import ForbiddenError |
|
43 | 44 |
|
44 | 45 | # ===== |
45 | 46 | _COOKIE_AUTH_TOKEN = "auth_token" |
| 47 | +_COOKIE_OAUTH_SESSION = "oauth-session" |
46 | 48 |
|
47 | 49 |
|
48 | 50 | async def _check_xhdr(auth_manager: AuthManager, _: HttpExposed, req: Request) -> bool: |
@@ -136,3 +138,91 @@ async def __logout_handler(self, req: Request) -> Response: |
136 | 138 | @exposed_http("GET", "/auth/check", allow_usc=False) |
137 | 139 | async def __check_handler(self, _: Request) -> Response: |
138 | 140 | return make_json_response() |
| 141 | + |
| 142 | + @exposed_http("GET", "/auth/oauth/providers", auth_required=False) |
| 143 | + async def __oauth_providers(self, request: Request) -> Response: |
| 144 | + """ |
| 145 | + Return a json containing the available Providers with short_name and long_name and if oauth is enabled |
| 146 | + @param request: |
| 147 | + @return: json with provider infos |
| 148 | + """ |
| 149 | + response: dict[str, (bool | dict)] = {} |
| 150 | + if self.__auth_manager.oauth_manager is None: |
| 151 | + response.update({'enabled': False}) |
| 152 | + else: |
| 153 | + response.update({'enabled': True, 'providers': self.__auth_manager.oauth_manager.get_providers()}) |
| 154 | + return make_json_response(response) |
| 155 | + |
| 156 | + @exposed_http("GET", "/auth/oauth/login/{provider}", auth_required=False) |
| 157 | + async def __oauth(self, request: Request) -> None: |
| 158 | + """ |
| 159 | + Creates the redirect to the Provider specified in the URL. Checks if the provider is valid. |
| 160 | + Also sets a cookie containing session information. |
| 161 | + @param request: |
| 162 | + @return: redirect to provider |
| 163 | + """ |
| 164 | + if self.__auth_manager.oauth_manager is None: |
| 165 | + return |
| 166 | + provider = format(request.match_info['provider']) |
| 167 | + if not self.__auth_manager.oauth_manager.valid_provider(provider): |
| 168 | + raise HTTPNotFound(reason="Unknown provider %s" % provider) |
| 169 | + |
| 170 | + redirect_url = request.url.with_path(f"/api/auth/oauth/callback/{provider}").with_scheme('https') |
| 171 | + oauth_cookie = request.cookies.get(_COOKIE_OAUTH_SESSION, "") |
| 172 | + |
| 173 | + is_valid_session = await self.__auth_manager.oauth_manager.is_valid_session(provider, oauth_cookie) |
| 174 | + if not is_valid_session: |
| 175 | + session = await self.__auth_manager.oauth_manager.register_new_session(provider) |
| 176 | + else: |
| 177 | + session = oauth_cookie |
| 178 | + |
| 179 | + response = HTTPFound( |
| 180 | + await self.__auth_manager.oauth_manager.get_authorize_url( |
| 181 | + provider=provider, redirect_url=redirect_url, session=session, |
| 182 | + ) |
| 183 | + ) |
| 184 | + response.set_cookie(name=_COOKIE_OAUTH_SESSION, value=session, secure=True, httponly=True, samesite="Lax") |
| 185 | + |
| 186 | + # 302 redirect to provider: |
| 187 | + raise response |
| 188 | + |
| 189 | + @exposed_http("GET", "/auth/oauth/callback/{provider}", auth_required=False) |
| 190 | + async def __callback(self, request: Request) -> Response: |
| 191 | + """ |
| 192 | + After successful login on the side of the provider, the user gets redirected here. If everything is correct, |
| 193 | + the user gets logged in with the username provided by the Provider. |
| 194 | + @param request: |
| 195 | + @return: |
| 196 | + """ |
| 197 | + if self.__auth_manager.oauth_manager is None: |
| 198 | + return make_json_response() |
| 199 | + |
| 200 | + if not request.match_info['provider']: |
| 201 | + raise HTTPUnauthorized(reason="Provider is missing") |
| 202 | + provider = format(request.match_info['provider']) |
| 203 | + if not self.__auth_manager.oauth_manager.valid_provider(provider): |
| 204 | + raise HTTPNotFound(reason="Unknown provider %s" % provider) |
| 205 | + |
| 206 | + if _COOKIE_OAUTH_SESSION not in request.cookies.keys(): |
| 207 | + raise HTTPUnauthorized(reason="Cookie is missing") |
| 208 | + oauth_session = request.cookies[_COOKIE_OAUTH_SESSION] |
| 209 | + |
| 210 | + if not self.__auth_manager.oauth_manager.is_redirect_from_provider(provider=provider, request_query=dict(request.query)): |
| 211 | + raise HTTPUnauthorized(reason="Authorization Code is missing") |
| 212 | + |
| 213 | + redirect_url = request.url.with_query("").with_path(f"/api/auth/oauth/callback/{provider}").with_scheme('https') |
| 214 | + user = await self.__auth_manager.oauth_manager.get_user_info( |
| 215 | + provider=provider, |
| 216 | + oauth_session=oauth_session, |
| 217 | + request_query=dict(request.query), |
| 218 | + redirect_url=redirect_url |
| 219 | + ) |
| 220 | + |
| 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}) |
| 227 | + raise ForbiddenError() |
| 228 | + return make_json_response() |
0 commit comments