Skip to content

Commit

Permalink
Added cnames support, removed interfaces from sdk and replaced with s…
Browse files Browse the repository at this point in the history
…ervices
  • Loading branch information
alexbalakirev committed Aug 30, 2024
1 parent 482a04a commit 0e1d388
Show file tree
Hide file tree
Showing 17 changed files with 58 additions and 325 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The Corbado Python SDK provides the following services:
To use a specific service, such as `users`, invoke it as shown below:

```Python
user_service: UserInterface = sdk.users
user_service: UserService = sdk.users
```

## :books: Advanced
Expand Down
4 changes: 0 additions & 4 deletions src/corbado_python_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
UserStatus,
UserUpdateReq,
)
from .services import IdentifierInterface, SessionInterface, UserInterface

__all__ = [
"IdentifierCreateReq",
Expand All @@ -20,12 +19,9 @@
"IdentifierType",
"UserCreateReq",
"UserUpdateReq",
"IdentifierInterface",
"UserStatus",
"StandardException",
"UserEntity",
"CorbadoSDK",
"Config",
"UserInterface",
"SessionInterface",
]
8 changes: 8 additions & 0 deletions src/corbado_python_sdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Config(BaseModel):

backend_api: str = "https://backendapi.cloud.corbado.io/v2"
short_session_cookie_name: str = "cbo_short_session"
cname: Optional[Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]] = None

_issuer: Optional[Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]] = None
_frontend_api: Optional[str] = None
Expand Down Expand Up @@ -102,6 +103,13 @@ def issuer(self) -> str:
str: issuer.
"""
if not self._issuer:
if self.cname:
if self.cname.startswith("https://"):
self._issuer = self.cname
else:
self._issuer = "https://" + self.cname
return self._issuer

self._issuer = self.frontend_api
return self._issuer

Expand Down
27 changes: 11 additions & 16 deletions src/corbado_python_sdk/corbado_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@
SessionService,
UserService,
)
from corbado_python_sdk.services.interface import (
IdentifierInterface,
SessionInterface,
UserInterface,
)

CORBADO_HEADER_NAME = "X-Corbado-SDK"

Expand All @@ -35,7 +30,7 @@ class CorbadoSDK(BaseModel):
config (Config): The configuration object for the SDK.
api_client (ApiClient): The API client used to make requests to the backend API.
sessions (SessionService): The session service service.
users (UserInterface): The user service.
users (UserService): The user service.
"""

