94 lines
3.1 KiB
Python
94 lines
3.1 KiB
Python
"""
|
|
Client Schemas
|
|
|
|
Pydantic schemas for OIDC client-related requests and responses.
|
|
"""
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
from typing import List, Optional
|
|
from datetime import datetime
|
|
|
|
|
|
# ==========================================
|
|
# Base Schemas
|
|
# ==========================================
|
|
|
|
class ClientBase(BaseModel):
|
|
"""Base client schema with common fields."""
|
|
client_name: str = Field(..., min_length=1, max_length=255, description="Client application name")
|
|
redirect_uris: List[str] = Field(..., min_items=1, description="List of allowed redirect URIs")
|
|
allowed_scopes: List[str] = Field(default_factory=lambda: ["openid", "profile", "email"], description="Allowed OAuth scopes")
|
|
|
|
|
|
# ==========================================
|
|
# Request Schemas (Input)
|
|
# ==========================================
|
|
|
|
class ClientCreate(ClientBase):
|
|
"""Schema for creating a new OIDC client."""
|
|
client_id: Optional[str] = Field(None, description="Client ID (auto-generated if not provided)")
|
|
client_secret: Optional[str] = Field(None, description="Client secret (auto-generated if not provided)")
|
|
|
|
@field_validator('redirect_uris')
|
|
@classmethod
|
|
def validate_redirect_uris(cls, v: List[str]) -> List[str]:
|
|
"""Validate redirect URIs."""
|
|
if not v:
|
|
raise ValueError('At least one redirect URI is required')
|
|
|
|
for uri in v:
|
|
if not uri.startswith(('http://', 'https://')):
|
|
raise ValueError(f'Invalid redirect URI: {uri}. Must start with http:// or https://')
|
|
|
|
return v
|
|
|
|
|
|
class ClientUpdate(BaseModel):
|
|
"""Schema for updating an OIDC client."""
|
|
client_name: Optional[str] = Field(None, min_length=1, max_length=255)
|
|
redirect_uris: Optional[List[str]] = None
|
|
allowed_scopes: Optional[List[str]] = None
|
|
new_client_secret: Optional[str] = Field(None, description="New client secret (optional)")
|
|
|
|
@field_validator('redirect_uris')
|
|
@classmethod
|
|
def validate_redirect_uris(cls, v: Optional[List[str]]) -> Optional[List[str]]:
|
|
"""Validate redirect URIs if provided."""
|
|
if v is not None:
|
|
if not v:
|
|
raise ValueError('At least one redirect URI is required')
|
|
|
|
for uri in v:
|
|
if not uri.startswith(('http://', 'https://')):
|
|
raise ValueError(f'Invalid redirect URI: {uri}')
|
|
|
|
return v
|
|
|
|
|
|
# ==========================================
|
|
# Response Schemas (Output)
|
|
# ==========================================
|
|
|
|
class ClientResponse(BaseModel):
|
|
"""Schema for client responses."""
|
|
id: int
|
|
client_id: str
|
|
client_name: str
|
|
redirect_uris: List[str]
|
|
allowed_scopes: List[str]
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class ClientWithSecret(ClientResponse):
|
|
"""Schema for client response including secret (only for creation)."""
|
|
client_secret: str = Field(..., description="Client secret (only shown once)")
|
|
|
|
|
|
class ClientListResponse(BaseModel):
|
|
"""Schema for client list."""
|
|
clients: List[ClientResponse]
|
|
total: int
|