sso
This commit is contained in:
33
backend/routers/apps.py
Normal file
33
backend/routers/apps.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
import secrets
|
||||
from .. import database, models, schemas, auth_utils
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/apps",
|
||||
tags=["Applications"],
|
||||
dependencies=[Depends(auth_utils.get_current_admin_user)]
|
||||
)
|
||||
|
||||
@router.post("/", response_model=schemas.ApplicationOut)
|
||||
async def create_application(app: schemas.ApplicationCreate, db: Session = Depends(database.get_db)):
|
||||
db_app = db.query(models.Application).filter(models.Application.name == app.name).first()
|
||||
if db_app:
|
||||
raise HTTPException(status_code=400, detail="Application already exists")
|
||||
|
||||
api_key = secrets.token_urlsafe(32)
|
||||
db_app = models.Application(
|
||||
name=app.name,
|
||||
url=app.url,
|
||||
api_key=api_key
|
||||
)
|
||||
db.add(db_app)
|
||||
db.commit()
|
||||
db.refresh(db_app)
|
||||
return db_app
|
||||
|
||||
@router.get("/", response_model=List[schemas.ApplicationOut])
|
||||
async def read_applications(skip: int = 0, limit: int = 100, db: Session = Depends(database.get_db)):
|
||||
apps = db.query(models.Application).offset(skip).limit(limit).all()
|
||||
return apps
|
||||
22
backend/routers/auth.py
Normal file
22
backend/routers/auth.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlalchemy.orm import Session
|
||||
from .. import database, models, auth_utils, schemas
|
||||
from datetime import timedelta
|
||||
|
||||
router = APIRouter(tags=["Authentication"])
|
||||
|
||||
@router.post("/token", response_model=schemas.Token)
|
||||
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(database.get_db)):
|
||||
user = db.query(models.User).filter(models.User.username == form_data.username).first()
|
||||
if not user or not auth_utils.verify_password(form_data.password, user.hashed_password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token_expires = timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = auth_utils.create_access_token(
|
||||
data={"sub": user.username}, expires_delta=access_token_expires
|
||||
)
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
31
backend/routers/sso.py
Normal file
31
backend/routers/sso.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from .. import database, models, schemas, auth_utils
|
||||
|
||||
router = APIRouter(tags=["SSO"])
|
||||
|
||||
@router.post("/verify", response_model=schemas.SSOVerifyResponse)
|
||||
async def verify_user(request: schemas.SSOVerifyRequest, db: Session = Depends(database.get_db)):
|
||||
# 1. Validate API Key
|
||||
app = db.query(models.Application).filter(models.Application.api_key == request.api_key).first()
|
||||
if not app:
|
||||
raise HTTPException(status_code=403, detail="Invalid API Key")
|
||||
|
||||
# 2. Validate User Credentials
|
||||
user = db.query(models.User).filter(models.User.username == request.username).first()
|
||||
if not user or not auth_utils.verify_password(request.password, user.hashed_password):
|
||||
return {"authorized": False, "message": "Invalid username or password"}
|
||||
|
||||
if not user.is_active:
|
||||
return {"authorized": False, "message": "User account is inactive"}
|
||||
|
||||
# 3. Check Assignment
|
||||
assignment = db.query(models.UserApplication).filter(
|
||||
models.UserApplication.user_id == user.id,
|
||||
models.UserApplication.application_id == app.id
|
||||
).first()
|
||||
|
||||
if not assignment:
|
||||
return {"authorized": False, "message": "User not authorized for this application"}
|
||||
|
||||
return {"authorized": True, "message": "Authorized", "user": user}
|
||||
78
backend/routers/users.py
Normal file
78
backend/routers/users.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from .. import database, models, schemas, auth_utils
|
||||
from ..services import email
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/users",
|
||||
tags=["Users"],
|
||||
dependencies=[Depends(auth_utils.get_current_admin_user)]
|
||||
)
|
||||
|
||||
@router.post("/", response_model=schemas.UserOut)
|
||||
async def create_user(user: schemas.UserCreate, background_tasks: BackgroundTasks, db: Session = Depends(database.get_db)):
|
||||
db_user = db.query(models.User).filter(models.User.username == user.username).first()
|
||||
if db_user:
|
||||
raise HTTPException(status_code=400, detail="Username already registered")
|
||||
|
||||
hashed_password = auth_utils.get_password_hash(user.password)
|
||||
db_user = models.User(
|
||||
username=user.username,
|
||||
email=user.email,
|
||||
hashed_password=hashed_password,
|
||||
is_active=user.is_active,
|
||||
is_admin=user.is_admin
|
||||
)
|
||||
db.add(db_user)
|
||||
db.commit()
|
||||
db.refresh(db_user)
|
||||
|
||||
# Send email
|
||||
background_tasks.add_task(email.send_welcome_email, user.email, user.username, user.password)
|
||||
|
||||
return db_user
|
||||
|
||||
@router.get("/", response_model=List[schemas.UserOut])
|
||||
async def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(database.get_db)):
|
||||
users = db.query(models.User).offset(skip).limit(limit).all()
|
||||
return users
|
||||
|
||||
@router.put("/{user_id}", response_model=schemas.UserOut)
|
||||
async def update_user(user_id: int, user_update: schemas.UserUpdate, background_tasks: BackgroundTasks, db: Session = Depends(database.get_db)):
|
||||
db_user = db.query(models.User).filter(models.User.id == user_id).first()
|
||||
if not db_user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
if user_update.password:
|
||||
db_user.hashed_password = auth_utils.get_password_hash(user_update.password)
|
||||
# Send email on password change
|
||||
background_tasks.add_task(email.send_welcome_email, db_user.email, db_user.username, user_update.password)
|
||||
|
||||
if user_update.email:
|
||||
db_user.email = user_update.email
|
||||
if user_update.username:
|
||||
db_user.username = user_update.username
|
||||
if user_update.is_active is not None:
|
||||
db_user.is_active = user_update.is_active
|
||||
if user_update.is_admin is not None:
|
||||
db_user.is_admin = user_update.is_admin
|
||||
|
||||
db.commit()
|
||||
db.refresh(db_user)
|
||||
return db_user
|
||||
|
||||
@router.post("/{user_id}/assign/{app_id}")
|
||||
async def assign_app_to_user(user_id: int, app_id: int, db: Session = Depends(database.get_db)):
|
||||
assignment = db.query(models.UserApplication).filter(
|
||||
models.UserApplication.user_id == user_id,
|
||||
models.UserApplication.application_id == app_id
|
||||
).first()
|
||||
|
||||
if assignment:
|
||||
return {"message": "Already assigned"}
|
||||
|
||||
new_assignment = models.UserApplication(user_id=user_id, application_id=app_id)
|
||||
db.add(new_assignment)
|
||||
db.commit()
|
||||
return {"message": "Assigned successfully"}
|
||||
Reference in New Issue
Block a user