]>
git.proxmox.com Git - pve-access-control.git/blob - PVE/Auth/Plugin.pm
1 package PVE
::Auth
::Plugin
;
9 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_lock_file);
10 use PVE
::JSONSchema
qw(get_standard_option);
11 use PVE
::SectionConfig
;
14 use base
qw(PVE::SectionConfig);
16 my $domainconfigfile = "domains.cfg";
18 cfs_register_file
($domainconfigfile,
19 sub { __PACKAGE__-
>parse_config(@_); },
20 sub { __PACKAGE__-
>write_config(@_); });
22 sub lock_domain_config
{
23 my ($code, $errmsg) = @_;
25 cfs_lock_file
($domainconfigfile, undef, $code);
28 $errmsg ?
die "$errmsg: $err" : die $err;
32 our $realm_regex = qr/[A-Za-z][A-Za-z0-9\.\-_]+/;
33 our $user_regex = qr![^\s:/]+!;
35 PVE
::JSONSchema
::register_format
('pve-realm', \
&pve_verify_realm
);
36 sub pve_verify_realm
{
37 my ($realm, $noerr) = @_;
39 if ($realm !~ m/^${realm_regex}$/) {
40 return undef if $noerr;
41 die "value does not look like a valid realm\n";
46 PVE
::JSONSchema
::register_standard_option
('realm', {
47 description
=> "Authentication domain ID",
48 type
=> 'string', format
=> 'pve-realm',
52 my $realm_sync_options_desc = {
54 description
=> "Select what to sync.",
56 enum
=> [qw(users groups both)],
60 description
=> "If set, uses the LDAP Directory as source of truth,"
61 ." deleting users or groups not returned from the sync. Otherwise"
62 ." only syncs information which is not already present, and does not"
63 ." deletes or modifies anything else.",
68 description
=> "Enable newly synced users immediately.",
74 description
=> "Remove ACLs for users or groups which were removed from"
75 ." the config during a sync.",
80 PVE
::JSONSchema
::register_standard_option
('realm-sync-options', $realm_sync_options_desc);
81 PVE
::JSONSchema
::register_format
('realm-sync-options', $realm_sync_options_desc);
83 PVE
::JSONSchema
::register_format
('pve-userid', \
&verify_username
);
85 my ($username, $noerr) = @_;
87 $username = '' if !$username;
88 my $len = length($username);
90 die "user name '$username' is too short\n" if !$noerr;
94 die "user name '$username' is too long ($len > 64)\n" if !$noerr;
98 # we only allow a limited set of characters
99 # colon is not allowed, because we store usernames in
100 # colon separated lists)!
101 # slash is not allowed because it is used as pve API delimiter
102 # also see "man useradd"
103 if ($username =~ m!^(${user_regex})\@(${realm_regex})$!) {
104 return wantarray ?
($username, $1, $2) : $username;
107 die "value '$username' does not look like a valid user name\n" if !$noerr;
112 PVE
::JSONSchema
::register_standard_option
('userid', {
113 description
=> "User ID",
114 type
=> 'string', format
=> 'pve-userid',
120 description
=> "The type of 2nd factor authentication.",
121 format_description
=> 'TFATYPE',
123 enum
=> [qw(yubico oath)],
126 description
=> "Yubico API ID.",
127 format_description
=> 'ID',
132 description
=> "Yubico API Key.",
133 format_description
=> 'KEY',
138 description
=> "Yubico API URL.",
139 format_description
=> 'URL',
144 description
=> "TOTP digits.",
145 format_description
=> 'COUNT',
147 minimum
=> 6, maximum
=> 8,
152 description
=> "TOTP time period.",
153 format_description
=> 'SECONDS',
161 PVE
::JSONSchema
::register_format
('pve-tfa-config', $tfa_format);
163 PVE
::JSONSchema
::register_standard_option
('tfa', {
164 description
=> "Use Two-factor authentication.",
165 type
=> 'string', format
=> 'pve-tfa-config',
170 sub parse_tfa_config
{
173 return PVE
::JSONSchema
::parse_property_string
($tfa_format, $data);
178 type
=> { description
=> "Realm type." },
179 realm
=> get_standard_option
('realm'),
187 sub parse_section_header
{
188 my ($class, $line) = @_;
190 if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
191 my ($type, $realm) = (lc($1), $2);
192 my $errmsg = undef; # set if you want to skip whole section
193 eval { pve_verify_realm
($realm); };
195 my $config = {}; # to return additional attributes
196 return ($type, $realm, $errmsg, $config);
202 my ($class, $filename, $raw) = @_;
204 my $cfg = $class->SUPER::parse_config
($filename, $raw);
207 foreach my $realm (keys %{$cfg->{ids
}}) {
208 my $data = $cfg->{ids
}->{$realm};
209 # make sure there is only one default marker
210 if ($data->{default}) {
212 delete $data->{default};
218 if ($data->{comment
}) {
219 $data->{comment
} = PVE
::Tools
::decode_text
($data->{comment
});
224 # add default domains
226 $cfg->{ids
}->{pve
}->{type
} = 'pve'; # force type
227 $cfg->{ids
}->{pve
}->{comment
} = "Proxmox VE authentication server"
228 if !$cfg->{ids
}->{pve
}->{comment
};
230 $cfg->{ids
}->{pam
}->{type
} = 'pam'; # force type
231 $cfg->{ids
}->{pam
}->{plugin
} = 'PVE::Auth::PAM';
232 $cfg->{ids
}->{pam
}->{comment
} = "Linux PAM standard authentication"
233 if !$cfg->{ids
}->{pam
}->{comment
};
239 my ($class, $filename, $cfg) = @_;
241 foreach my $realm (keys %{$cfg->{ids
}}) {
242 my $data = $cfg->{ids
}->{$realm};
243 if ($data->{comment
}) {
244 $data->{comment
} = PVE
::Tools
::encode_text
($data->{comment
});
248 $class->SUPER::write_config
($filename, $cfg);
251 sub authenticate_user
{
252 my ($class, $config, $realm, $username, $password) = @_;
258 my ($class, $config, $realm, $username, $password) = @_;
260 my $type = $class->type();
262 die "can't set password on auth type '$type'\n";
266 my ($class, $config, $realm, $username) = @_;
268 # do nothing by default
271 # called during addition of realm (before the new domain config got written)
272 # `password` is moved to %param to avoid writing it out to the config
273 # die to abort additon if there are (grave) problems
274 # NOTE: runs in a domain config *locked* context
276 my ($class, $realm, $config, %param) = @_;
277 # do nothing by default
280 # called during domain configuration update (before the updated domain config got
281 # written). `password` is moved to %param to avoid writing it out to the config
282 # die to abort the update if there are (grave) problems
283 # NOTE: runs in a domain config *locked* context
285 my ($class, $realm, $config, %param) = @_;
286 # do nothing by default
289 # called during deletion of realms (before the new domain config got written)
290 # and if the activate check on addition fails, to cleanup all storage traces
291 # which on_add_hook may have created.
292 # die to abort deletion if there are (very grave) problems
293 # NOTE: runs in a storage config *locked* context
295 my ($class, $realm, $config) = @_;
296 # do nothing by default