← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 19:05:14 2015
Reported on Fri Jul 31 19:08:09 2015

Filename/var/www/foswiki11/lib/Foswiki/Users/BaseUserMapping.pm
StatementsExecuted 13849 statements in 20.9ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
378119.02ms9.79msFoswiki::Users::BaseUserMapping::::findUserByWikiNameFoswiki::Users::BaseUserMapping::findUserByWikiName
1987225.12ms5.12msFoswiki::Users::BaseUserMapping::::handlesUserFoswiki::Users::BaseUserMapping::handlesUser
753331.40ms1.40msFoswiki::Users::BaseUserMapping::::isGroupFoswiki::Users::BaseUserMapping::isGroup
1111.07ms8.86msFoswiki::Users::BaseUserMapping::::BEGIN@33Foswiki::Users::BaseUserMapping::BEGIN@33
111730µs782µsFoswiki::Users::BaseUserMapping::::BEGIN@39Foswiki::Users::BaseUserMapping::BEGIN@39
11165µs74µsFoswiki::Users::BaseUserMapping::::newFoswiki::Users::BaseUserMapping::new
11147µs52µsFoswiki::Users::BaseUserMapping::::finishFoswiki::Users::BaseUserMapping::finish
41144µs82µsFoswiki::Users::BaseUserMapping::::eachGroupMemberFoswiki::Users::BaseUserMapping::eachGroupMember
11116µs122µsFoswiki::Users::BaseUserMapping::::isAdminFoswiki::Users::BaseUserMapping::isAdmin
11114µs28µsFoswiki::Users::BaseUserMapping::::BEGIN@30Foswiki::Users::BaseUserMapping::BEGIN@30
11111µs26µsFoswiki::Users::BaseUserMapping::::BEGIN@36Foswiki::Users::BaseUserMapping::BEGIN@36
11110µs40µsFoswiki::Users::BaseUserMapping::::BEGIN@38Foswiki::Users::BaseUserMapping::BEGIN@38
11110µs15µsFoswiki::Users::BaseUserMapping::::BEGIN@31Foswiki::Users::BaseUserMapping::BEGIN@31
1114µs4µsFoswiki::Users::BaseUserMapping::::BEGIN@37Foswiki::Users::BaseUserMapping::BEGIN@37
0000s0sFoswiki::Users::BaseUserMapping::::__ANON__[:342]Foswiki::Users::BaseUserMapping::__ANON__[:342]
0000s0sFoswiki::Users::BaseUserMapping::::checkPasswordFoswiki::Users::BaseUserMapping::checkPassword
0000s0sFoswiki::Users::BaseUserMapping::::eachGroupFoswiki::Users::BaseUserMapping::eachGroup
0000s0sFoswiki::Users::BaseUserMapping::::eachMembershipFoswiki::Users::BaseUserMapping::eachMembership
0000s0sFoswiki::Users::BaseUserMapping::::eachUserFoswiki::Users::BaseUserMapping::eachUser
0000s0sFoswiki::Users::BaseUserMapping::::getEmailsFoswiki::Users::BaseUserMapping::getEmails
0000s0sFoswiki::Users::BaseUserMapping::::getLoginNameFoswiki::Users::BaseUserMapping::getLoginName
0000s0sFoswiki::Users::BaseUserMapping::::getWikiNameFoswiki::Users::BaseUserMapping::getWikiName
0000s0sFoswiki::Users::BaseUserMapping::::groupAllowsChangeFoswiki::Users::BaseUserMapping::groupAllowsChange
0000s0sFoswiki::Users::BaseUserMapping::::login2cUIDFoswiki::Users::BaseUserMapping::login2cUID
0000s0sFoswiki::Users::BaseUserMapping::::loginTemplateNameFoswiki::Users::BaseUserMapping::loginTemplateName
0000s0sFoswiki::Users::BaseUserMapping::::passwordErrorFoswiki::Users::BaseUserMapping::passwordError
0000s0sFoswiki::Users::BaseUserMapping::::setPasswordFoswiki::Users::BaseUserMapping::setPassword
0000s0sFoswiki::Users::BaseUserMapping::::userExistsFoswiki::Users::BaseUserMapping::userExists
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Users::BaseUserMapping
6
7User mapping is the process by which Foswiki maps from a username
8(a login name)
9to a display name and back. It is also where groups are maintained.
10
11The BaseMapper provides support for a small number of predefined users.
12No registration - this is a read only usermapper. It uses the mapper
13prefix 'BaseUserMapping_'.
14
15---++ Users
16 * $Foswiki::cfg{AdminUserLogin} - uses the password that
17 was set in Configure (IF its not null)
18 * $Foswiki::cfg{DefaultUserLogin} - WikiGuest
19 * UnknownUser
20 * ProjectContributor
21 * $Foswiki::cfg{Register}{RegistrationAgentWikiName}
22
23---+++ Groups
24 * $Foswiki::cfg{SuperAdminGroup}
25 * BaseGroup
26
27=cut
28
29package Foswiki::Users::BaseUserMapping;
30229µs241µs
# spent 28µs (14+14) within Foswiki::Users::BaseUserMapping::BEGIN@30 which was called: # once (14µs+14µs) by Foswiki::Users::new at line 30
use strict;
# spent 28µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@30 # spent 14µs making 1 call to strict::import
31225µs221µs
# spent 15µs (10+6) within Foswiki::Users::BaseUserMapping::BEGIN@31 which was called: # once (10µs+6µs) by Foswiki::Users::new at line 31
use warnings;
# spent 15µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@31 # spent 6µs making 1 call to warnings::import
32
332123µs18.86ms
# spent 8.86ms (1.07+7.79) within Foswiki::Users::BaseUserMapping::BEGIN@33 which was called: # once (1.07ms+7.79ms) by Foswiki::Users::new at line 33
use Foswiki::UserMapping ();
# spent 8.86ms making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@33
3418µsour @ISA = ('Foswiki::UserMapping');
35
36226µs242µs
# spent 26µs (11+16) within Foswiki::Users::BaseUserMapping::BEGIN@36 which was called: # once (11µs+16µs) by Foswiki::Users::new at line 36
use Assert;
# spent 26µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@36 # spent 16µs making 1 call to Assert::import
37224µs14µs
# spent 4µs within Foswiki::Users::BaseUserMapping::BEGIN@37 which was called: # once (4µs+0s) by Foswiki::Users::new at line 37
use Error ();
# spent 4µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@37
38228µs270µs
# spent 40µs (10+30) within Foswiki::Users::BaseUserMapping::BEGIN@38 which was called: # once (10µs+30µs) by Foswiki::Users::new at line 38
use Digest::MD5 qw(md5_hex);
# spent 40µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@38 # spent 30µs making 1 call to Exporter::import
3921.35ms2808µs
# spent 782µs (730+52) within Foswiki::Users::BaseUserMapping::BEGIN@39 which was called: # once (730µs+52µs) by Foswiki::Users::new at line 39
use Crypt::PasswdMD5 qw(apache_md5_crypt);
# spent 782µs making 1 call to Foswiki::Users::BaseUserMapping::BEGIN@39 # spent 25µs making 1 call to Exporter::import
40
411500nsour $DEFAULT_USER_CUID = 'BaseUserMapping_666';
421200nsour $UNKNOWN_USER_CUID = 'BaseUserMapping_999';
431200nsour %BASE_USERS;
441100nsour %BASE_GROUPS;
45
46=begin TML
47
48---++ ClassMethod new ($session)
49
50Construct the BaseUserMapping object
51
52=cut
53
54# Constructs a new user mapping handler of this type, referring to $session
55# for any required Foswiki services.
56
# spent 74µs (65+9) within Foswiki::Users::BaseUserMapping::new which was called: # once (65µs+9µs) by Foswiki::Users::new at line 92 of /var/www/foswiki11/lib/Foswiki/Users.pm
sub new {
571800ns my ( $class, $session ) = @_;
58
59 # $DEFAULT_USER_CUID , $UNKNOWN_USER_CUID, %BASE_USERS and %BASE_GROUPS
60 # could be initialised statically, but tests have been written that rely
61 # on being able to override the $Foswiki::cfg settings that are part of
62 # them. Since it's a low cost op to re-initialise them each time this
63 # singleton is built, we will contiue to do so (at least until those
64 # tests have been revisited)
651200ns $DEFAULT_USER_CUID = 'BaseUserMapping_666';
661100ns $UNKNOWN_USER_CUID = 'BaseUserMapping_999';
67112µs %BASE_USERS = (
68 BaseUserMapping_111 => {
69 login => 'ProjectContributor',
70 wikiname => 'ProjectContributor',
71 },
72 BaseUserMapping_222 => {
73 login => $Foswiki::cfg{Register}{RegistrationAgentWikiName}
74 || 'RegistrationAgent',
75 wikiname => $Foswiki::cfg{Register}{RegistrationAgentWikiName}
76 || 'RegistrationAgent',
77 },
78 BaseUserMapping_333 => {
79 login => $Foswiki::cfg{AdminUserLogin} || 'admin',
80 wikiname => $Foswiki::cfg{AdminUserWikiName} || 'AdminUser',
81 email => $Foswiki::cfg{WebMasterEmail} || 'email not set',
82 password => $Foswiki::cfg{Password},
83 },
84 $DEFAULT_USER_CUID => {
85 login => $Foswiki::cfg{DefaultUserLogin} || 'guest',
86 wikiname => $Foswiki::cfg{DefaultUserWikiName} || 'WikiGuest',
87 },
88 $UNKNOWN_USER_CUID => {
89 login => 'unknown',
90 wikiname => 'UnknownUser',
91 }
92 );
9313µs %BASE_GROUPS = (
94 $Foswiki::cfg{SuperAdminGroup} => [
95 'BaseUserMapping_333',
96
97# Registration agent was here so registration can still take
98# place on an otherwise locked down USERSWEB.
99# Jan2010: Sven removed it, otherwise anyone registering can add themselves as admin.
100#'BaseUserMapping_222'
101 ],
102 BaseGroup => [
103 'BaseUserMapping_333', $DEFAULT_USER_CUID,
104 $UNKNOWN_USER_CUID, 'BaseUserMapping_111',
105 'BaseUserMapping_222',
106 ],
107
108 # RegistrationGroup => ['BaseUserMapping_222']
109 );
110
111115µs19µs my $this = $class->SUPER::new( $session, 'BaseUserMapping_' );
# spent 9µs making 1 call to Foswiki::UserMapping::new
1121600ns $Foswiki::cfg{Register}{RegistrationAgentWikiName} ||= 'RegistrationAgent';
113
114 # set up our users
1151500ns $this->{L2U} = {}; # login 2 cUID
1161300ns $this->{U2L} = {}; # cUID 2 login
1171300ns $this->{W2U} = {}; # wikiname 2 cUID
1181300ns $this->{U2W} = {}; # cUID 2 wikiname
1191300ns $this->{U2E} = {}; # cUID 2 email
1201600ns $this->{L2P} = {}; # login 2 password
121
12217µs while ( my ( $k, $v ) = each %BASE_USERS ) {
12353µs $this->{U2L}->{$k} = $v->{login};
12453µs $this->{U2W}->{$k} = $v->{wikiname};
12552µs $this->{U2E}->{$k} = $v->{email} if defined $v->{email};
126
12754µs $this->{L2U}->{ $v->{login} } = $k;
12852µs $this->{L2P}->{ $v->{login} } = $v->{password}
129 if defined $v->{password};
130
13153µs $this->{W2U}->{ $v->{wikiname} } = $k;
132 }
133
13412µs %{ $this->{GROUPS} } = %BASE_GROUPS;
135
13614µs return $this;
137}
138
139=begin TML
140
141---++ ObjectMethod finish()
142Break circular references.
143
144=cut
145
146# Note to developers; please undef *all* fields in the object explicitly,
147# whether they are references or not. That way this method is "golden
148# documentation" of the live fields in the object.
149
# spent 52µs (47+5) within Foswiki::Users::BaseUserMapping::finish which was called: # once (47µs+5µs) by Foswiki::Users::finish at line 163 of /var/www/foswiki11/lib/Foswiki/Users.pm
sub finish {
1501400ns my $this = shift;
15118µs undef $this->{U2L};
15212µs undef $this->{U2W};
1531800ns undef $this->{L2P};
15411µs undef $this->{U2E};
15514µs undef $this->{L2U};
15615µs undef $this->{W2U};
15712µs undef $this->{GROUPS};
158122µs15µs $this->SUPER::finish();
# spent 5µs making 1 call to Foswiki::UserMapping::finish
159}
160
161=begin TML
162
163---++ ObjectMethod loginTemplateName () -> templateFile
164
165allows UserMappings to come with customised login screens - that should preffereably only over-ride the UI function
166
167=cut
168
169sub loginTemplateName {
170 return 'login.sudo';
171}
172
173=begin TML
174
175---++ ObjectMethod handlesUser ( $cUID, $login, $wikiname) -> $boolean
176
177See baseclass for documentation.
178
179In the BaseUserMapping case, we know all
180the details of the users we specialise in.
181
182=cut
183
184
# spent 5.12ms within Foswiki::Users::BaseUserMapping::handlesUser which was called 1987 times, avg 3µs/call: # 1069 times (2.32ms+0s) by Foswiki::Users::TopicUserMapping::_cacheUser at line 1595 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 2µs/call # 918 times (2.80ms+0s) by Foswiki::Users::_getMapping at line 211 of /var/www/foswiki11/lib/Foswiki/Users.pm, avg 3µs/call
sub handlesUser {
18519871.09ms my ( $this, $cUID, $login, $wikiname ) = @_;
186
1871987316µs return 1 if ( defined($cUID) && defined( $this->{U2L}{$cUID} ) );
1881987915µs return 1 if ( defined($login) && defined( $this->{L2U}{$login} ) );
18919831.56ms return 1 if ( defined($wikiname) && defined( $this->{W2U}{$wikiname} ) );
190
19116593.80ms return 0;
192}
193
194=begin TML
195
196---++ ObjectMethod login2cUID ($login) -> $cUID
197
198Convert a login name to the corresponding canonical user name. The
199canonical name can be any string of 7-bit alphanumeric and underscore
200characters, and must correspond 1:1 to the login name.
201(undef on failure)
202
203=cut
204
205sub login2cUID {
206 my ( $this, $login ) = @_;
207
208 return $this->{L2U}{$login};
209
210 #alternative impl - slower, but more re-useable
211 #my @list = findUserByWikiName($this, $login);
212 #return shift @list;
213}
214
215=begin TML
216
217---++ ObjectMethod getLoginName ($cUID) -> login
218
219converts an internal cUID to that user's login
220(undef on failure)
221
222=cut
223
224sub getLoginName {
225 my ( $this, $user ) = @_;
226 return $this->{U2L}{$user};
227}
228
229=begin TML
230
231---++ ObjectMethod getWikiName ($cUID) -> wikiname
232
233Map a canonical user name to a wikiname
234
235=cut
236
237sub getWikiName {
238 my ( $this, $cUID ) = @_;
239 return $this->{U2W}->{$cUID} || getLoginName( $this, $cUID );
240}
241
242=begin TML
243
244---++ ObjectMethod userExists( $user ) -> $boolean
245
246Determine if the user already exists or not.
247
248=cut
249
250sub userExists {
251 my ( $this, $cUID ) = @_;
252 ASSERT($cUID) if DEBUG;
253 return 0 unless defined $cUID;
254 return $this->{U2L}{$cUID};
255}
256
257=begin TML
258
259---++ ObjectMethod eachUser () -> listIterator of cUIDs
260
261See baseclass for documentation.
262
263=cut
264
265sub eachUser {
266 my ($this) = @_;
267
268 my @list = keys( %{ $this->{U2W} } );
269 require Foswiki::ListIterator;
270 return new Foswiki::ListIterator( \@list );
271}
272
273=begin TML
274
275---++ ObjectMethod eachGroupMember ($group) -> listIterator of cUIDs
276
277See baseclass for documentation.
278
279The basemapper implementation assumes that there are no nested groups in the
280basemapper.
281
282=cut
283
284
# spent 82µs (44+38) within Foswiki::Users::BaseUserMapping::eachGroupMember which was called 4 times, avg 21µs/call: # 4 times (44µs+38µs) by Foswiki::UserMapping::isInGroup at line 419 of /var/www/foswiki11/lib/Foswiki/UserMapping.pm, avg 21µs/call
sub eachGroupMember {
28543µs my $this = shift;
28643µs my $group = shift;
287
28844µs my $members = $this->{GROUPS}{$group};
289
290 #print STDERR "eachGroupMember($group): ".join(',', @{$members});
291
29243µs require Foswiki::ListIterator;
293425µs438µs return new Foswiki::ListIterator($members);
# spent 38µs making 4 calls to Foswiki::ListIterator::new, avg 10µs/call
294}
295
296=begin TML
297
298---++ ObjectMethod isGroup ($name) -> boolean
299
300See baseclass for documentation.
301
302=cut
303
304
# spent 1.40ms within Foswiki::Users::BaseUserMapping::isGroup which was called 753 times, avg 2µs/call: # 378 times (769µs+0s) by Foswiki::Users::BaseUserMapping::findUserByWikiName at line 406, avg 2µs/call # 374 times (629µs+0s) by Foswiki::Users::isGroup at line 839 of /var/www/foswiki11/lib/Foswiki/Users.pm, avg 2µs/call # once (7µs+0s) by Foswiki::UserMapping::isInGroup at line 426 of /var/www/foswiki11/lib/Foswiki/UserMapping.pm
sub isGroup {
305753319µs my ( $this, $name ) = @_;
306753130µs $name ||= "";
307
308 #TODO: what happens to the code if we implement this using an iterator too?
3097538.23ms return ( $this->{GROUPS}->{$name} );
310}
311
312=begin TML
313
314---++ ObjectMethod eachGroup () -> ListIterator of groupnames
315
316See baseclass for documentation.
317
318=cut
319
320sub eachGroup {
321 my ($this) = @_;
322 my @groups = keys( %{ $this->{GROUPS} } );
323
324 require Foswiki::ListIterator;
325 return new Foswiki::ListIterator( \@groups );
326}
327
328=begin TML
329
330---++ ObjectMethod eachMembership ($cUID) -> ListIterator of groups this user is in
331
332See baseclass for documentation.
333
334=cut
335
336sub eachMembership {
337 my ( $this, $cUID ) = @_;
338
339 my $it = $this->eachGroup();
340 $it->{filter} = sub {
341 $this->isInGroup( $cUID, $_[0] );
342 };
343 return $it;
344}
345
346=begin TML
347
348---++ ObjectMethod groupAllowsChange($group) -> boolean
349
350returns 0 if the group is 'owned by the BaseMapper and it wants to veto adding to that group
351
352=cut
353
354sub groupAllowsChange {
355 my $this = shift;
356 my $group = shift;
357 ASSERT( defined $group ) if DEBUG;
358
359 return 0
360 if ( ( $group eq 'BaseGroup' )
361 or ( $group eq 'RegistrationGroup' ) );
362 return 1;
363}
364
365=begin TML
366
367---++ ObjectMethod isAdmin( $cUID ) -> $boolean
368
369True if the user is an admin
370 * is a member of the $Foswiki::cfg{SuperAdminGroup}
371
372=cut
373
374
# spent 122µs (16+106) within Foswiki::Users::BaseUserMapping::isAdmin which was called: # once (16µs+106µs) by Foswiki::Users::isAdmin at line 626 of /var/www/foswiki11/lib/Foswiki/Users.pm
sub isAdmin {
37511µs my ( $this, $cUID ) = @_;
376116µs1106µs return $this->isInGroup( $cUID, $Foswiki::cfg{SuperAdminGroup} );
# spent 106µs making 1 call to Foswiki::UserMapping::isInGroup
377}
378
379=begin TML
380
381---++ ObjectMethod getEmails($name) -> @emailAddress
382
383If $name is a cUID, return their email addresses. If it is a group,
384return the addresses of everyone in the group.
385
386=cut
387
388sub getEmails {
389 my ( $this, $user ) = @_;
390
391 return $this->{U2E}{$user} || ();
392}
393
394=begin TML
395
396---++ ObjectMethod findUserByWikiName ($wikiname) -> list of cUIDs associated with that wikiname
397
398See baseclass for documentation.
399
400=cut
401
402
# spent 9.79ms (9.02+769µs) within Foswiki::Users::BaseUserMapping::findUserByWikiName which was called 378 times, avg 26µs/call: # 378 times (9.02ms+769µs) by Foswiki::Users::findUserByWikiName at line 535 of /var/www/foswiki11/lib/Foswiki/Users.pm, avg 26µs/call
sub findUserByWikiName {
403378206µs my ( $this, $wn ) = @_;
404378179µs my @users = ();
405
406378628µs378769µs if ( $this->isGroup($wn) ) {
# spent 769µs making 378 calls to Foswiki::Users::BaseUserMapping::isGroup, avg 2µs/call
407 push( @users, $wn );
408 }
409 else {
410
411 # Add additional mappings defined in WikiUsers
412378625µs if ( $this->{W2U}->{$wn} ) {
413 push( @users, $this->{W2U}->{$wn} );
414 }
415 elsif ( $this->{L2U}->{$wn} ) {
416
417 # The wikiname is also a login name for the purposes of this
418 # mapping. We have to do this because Foswiki defines access controls
419 # in terms of mapped users, and if a wikiname is *missing* from the
420 # mapping there is "no such user".
421 push( @users, $this->{L2U}->{$wn} );
422 }
423 }
4243781.11ms return \@users;
425}
426
427=begin TML
428
429---++ ObjectMethod checkPassword( $login, $passwordU ) -> $boolean
430
431Finds if the password is valid for the given user.
432
433Returns 1 on success, undef on failure.
434
435=cut
436
437sub checkPassword {
438 my ( $this, $login, $pass ) = @_;
439
440 my $hash = $this->{L2P}->{$login};
441
442 if ($hash) {
443 if ( length($hash) == 13 ) {
444 return 1 if ( crypt( $pass, $hash ) eq $hash );
445 }
446 elsif ( length($hash) == 42 ) {
447 my $salt = substr( $hash, 0, 10 );
448 return 1
449 if ( $salt . Digest::MD5::md5_hex( $salt . $pass ) eq $hash );
450 }
451 else {
452 my $salt = substr( $hash, 0, 14 );
453 return 1
454 if (
455 Crypt::PasswdMD5::apache_md5_crypt( $pass, $salt ) eq $hash );
456 }
457 }
458
459 # be a little more helpful to the admin
460 if ( $login eq $Foswiki::cfg{AdminUserLogin} && !$hash ) {
461 $this->{error} =
462 'To login as ' . $login . ', you must set {Password} in configure.';
463 }
464 return 0;
465}
466
467=begin TML
468
469---++ ObjectMethod setPassword( $cUID, $newPassU, $oldPassU ) -> $boolean
470
471If the $oldPassU matches matches the user's password, then it will
472replace it with $newPassU.
473
474If $oldPassU is not correct and not 1, will return 0.
475
476If $oldPassU is 1, will force the change irrespective of
477the existing password, adding the user if necessary.
478
479Otherwise returns 1 on success, undef on failure.
480
481=cut
482
483sub setPassword {
484 my ( $this, $cUID, $newPassU, $oldPassU ) = @_;
485 throw Error::Simple(
486 'cannot change user passwords using Foswiki::BaseUserMapping');
487}
488
489=begin TML
490
491---++ ObjectMethod passwordError( ) -> $string
492
493returns a string indicating the error that happened in the password handlers
494TODO: these delayed error's should be replaced with Exceptions.
495
496returns undef if no error
497
498=cut
499
500sub passwordError {
501 my $this = shift;
502
503 return $this->{error};
504}
505
50614µs1;
507__END__