+ my $user_cfg = $cached_usercfg || cfs_read_file('user.cfg');
+ my $user = $user_cfg->{users}->{$userid}
+ or die "user '$userid' not found\n";
+
+ my $domain_cfg = $cached_domaincfg || cfs_read_file('domains.cfg');
+ my $realm_cfg = $domain_cfg->{ids}->{$realm};
+ die "auth domain '$realm' does not exist\n" if !$realm_cfg;
+
+ my $realm_tfa = $realm_cfg->{tfa};
+ if (defined($realm_tfa)) {
+ $realm_tfa = PVE::Auth::Plugin::parse_tfa_config($realm_tfa);
+ # If the realm has a TFA setting, we're only allowed to use that.
+ if (defined($data)) {
+ my $required_type = $realm_tfa->{type};
+ if ($required_type ne $type) {
+ die "realm '$realm' only allows TFA of type '$required_type\n";
+ }
+
+ if (defined($data->{config})) {
+ # XXX: Is it enough if the type matches? Or should the configuration also match?
+ }
+
+ # realm-configured tfa always uses a simple key list, so use the user.cfg
+ $user->{keys} = $data->{keys};
+ } else {
+ die "realm '$realm' does not allow removing the 2nd factor\n";
+ }
+ } else {
+ # Without a realm-enforced TFA setting the user can add a u2f or totp entry by themselves.
+ # The 'yubico' type requires yubico server settings, which have to be configured on the
+ # realm, so this is not supported here:
+ die "domain '$realm' does not support TFA type '$type'\n"
+ if defined($data) && !$USER_CONTROLLED_TFA_TYPES->{$type};
+ }
+
+ # Custom TFA entries are stored in priv/tfa.cfg as they can be more complet: u2f uses a
+ # public key and a key handle, TOTP requires the usual totp settings...
+
+ my $tfa_cfg = cfs_read_file('priv/tfa.cfg');
+ my $tfa = ($tfa_cfg->{users}->{$userid} //= {});