]>
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