Skip to content
Snippets Groups Projects
Commit 31d8c91b authored by Hangzhi Yu's avatar Hangzhi Yu
Browse files

WIP: Add shared secret mechanism

parent 752416ea
No related branches found
No related tags found
2 merge requests!3Draft: Resolve "Implement shared secret mechanism",!2Frontend
<template>
<div class="d-flex justify-center align-center flex-column text-center">
<h1 class="text-h2" :v-text="appName"></h1>
<h1 class="text-h2">maka</h1>
</div>
</template>
<script>
import gqlAppName from "./appName.graphql";
export default {
name: "Empty",
data() {
return {
appName: null,
};
},
apollo: {
appName: gqlAppName,
},
};
</script>
......
<template>
<div class="d-flex justify-center align-center flex-column text-center">
<h1 class="text-h5">{{ $t("maka.shared_secret.enter") }}</h1>
<v-text-field v-model="sharedSecret" type="password">
<v-btn
slot="append"
icon
@click="sendSharedSecret"
>
<v-icon color="primary">
mdi-send-outline
</v-icon>
</v-btn>
</v-text-field>
<div>{{ "shared secret correct: " + sharedSecretStatus }}</div>
</div>
</template>
<script>
import { gqlSubmitSharedSecret, gqlSharedSecretStatus } from "./sharedSecret.graphql";
export default {
name: "SharedSecret",
data() {
return {
sharedSecret: "",
submitSharedSecretStatus: false,
sharedSecretStatus: false,
};
},
methods: {
sendSharedSecret() {
this.$apollo.queries.submitSharedSecretStatus.setVariables({ sharedSecret: this.sharedSecret });
this.$apollo.queries.submitSharedSecretStatus.skip = false;
},
},
apollo: {
submitSharedSecretStatus: {
query: gqlSubmitSharedSecret,
skip: true,
result ({ data, loading, networkStatus }) {
this.$apollo.queries.sharedSecretStatus.skip = false;
this.$apollo.queries.sharedSecretStatus.refetch();
},
},
sharedSecretStatus: {
query: gqlSharedSecretStatus,
skip: true,
},
},
};
</script>
<style scoped>
</style>
\ No newline at end of file
query gqlSubmitSharedSecret($sharedSecret: String!) {
submitSharedSecretStatus: submitSharedSecret(sharedSecret: $sharedSecret)
}
query gqlSharedSecretStatus {
sharedSecretStatus
}
......@@ -21,5 +21,16 @@ export default {
permission: "",
},
},
{
path: "check_shared_secret",
component: () => import("./components/SharedSecret.vue"),
name: "maka.checkSharedSecret",
meta: {
inMenu: true,
titleKey: "maka.shared_secret.title",
icon: "",
permission: "",
},
},
],
}
{
"maka": {
"menu_title": "AlekSIS-App-Maka"
"menu_title": "AlekSIS-App-Maka",
"shared_secret": {
"title": "Shared secret",
"enter": "Shared secret needed for accessing page"
}
}
}
from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.forms import PasswordInput
from django.forms.widgets import SelectMultiple
from django.utils.translation import gettext_lazy as _
from colorfield.widgets import ColorWidget
from dynamic_preferences.preferences import Section
from dynamic_preferences.serializers import StringSerializer
from dynamic_preferences.types import (
BooleanPreference,
ChoicePreference,
FilePreference,
IntegerPreference,
LongStringPreference,
ModelMultipleChoicePreference,
MultipleChoicePreference,
StringPreference,
)
from oauth2_provider.models import AbstractApplication
from aleksis.core.registries import person_preferences_registry, site_preferences_registry
maka = Section("maka", verbose_name=_("Grade management"))
class PasswordSerializer(StringSerializer):
"""Serializer hashing the given string before saving it."""
@classmethod
def to_db(cls, value, **kwargs):
return str(make_password(value))
@site_preferences_registry.register
class SharedSecret(StringPreference):
"""Shared secret for accessing grade management pages."""
section = maka
name = "shared_secret"
default = make_password("aleksis")
required = True
widget = PasswordInput
serializer = PasswordSerializer
verbose_name = _("Shared secret")
help_text = _("This is the global shared secret key used to access all grade management pages requiring two factor authentification. It is not possible to see the secret again after setting it; please write it down safely.")
import rules
from rules import is_superuser
from aleksis.core.util.predicates import has_person
from .util.predicates import has_shared_secret
# View 2FA (shared secret) protected pages
protected_page_predicate = has_person & has_shared_secret
rules.add_perm("maka.protected_page_rule", protected_page_predicate)
from django.apps import apps
from django.contrib.auth.hashers import check_password
import graphene
from graphene_django.types import DjangoObjectType
from aleksis.core.schema.base import FilterOrderList
from aleksis.core.util.core_helpers import get_site_preferences
from ..models import Grade, GradeChoice, GradeSet, Effort, EffortType
from .grade_set import (
......@@ -43,9 +45,18 @@ class Query(graphene.ObjectType):
ranking_types = FilterOrderList(EffortTypeType)
rankings = FilterOrderList(EffortTypeType)
submit_shared_secret = graphene.Boolean(shared_secret=graphene.String(required=True))
shared_secret_status = graphene.Boolean()
def resolve_app_name(root, info, **kwargs) -> str:
return apps.get_app_config("maka").verbose_name
def resolve_submit_shared_secret(root, info, shared_secret) -> bool:
info.context.session["maka_shared_secret_correct"] = check_password(shared_secret, get_site_preferences()["maka__shared_secret"])
return True
def resolve_shared_secret_status(root, info) -> bool:
return info.context.session.get("maka_shared_secret_correct")
class Mutation(graphene.ObjectType):
create_grade_sets = GradeSetBatchCreateMutation.Field()
......
from django.contrib.auth.models import User
from django.http import HttpRequest
from rules import predicate
@predicate
def has_shared_secret(user: User, request: HttpRequest) -> bool:
return request.session.get("maka_shared_secret_correct")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment