feat(api): testing oauth
This commit is contained in:
parent
a788fadb1c
commit
a78c97bb09
2 changed files with 137 additions and 1 deletions
|
|
@ -98,3 +98,72 @@ async def create_tenant(data: schemas.UserSignupSchema):
|
|||
"user": r
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async def create_oauth_tenant(fullname: str, email: str):
|
||||
logger.info(f"==== Signup oauth started at {TimeUTC.to_human_readable(TimeUTC.now())} UTC")
|
||||
errors = []
|
||||
if not config("MULTI_TENANTS", cast=bool, default=False) and await tenants.tenants_exists():
|
||||
return {"errors": ["tenants already registered"]}
|
||||
|
||||
logger.debug(f"email: {email}")
|
||||
|
||||
if email is None or len(email) < 5:
|
||||
errors.append("Invalid email address.")
|
||||
else:
|
||||
if users.email_exists(email):
|
||||
errors.append("Email address already in use.")
|
||||
if users.get_deleted_user_by_email(email) is not None:
|
||||
errors.append("Email address previously deleted.")
|
||||
|
||||
if fullname is None or len(fullname) < 1 or not helper.is_alphabet_space_dash(fullname):
|
||||
errors.append("Invalid full name.")
|
||||
|
||||
if len(errors) > 0:
|
||||
logger.warning(
|
||||
f"==> signup error for:\n email:{email}, fullname:{fullname}")
|
||||
logger.warning(errors)
|
||||
return {"errors": errors}
|
||||
|
||||
project_name = "my first project"
|
||||
params = {
|
||||
"email": email, "fullname": fullname, "projectName": project_name,
|
||||
"data": json.dumps({"lastAnnouncementView": TimeUTC.now()}),
|
||||
"permissions": [p.value for p in schemas.Permissions]
|
||||
}
|
||||
query = """WITH t AS (
|
||||
INSERT INTO public.tenants (name, plan)
|
||||
VALUES (%(organizationName)s, %(plan)s::jsonb)
|
||||
RETURNING tenant_id, api_key
|
||||
),
|
||||
r AS (
|
||||
INSERT INTO public.roles(tenant_id, name, description, permissions, protected)
|
||||
VALUES ((SELECT tenant_id FROM t), 'Owner', 'Owner', %(permissions)s::text[], TRUE),
|
||||
((SELECT tenant_id FROM t), 'Member', 'Member', %(permissions)s::text[], FALSE)
|
||||
RETURNING *
|
||||
),
|
||||
u AS (
|
||||
INSERT INTO public.users (tenant_id, email, role, name, verified_email, data, role_id)
|
||||
VALUES ((SELECT tenant_id FROM t), %(email)s, 'owner', %(fullname)s, TRUE,%(data)s, (SELECT role_id FROM r WHERE name ='Owner'))
|
||||
RETURNING user_id,email,role,name,role_id
|
||||
)
|
||||
INSERT INTO public.projects (tenant_id, name, active)
|
||||
VALUES ((SELECT t.tenant_id FROM t), %(projectName)s, TRUE)
|
||||
RETURNING tenant_id,project_id, (SELECT api_key FROM t) AS api_key;"""
|
||||
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(cur.mogrify(query, params))
|
||||
t = cur.fetchone()
|
||||
|
||||
telemetry.new_client(tenant_id=t["tenant_id"])
|
||||
r = users.authenticate(email, "password")
|
||||
r["smtp"] = smtp.has_smtp()
|
||||
|
||||
return {
|
||||
'jwt': r.pop('jwt'),
|
||||
'refreshToken': r.pop('refreshToken'),
|
||||
'refreshTokenMaxAge': r.pop('refreshTokenMaxAge'),
|
||||
'data': {
|
||||
"user": r
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,11 @@ import logging
|
|||
from typing import Optional, Union
|
||||
|
||||
from decouple import config
|
||||
from fastapi import Body, Depends, BackgroundTasks, Request
|
||||
from fastapi import Body, Depends, BackgroundTasks, Request, RedirectResponse
|
||||
from fastapi import HTTPException, status
|
||||
from starlette.responses import RedirectResponse, FileResponse, JSONResponse, Response
|
||||
import httpx
|
||||
import os
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import scope
|
||||
|
|
@ -55,6 +57,71 @@ if config("MULTI_TENANTS", cast=bool, default=False) or not tenants.tenants_exis
|
|||
return content
|
||||
|
||||
|
||||
# Environment variables (ensure these are set)
|
||||
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
|
||||
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
|
||||
GOOGLE_REDIRECT_URI = os.getenv("GOOGLE_REDIRECT_URI")
|
||||
|
||||
|
||||
if config("MULTI_TENANTS", cast=bool, default=False) or not tenants.tenants_exists_sync(use_pool=False):
|
||||
@public_app.get('/signup-oauth', tags=['signup'])
|
||||
async def signup_oauth_handler():
|
||||
google_authorization_url = (
|
||||
"https://accounts.google.com/o/oauth2/auth"
|
||||
f"?client_id={GOOGLE_CLIENT_ID}"
|
||||
f"&response_type=code"
|
||||
f"&redirect_uri={GOOGLE_REDIRECT_URI}"
|
||||
f"&scope=email%20profile"
|
||||
)
|
||||
return RedirectResponse(url=google_authorization_url)
|
||||
|
||||
|
||||
if config("MULTI_TENANTS", cast=bool, default=False) or not tenants.tenants_exists_sync(use_pool=False):
|
||||
@public_app.get('/signup-oauth-callback', tags=['signup'])
|
||||
async def signup_oauth_callback_handler(code: str):
|
||||
# Exchange code for token
|
||||
token_response = httpx.post(
|
||||
url="https://oauth2.googleapis.com/token",
|
||||
data={
|
||||
"client_id": GOOGLE_CLIENT_ID,
|
||||
"client_secret": GOOGLE_CLIENT_SECRET,
|
||||
"code": code,
|
||||
"grant_type": "authorization_code",
|
||||
"redirect_uri": GOOGLE_REDIRECT_URI,
|
||||
},
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||
)
|
||||
token_response_data = token_response.json()
|
||||
access_token = token_response_data.get("access_token")
|
||||
|
||||
if not access_token:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not retrieve access token")
|
||||
|
||||
# Retrieve user info
|
||||
user_info_response = httpx.get(
|
||||
url="https://www.googleapis.com/oauth2/v1/userinfo",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
)
|
||||
user_info = user_info_response.json()
|
||||
name = user_info.get("name")
|
||||
email = user_info.get("email")
|
||||
|
||||
if not email:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not retrieve user email")
|
||||
if not name:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not retrieve user name")
|
||||
|
||||
content = await signup.create_oauth_tenant(name, email)
|
||||
if "errors" in content:
|
||||
return content
|
||||
refresh_token = content.pop("refreshToken")
|
||||
refresh_token_max_age = content.pop("refreshTokenMaxAge")
|
||||
response = JSONResponse(content=content)
|
||||
response.set_cookie(key="refreshToken", value=refresh_token, path="/api/refresh",
|
||||
max_age=refresh_token_max_age, secure=True, httponly=True)
|
||||
return response
|
||||
|
||||
|
||||
@public_app.post('/login', tags=["authentication"])
|
||||
def login_user(response: JSONResponse, spot: Optional[bool] = False, data: schemas.UserLoginSchema = Body(...)):
|
||||
if helper.allow_captcha() and not captcha.is_valid(data.g_recaptcha_response):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue