the middle of the idiots
This commit is contained in:
		
							
								
								
									
										108
									
								
								qwen/python/merchants_of_hope/services/auth_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								qwen/python/merchants_of_hope/services/auth_service.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
"""
 | 
			
		||||
Authentication service with OIDC and social media support
 | 
			
		||||
"""
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from jose import jwt
 | 
			
		||||
from fastapi import HTTPException, status
 | 
			
		||||
from sqlalchemy.orm import Session
 | 
			
		||||
 | 
			
		||||
from ..config.settings import settings
 | 
			
		||||
from ..models import User
 | 
			
		||||
from ..database import SessionLocal
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
 | 
			
		||||
    """Create a JWT access token"""
 | 
			
		||||
    to_encode = data.copy()
 | 
			
		||||
    if expires_delta:
 | 
			
		||||
        expire = datetime.utcnow() + expires_delta
 | 
			
		||||
    else:
 | 
			
		||||
        expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
 | 
			
		||||
    to_encode.update({"exp": expire})
 | 
			
		||||
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
 | 
			
		||||
    return encoded_jwt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def verify_token(token: str) -> dict:
 | 
			
		||||
    """Verify a JWT token and return the payload"""
 | 
			
		||||
    try:
 | 
			
		||||
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
 | 
			
		||||
        return payload
 | 
			
		||||
    except jwt.JWTError:
 | 
			
		||||
        raise HTTPException(
 | 
			
		||||
            status_code=status.HTTP_401_UNAUTHORIZED,
 | 
			
		||||
            detail="Could not validate credentials",
 | 
			
		||||
            headers={"WWW-Authenticate": "Bearer"},
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def authenticate_user(db: Session, username: str, password: str) -> Optional[User]:
 | 
			
		||||
    """Authenticate a user with username and password"""
 | 
			
		||||
    user = db.query(User).filter(User.username == username).first()
 | 
			
		||||
    if not user or not verify_password_correct(password, user.hashed_password):
 | 
			
		||||
        return None
 | 
			
		||||
    if not user.is_active:
 | 
			
		||||
        return None
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_oidc_config():
 | 
			
		||||
    """Get OIDC configuration"""
 | 
			
		||||
    return {
 | 
			
		||||
        "issuer": settings.OIDC_ISSUER,
 | 
			
		||||
        "authorization_endpoint": f"{settings.OIDC_ISSUER}/authorize" if settings.OIDC_ISSUER else None,
 | 
			
		||||
        "token_endpoint": f"{settings.OIDC_ISSUER}/token" if settings.OIDC_ISSUER else None,
 | 
			
		||||
        "userinfo_endpoint": f"{settings.OIDC_ISSUER}/userinfo" if settings.OIDC_ISSUER else None,
 | 
			
		||||
        "jwks_uri": f"{settings.OIDC_ISSUER}/.well-known/jwks.json" if settings.OIDC_ISSUER else None,
 | 
			
		||||
        "client_id": settings.OIDC_CLIENT_ID,
 | 
			
		||||
        "redirect_uri": settings.OIDC_REDIRECT_URI,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def handle_oidc_callback(code: str) -> User:
 | 
			
		||||
    """
 | 
			
		||||
    Handle OIDC callback and return or create a user
 | 
			
		||||
    This is a simplified implementation - in a real app you'd exchange the code
 | 
			
		||||
    for tokens and fetch user info from the OIDC provider
 | 
			
		||||
    """
 | 
			
		||||
    # In a real implementation, you would:
 | 
			
		||||
    # 1. Exchange the authorization code for access/id tokens
 | 
			
		||||
    # 2. Validate the ID token
 | 
			
		||||
    # 3. Fetch user info from the userinfo endpoint
 | 
			
		||||
    # 4. Create or update the user in your database
 | 
			
		||||
    # 5. Return the user object
 | 
			
		||||
    
 | 
			
		||||
    # For now, return a placeholder - this would be replaced with real OIDC logic
 | 
			
		||||
    raise NotImplementedError("OIDC callback handling not fully implemented")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def handle_social_login(provider: str, access_token: str) -> User:
 | 
			
		||||
    """
 | 
			
		||||
    Handle social media login (Google, Facebook, etc.)
 | 
			
		||||
    This is a simplified implementation
 | 
			
		||||
    """
 | 
			
		||||
    # In a real implementation, you would:
 | 
			
		||||
    # 1. Validate the access token with the social provider
 | 
			
		||||
    # 2. Fetch user info from the provider's API
 | 
			
		||||
    # 3. Create or update the user in your database
 | 
			
		||||
    # 4. Return the user object
 | 
			
		||||
    
 | 
			
		||||
    # For now, return a placeholder - this would be replaced with real social login logic
 | 
			
		||||
    raise NotImplementedError("Social login handling not fully implemented")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def hash_password(password: str) -> str:
 | 
			
		||||
    """
 | 
			
		||||
    Hash a password using bcrypt
 | 
			
		||||
    """
 | 
			
		||||
    from ..utils.security import get_password_hash
 | 
			
		||||
    return get_password_hash(password)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def verify_password_correct(plain_password: str, hashed_password: str) -> bool:
 | 
			
		||||
    """
 | 
			
		||||
    Verify a plain password against its hash
 | 
			
		||||
    """
 | 
			
		||||
    from ..utils.security import verify_password as verify_password_util
 | 
			
		||||
    return verify_password_util(plain_password, hashed_password)
 | 
			
		||||
		Reference in New Issue
	
	Block a user