]>
git.proxmox.com Git - pve-access-control.git/blob - PVE/Auth/Plugin.pm
1 package PVE
::Auth
::Plugin
;
8 use PVE
::SectionConfig
;
9 use PVE
::JSONSchema
qw(get_standard_option);
10 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_lock_file);
12 use base
qw(PVE::SectionConfig);
14 my $domainconfigfile = "domains.cfg";
16 cfs_register_file
($domainconfigfile,
17 sub { __PACKAGE__-
>parse_config(@_); },
18 sub { __PACKAGE__-
>write_config(@_); });
20 sub lock_domain_config
{
21 my ($code, $errmsg) = @_;
23 cfs_lock_file
($domainconfigfile, undef, $code);
26 $errmsg ?
die "$errmsg: $err" : die $err;
30 our $realm_regex = qr/[A-Za-z][A-Za-z0-9\.\-_]+/;
31 our $user_regex = qr![^\s:/]+!;
33 PVE
::JSONSchema
::register_format
('pve-realm', \
&pve_verify_realm
);
34 sub pve_verify_realm
{
35 my ($realm, $noerr) = @_;
37 if ($realm !~ m/^${realm_regex}$/) {
38 return undef if $noerr;
39 die "value does not look like a valid realm\n";
44 PVE
::JSONSchema
::register_standard_option
('realm', {
45 description
=> "Authentication domain ID",
46 type
=> 'string', format
=> 'pve-realm',
50 my $realm_sync_options_desc = {
52 description
=> "Select what to sync.",
54 enum
=> [qw(users groups both)],
58 description
=> "If set, uses the LDAP Directory as source of truth,"
59 ." deleting users or groups not returned from the sync. Otherwise"
60 ." only syncs information which is not already present, and does not"
61 ." deletes or modifies anything else.",
66 description
=> "Enable newly synced users immediately.",
72 description
=> "Remove ACLs for users or groups which were removed from"
73 ." the config during a sync.",
78 PVE
::JSONSchema
::register_standard_option
('realm-sync-options', $realm_sync_options_desc);
79 PVE
::JSONSchema
::register_format
('realm-sync-options', $realm_sync_options_desc);
81 PVE
::JSONSchema
::register_format
('pve-userid', \
&verify_username
);
83 my ($username, $noerr) = @_;
85 $username = '' if !$username;
86 my $len = length($username);
88 die "user name '$username' is too short\n" if !$noerr;
92 die "user name '$username' is too long ($len > 64)\n" if !$noerr;
96 # we only allow a limited set of characters
97 # colon is not allowed, because we store usernames in
98 # colon separated lists)!
99 # slash is not allowed because it is used as pve API delimiter
100 # also see "man useradd"
101 if ($username =~ m!^(${user_regex})\@(${realm_regex})$!) {
102 return wantarray ?
($username, $1, $2) : $username;
105 die "value '$username' does not look like a valid user name\n" if !$noerr;
110 PVE
::JSONSchema
::register_standard_option
('userid', {
111 description
=> "User ID",
112 type
=> 'string', format
=> 'pve-userid',
118 description
=> "The type of 2nd factor authentication.",
119 format_description
=> 'TFATYPE',
121 enum
=> [qw(yubico oath)],
124 description
=> "Yubico API ID.",
125 format_description
=> 'ID',
130 description
=> "Yubico API Key.",
131 format_description
=> 'KEY',
136 description
=> "Yubico API URL.",
137 format_description
=> 'URL',
142 description
=> "TOTP digits.",
143 format_description
=> 'COUNT',
145 minimum
=> 6, maximum
=> 8,
150 description
=> "TOTP time period.",
151 format_description
=> 'SECONDS',
159 PVE
::JSONSchema
::register_format
('pve-tfa-config', $tfa_format);
161 PVE
::JSONSchema
::register_standard_option
('tfa', {
162 description
=> "Use Two-factor authentication.",
163 type
=> 'string', format
=> 'pve-tfa-config',
168 sub parse_tfa_config
{
171 return PVE
::JSONSchema
::parse_property_string
($tfa_format, $data);
176 type
=> { description
=> "Realm type." },
177 realm
=> get_standard_option
('realm'),
185 sub parse_section_header
{
186 my ($class, $line) = @_;
188 if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
189 my ($type, $realm) = (lc($1), $2);
190 my $errmsg = undef; # set if you want to skip whole section
191 eval { pve_verify_realm
($realm); };
193 my $config = {}; # to return additional attributes
194 return ($type, $realm, $errmsg, $config);
200 my ($class, $filename, $raw) = @_;
202 my $cfg = $class->SUPER::parse_config
($filename, $raw);
205 foreach my $realm (keys %{$cfg->{ids
}}) {
206 my $data = $cfg->{ids
}->{$realm};
207 # make sure there is only one default marker
208 if ($data->{default}) {
210 delete $data->{default};
216 if ($data->{comment
}) {
217 $data->{comment
} = PVE
::Tools
::decode_text
($data->{comment
});
222 # add default domains
224 $cfg->{ids
}->{pve
}->{type
} = 'pve'; # force type
225 $cfg->{ids
}->{pve
}->{comment
} = "Proxmox VE authentication server"
226 if !$cfg->{ids
}->{pve
}->{comment
};
228 $cfg->{ids
}->{pam
}->{type
} = 'pam'; # force type
229 $cfg->{ids
}->{pam
}->{plugin
} = 'PVE::Auth::PAM';
230 $cfg->{ids
}->{pam
}->{comment
} = "Linux PAM standard authentication"
231 if !$cfg->{ids
}->{pam
}->{comment
};
237 my ($class, $filename, $cfg) = @_;
239 foreach my $realm (keys %{$cfg->{ids
}}) {
240 my $data = $cfg->{ids
}->{$realm};
241 if ($data->{comment
}) {
242 $data->{comment
} = PVE
::Tools
::encode_text
($data->{comment
});
246 $class->SUPER::write_config
($filename, $cfg);
249 sub authenticate_user
{
250 my ($class, $config, $realm, $username, $password) = @_;
256 my ($class, $config, $realm, $username, $password) = @_;
258 my $type = $class->type();
260 die "can't set password on auth type '$type'\n";
264 my ($class, $config, $realm, $username) = @_;
266 # do nothing by default