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