From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 dart-login-manager] support new TFA login flow
Date: Tue, 14 Dec 2021 10:08:14 +0100 [thread overview]
Message-ID: <20211214090814.45225-2-w.bumiller@proxmox.com> (raw)
In-Reply-To: <20211214090814.45225-1-w.bumiller@proxmox.com>
For now this just shows a simple dialog to select the TFA type, this
can probably be switched to using tabs or a dropdown or something.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
Changes to v1:
* Support the old TFA API by checking if the tfa challenge's `oldApi`
property is set. Therefore the tfaType property of the tfa form is
now optional.
lib/proxmox_login_form.dart | 92 +++++++++++++++++++++++++++++++++----
lib/proxmox_tfa_form.dart | 17 +++++--
2 files changed, 97 insertions(+), 12 deletions(-)
diff --git a/lib/proxmox_login_form.dart b/lib/proxmox_login_form.dart
index 59a9f61..32f8741 100644
--- a/lib/proxmox_login_form.dart
+++ b/lib/proxmox_login_form.dart
@@ -398,12 +398,85 @@ class _ProxmoxLoginPageState extends State<ProxmoxLoginPage> {
var client = await proxclient.authenticate(
'$username@$realm', password, origin, settings.sslValidation!);
- if (client.credentials.tfa) {
- client = await Navigator.of(context).push(MaterialPageRoute(
- builder: (context) => ProxmoxTfaForm(
- apiClient: client,
- ),
- ));
+ if (client.credentials.tfa != null) {
+ var tfa = client.credentials.tfa!;
+
+ if (tfa.oldApi) {
+ client = await Navigator.of(context).push(MaterialPageRoute(
+ builder: (context) => ProxmoxTfaForm(
+ apiClient: client,
+ tfaType: null,
+ message: 'Enter your TFA code',
+ ),
+ ));
+ } else {
+ if (!tfa.totp && !tfa.yubico && tfa.recovery.isEmpty) {
+ return await showDialog<void>(
+ context: context,
+ builder: (context) => AlertDialog(
+ title: Text('TFA Error'),
+ content: Text('No supported TFA method available.'),
+ actions: [
+ FlatButton(
+ onPressed: () => Navigator.of(context).pop(),
+ child: Text('Close'),
+ ),
+ ],
+ ),
+ );
+ }
+
+ final route = (await showDialog<MaterialPageRoute>(
+ context: context,
+ builder: (BuildContext context) {
+ var buttons = <Widget>[];
+
+ void simpleTfa(String label, String tfaType, String message) {
+ buttons.add(
+ SimpleDialogOption(
+ onPressed: () => Navigator.pop(
+ context,
+ MaterialPageRoute(
+ builder: (context) => ProxmoxTfaForm(
+ apiClient: client,
+ tfaType: tfaType,
+ message: message,
+ ),
+ ),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [ Text(label) ],
+ ),
+ ),
+ );
+ };
+
+ if (tfa.totp) {
+ simpleTfa('TOTP', 'totp', 'Enter your TOTP code');
+ }
+
+ if (tfa.yubico) {
+ simpleTfa('Yubico OTP', 'yubico', 'Enter your Yubico OTP code');
+ }
+
+ if (!tfa.recovery.isEmpty) {
+ simpleTfa('Recovery Code', 'recovery', 'Enter a Recovery Code');
+ }
+
+ return SimpleDialog(
+ title: const Text("Select 2nd Factor"),
+ children: buttons,
+ );
+ }
+ ));
+
+ if (route == null)
+ return;
+
+ client = await Navigator.of(context).push(route!);
+ }
}
final status = await client.getClusterStatus();
@@ -466,10 +539,11 @@ class _ProxmoxLoginPageState extends State<ProxmoxLoginPage> {
builder: (context) => ProxmoxCertificateErrorDialog(),
);
}
+ } finally {
+ setState(() {
+ _progressModel.inProgress = false;
+ });
}
- setState(() {
- _progressModel.inProgress = false;
- });
}
Future<List<PveAccessDomainModel?>?> _getAccessDomains() async {
diff --git a/lib/proxmox_tfa_form.dart b/lib/proxmox_tfa_form.dart
index db3cfa7..fcfb0e2 100644
--- a/lib/proxmox_tfa_form.dart
+++ b/lib/proxmox_tfa_form.dart
@@ -1,11 +1,19 @@
import 'package:flutter/material.dart';
import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart';
+import 'package:proxmox_dart_api_client/src/tfa_challenge.dart';
import 'package:proxmox_login_manager/proxmox_login_form.dart';
class ProxmoxTfaForm extends StatefulWidget {
final ProxmoxApiClient? apiClient;
+ final String? tfaType;
+ final String message;
- const ProxmoxTfaForm({Key? key, this.apiClient}) : super(key: key);
+ const ProxmoxTfaForm({
+ Key? key,
+ this.apiClient,
+ required this.tfaType,
+ required this.message,
+ }) : super(key: key);
@override
_ProxmoxTfaFormState createState() => _ProxmoxTfaFormState();
@@ -57,7 +65,7 @@ class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
fontWeight: FontWeight.bold),
),
Text(
- 'Check your second factor provider',
+ widget.message,
style: TextStyle(
color: Colors.white38, fontWeight: FontWeight.bold),
),
@@ -108,7 +116,10 @@ class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
});
try {
final client =
- await widget.apiClient!.finishTfaChallenge(_codeController.text);
+ await widget.apiClient!.finishTfaChallenge(
+ widget.tfaType,
+ _codeController.text,
+ );
Navigator.of(context).pop(client);
} on ProxmoxApiException catch (e) {
showDialog(
--
2.30.2
prev parent reply other threads:[~2021-12-14 9:08 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-14 9:08 [pve-devel] [PATCH v2 dart-client] switch to new authentication API Wolfgang Bumiller
2021-12-14 9:08 ` Wolfgang Bumiller [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211214090814.45225-2-w.bumiller@proxmox.com \
--to=w.bumiller@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.