model_config = ConfigDict(
Expand All @@ -44,8 +39,8 @@ class CorbadoSDK(BaseModel):
config: Config
_api_client: Optional[ApiClient] = None
_sessions: Optional[SessionService] = None
_users: Optional[UserInterface] = None
_identifiers: Optional[IdentifierInterface] = None
_users: Optional[UserService] = None
_identifiers: Optional[IdentifierService] = None

@property
def api_client(self) -> ApiClient:
Expand All @@ -65,13 +60,13 @@ def api_client(self) -> ApiClient:
self._api_client.set_default_header(header_name=CORBADO_HEADER_NAME, header_value=json.dumps(data)) # type: ignore
return self._api_client

# --------- Interfaces ---------------#
# --------- Services ---------------#
@property
def sessions(self) -> SessionInterface:
"""Get user SessionInterface.
def sessions(self) -> SessionService:
"""Get user SessionService.
Returns:
SessionInterface: SessionService object.
SessionService: SessionService object.
"""
if not self._sessions:
self._sessions = SessionService(
Expand All @@ -83,11 +78,11 @@ def sessions(self) -> SessionInterface:
return self._sessions

@property
def users(self) -> UserInterface:
def users(self) -> UserService:
"""Get user service.
Returns:
UserInterface: UserService object.
UserService: UserService object.
"""
if not self._users:
client = UsersApi(api_client=self.api_client)
Expand All @@ -96,11 +91,11 @@ def users(self) -> UserInterface:
return self._users

@property
def identifiers(self) -> IdentifierInterface:
def identifiers(self) -> IdentifierService:
"""Get identifier service.
Returns:
IdentifierInterface: IdentifierService object.
IdentifierService: IdentifierService object.
"""
if not self._identifiers:
client = IdentifiersApi(api_client=self.api_client)
Expand Down
6 changes: 5 additions & 1 deletion src/corbado_python_sdk/entities/session_validation_result.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
from typing_extensions import Optional


class SessionValidationResult(BaseModel):
"""Result class for SessionService validation."""

model_config = ConfigDict(
arbitrary_types_allowed=True,
)
authenticated: bool = Field(default=False, description="Indicates success of validation by session service.")
user_id: Optional[str] = Field(default=None, description="The user ID.")
full_name: Optional[str] = Field(default=None, description="The full name.")
error: Optional[Exception] = Field(default=None, description="Error occurred during validation.")
2 changes: 1 addition & 1 deletion src/corbado_python_sdk/entities/user_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class UserEntity(User):
"""Represents a user entity."""

model_config = ConfigDict(populate_by_name=True, from_attributes=True)
model_config = ConfigDict(populate_by_name=True, from_attributes=True, arbitrary_types_allowed=True)

@classmethod
def from_user(cls, user: User) -> "UserEntity":
Expand Down
10 changes: 2 additions & 8 deletions src/corbado_python_sdk/services/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
from .interface import IdentifierInterface as IdentifierInterface
from .interface import SessionInterface as SessionInterface
from .interface import UserInterface as UserInterface
from .implementation import IdentifierService, SessionService, UserService

__all__ = [
"IdentifierInterface",
"UserInterface",
"SessionInterface",
]
__all__ = ["IdentifierService", "SessionService", "UserService"]
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@
IdentifierUpdateReq,
)
from corbado_python_sdk.generated.models.paging import Paging
from corbado_python_sdk.services.interface.identifier_interface import (
IdentifierInterface,
)


class IdentifierService(BaseModel, IdentifierInterface):
class IdentifierService(BaseModel):
"""This class provides functionality for managing login identifiers."""

model_config = ConfigDict(
Expand Down
34 changes: 11 additions & 23 deletions src/corbado_python_sdk/services/implementation/session_service.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import jwt
from jwt import decode
from jwt.exceptions import PyJWTError
from jwt.jwks_client import PyJWKClient
from pydantic import BaseModel, ConfigDict, StringConstraints
from pydantic import BaseModel, ConfigDict, StrictStr, StringConstraints
from typing_extensions import Annotated

from corbado_python_sdk.entities.session_validation_result import (
SessionValidationResult,
)
from corbado_python_sdk.services.interface import SessionInterface

DEFAULT_SHORT_SESSION_LENGTH = 300


class SessionService(SessionInterface, BaseModel):
"""
Implementation of SessionInterface.
class SessionService(BaseModel):
"""This class provides functionality for managing sessions.
This class provides functionality for managing sessions, including validation and retrieval of user information
from short-term session tokens.
Including validation and retrieval of user information from short-term session tokens.
Attributes:
model_config (ConfigDict): Configuration dictionary for the model.
Expand Down Expand Up @@ -68,11 +64,11 @@ def __init__(self, **kwargs) -> None: # type: ignore
cache_jwk_set=self.cache_jwk_set,
)

def get_and_validate_short_session_value(self, short_session: str) -> SessionValidationResult:
def get_and_validate_short_session_value(self, short_session: StrictStr) -> SessionValidationResult:
"""Validate the given short-term session (represented as JWT) value.
Args:
short_session (str): jwt
short_session (StrictStr): jwt
Returns:
SessionValidationResult: SessionValidationResult with authenticated=True on success,
Expand All @@ -84,36 +80,28 @@ def get_and_validate_short_session_value(self, short_session: str) -> SessionVal
# retrieve signing key
signing_key: jwt.PyJWK = self._jwk_client.get_signing_key_from_jwt(token=short_session)
# decode short session (jwt) with signing key
payload = decode(jwt=short_session, key=signing_key.key, algorithms=["RS256"])
payload = decode(jwt=short_session, key=signing_key.key, algorithms=["RS256"], issuer=self.issuer)

# extract information from decoded payload
sub = payload.get("sub")
full_name = payload.get("name")

# check issuer
if payload.get("iss") and payload["iss"] != self.issuer:
self.set_issuer_mismatch_error(issuer=payload["iss"])
# return unauthenticated user on issuer mismatch
return SessionValidationResult(authenticated=False)
return SessionValidationResult(authenticated=True, user_id=sub, full_name=full_name)
except PyJWTError as error:
except Exception as error:
# return unauthenticated user on error
self.set_validation_error(error)
return SessionValidationResult(authenticated=False)
return SessionValidationResult(authenticated=False, error=error)

def get_current_user(self, short_session: str) -> SessionValidationResult:
def get_current_user(self, short_session: StrictStr) -> SessionValidationResult:
"""Return current user for the short session.
Args:
short_session (str): Short session.
short_session (StrictStr): Short session.
Returns:
SessionValidationResult: SessionValidationResult with authenticated=True on success, otherwise with
authenticated=False.
"""
if not short_session:
return SessionValidationResult(authenticated=False)

user: SessionValidationResult = self.get_and_validate_short_session_value(short_session)
return user

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
from corbado_python_sdk.generated.models import UserCreateReq
from corbado_python_sdk.generated.models.user import User
from corbado_python_sdk.generated.models.user_status import UserStatus
from corbado_python_sdk.services.interface import UserInterface


class UserService(
BaseModel,
UserInterface,
):
"""Service for managing users."""

Expand Down
9 changes: 0 additions & 9 deletions src/corbado_python_sdk/services/interface/__init__.py

This file was deleted.

Loading

0 comments on commit 0e1d388

Please sign in to comment.