Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MFA #405

Merged
merged 18 commits into from
Sep 9, 2024
Merged

MFA #405

Show file tree
Hide file tree
Changes from 4 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></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
27 changes: 26 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_provider: t.Optional[MFAProvider] = None,
dantownsend marked this conversation as resolved.
Show resolved Hide resolved
) -> 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,21 @@ def __init__(
),
)

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

if mfa_provider:
private_app.mount(
path="/mfa-setup/",
app=RateLimitingMiddleware(
app=mfa_setup(
provider=mfa_provider,
auth_table=self.auth_table,
),
provider=rate_limit_provider,
),
)
dantownsend marked this conversation as resolved.
Show resolved Hide resolved

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

public_app = FastAPI(
Expand All @@ -705,6 +727,7 @@ def __init__(
max_session_expiry=max_session_expiry,
redirect_to=None,
production=production,
mfa_providers=[mfa_provider],
Fixed Show fixed Hide fixed
),
provider=rate_limit_provider,
),
Expand Down Expand Up @@ -1083,6 +1106,7 @@ def create_admin(
allowed_hosts: t.Sequence[str] = [],
debug: bool = False,
sidebar_links: t.Dict[str, str] = {},
mfa_provider: t.Optional[MFAProvider] = None,
):
"""
:param tables:
Expand Down Expand Up @@ -1249,4 +1273,5 @@ def create_admin(
allowed_hosts=allowed_hosts,
debug=debug,
sidebar_links=sidebar_links,
mfa_provider=mfa_provider,
)
13 changes: 13 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,10 @@ def booking_endpoint(request: Request, data: BookingModel) -> str:
"Top Movies": "/#/movie?__order=-box_office",
"Google": "https://google.com",
},
mfa_provider=AuthenticatorProvider(
db_encryption_key="wqsOqyTTEsrWppZeIMS8a3l90yPUtrqT48z7FS6_U8g=",
secret_table=AuthenticatorSecret,
),
)


Expand Down
Loading