Skip to content

Commit 690da5f

Browse files
committed
feat: moved token level exchange to a higher level
1 parent 0198362 commit 690da5f

File tree

6 files changed

+352
-126
lines changed

6 files changed

+352
-126
lines changed

app/auth.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,35 @@ async def websocket_authenticate(websocket: WebSocket) -> str | None:
8686
return None
8787

8888

89-
async def exchange_token_for_provider(
89+
async def exchange_token(user_token: str, url: str) -> str:
90+
"""
91+
Retrieve the exchanged token for accessing an external backend. This is done by exchanging the
92+
user's token for a platform-specific token using the configured token provider.
93+
94+
:param url: The URL of the backend for which to exchange the token. This URL should be
95+
configured in the BACKEND_CONFIG environment variable.
96+
:return: The bearer token as a string.
97+
"""
98+
99+
provider = settings.backend_auth_config[url].token_provider
100+
token_prefix = settings.backend_auth_config[url].token_prefix
101+
102+
if not provider or not token_prefix:
103+
raise ValueError(
104+
f"Backend '{url}' must define 'token_provider' and 'token_prefix'"
105+
)
106+
107+
platform_token = await _exchange_token_for_provider(
108+
initial_token=user_token, provider=provider
109+
)
110+
return (
111+
f"{token_prefix}/{platform_token['access_token']}"
112+
if token_prefix
113+
else platform_token["access_token"]
114+
)
115+
116+
117+
async def _exchange_token_for_provider(
90118
initial_token: str, provider: str
91119
) -> Dict[str, Any]:
92120
"""
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
from pydantic import BaseModel
44

55

6-
class OpenEOAuthMethod(str, Enum):
6+
class AuthMethod(str, Enum):
77
CLIENT_CREDENTIALS = "CLIENT_CREDENTIALS"
88
USER_CREDENTIALS = "USER_CREDENTIALS"
99

1010

11-
class OpenEOBackendConfig(BaseModel):
12-
auth_method: OpenEOAuthMethod = OpenEOAuthMethod.USER_CREDENTIALS
11+
class BackendAuthConfig(BaseModel):
12+
auth_method: AuthMethod = AuthMethod.USER_CREDENTIALS
1313
client_credentials: Optional[str] = None
1414
token_provider: Optional[str] = None
1515
token_prefix: Optional[str] = None

app/config/settings.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pydantic import Field
55
from pydantic_settings import BaseSettings, SettingsConfigDict
66

7-
from app.config.openeo.settings import OpenEOAuthMethod, OpenEOBackendConfig
7+
from app.config.schemas import AuthMethod, BackendAuthConfig
88

99

1010
class Settings(BaseSettings):
@@ -40,29 +40,28 @@ class Settings(BaseSettings):
4040
default="", json_schema_extra={"env": "KEYCLOAK_CLIENT_SECRET"}
4141
)
4242

43-
# openEO Settings
44-
openeo_backends: str | None = Field(
45-
default="", json_schema_extra={"env": "OPENEO_BACKENDS"}
43+
# Backend auth configuration
44+
backends: str | None = Field(
45+
default="", json_schema_extra={"env": "BACKENDS"}
4646
)
47+
backend_auth_config: Dict[str, BackendAuthConfig] = Field(default_factory=dict)
4748

48-
openeo_backend_config: Dict[str, OpenEOBackendConfig] = Field(default_factory=dict)
49-
50-
def load_openeo_backends_from_env(self):
49+
def load_backends_auth_config(self):
5150
"""
5251
Populate self.backends from BACKENDS_JSON if provided, otherwise keep defaults.
5352
BACKENDS_JSON should be a JSON object keyed by hostname with BackendConfig-like values.
5453
"""
5554
required_fields = []
56-
if self.openeo_backends:
55+
if self.backends:
5756

5857
try:
59-
raw = json.loads(self.openeo_backends)
58+
raw = json.loads(self.backends)
6059
for host, cfg in raw.items():
61-
backend = OpenEOBackendConfig(**cfg)
60+
backend = BackendAuthConfig(**cfg)
6261

63-
if backend.auth_method == OpenEOAuthMethod.CLIENT_CREDENTIALS:
62+
if backend.auth_method == AuthMethod.CLIENT_CREDENTIALS:
6463
required_fields = ["client_credentials"]
65-
elif backend.auth_method == OpenEOAuthMethod.USER_CREDENTIALS:
64+
elif backend.auth_method == AuthMethod.USER_CREDENTIALS:
6665
required_fields = ["token_provider"]
6766

6867
for field in required_fields:
@@ -71,11 +70,11 @@ def load_openeo_backends_from_env(self):
7170
f"Backend '{host}' must define '{field}' when "
7271
f"OPENEO_AUTH_METHOD={backend.auth_method}"
7372
)
74-
self.openeo_backend_config[host] = OpenEOBackendConfig(**cfg)
73+
self.backend_auth_config[host] = BackendAuthConfig(**cfg)
7574
except Exception:
7675
# Fall back or raise as appropriate
7776
raise
7877

7978

8079
settings = Settings()
81-
settings.load_openeo_backends_from_env()
80+
settings.load_backends_auth_config()

app/platforms/implementations/openeo.py

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from loguru import logger
1010
from stac_pydantic import Collection
1111

12-
from app.auth import exchange_token_for_provider
13-
from app.config.settings import OpenEOAuthMethod, settings
12+
from app.auth import exchange_token
13+
from app.config.schemas import AuthMethod
14+
from app.config.settings import settings
1415
from app.platforms.base import BaseProcessingPlatform
1516
from app.platforms.dispatcher import register_platform
1617
from app.schemas.enum import OutputFormatEnum, ProcessingStatusEnum, ProcessTypeEnum
@@ -58,28 +59,6 @@ def _connection_expired(self, connection: openeo.Connection) -> bool:
5859
logger.warning("No JWT bearer token found in connection.")
5960
return True
6061

61-
async def _get_bearer_token(self, user_token: str, url: str) -> str:
62-
"""
63-
Retrieve the bearer token for the OpenEO backend. This is done by exchanging the user's
64-
token for a platform-specific token using the configured token provider.
65-
66-
:param url: The URL of the OpenEO backend.
67-
:return: The bearer token as a string.
68-
"""
69-
70-
provider = settings.openeo_backend_config[url].token_provider
71-
token_prefix = settings.openeo_backend_config[url].token_prefix
72-
73-
if not provider or not token_prefix:
74-
raise ValueError(
75-
f"Backend '{url}' must define 'token_provider' and 'token_prefix'"
76-
)
77-
78-
platform_token = await exchange_token_for_provider(
79-
initial_token=user_token, provider=provider
80-
)
81-
return f"{token_prefix}/{platform_token['access_token']}"
82-
8362
async def _authenticate_user(
8463
self, user_token: str, url: str, connection: openeo.Connection
8564
) -> openeo.Connection:
@@ -88,19 +67,19 @@ async def _authenticate_user(
8867
This method can be used to set the user's token for the connection.
8968
"""
9069

91-
if url not in settings.openeo_backend_config:
70+
if url not in settings.backend_auth_config:
9271
raise ValueError(f"No OpenEO backend configuration found for URL: {url}")
9372

9473
if (
95-
settings.openeo_backend_config[url].auth_method
96-
== OpenEOAuthMethod.USER_CREDENTIALS
74+
settings.backend_auth_config[url].auth_method
75+
== AuthMethod.USER_CREDENTIALS
9776
):
9877
logger.debug("Using user credentials for OpenEO connection authentication")
99-
bearer_token = await self._get_bearer_token(user_token, url)
78+
bearer_token = await exchange_token(user_token=user_token, url=url)
10079
connection.authenticate_bearer_token(bearer_token=bearer_token)
10180
elif (
102-
settings.openeo_backend_config[url].auth_method
103-
== OpenEOAuthMethod.CLIENT_CREDENTIALS
81+
settings.backend_auth_config[url].auth_method
82+
== AuthMethod.CLIENT_CREDENTIALS
10483
):
10584
logger.debug(
10685
"Using client credentials for OpenEO connection authentication"
@@ -115,7 +94,7 @@ async def _authenticate_user(
11594
else:
11695
raise ValueError(
11796
"Unsupported OpenEO authentication method: "
118-
f"{settings.openeo_backend_config[url].auth_method}"
97+
f"{settings.backend_auth_config[url].auth_method}"
11998
)
12099

121100
return connection
@@ -145,7 +124,7 @@ def _get_client_credentials(self, url: str) -> tuple[str, str, str]:
145124
:param url: The URL of the OpenEO backend.
146125
:return: A tuple containing provider ID, client ID, and client secret.
147126
"""
148-
credentials_str = settings.openeo_backend_config[url].client_credentials
127+
credentials_str = settings.backend_auth_config[url].client_credentials
149128

150129
if not credentials_str:
151130
raise ValueError(

0 commit comments

Comments
 (0)