Bromeo777 commited on
Commit
8bd5f4a
·
verified ·
1 Parent(s): 5599f11

Add app\api\v1\auth.py

Browse files
Files changed (1) hide show
  1. app//api//v1//auth.py +122 -0
app//api//v1//auth.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/v1/auth.py
2
+ # Final Version: Compatible with deps.py - imports auth functions from deps
3
+ # No circular imports, uses existing security utilities
4
+ # SSO DISABLED
5
+
6
+ import logging
7
+ from datetime import timedelta
8
+ from typing import Any, Optional
9
+
10
+ from fastapi import APIRouter, Depends, HTTPException, status, Query, Request
11
+ from fastapi.security import OAuth2PasswordRequestForm
12
+ from fastapi.responses import RedirectResponse
13
+ from sqlalchemy.ext.asyncio import AsyncSession
14
+
15
+ # Import from deps (source of truth) - NO circular import
16
+ from app.api import deps
17
+ from app.core.config import settings
18
+ from app.core import security
19
+ from app.db import queries
20
+ from app.models.user import User
21
+ from app.schemas.user import UserCreate
22
+ from app.schemas.common import Token
23
+
24
+ # SSO DISABLED - file deleted
25
+ # from app.services.auth.sso import sso_service
26
+
27
+ logger = logging.getLogger("rm_research.auth")
28
+
29
+ router = APIRouter()
30
+
31
+ # ------------------------------------------------------------------------------
32
+ # Utilities
33
+ # ------------------------------------------------------------------------------
34
+
35
+ def normalize_email(email: str) -> str:
36
+ """Standardize email for multi-tenant unique indexing."""
37
+ return email.strip().lower()
38
+
39
+ # ------------------------------------------------------------------------------
40
+ # Traditional Authentication
41
+ # ------------------------------------------------------------------------------
42
+
43
+ @router.post("/register", response_model=Token, status_code=status.HTTP_201_CREATED)
44
+ async def register_user(
45
+ user_in: UserCreate,
46
+ db: AsyncSession = Depends(deps.get_db),
47
+ ) -> Any:
48
+ """Self-service registration for independent researchers."""
49
+ email_normalized = normalize_email(user_in.email)
50
+ existing_user = await queries.get_user_by_email(db, email=email_normalized)
51
+
52
+ if existing_user:
53
+ raise HTTPException(
54
+ status_code=status.HTTP_400_BAD_REQUEST,
55
+ detail="A user with this email already exists."
56
+ )
57
+
58
+ db_user = User(
59
+ email=email_normalized,
60
+ hashed_password=security.get_password_hash(user_in.password),
61
+ is_active=True,
62
+ is_premium=False
63
+ )
64
+ db.add(db_user)
65
+ await db.commit()
66
+ await db.refresh(db_user)
67
+
68
+ access_token = security.create_access_token(subject=db_user.email)
69
+ return Token(
70
+ access_token=access_token,
71
+ token_type="bearer",
72
+ is_premium=db_user.is_premium
73
+ )
74
+
75
+ @router.post("/login", response_model=Token)
76
+ async def login_access_token(
77
+ db: AsyncSession = Depends(deps.get_db),
78
+ form_data: OAuth2PasswordRequestForm = Depends()
79
+ ) -> Any:
80
+ """Standard OAuth2 compatible token login."""
81
+ email_normalized = normalize_email(form_data.username)
82
+ user = await queries.get_user_by_email(db, email=email_normalized)
83
+
84
+ if not user or not security.verify_password(form_data.password, user.hashed_password):
85
+ raise HTTPException(
86
+ status_code=status.HTTP_401_UNAUTHORIZED,
87
+ detail="Incorrect email or password",
88
+ headers={"WWW-Authenticate": "Bearer"},
89
+ )
90
+
91
+ if not user.is_active:
92
+ raise HTTPException(
93
+ status_code=status.HTTP_403_FORBIDDEN,
94
+ detail="Inactive user"
95
+ )
96
+
97
+ access_token = security.create_access_token(subject=user.email)
98
+ return Token(
99
+ access_token=access_token,
100
+ token_type="bearer",
101
+ is_premium=user.is_premium
102
+ )
103
+
104
+ # ------------------------------------------------------------------------------
105
+ # Institutional SSO Hub - DISABLED
106
+ # ------------------------------------------------------------------------------
107
+
108
+ @router.get("/sso/initiate")
109
+ async def initiate_sso():
110
+ """SSO disabled - institutional authentication not available."""
111
+ raise HTTPException(
112
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
113
+ detail="SSO not configured"
114
+ )
115
+
116
+ @router.post("/sso/callback")
117
+ async def sso_callback():
118
+ """SSO disabled - institutional authentication not available."""
119
+ raise HTTPException(
120
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
121
+ detail="SSO not configured"
122
+ )