← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/UserMapping.pm
StatementsExecuted 36 statements in 1.15ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
11133µs73µsFoswiki::UserMapping::::isInGroupFoswiki::UserMapping::isInGroup
22217µs17µsFoswiki::UserMapping::::newFoswiki::UserMapping::new
11113µs17µsFoswiki::UserMapping::::BEGIN@36Foswiki::UserMapping::BEGIN@36
11112µs24µsFoswiki::UserMapping::::BEGIN@35Foswiki::UserMapping::BEGIN@35
1119µs32µsFoswiki::UserMapping::::BEGIN@37Foswiki::UserMapping::BEGIN@37
2228µs8µsFoswiki::UserMapping::::finishFoswiki::UserMapping::finish
1116µs6µsFoswiki::UserMapping::::BEGIN@39Foswiki::UserMapping::BEGIN@39
1115µs5µsFoswiki::UserMapping::::BEGIN@38Foswiki::UserMapping::BEGIN@38
1113µs3µsFoswiki::UserMapping::::BEGIN@41Foswiki::UserMapping::BEGIN@41
0000s0sFoswiki::UserMapping::::addUserFoswiki::UserMapping::addUser
0000s0sFoswiki::UserMapping::::addUserToGroupFoswiki::UserMapping::addUserToGroup
0000s0sFoswiki::UserMapping::::checkPasswordFoswiki::UserMapping::checkPassword
0000s0sFoswiki::UserMapping::::eachGroupFoswiki::UserMapping::eachGroup
0000s0sFoswiki::UserMapping::::eachGroupMemberFoswiki::UserMapping::eachGroupMember
0000s0sFoswiki::UserMapping::::eachMembershipFoswiki::UserMapping::eachMembership
0000s0sFoswiki::UserMapping::::eachUserFoswiki::UserMapping::eachUser
0000s0sFoswiki::UserMapping::::findUserByEmailFoswiki::UserMapping::findUserByEmail
0000s0sFoswiki::UserMapping::::findUserByWikiNameFoswiki::UserMapping::findUserByWikiName
0000s0sFoswiki::UserMapping::::getEmailsFoswiki::UserMapping::getEmails
0000s0sFoswiki::UserMapping::::getLoginNameFoswiki::UserMapping::getLoginName
0000s0sFoswiki::UserMapping::::getWikiNameFoswiki::UserMapping::getWikiName
0000s0sFoswiki::UserMapping::::groupAllowsChangeFoswiki::UserMapping::groupAllowsChange
0000s0sFoswiki::UserMapping::::groupAllowsViewFoswiki::UserMapping::groupAllowsView
0000s0sFoswiki::UserMapping::::handlesUserFoswiki::UserMapping::handlesUser
0000s0sFoswiki::UserMapping::::isAdminFoswiki::UserMapping::isAdmin
0000s0sFoswiki::UserMapping::::isGroupFoswiki::UserMapping::isGroup
0000s0sFoswiki::UserMapping::::login2cUIDFoswiki::UserMapping::login2cUID
0000s0sFoswiki::UserMapping::::loginTemplateNameFoswiki::UserMapping::loginTemplateName
0000s0sFoswiki::UserMapping::::passwordErrorFoswiki::UserMapping::passwordError
0000s0sFoswiki::UserMapping::::removeUserFoswiki::UserMapping::removeUser
0000s0sFoswiki::UserMapping::::removeUserFromGroupFoswiki::UserMapping::removeUserFromGroup
0000s0sFoswiki::UserMapping::::setEmailsFoswiki::UserMapping::setEmails
0000s0sFoswiki::UserMapping::::setPasswordFoswiki::UserMapping::setPassword
0000s0sFoswiki::UserMapping::::supportsRegistrationFoswiki::UserMapping::supportsRegistration
0000s0sFoswiki::UserMapping::::userExistsFoswiki::UserMapping::userExists
0000s0sFoswiki::UserMapping::::validateRegistrationFieldFoswiki::UserMapping::validateRegistrationField
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::UserMapping
6
7This is a virtual base class (a.k.a an interface) for all user mappers. It is
8*not* useable as a mapping in Foswiki - use the BaseUserMapping for default
9behaviour.
10
11User mapping is the process by which Foswiki maps from a username (a login name)
12to a display name and back. It is also where groups are maintained.
13
14See Foswiki::Users::BaseUserMapping and Foswiki::Users::TopicUserMapping for
15the default implementations of this interface.
16
17If you want to write a user mapper, you will need to implement the methods
18described in this class.
19
20User mappings work by mapping both login names and display names to a
21_canonical user id_. This user id is composed from a prefix that defines
22the mapper in use (something like 'BaseUserMapping_' or 'LdapUserMapping_')
23and a unique user id that the mapper uses to identify the user.
24
25The null prefix is reserver for the TopicUserMapping for compatibility
26with old Foswiki releases.
27
28__Note:__ in all the following documentation, =$cUID= refers to a
29*canonical user id*.
30
31=cut
32
33package Foswiki::UserMapping;
34
35225µs236µs
# spent 24µs (12+12) within Foswiki::UserMapping::BEGIN@35 which was called: # once (12µs+12µs) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 35
use strict;
# spent 24µs making 1 call to Foswiki::UserMapping::BEGIN@35 # spent 12µs making 1 call to strict::import
36229µs220µs
# spent 17µs (13+4) within Foswiki::UserMapping::BEGIN@36 which was called: # once (13µs+4µs) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 36
use warnings;
# spent 17µs making 1 call to Foswiki::UserMapping::BEGIN@36 # spent 4µs making 1 call to warnings::import
37224µs256µs
# spent 32µs (9+24) within Foswiki::UserMapping::BEGIN@37 which was called: # once (9µs+24µs) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 37
use Assert;
# spent 32µs making 1 call to Foswiki::UserMapping::BEGIN@37 # spent 24µs making 1 call to Exporter::import
38219µs15µs
# spent 5µs within Foswiki::UserMapping::BEGIN@38 which was called: # once (5µs+0s) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 38
use Error ();
# spent 5µs making 1 call to Foswiki::UserMapping::BEGIN@38
39242µs16µs
# spent 6µs within Foswiki::UserMapping::BEGIN@39 which was called: # once (6µs+0s) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 39
use Foswiki::Func;
# spent 6µs making 1 call to Foswiki::UserMapping::BEGIN@39
40
41
# spent 3µs within Foswiki::UserMapping::BEGIN@41 which was called: # once (3µs+0s) by Foswiki::Users::BaseUserMapping::BEGIN@33 at line 46
BEGIN {
4214µs if ( $Foswiki::cfg{UseLocale} ) {
43 require locale;
44 import locale();
45 }
461935µs13µs}
# spent 3µs making 1 call to Foswiki::UserMapping::BEGIN@41
47
48=begin TML
49
50---++ PROTECTED ClassMethod new ($session, $mapping_id)
51
52Construct a user mapping object, using the given mapping id.
53
54=cut
55
56
# spent 17µs within Foswiki::UserMapping::new which was called 2 times, avg 9µs/call: # once (9µs+0s) by Foswiki::Users::TopicUserMapping::new at line 59 of /var/www/foswikidev/core/lib/Foswiki/Users/TopicUserMapping.pm # once (8µs+0s) by Foswiki::Users::BaseUserMapping::new at line 119 of /var/www/foswikidev/core/lib/Foswiki/Users/BaseUserMapping.pm
sub new {
5722µs my ( $class, $session, $mid ) = @_;
58212µs my $this = bless(
59 {
60 mapping_id => $mid || '',
61 session => $session,
62 },
63 $class
64 );
65211µs return $this;
66}
67
68=begin TML
69
70---++ ObjectMethod finish()
71Break circular references.
72
73=cut
74
75
# spent 8µs within Foswiki::UserMapping::finish which was called 2 times, avg 4µs/call: # once (4µs+0s) by Foswiki::Users::BaseUserMapping::finish at line 166 of /var/www/foswikidev/core/lib/Foswiki/Users/BaseUserMapping.pm # once (3µs+0s) by Foswiki::Users::TopicUserMapping::finish at line 104 of /var/www/foswikidev/core/lib/Foswiki/Users/TopicUserMapping.pm
sub finish {
762900ns my $this = shift;
7722µs undef $this->{mapping_id};
78210µs undef $this->{session};
79}
80
81=begin TML
82
83---++ ObjectMethod loginTemplateName () -> $templateFile
84
85Allows UserMappings to come with customised login screens - that should
86preferably only over-ride the UI function
87
88Default is "login"
89
90=cut
91
92sub loginTemplateName {
93 return 'login';
94}
95
96=begin TML
97
98---++ ObjectMethod supportsRegistration() -> $boolean
99
100Return true if the UserMapper supports registration (ie can create new users)
101
102Default is *false*
103
104=cut
105
106sub supportsRegistration {
107 return 0; # NO, we don't
108}
109
110=begin TML
111
112---++ ObjectMethod handlesUser ( $cUID, $login, $wikiname) -> $boolean
113
114Called by the Foswiki::Users object to determine which loaded mapping
115to use for a given user (must be fast).
116
117The user can be identified by any of $cUID, $login or $wikiname. Any of
118these parameters may be undef, and they should be tested in order; cUID
119first, then login, then wikiname.
120
121=cut
122
123sub handlesUser {
124 return 0;
125}
126
127=begin TML
128
129---++ ObjectMethod login2cUID($login, $dontcheck) -> cUID
130
131Convert a login name to the corresponding canonical user name. The
132canonical name can be any string of 7-bit alphanumeric and underscore
133characters, and must map 1:1 to the login name.
134(undef on failure)
135
136(if $dontcheck is true, return a cUID for a nonexistant user too.
137This is used for registration)
138
139Subclasses *must* implement this method.
140
141Note: This method was previously (in TWiki 4.2.0) known as getCanonicalUserID.
142The name was changed to avoid confusion with Foswiki::Users::getCanonicalUserID,
143which has a more generic function. However to support older user mappers,
144getCanonicalUserID will still be called if login2cUID is not defined.
145
146=cut
147
148sub login2cUID {
149 ASSERT( 0, 'Must be implemented' );
150}
151
152=begin TML
153
154---++ ObjectMethod getLoginName ($cUID) -> login
155
156Converts an internal cUID to that user's login
157(undef on failure)
158
159Subclasses *must* implement this method.
160
161=cut
162
163sub getLoginName {
164 ASSERT(0);
165}
166
167=begin TML
168
169---++ ObjectMethod addUser ($login, $wikiname, $password, $emails) -> $cUID
170
171Add a user to the persistent mapping that maps from usernames to wikinames
172and vice-versa.
173
174$login and $wikiname must be acceptable to $Foswiki::cfg{NameFilter}.
175$login must *always* be specified. $wikiname may be undef, in which case
176the user mapper should make one up.
177
178This function must return a canonical user id that it uses to uniquely
179identify the user. This can be the login name, or the wikiname if they
180are all guaranteed unigue, or some other string consisting only of 7-bit
181alphanumerics and underscores.
182
183If you fail to create a new user (for eg your Mapper has read only access),
184<pre>
185 throw Error::Simple('Failed to add user: '.$error);
186</pre>
187where $error is a descriptive string.
188
189Throws an Error::Simple if user adding is not supported (the default).
190
191=cut
192
193sub addUser {
194 throw Error::Simple('Failed to add user: adding users is not supported');
195}
196
197=begin TML
198
199---++ ObjectMethod removeUser( $cUID ) -> $boolean
200
201Delete the users entry from this mapper. Throws an Error::Simple if
202user removal is not supported (the default).
203
204=cut
205
206sub removeUser {
207 throw Error::Simple('Failed to remove user: user removal is not supported');
208}
209
210=begin TML
211
212---++ ObjectMethod getWikiName ($cUID) -> $wikiname
213
214Map a canonical user name to a wikiname.
215
216Returns the $cUID by default.
217
218=cut
219
220sub getWikiName {
221 my ( $this, $cUID ) = @_;
222 return $cUID;
223}
224
225=begin TML
226
227---++ ObjectMethod userExists($cUID) -> $boolean
228
229Determine if the user already exists or not. Whether a user exists
230or not is determined by the password manager.
231
232Subclasses *must* implement this method.
233
234=cut
235
236sub userExists {
237 ASSERT(0);
238}
239
240=begin TML
241
242---++ ObjectMethod eachUser () -> $iterator
243
244Get an iterator over the list of all cUIDs of the registered
245users *not* including groups.
246
247Subclasses *must* implement this method.
248
249=cut
250
251sub eachUser {
252 ASSERT(0);
253}
254
255=begin TML
256
257---++ ObjectMethod eachGroupMember ($group, $expand) -> $iterator
258
259Return a iterator over the canonical user ids of users that are members
260of this group. Should only be called on groups.
261
262Note that groups may be defined recursively, so a group may contain other
263groups. Unless $expand is set to false, this method should *only* return
264users i.e. all contained groups should be fully expanded.
265
266Subclasses *must* implement this method.
267
268=cut
269
270sub eachGroupMember {
271 ASSERT(0);
272}
273
274=begin TML
275
276---++ ObjectMethod isGroup ($name) -> boolean
277
278Establish if a user refers to a group or not. If $name is not
279a group name it will probably be a canonical user id, though that
280should not be assumed.
281
282Subclasses *must* implement this method.
283
284=cut
285
286sub isGroup {
287 ASSERT(0);
288}
289
290=begin TML
291
292---++ ObjectMethod eachGroup () -> $iterator
293
294Get an iterator over the list of all the group names.
295
296Subclasses *must* implement this method.
297
298=cut
299
300sub eachGroup {
301 ASSERT(0);
302}
303
304=begin TML
305
306---++ ObjectMethod eachMembership($cUID) -> $iterator
307
308Return an iterator over the names of groups that $cUID is a member of.
309
310Subclasses *must* implement this method.
311
312=cut
313
314sub eachMembership {
315 ASSERT(0);
316}
317
318=begin TML
319
320---++ ObjectMethod groupAllowsView($group) -> boolean
321
322returns 1 if the group is able to be viewed by the current logged in user
323
324=cut
325
326sub groupAllowsView {
327 return 1;
328}
329
330=begin TML
331
332---++ ObjectMethod groupAllowsChange($group) -> boolean
333
334returns 1 if the group is able to be modified by the current logged in user
335
336=cut
337
338sub groupAllowsChange {
339 return 0;
340}
341
342=begin TML
343
344---++ ObjectMethod addToGroup( $cuid, $group, $create ) -> $boolean
345adds the user specified by the cuid to the group.
346
347Mapper should throws Error::Simple if errors are encountered. For example,
348if the group does not exist, and the create flag is not supplied:
349<pre>
350 throw Error::Simple( $this->{session}
351 ->i18n->maketext('Group does not exist and create not permitted')
352 ) unless ($create);
353</pre>
354
355=cut
356
357sub addUserToGroup {
358 return 0;
359}
360
361=begin TML
362
363---++ ObjectMethod removeFromGroup( $cuid, $group ) -> $boolean
364
365Mapper should throws Error::Simple if errors are encountered. For example,
366if the user does not exist in the group:
367<pre>
368 throw Error::Simple(
369 $this->{session}->i18n->maketext(
370 'User [_1] not in group, cannot be removed', $cuid
371 )
372 );
373</pre>
374
375=cut
376
377sub removeUserFromGroup {
378 return 0;
379}
380
381=begin TML
382
383---++ ObjectMethod isAdmin( $cUID ) -> $boolean
384
385True if the user is an administrator.
386
387=cut
388
389sub isAdmin {
390 return 0;
391}
392
393=begin TML
394
395---++ ObjectMethod isInGroup ($cUID, $group, $options ) -> $bool
396
397
398Test if the user identified by $cUID is in the given group. The default
399implementation iterates over all the members of $group, which is rather
400inefficient. $options is a hash array of options effecting the search.
401Available options are:
402
403 * =expand => 1= 0/1 - should nested groups be expanded when searching for the cUID? Default is 1 - expand nested groups
404
405=cut
406
4071200nsmy %scanning;
408
409
# spent 73µs (33+40) within Foswiki::UserMapping::isInGroup which was called: # once (33µs+40µs) by Foswiki::Users::BaseUserMapping::isAdmin at line 384 of /var/www/foswikidev/core/lib/Foswiki/Users/BaseUserMapping.pm
sub isInGroup {
41011µs my ( $this, $cUID, $group, $options ) = @_;
411 ASSERT($cUID) if DEBUG;
412
4131700ns my $expand = $options->{expand};
4141400ns $expand = 1 unless ( defined $expand );
415
416 # If not recursively, clear the scanning hash
417111µs if ( ( caller(1) )[3] ne ( caller(0) )[3] ) {
418 %scanning = ();
419 }
420
421 #use Carp;
422 #Carp::cluck "Scanning for JoeUser\n" if $cUID eq 'JoeUser';
423 #die "Scanning for JoeUser\n" if $cUID eq 'JoeUser';
424
4251300ns my @users;
42615µs124µs my $it = $this->eachGroupMember( $group, { expand => $expand } );
# spent 24µs making 1 call to Foswiki::Users::BaseUserMapping::eachGroupMember
42713µs18µs while ( $it->hasNext() ) {
# spent 8µs making 1 call to Foswiki::ListIterator::hasNext
42812µs18µs my $u = $it->next();
# spent 8µs making 1 call to Foswiki::ListIterator::next
4291400ns next if $scanning{$u};
4301600ns $scanning{$u} = 1;
431
43216µs return 1 if $u eq $cUID;
433 }
434 return 0;
435}
436
437=begin TML
438
439---++ ObjectMethod findUserByEmail( $email ) -> \@users
440 * =$email= - email address to look up
441Return a list of canonical user names for the users that have this email
442registered with the password manager or the user mapping manager.
443
444=cut
445
446sub findUserByEmail {
447 return [];
448}
449
450=begin TML
451
452---++ ObjectMethod getEmails($name) -> @emailAddress
453
454If $name is a cUID, return that user's email addresses. If it is a group,
455return the addresses of everyone in the group.
456
457Duplicates should be removed from the list.
458
459=cut
460
461sub getEmails {
462 return ();
463}
464
465=begin TML
466
467---++ ObjectMethod setEmails($cUID, @emails)
468
469Set the email address(es) for the given user.
470
471=cut
472
473sub setEmails {
474}
475
476=begin TML
477
478---++ ObjectMethod findUserByWikiName ($wikiname) -> list of cUIDs associated with that wikiname
479 * =$wikiname= - wikiname to look up
480Return a list of canonical user names for the users that have this wikiname.
481Since a single wikiname might be used by multiple login ids, we need a list.
482
483Note that if $wikiname is the name of a group, the group will *not* be
484expanded.
485
486Subclasses *must* implement this method.
487
488=cut
489
490sub findUserByWikiName {
491 ASSERT(0);
492}
493
494=begin TML
495
496---++ ObjectMethod checkPassword( $login, $passwordU ) -> $boolean
497
498Finds if the password is valid for the given login. This is called using
499a login name rather than a cUID because the user may not have been mapped
500at the time it is called.
501
502Returns 1 on success, undef on failure.
503
504Default behaviour is to return 1.
505
506=cut
507
508sub checkPassword {
509 return 1;
510}
511
512=begin TML
513
514---++ ObjectMethod setPassword( $cUID, $newPassU, $oldPassU ) -> $boolean
515
516If the $oldPassU matches matches the user's password, then it will
517replace it with $newPassU.
518
519If $oldPassU is not correct and not 1, will return 0.
520
521If $oldPassU is 1, will force the change irrespective of
522the existing password, adding the user if necessary.
523
524Otherwise returns 1 on success, undef on failure.
525
526Default behaviour is to fail.
527
528=cut
529
530sub setPassword {
531 return;
532}
533
534=begin TML
535
536---++ ObjectMethod passwordError( ) -> $string
537
538Returns a string indicating the error that happened in the password handlers
539TODO: these delayed errors should be replaced with Exceptions.
540
541returns undef if no error (the default)
542
543=cut
544
545sub passwordError {
546 return;
547}
548
549=begin TML
550
551---++ ObjectMethod validateRegistrationField($field, $value ) -> $string
552
553Returns a string containing the sanitized registration field, or can throw an oops
554if the field contains illegal data to block the registration.
555
556returns the string unchanged if no issue found.
557
558=cut
559
560sub validateRegistrationField {
561
562 #my ($this, $field, $value) = @_;
563
564 # Filter username per the login validation rules.
565 # Note: loginname excluded as it's validated directly in the mapper
566
567 return $_[2] if ( lc( $_[1] ) eq 'loginname' );
568
569 if ( ( lc( $_[1] ) eq 'username' )
570 && length( $_[2] )
571 && !( $_[2] =~ m/$Foswiki::cfg{LoginNameFilterIn}/ ) )
572 {
573 throw Error::Simple("Invalid $_[1]");
574 }
575
576 # Don't check contents of password - it's never displayed.
577 return $_[2] if ( lc( $_[1] ) eq 'password' || lc( $_[1] ) eq 'confirm' );
578
579 unless ( $_[1] =~ m/^(?:firstname|lastname|email|wikiname|name|)$/i ) {
580
581# SMELL This would be better but for now I can't make it work.
582# Undefined subroutine &Foswiki::Macros::ENCODE called
583#
584#require Foswiki::Macros::ENCODE;
585#my $session = $Foswiki::Plugins::SESSION;
586#my $value = Foswiki::Macros::ENCODE->ENCODE( $session, { type => 'safe', _DEFAULT => $_[2] } );
587#print STDERR "Encoding $_[1] as $value\n";
588
589 # This is the "safe" encode in ENCODE.pm
590 $_[2] =~ s/([<>%'"])/'&#'.ord($1).';'/ge;
591 }
592
593 # Don't allow html markup in any other fields.
594 # This should never hit if the encoding works correctly.
595 throw Error::Simple("Invalid $_[1]") if ( $_[2] =~ m/[<>]+/ );
596
597 return $_[2];
598}
599
60013µs1;
601__END__