diff --git a/dev-requirements.txt b/dev-requirements.txt
index 05818ca08..3609760a7 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -3,3 +3,6 @@ django-debug-toolbar
pre-commit
black
pylint
+django-extensions
+Werkzeug
+pyOpenSSL
diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev
index cc5258784..29d455c46 100644
--- a/docker/Dockerfile.dev
+++ b/docker/Dockerfile.dev
@@ -15,8 +15,6 @@ COPY requirements.txt /tmp
COPY test-requirements.txt /tmp
RUN python -m pip install -U pip
RUN pip install -r requirements.txt -r test-requirements.txt
-RUN pip install django-extensions Werkzeug pyOpenSSL
-
FROM base as run
COPY docker/doveadm /usr/local/bin
RUN chmod +x /usr/local/bin/doveadm
diff --git a/frontend/src/api/auth.js b/frontend/src/api/auth.js
index 8a661346c..d5257bf0a 100644
--- a/frontend/src/api/auth.js
+++ b/frontend/src/api/auth.js
@@ -16,4 +16,7 @@ export default {
beginFidoRegistration() {
return repository.post('/fido/registration/begin/')
},
+ endFidoRegistration(data) {
+ return repository.post('/fido/registration/end/', data)
+ }
}
diff --git a/frontend/src/components/account/FidoAuthForm.vue b/frontend/src/components/account/FidoAuthForm.vue
index f0224a55a..3a786d62c 100644
--- a/frontend/src/components/account/FidoAuthForm.vue
+++ b/frontend/src/components/account/FidoAuthForm.vue
@@ -15,10 +15,12 @@
}}
-
-
- {{ $gettext('Add WebAuthN device') }}
-
+
+
+
+ {{ $gettext('Add WebAuthN device') }}
+
+
@@ -34,6 +36,7 @@
import { ref, onMounted } from 'vue'
import authApi from '@/api/auth.js'
import { useGettext } from 'vue3-gettext'
+import rules from '@/plugins/rules.js'
const { $gettext } = useGettext()
@@ -41,13 +44,22 @@ const name = ref()
const registrationLoading = ref(false)
const creationOption = ref()
const browserCapable = !!(navigator.credentials && navigator.credentials.create && navigator.credentials.get && window.PublicKeyCredential)
+const fidoForm = ref()
async function startFidoRegistration() {
+ const { valid } = await fidoForm.value.validate()
+ if (!valid) {
+ return
+ }
if (creationOption.value) {
navigator.credentials.create({...creationOption.value})
.then(function (attestation) {
const result = createResponseToJSON(attestation)
+ result.name = name.value
console.log(result)
+ authApi.endFidoRegistration(result).then((resp) => {
+ console.log(resp)
+ })
})
}
}
diff --git a/modoboa/core/api/v2/serializers.py b/modoboa/core/api/v2/serializers.py
index 2ab2ae9d4..d037c0c67 100644
--- a/modoboa/core/api/v2/serializers.py
+++ b/modoboa/core/api/v2/serializers.py
@@ -249,9 +249,10 @@ class FidoRegistrationSerializer(serializers.Serializer):
type = serializers.CharField()
id = serializers.CharField()
- raw_id = serializers.CharField()
+ rawId = serializers.CharField()
authenticatorAttachment = serializers.CharField()
response = serializers.JSONField()
+ name = serializers.CharField()
class LogSerializer(serializers.ModelSerializer):
diff --git a/modoboa/core/fido2_auth.py b/modoboa/core/fido2_auth.py
index d57e3436b..536f63eb9 100644
--- a/modoboa/core/fido2_auth.py
+++ b/modoboa/core/fido2_auth.py
@@ -33,7 +33,8 @@ def begin_registration(request):
display_name=request.user.username,
),
get_creds_from_user(request.user.pk),
- user_verification=UserVerificationRequirement.DISCOURAGED
+ user_verification=UserVerificationRequirement.DISCOURAGED,
+ extensions={"credentialProtectionPolicy":"userVerificationOptional"}
)
request.session['fido2_state'] = state
return options
@@ -42,8 +43,8 @@ def begin_registration(request):
def end_registration(data, fido2_state, user_id):
set_json_mapping()
server = create_fido2_server()
- server.authenticate_complete(
+ auth_data = server.register_complete(
fido2_state,
- get_creds_from_user(user_id),
- data["response"],
+ data
)
+ print(auth_data)
diff --git a/modoboa/core/models.py b/modoboa/core/models.py
index 5d8a55c92..44a4c0753 100644
--- a/modoboa/core/models.py
+++ b/modoboa/core/models.py
@@ -416,11 +416,9 @@ class UserFidoKeys(models.Model):
user = models.ForeignKey(User ,on_delete=models.CASCADE)
name = models.CharField(max_length=255)
enabled = models.BooleanField(default=True)
- platform = models.CharField(max_length=255,default='')
added_on = models.DateTimeField(auto_now_add=True)
last_used = models.DateTimeField(null=True,default=None)
- credential_id = models.CharField(max_length=255, unique=True)
- token = models.CharField(max_length=255, null=False)
+ credential_data = models.CharField(max_length=4096)
def populate_callback(user, group="SimpleUsers"):