Skip to content
Merged

MFA #405

Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions admin_ui/src/components/DropDownMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
</ul>
</template>

<script lang="ts">
import { defineComponent } from "vue"

export default defineComponent({})
</script>
<script setup lang="ts"></script>

<style lang="less">
@import "../vars.less";
Expand Down
11 changes: 8 additions & 3 deletions admin_ui/src/components/NavDropDownMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@
><font-awesome-icon icon="key" />{{ $t("Change Password") }}
</router-link>
</li>
<li>
<a href="/api/mfa-setup/">
<font-awesome-icon icon="mobile-alt" />{{ $t("MFA Setup") }}
</a>
</li>
<li v-if="darkMode">
<a href="#" v-on:click.prevent="updateDarkMode(false)">
<a href="#" @click.prevent="updateDarkMode(false)">
<font-awesome-icon icon="sun" />{{ $t("Light Mode") }}
</a>
</li>
<li v-else>
<a href="#" v-on:click.prevent="updateDarkMode(true)">
<a href="#" @click.prevent="updateDarkMode(true)">
<font-awesome-icon icon="moon" />{{ $t("Dark Mode") }}
</a>
</li>
Expand All @@ -29,7 +34,7 @@
>
</li>
<li>
<a href="#" v-on:click.prevent="showAboutModal">
<a href="#" @click.prevent="showAboutModal">
<font-awesome-icon icon="info-circle" />{{ $t("About") }}
Piccolo
</a>
Expand Down
2 changes: 2 additions & 0 deletions admin_ui/src/fontawesome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
faLayerGroup,
faLevelUpAlt,
faLink,
faMobileAlt,
faMoon,
faPlus,
faQuestionCircle,
Expand Down Expand Up @@ -74,6 +75,7 @@ library.add(
faLayerGroup,
faLevelUpAlt,
faLink,
faMobileAlt,
faMoon,
faPlus,
faQuestionCircle,
Expand Down
5 changes: 5 additions & 0 deletions admin_ui/src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
<p>
{{ $t("Select a table in the sidebar to get started.") }}
</p>
<p>
<a href="/api/mfa-setup/">
<font-awesome-icon icon="mobile-alt" />{{ $t("MFA Setup") }}
</a>
</p>
</div>
</BaseView>
</template>
Expand Down
33 changes: 32 additions & 1 deletion piccolo_admin/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
from piccolo_api.fastapi.endpoints import FastAPIKwargs, FastAPIWrapper
from piccolo_api.media.base import MediaStorage
from piccolo_api.media.local import LocalMediaStorage
from piccolo_api.mfa.endpoints import mfa_setup
from piccolo_api.mfa.provider import MFAProvider
from piccolo_api.openapi.endpoints import swagger_ui
from piccolo_api.rate_limiting.middleware import (
InMemoryLimitProvider,
Expand Down Expand Up @@ -431,12 +433,17 @@ def __init__(
allowed_hosts: t.Sequence[str] = [],
debug: bool = False,
sidebar_links: t.Dict[str, str] = {},
mfa_providers: t.Optional[t.Sequence[MFAProvider]] = None,
) -> None:
super().__init__(
title=site_name,
description=f"{site_name} documentation",
middleware=[
Middleware(CSRFMiddleware, allowed_hosts=allowed_hosts)
Middleware(
CSRFMiddleware,
allowed_hosts=allowed_hosts,
allow_form_param=True,
)
],
debug=debug,
exception_handlers={500: log_error},
Expand Down Expand Up @@ -680,6 +687,27 @@ def __init__(
),
)

#######################################################################
# MFA

if mfa_providers:
if len(mfa_providers) > 1:
raise ValueError(
"Only a single mfa_provider is currently supported."
)

for mfa_provider in mfa_providers:
private_app.mount(
path="/mfa-setup/",
app=RateLimitingMiddleware(
app=mfa_setup(
provider=mfa_provider,
auth_table=self.auth_table,
),
provider=InMemoryLimitProvider(limit=5, timespan=300),
),
)

#######################################################################

public_app = FastAPI(
Expand All @@ -705,6 +733,7 @@ def __init__(
max_session_expiry=max_session_expiry,
redirect_to=None,
production=production,
mfa_providers=[mfa_provider],
),
provider=rate_limit_provider,
),
Expand Down Expand Up @@ -1083,6 +1112,7 @@ def create_admin(
allowed_hosts: t.Sequence[str] = [],
debug: bool = False,
sidebar_links: t.Dict[str, str] = {},
mfa_providers: t.Optional[t.Sequence[MFAProvider]] = None,
):
"""
:param tables:
Expand Down Expand Up @@ -1249,4 +1279,5 @@ def create_admin(
allowed_hosts=allowed_hosts,
debug=debug,
sidebar_links=sidebar_links,
mfa_providers=mfa_providers,
)
15 changes: 15 additions & 0 deletions piccolo_admin/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
from piccolo.table import Table, create_db_tables_sync, drop_db_tables_sync
from piccolo_api.media.local import LocalMediaStorage
from piccolo_api.media.s3 import S3MediaStorage
from piccolo_api.mfa.authenticator.provider import AuthenticatorProvider
from piccolo_api.mfa.authenticator.tables import (
AuthenticatorSecret as AuthenticatorSecret_,
)
from piccolo_api.session_auth.tables import SessionsBase
from pydantic import BaseModel, field_validator
from starlette.requests import Request
Expand Down Expand Up @@ -139,6 +143,10 @@ class User(BaseUser, tablename="piccolo_user"):
pass


class AuthenticatorSecret(AuthenticatorSecret_):
pass


class Director(Table, help_text="The main director for a movie."):
class Gender(str, enum.Enum):
male = "m"
Expand Down Expand Up @@ -439,6 +447,7 @@ def booking_endpoint(request: Request, data: BookingModel) -> str:
Studio,
User,
Sessions,
AuthenticatorSecret,
Ticket,
ArrayColumns,
NullableColumns,
Expand Down Expand Up @@ -607,6 +616,12 @@ def booking_endpoint(request: Request, data: BookingModel) -> str:
"Top Movies": "/#/movie?__order=-box_office",
"Google": "https://google.com",
},
mfa_providers=[
AuthenticatorProvider(
db_encryption_key="wqsOqyTTEsrWppZeIMS8a3l90yPUtrqT48z7FS6_U8g=",
secret_table=AuthenticatorSecret,
),
],
)


Expand Down