Config superuser (#59)
* backend: automatically create super user, fixes #57 - if SUPERUSER_EMAIL is set, superuser is created with `is_superuser` and `is_verified` settings, if user doesn't already exist. - if SUPERUSER_PASSWORD if set, the password for superuser is set, otherwise a random password is generated update sample SUPERUSER_EMAIL and SUPERUSER_PASSWORD in config file and chart. - ensure verification email is not sent if user already verified
This commit is contained in:
parent
eaf8055063
commit
53beb84c01
@ -34,13 +34,13 @@ class EmailSender:
|
||||
|
||||
def get_origin(self, headers):
|
||||
""" Return origin of the received request"""
|
||||
scheme = headers.get("X-Forwarded-Proto")
|
||||
if not scheme:
|
||||
scheme = "http"
|
||||
if not headers:
|
||||
return self.default_origin
|
||||
|
||||
scheme = headers.get("X-Forwarded-Proto")
|
||||
host = headers.get("Host")
|
||||
if not host:
|
||||
host = self.default_origin
|
||||
if not scheme or not host:
|
||||
return self.default_origin
|
||||
|
||||
return scheme + "://" + host
|
||||
|
||||
|
@ -9,10 +9,12 @@ import asyncio
|
||||
from typing import Dict, Optional
|
||||
|
||||
from pydantic import EmailStr, UUID4
|
||||
import passlib.pwd
|
||||
|
||||
from fastapi import Request, Response, HTTPException, Depends
|
||||
|
||||
from fastapi_users import FastAPIUsers, models, BaseUserManager
|
||||
from fastapi_users.manager import UserAlreadyExists
|
||||
from fastapi_users.authentication import JWTAuthentication
|
||||
from fastapi_users.db import MongoDBUserDatabase
|
||||
|
||||
@ -35,10 +37,10 @@ class User(models.BaseUser):
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# use custom model as model.BaseeserCreate includes is_* fields which should not be set
|
||||
class UserCreate(models.CreateUpdateDictModel):
|
||||
# use custom model as model.BaseUserCreate includes is_* field
|
||||
class UserCreateIn(models.CreateUpdateDictModel):
|
||||
"""
|
||||
User Creation Model
|
||||
User Creation Model exposed to API
|
||||
"""
|
||||
|
||||
email: EmailStr
|
||||
@ -52,6 +54,20 @@ class UserCreate(models.CreateUpdateDictModel):
|
||||
newArchiveName: Optional[str] = ""
|
||||
|
||||
|
||||
# ============================================================================
|
||||
class UserCreate(models.BaseUserCreate):
|
||||
"""
|
||||
User Creation Model
|
||||
"""
|
||||
|
||||
name: Optional[str] = ""
|
||||
|
||||
inviteToken: Optional[str]
|
||||
|
||||
newArchive: bool
|
||||
newArchiveName: Optional[str] = ""
|
||||
|
||||
|
||||
# ============================================================================
|
||||
class UserUpdate(User, models.CreateUpdateDictModel):
|
||||
"""
|
||||
@ -124,6 +140,27 @@ class UserManager(BaseUserManager[UserCreate, UserDB]):
|
||||
)
|
||||
return await cursor.to_list(length=1000)
|
||||
|
||||
async def create_super_user(self):
|
||||
""" Initialize a super user from env vars """
|
||||
email = os.environ.get("SUPERUSER_EMAIL")
|
||||
password = os.environ.get("SUPERUSER_PASSWORD")
|
||||
if not email:
|
||||
print("No superuser defined", flush=True)
|
||||
return
|
||||
|
||||
if not password:
|
||||
password = passlib.pwd.genword()
|
||||
|
||||
try:
|
||||
res = await self.create(
|
||||
UserCreate(email=email, password=password, is_superuser=True, newArchive=False, is_verified=True)
|
||||
)
|
||||
print(f"Super user {email} created", flush=True)
|
||||
print(res, flush=True)
|
||||
|
||||
except UserAlreadyExists:
|
||||
print(f"User {email} already exists", flush=True)
|
||||
|
||||
async def on_after_register_custom(
|
||||
self, user: UserDB, user_create: UserCreate, request: Optional[Request]
|
||||
):
|
||||
@ -144,6 +181,8 @@ class UserManager(BaseUserManager[UserCreate, UserDB]):
|
||||
user=user,
|
||||
)
|
||||
|
||||
is_verified = hasattr(user_create, "is_verified") and user_create.is_verified
|
||||
|
||||
if user_create.inviteToken:
|
||||
try:
|
||||
await self.archive_ops.handle_new_user_invite(
|
||||
@ -152,10 +191,11 @@ class UserManager(BaseUserManager[UserCreate, UserDB]):
|
||||
except HTTPException as exc:
|
||||
print(exc)
|
||||
|
||||
# if user has been invited, mark as verified immediately
|
||||
await self._update(user, {"is_verified": True})
|
||||
if not is_verified:
|
||||
# if user has been invited, mark as verified immediately
|
||||
await self._update(user, {"is_verified": True})
|
||||
|
||||
else:
|
||||
elif not is_verified:
|
||||
asyncio.create_task(self.request_verify(user, request))
|
||||
|
||||
async def on_after_forgot_password(
|
||||
@ -202,7 +242,7 @@ def init_users_api(app, user_manager):
|
||||
lambda: user_manager,
|
||||
[jwt_authentication],
|
||||
User,
|
||||
UserCreate,
|
||||
UserCreateIn,
|
||||
UserUpdate,
|
||||
UserDB,
|
||||
)
|
||||
@ -261,4 +301,6 @@ def init_users_api(app, user_manager):
|
||||
|
||||
app.include_router(users_router, prefix="/users", tags=["users"])
|
||||
|
||||
asyncio.create_task(user_manager.create_super_user())
|
||||
|
||||
return fastapi_users
|
||||
|
@ -23,6 +23,9 @@ stringData:
|
||||
EMAIL_SENDER: "{{ .Values.email.sender_email }}"
|
||||
EMAIL_PASSWORD: "{{ .Values.email.password }}"
|
||||
|
||||
SUPERUSER_EMAIL: "{{ .Values.superuser.email }}"
|
||||
SUPERUSER_PASSWORD: "{{ .Values.superuser.password }}"
|
||||
|
||||
{{- range $storage := .Values.storages }}
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -5,6 +5,13 @@ name: browsertrix-cloud
|
||||
registration_enabled: 1
|
||||
jwt_token_lifetime_minutes: 60
|
||||
|
||||
superuser:
|
||||
# set this to enable a superuser admin
|
||||
email: admin@example.com
|
||||
|
||||
# optional: if not set, automatically generated
|
||||
password:
|
||||
|
||||
|
||||
# API Image
|
||||
# =========================================
|
||||
|
@ -9,6 +9,11 @@ MONGO_INITDB_ROOT_PASSWORD=example
|
||||
MINIO_ROOT_USER=ADMIN
|
||||
MINIO_ROOT_PASSWORD=PASSW0RD
|
||||
|
||||
SUPERUSER_EMAIL=admin@example.com
|
||||
|
||||
# if blank, a password is generated automatically
|
||||
SUPERUSER_PASSWORD=
|
||||
|
||||
STORE_ENDPOINT_URL=http://minio:9000/test-bucket/
|
||||
STORE_ACCESS_ENDPOINT_URL=http://localhost:9000/test-bucket/
|
||||
STORE_ACCESS_KEY=ADMIN
|
||||
|
Loading…
Reference in New Issue
Block a user