Skip to content

Commit f1e51aa

Browse files
committed
use oauth lib for oidc
let the lib do the work instead of building requests and urls uses the well-known endpoint fixes the urls only working on fief
1 parent 8df711f commit f1e51aa

5 files changed

Lines changed: 126 additions & 38 deletions

File tree

carbonserver/carbonserver/api/routers/authenticate.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import random
44
from typing import Optional
5+
from authlib.integrations.starlette_client import OAuth, OAuthError
56

67
import requests
78
from dependency_injector.wiring import Provide, inject
@@ -83,8 +84,17 @@ async def get_login(
8384
if auth_provider is None:
8485
raise HTTPException(status_code=501, detail="Authentication not configured")
8586
login_url = request.url_for("login")
86-
8787
if code:
88+
try:
89+
token = await auth_provider.client.authorize_access_token(request)
90+
except OAuthError as error:
91+
return "Error"
92+
user = token.get('userinfo')
93+
if user:
94+
request.session['user'] = dict(user)
95+
return RedirectResponse(url='/')
96+
97+
return
8898
client_id, client_secret = auth_provider.get_client_credentials()
8999
res = requests.post(
90100
auth_provider.get_token_endpoint(),
@@ -132,9 +142,8 @@ async def get_login(
132142
secure=True,
133143
)
134144
return response
145+
return await auth_provider.get_authorize_url(request, str(login_url))
135146

136147
state = str(int(random.random() * 1000))
137148
client_id, _ = auth_provider.get_client_credentials()
138-
authorize_url = auth_provider.get_authorize_endpoint()
139-
url = f"{authorize_url}?response_type=code&client_id={client_id}&redirect_uri={login_url}&scope={' '.join(OAUTH_SCOPES)}&state={state}"
140-
return RedirectResponse(url=url)
149+
return await auth_provider.client.authorize_redirect(request, str(login_url), scope=' '.join(OAUTH_SCOPES))

carbonserver/carbonserver/api/services/auth_providers/oidc_auth_provider.py

Lines changed: 107 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,83 @@
88
import asyncio
99
from typing import Any, Dict, List, Optional, Tuple
1010
from urllib.parse import urlencode
11+
from carbonserver.config import settings
1112

1213
import httpx
13-
from fastapi_oidc import discovery
14+
from fastapi_oidc import discovery, get_auth
1415
from jose import jwt
1516

1617
DEFAULT_SIGNATURE_CACHE_TTL = 3600 # seconds
17-
18+
OAUTH_SCOPES = ["openid", "email", "profile"]
19+
20+
from authlib.integrations.starlette_client import OAuth
21+
oauth = OAuth()
22+
oauth.register(
23+
"client",
24+
client_id=settings.oidc_client_id,
25+
client_secret=settings.oidc_client_secret,
26+
server_metadata_url=settings.oidc_well_known_url,
27+
client_kwargs={"scope": "openid profile email"},
28+
)
1829

1930
class OIDCAuthProvider:
31+
def __init__(
32+
self,
33+
base_url: str,
34+
client_id: str,
35+
client_secret: str,
36+
*,
37+
signature_cache_ttl: int = DEFAULT_SIGNATURE_CACHE_TTL,
38+
openid_configuration: Optional[Dict[str, Any]] = None,
39+
):
40+
self.client = oauth._clients["client"]
41+
42+
async def get_authorize_url(self, request, login_url):
43+
return self.client.authorize_redirect(request, str(login_url), scope=' '.join(OAUTH_SCOPES))
44+
45+
def get_client_credentials(self) -> Tuple[str, str]:
46+
return (self.client.client_id, self.client.client_secret)
47+
48+
def validate_access_token(self, token):
49+
...
50+
51+
52+
53+
# async def get_authorize_url(self, redirect_uri: str, **kwargs) -> str:
54+
# return (await self.client.create_authorization_url(redirect_uri=redirect_uri, **kwargs))["url"]
55+
56+
# def get_token_endpoint(self) -> str:
57+
# if (
58+
# self._openid_configuration
59+
# and "token_endpoint" in self._openid_configuration
60+
# ):
61+
# return self._openid_configuration["token_endpoint"]
62+
# return f"{self.base_url}/api/token"
63+
64+
# def get_authorize_endpoint(self) -> str:
65+
# """
66+
# Get the authorization endpoint URL.
67+
68+
# Returns:
69+
# The authorization endpoint URL
70+
# """
71+
# if (
72+
# self._openid_configuration
73+
# and "authorization_endpoint" in self._openid_configuration
74+
# ):
75+
# return self._openid_configuration["authorization_endpoint"]
76+
# return f"{self.base_url}/authorize"
77+
78+
79+
80+
81+
82+
"""
83+
['OAUTH_APP_CONFIG', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_create_oauth2_authorization_url', '_fetch_token', '_format_state_params', '_get_oauth_client', '_on_update_token', '_server_metadata_url', '_update_token', '_user_agent', 'access_token_params', 'access_token_url', 'api_base_url', 'authorize_access_token', 'authorize_params', 'authorize_redirect', 'authorize_url', 'client_auth_methods', 'client_cls', 'client_id', 'client_kwargs', 'client_secret', 'compliance_fix', 'create_authorization_url', 'delete', 'fetch_access_token', 'fetch_jwk_set', 'framework', 'get', 'load_server_metadata', 'name', 'parse_id_token', 'patch', 'post', 'put', 'request', 'save_authorize_data', 'server_metadata', 'userinfo']
84+
85+
"""
86+
87+
class OffOIDCAuthProvider:
2088
"""
2189
Generic OIDC authentication provider implementation.
2290
@@ -185,39 +253,44 @@ async def get_user_info(self, access_token: str) -> Dict[str, Any]:
185253
response.raise_for_status()
186254
return response.json()
187255

188-
def get_token_endpoint(self) -> str:
189-
"""
190-
Get the token endpoint URL.
256+
# def get_token_endpoint(self) -> str:
257+
# """
258+
# Get the token endpoint URL.
191259

192-
Returns:
193-
The token endpoint URL
194-
"""
195-
if (
196-
self._openid_configuration
197-
and "token_endpoint" in self._openid_configuration
198-
):
199-
return self._openid_configuration["token_endpoint"]
200-
return f"{self.base_url}/api/token"
201-
202-
def get_authorize_endpoint(self) -> str:
203-
"""
204-
Get the authorization endpoint URL.
260+
# Returns:
261+
# The token endpoint URL
262+
# """
263+
# if (
264+
# self._openid_configuration
265+
# and "token_endpoint" in self._openid_configuration
266+
# ):
267+
# return self._openid_configuration["token_endpoint"]
268+
# return f"{self.base_url}/api/token"
205269

206-
Returns:
207-
The authorization endpoint URL
208-
"""
209-
if (
210-
self._openid_configuration
211-
and "authorization_endpoint" in self._openid_configuration
212-
):
213-
return self._openid_configuration["authorization_endpoint"]
214-
return f"{self.base_url}/authorize"
270+
# def get_authorize_endpoint(self) -> str:
271+
# """
272+
# Get the authorization endpoint URL.
215273

216-
def get_client_credentials(self) -> Tuple[str, str]:
217-
"""
218-
Get the client ID and client secret.
274+
# Returns:
275+
# The authorization endpoint URL
276+
# """
277+
# if (
278+
# self._openid_configuration
279+
# and "authorization_endpoint" in self._openid_configuration
280+
# ):
281+
# return self._openid_configuration["authorization_endpoint"]
282+
# return f"{self.base_url}/authorize"
219283

220-
Returns:
221-
A tuple of (client_id, client_secret)
222-
"""
223-
return (self.client_id, self.client_secret)
284+
285+
286+
287+
288+
289+
# def get_client_credentials(self) -> Tuple[str, str]:
290+
# """
291+
# Get the client ID and client secret.
292+
293+
# Returns:
294+
# A tuple of (client_id, client_secret)
295+
# """
296+
# return (self.client_id, self.client_secret)

carbonserver/carbonserver/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Settings(BaseSettings):
1515
oidc_client_id: str = ""
1616
oidc_client_secret: str = ""
1717
oidc_issuer_url: str = "https://auth.codecarbon.io/codecarbon-dev"
18+
oidc_well_known_url: str = ""
1819

1920
# Deprecated: Old Fief-specific settings (use OIDC settings instead)
2021
@property
@@ -43,6 +44,7 @@ class Config:
4344
"oidc_client_id": {"env": ["OIDC_CLIENT_ID", "FIEF_CLIENT_ID"]},
4445
"oidc_client_secret": {"env": ["OIDC_CLIENT_SECRET", "FIEF_CLIENT_SECRET"]},
4546
"oidc_issuer_url": {"env": ["OIDC_ISSUER_URL", "FIEF_URL"]},
47+
"oidc_well_known_url": {"env": ["OIDC_WELL_KNOWN_URL", "FIEF_URL"+"/.well-known/openid-configuration"]},
4648
}
4749

4850

carbonserver/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from carbonserver.container import ServerContainer
2626
from carbonserver.database.database import engine
2727
from carbonserver.logger import logger
28+
from starlette.middleware.sessions import SessionMiddleware
2829

2930

3031
async def db_exception_handler(request: Request, exc: DBException):
@@ -54,6 +55,7 @@ def create_app() -> FastAPI:
5455
server.add_exception_handler(DBException, db_exception_handler)
5556
server.add_exception_handler(ValidationError, validation_exception_handler)
5657
server.add_exception_handler(Exception, generic_exception_handler)
58+
server.add_middleware(SessionMiddleware, secret_key="some-random-string")
5759

5860
return server
5961

carbonserver/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ dependencies = [
4040
"PyJWT",
4141
"logfire[fastapi]>=1.0.1",
4242
"fastapi-oidc>=0.0.9",
43+
"authlib>=1.6.6",
44+
"itsdangerous>=2.2.0",
4345
]
4446

4547
[project.urls]

0 commit comments

Comments
 (0)