]>
git.proxmox.com Git - pve-access-control.git/blob - src/PVE/API2/TFA.pm
1 package PVE
::API2
::TFA
;
6 use PVE
::AccessControl
;
7 use PVE
::Cluster
qw(cfs_read_file);
8 use PVE
::JSONSchema
qw(get_standard_option);
9 use PVE
::Exception
qw(raise raise_perm_exc raise_param_exc);
10 use PVE
::RPCEnvironment
;
12 use PVE
::API2
::AccessControl
; # for old login api get_u2f_instance method
16 use base
qw(PVE::RESTHandler);
20 __PACKAGE__-
>register_method({
24 permissions
=> { user
=> 'all' },
25 protected
=> 1, # else we can't access shadow files
26 allowtoken
=> 0, # we don't want tokens to access TFA information
27 description
=> 'Finish a u2f challenge.',
29 additionalProperties
=> 0,
33 description
=> 'The response to the current authentication challenge.',
40 ticket
=> { type
=> 'string' },
47 my $rpcenv = PVE
::RPCEnvironment
::get
();
48 my $authuser = $rpcenv->get_user();
49 my ($username, undef, $realm) = PVE
::AccessControl
::verify_username
($authuser);
51 my ($tfa_type, $tfa_data) = PVE
::AccessControl
::user_get_tfa
($username, $realm, 0);
52 if (!defined($tfa_type)) {
53 raise
('no u2f data available');
57 if ($tfa_type eq 'u2f') {
58 my $challenge = $rpcenv->get_u2f_challenge()
59 or raise
('no active challenge');
61 my $keyHandle = $tfa_data->{keyHandle
};
62 my $publicKey = $tfa_data->{publicKey
};
63 raise
("incomplete u2f setup")
64 if !defined($keyHandle) || !defined($publicKey);
66 my $u2f = PVE
::API2
::AccessControl
::get_u2f_instance
($rpcenv, $publicKey, $keyHandle);
67 $u2f->set_challenge($challenge);
69 my ($counter, $present) = $u2f->auth_verify($param->{response
});
70 # Do we want to do anything with these?
72 # sanity check before handing off to the verification code:
73 my $keys = $tfa_data->{keys} or die "missing tfa keys\n";
74 my $config = $tfa_data->{config
} or die "bad tfa entry\n";
75 PVE
::AccessControl
::verify_one_time_pw
($tfa_type, $authuser, $keys, $config, $param->{response
});
79 my $clientip = $rpcenv->get_client_ip() || '';
80 syslog
('err', "authentication verification failure; rhost=$clientip user=$authuser msg=$err");
81 die PVE
::Exception-
>new("authentication failure\n", code
=> 401);
85 ticket
=> PVE
::AccessControl
::assemble_ticket
($authuser),
86 cap
=> $rpcenv->compute_api_permission($authuser),
92 my $TFA_TYPE_SCHEMA = {
94 description
=> 'TFA Entry Type.',
95 enum
=> [qw(totp u2f webauthn recovery yubico)],
98 my %TFA_INFO_PROPERTIES = (
101 description
=> 'The id used to reference this entry.',
105 description
=> 'User chosen description for this entry.',
109 description
=> 'Creation time of this entry as unix epoch.',
113 description
=> 'Whether this TFA entry is currently enabled.',
119 my $TYPED_TFA_ENTRY_SCHEMA = {
121 description
=> 'TFA Entry.',
123 type
=> $TFA_TYPE_SCHEMA,
124 %TFA_INFO_PROPERTIES,
128 my $TFA_ID_SCHEMA = {
130 description
=> 'A TFA entry id.',
133 __PACKAGE__-
>register_method ({
134 name
=> 'list_user_tfa',
139 ['userid-param', 'self'],
140 ['userid-group', ['User.Modify', 'Sys.Audit']],
143 protected
=> 1, # else we can't access shadow files
144 allowtoken
=> 0, # we don't want tokens to change the regular user's TFA settings
145 description
=> 'List TFA configurations of users.',
147 additionalProperties
=> 0,
149 userid
=> get_standard_option
('userid', {
150 completion
=> \
&PVE
::AccessControl
::complete_username
,
155 description
=> "A list of the user's TFA entries.",
157 items
=> $TYPED_TFA_ENTRY_SCHEMA,
161 my $tfa_cfg = cfs_read_file
('priv/tfa.cfg');
162 return $tfa_cfg->api_list_user_tfa($param->{userid
});
165 __PACKAGE__-
>register_method ({
166 name
=> 'get_tfa_entry',
167 path
=> '{userid}/{id}',
171 ['userid-param', 'self'],
172 ['userid-group', ['User.Modify', 'Sys.Audit']],
175 protected
=> 1, # else we can't access shadow files
176 allowtoken
=> 0, # we don't want tokens to change the regular user's TFA settings
177 description
=> 'A requested TFA entry if present.',
179 additionalProperties
=> 0,
181 userid
=> get_standard_option
('userid', {
182 completion
=> \
&PVE
::AccessControl
::complete_username
,
184 id
=> $TFA_ID_SCHEMA,
187 returns
=> $TYPED_TFA_ENTRY_SCHEMA,
190 my $tfa_cfg = cfs_read_file
('priv/tfa.cfg');
191 return $tfa_cfg->api_get_tfa_entry($param->{userid
}, $param->{id
});
194 __PACKAGE__-
>register_method ({
199 description
=> "Returns all or just the logged-in user, depending on privileges.",
202 protected
=> 1, # else we can't access shadow files
203 allowtoken
=> 0, # we don't want tokens to change the regular user's TFA settings
204 description
=> 'List TFA configurations of users.',
206 additionalProperties
=> 0,
210 description
=> "The list tuples of user and TFA entries.",
217 description
=> 'User this entry belongs to.',
221 items
=> $TYPED_TFA_ENTRY_SCHEMA,
229 my $rpcenv = PVE
::RPCEnvironment
::get
();
230 my $authuser = $rpcenv->get_user();
233 my $top_level_allowed = ($authuser eq 'root@pam');
235 my $tfa_cfg = cfs_read_file
('priv/tfa.cfg');
236 return $tfa_cfg->api_list_tfa($authuser, $top_level_allowed);