Filename | /var/www/foswiki11/lib/Foswiki/Users.pm |
Statements | Executed 22724 statements in 37.4ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
918 | 6 | 1 | 20.1ms | 75.2ms | _getMapping | Foswiki::Users::
533 | 2 | 2 | 10.3ms | 33.8ms | findUserByWikiName | Foswiki::Users::
1067 | 2 | 2 | 8.75ms | 9.38ms | mapLogin2cUID | Foswiki::Users::
1 | 1 | 1 | 7.07ms | 19.3ms | new | Foswiki::Users::
381 | 6 | 5 | 6.94ms | 98.5ms | getCanonicalUserID | Foswiki::Users::
1 | 1 | 1 | 4.22ms | 4.42ms | BEGIN@64 | Foswiki::Users::
325 | 2 | 1 | 3.65ms | 310ms | isInUserList | Foswiki::Users::
374 | 1 | 1 | 2.64ms | 226ms | isGroup | Foswiki::Users::
585 | 5 | 5 | 2.10ms | 4.58ms | isAdmin | Foswiki::Users::
1 | 1 | 1 | 414µs | 829µs | BEGIN@63 | Foswiki::Users::
42 | 4 | 4 | 175µs | 250µs | getLoginName | Foswiki::Users::
1 | 1 | 1 | 152µs | 1.79ms | finish | Foswiki::Users::
1 | 1 | 1 | 112µs | 98.2ms | initialiseUser | Foswiki::Users::
14 | 4 | 4 | 100µs | 136µs | getWikiName | Foswiki::Users::
3 | 1 | 1 | 76µs | 20.5ms | isInGroup | Foswiki::Users::
5 | 2 | 2 | 50µs | 151µs | webDotWikiName | Foswiki::Users::
10 | 1 | 1 | 35µs | 35µs | getLoginManager | Foswiki::Users::
1 | 1 | 1 | 26µs | 30µs | getCGISession | Foswiki::Users::
1 | 1 | 1 | 12µs | 25µs | BEGIN@59 | Foswiki::Users::
1 | 1 | 1 | 12µs | 14µs | BEGIN@408 | Foswiki::Users::
1 | 1 | 1 | 12µs | 31µs | BEGIN@313 | Foswiki::Users::
1 | 1 | 1 | 12µs | 39.0ms | loadSession | Foswiki::Users::
1 | 1 | 1 | 11µs | 13µs | BEGIN@406 | Foswiki::Users::
1 | 1 | 1 | 10µs | 15µs | BEGIN@60 | Foswiki::Users::
1 | 1 | 1 | 8µs | 20µs | BEGIN@61 | Foswiki::Users::
1 | 1 | 1 | 6µs | 7µs | supportsRegistration | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | addUser | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | addUserToGroup | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | checkPassword | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | eachGroup | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | eachGroupMember | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | eachMembership | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | eachUser | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | findUserByEmail | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | getEmails | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | groupAllowsChange | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | groupAllowsView | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | loginTemplateName | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | passwordError | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | randomPassword | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | removeUser | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | removeUserFromGroup | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | setEmails | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | setPassword | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | userExists | Foswiki::Users::
0 | 0 | 0 | 0s | 0s | validateRegistrationField | Foswiki::Users::
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 | ||||
6 | This package provides services for the lookup and manipulation of login and | ||||
7 | wiki names of users, and their authentication. | ||||
8 | |||||
9 | It is a Facade that presents a common interface to the User Mapping | ||||
10 | and Password modules. The rest of the core should *only* use the methods | ||||
11 | of this package, and should *never* call the mapping or password managers | ||||
12 | directly. | ||||
13 | |||||
14 | Foswiki uses the concept of a _login name_ which is used to authenticate a | ||||
15 | user. A login name maps to a _wiki name_ that is used to identify the user | ||||
16 | for display. Each login name is unique to a single user, though several | ||||
17 | login names may map to the same wiki name. | ||||
18 | |||||
19 | Using this module (and the associated plug-in user mapper) Foswiki supports | ||||
20 | the concept of _groups_. Groups are sets of login names that are treated | ||||
21 | equally for the purposes of access control. Group names do not have to be | ||||
22 | wiki names, though it is helpful for display if they are. | ||||
23 | |||||
24 | Internally in the code Foswiki uses something referred to as a _canonical user | ||||
25 | id_ or just _user id_. The user id is also used externally to uniquely identify | ||||
26 | the user when (for example) recording topic histories. The user id is *usually* | ||||
27 | just the login name, but it doesn't need to be. It just has to be a unique | ||||
28 | 7-bit alphanumeric and underscore string that can be mapped to/from login | ||||
29 | and wiki names by the user mapper. | ||||
30 | |||||
31 | The canonical user id should *never* be seen by a user. On the other hand, | ||||
32 | core code should never use anything *but* a canonical user id to refer | ||||
33 | to a user. | ||||
34 | |||||
35 | *Terminology* | ||||
36 | * A *login name* is the name used to log in to Foswiki. Each login name is | ||||
37 | assumed to be unique to a human. The Password module is responsible for | ||||
38 | authenticating and manipulating login names. | ||||
39 | * A *canonical user id* is an internal Foswiki representation of a user. Each | ||||
40 | canonical user id maps 1:1 to a login name. | ||||
41 | * A *wikiname* is how a user is displayed. Many user ids may map to a | ||||
42 | single wikiname. The user mapping module is responsible for mapping | ||||
43 | the user id to a wikiname. | ||||
44 | * A *group id* represents a group of users and other groups. | ||||
45 | The user mapping module is responsible for mapping from a group id to | ||||
46 | a list of canonical user ids for the users in that group. | ||||
47 | * An *email* is an email address asscoiated with a *login name*. A single | ||||
48 | login name may have many emails. | ||||
49 | |||||
50 | *NOTE:* | ||||
51 | * wherever the code references $cUID, its a canonical_id | ||||
52 | * wherever the code references $group, its a group_name | ||||
53 | * $name may be a group or a cUID | ||||
54 | |||||
55 | =cut | ||||
56 | |||||
57 | package Foswiki::Users; | ||||
58 | |||||
59 | 2 | 24µs | 2 | 38µs | # spent 25µs (12+13) within Foswiki::Users::BEGIN@59 which was called:
# once (12µs+13µs) by Foswiki::BEGIN@636 at line 59 # spent 25µs making 1 call to Foswiki::Users::BEGIN@59
# spent 13µs making 1 call to strict::import |
60 | 2 | 26µs | 2 | 20µs | # spent 15µs (10+5) within Foswiki::Users::BEGIN@60 which was called:
# once (10µs+5µs) by Foswiki::BEGIN@636 at line 60 # spent 15µs making 1 call to Foswiki::Users::BEGIN@60
# spent 5µs making 1 call to warnings::import |
61 | 2 | 28µs | 2 | 32µs | # spent 20µs (8+12) within Foswiki::Users::BEGIN@61 which was called:
# once (8µs+12µs) by Foswiki::BEGIN@636 at line 61 # spent 20µs making 1 call to Foswiki::Users::BEGIN@61
# spent 12µs making 1 call to Assert::import |
62 | |||||
63 | 2 | 94µs | 1 | 829µs | # spent 829µs (414+416) within Foswiki::Users::BEGIN@63 which was called:
# once (414µs+416µs) by Foswiki::BEGIN@636 at line 63 # spent 829µs making 1 call to Foswiki::Users::BEGIN@63 |
64 | 2 | 771µs | 1 | 4.42ms | # spent 4.42ms (4.22+202µs) within Foswiki::Users::BEGIN@64 which was called:
# once (4.22ms+202µs) by Foswiki::BEGIN@636 at line 64 # spent 4.42ms making 1 call to Foswiki::Users::BEGIN@64 |
65 | |||||
66 | #use Monitor; | ||||
67 | #Monitor::MonitorMethod('Foswiki::Users'); | ||||
68 | |||||
69 | =begin TML | ||||
70 | |||||
71 | ---++ ClassMethod new ($session) | ||||
72 | Construct the user management object that is the facade to the BaseUserMapping | ||||
73 | and the user mapping chosen in the configuration. | ||||
74 | |||||
75 | =cut | ||||
76 | |||||
77 | # spent 19.3ms (7.07+12.3) within Foswiki::Users::new which was called:
# once (7.07ms+12.3ms) by Foswiki::new at line 1762 of /var/www/foswiki11/lib/Foswiki.pm | ||||
78 | 1 | 1µs | my ( $class, $session ) = @_; | ||
79 | 1 | 6µs | my $this = bless( { session => $session }, $class ); | ||
80 | |||||
81 | # Do a dynamic 'use locale' for this module | ||||
82 | 1 | 1µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
83 | 1 | 600ns | require locale; | ||
84 | 1 | 3µs | 1 | 4µs | import locale(); # spent 4µs making 1 call to locale::import |
85 | } | ||||
86 | |||||
87 | # making basemapping | ||||
88 | 1 | 2µs | my $implBaseUserMappingManager = $Foswiki::cfg{BaseUserMappingManager} | ||
89 | || 'Foswiki::Users::BaseUserMapping'; | ||||
90 | 1 | 20µs | eval "require $implBaseUserMappingManager"; # spent 76µs executing statements in string eval | ||
91 | 1 | 400ns | die $@ if $@; | ||
92 | 1 | 7µs | 1 | 74µs | $this->{basemapping} = $implBaseUserMappingManager->new($session); # spent 74µs making 1 call to Foswiki::Users::BaseUserMapping::new |
93 | |||||
94 | 1 | 2µs | my $implUserMappingManager = $Foswiki::cfg{UserMappingManager}; | ||
95 | 1 | 500ns | $implUserMappingManager = 'Foswiki::Users::TopicUserMapping' | ||
96 | if ( $implUserMappingManager eq 'none' ); | ||||
97 | |||||
98 | 1 | 1µs | if ( $implUserMappingManager eq 'Foswiki::Users::BaseUserMapping' ) { | ||
99 | $this->{mapping} = $this->{basemapping}; #TODO: probly make undef.. | ||||
100 | } | ||||
101 | else { | ||||
102 | 1 | 21µs | eval "require $implUserMappingManager"; # spent 82µs executing statements in string eval | ||
103 | 1 | 600ns | die $@ if $@; | ||
104 | 1 | 7µs | 1 | 651µs | $this->{mapping} = $implUserMappingManager->new($session); # spent 651µs making 1 call to Foswiki::Users::TopicUserMapping::new |
105 | } | ||||
106 | |||||
107 | 1 | 3µs | 1 | 812µs | $this->{loginManager} = Foswiki::LoginManager::makeLoginManager($session); # spent 812µs making 1 call to Foswiki::LoginManager::makeLoginManager |
108 | |||||
109 | # caches - not only used for speedup, but also for authenticated but | ||||
110 | # unregistered users | ||||
111 | # SMELL: this is basically a user object, something we had previously | ||||
112 | # but dropped for efficiency reasons | ||||
113 | 1 | 700ns | $this->{cUID2WikiName} = {}; | ||
114 | 1 | 900ns | $this->{cUID2Login} = {}; | ||
115 | 1 | 700ns | $this->{isAdmin} = {}; | ||
116 | |||||
117 | # the UI for rego supported/not is different from rego temporarily | ||||
118 | # turned off | ||||
119 | 1 | 3µs | 1 | 7µs | if ( $this->supportsRegistration() ) { # spent 7µs making 1 call to Foswiki::Users::supportsRegistration |
120 | 1 | 1µs | 1 | 3µs | $session->enterContext('registration_supported'); # spent 3µs making 1 call to Foswiki::enterContext |
121 | 1 | 2µs | 1 | 2µs | $session->enterContext('registration_enabled') # spent 2µs making 1 call to Foswiki::enterContext |
122 | if $Foswiki::cfg{Register}{EnableNewUserRegistration}; | ||||
123 | } | ||||
124 | |||||
125 | 1 | 4µs | return $this; | ||
126 | } | ||||
127 | |||||
128 | =begin TML | ||||
129 | |||||
130 | ---++ ObjectMethod loadSession() | ||||
131 | |||||
132 | Setup the cgi session, from a cookie or the url. this may return | ||||
133 | the login, but even if it does, plugins will get the chance to | ||||
134 | override (in Foswiki.pm) | ||||
135 | |||||
136 | =cut | ||||
137 | |||||
138 | # spent 39.0ms (12µs+39.0) within Foswiki::Users::loadSession which was called:
# once (12µs+39.0ms) by Foswiki::new at line 1797 of /var/www/foswiki11/lib/Foswiki.pm | ||||
139 | 1 | 1µs | my ( $this, $defaultUser ) = @_; | ||
140 | |||||
141 | # $this is passed in because it will be used to password check | ||||
142 | # a command-line login. The {remoteUser} in the session will be | ||||
143 | # whatever was passed in to the new Foswiki() call. | ||||
144 | 1 | 7µs | 1 | 39.0ms | my $remoteUser = $this->{loginManager}->loadSession( $defaultUser, $this ); # spent 39.0ms making 1 call to Foswiki::LoginManager::loadSession |
145 | |||||
146 | 1 | 3µs | return $remoteUser; | ||
147 | } | ||||
148 | |||||
149 | =begin TML | ||||
150 | |||||
151 | ---++ ObjectMethod finish() | ||||
152 | Break circular references. | ||||
153 | |||||
154 | =cut | ||||
155 | |||||
156 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
157 | # whether they are references or not. That way this method is "golden | ||||
158 | # documentation" of the live fields in the object. | ||||
159 | # spent 1.79ms (152µs+1.64) within Foswiki::Users::finish which was called:
# once (152µs+1.64ms) by Foswiki::finish at line 2163 of /var/www/foswiki11/lib/Foswiki.pm | ||||
160 | 1 | 900ns | my $this = shift; | ||
161 | |||||
162 | 1 | 10µs | 1 | 34µs | $this->{loginManager}->finish() if $this->{loginManager}; # spent 34µs making 1 call to Foswiki::LoginManager::finish |
163 | 1 | 6µs | 1 | 52µs | $this->{basemapping}->finish() if $this->{basemapping}; # spent 52µs making 1 call to Foswiki::Users::BaseUserMapping::finish |
164 | |||||
165 | 1 | 7µs | 1 | 1.56ms | $this->{mapping}->finish() # spent 1.56ms making 1 call to Foswiki::Users::TopicUserMapping::finish |
166 | if $this->{mapping} | ||||
167 | && $this->{mapping} ne $this->{basemapping}; | ||||
168 | |||||
169 | 1 | 6µs | undef $this->{loginManager}; | ||
170 | 1 | 8µs | undef $this->{basemapping}; | ||
171 | 1 | 93µs | undef $this->{mapping}; | ||
172 | 1 | 700ns | undef $this->{session}; | ||
173 | 1 | 4µs | undef $this->{cUID2WikiName}; | ||
174 | 1 | 2µs | undef $this->{cUID2Login}; | ||
175 | 1 | 3µs | undef $this->{wikiName2cUID}; | ||
176 | 1 | 3µs | undef $this->{login2cUID}; | ||
177 | 1 | 7µs | undef $this->{isAdmin}; | ||
178 | |||||
179 | } | ||||
180 | |||||
181 | =begin TML | ||||
182 | |||||
183 | ---++ ObjectMethod loginTemplateName () -> templateFile | ||||
184 | |||||
185 | allows UserMappings to come with customised login screens - that should preffereably only over-ride the UI function | ||||
186 | |||||
187 | =cut | ||||
188 | |||||
189 | sub loginTemplateName { | ||||
190 | my $this = shift; | ||||
191 | |||||
192 | #use login.sudo.tmpl for admin logins | ||||
193 | return $this->{basemapping}->loginTemplateName() | ||||
194 | if ( $this->{session}->inContext('sudo_login') ); | ||||
195 | return $this->{mapping}->loginTemplateName() || 'login'; | ||||
196 | } | ||||
197 | |||||
198 | # ($cUID, $login, $wikiname, $noFallBack) -> usermapping object | ||||
199 | # spent 75.2ms (20.1+55.1) within Foswiki::Users::_getMapping which was called 918 times, avg 82µs/call:
# 533 times (3.70ms+7.91ms) by Foswiki::Users::findUserByWikiName at line 532, avg 22µs/call
# 378 times (16.3ms+47.1ms) by Foswiki::Users::getCanonicalUserID at line 478, avg 168µs/call
# 3 times (35µs+23µs) by Foswiki::Users::isInGroup at line 861, avg 19µs/call
# 2 times (46µs+37µs) by Foswiki::Users::isAdmin at line 617, avg 42µs/call
# once (8µs+6µs) by Foswiki::Users::getWikiName at line 709
# once (8µs+5µs) by Foswiki::Users::getLoginName at line 677 | ||||
200 | 918 | 624µs | my ( $this, $cUID, $login, $wikiname, $noFallBack ) = @_; | ||
201 | |||||
202 | 918 | 287µs | $login = '' unless defined $login; | ||
203 | 918 | 210µs | $wikiname = '' unless defined $wikiname; | ||
204 | |||||
205 | 918 | 864µs | $wikiname =~ s/^($Foswiki::cfg{UsersWebName}|%USERSWEB%|%MAINWEB%)\.//; | ||
206 | |||||
207 | # The base user mapper users must always override those defined in | ||||
208 | # custom mappings, even though that makes it impossible to maintain 100% | ||||
209 | # compatibility with earlier releases (guest user edits will get saved as | ||||
210 | # edits by $DEFAULT_USER_CUID). | ||||
211 | 918 | 2.09ms | 918 | 2.80ms | return $this->{basemapping} # spent 2.80ms making 918 calls to Foswiki::Users::BaseUserMapping::handlesUser, avg 3µs/call |
212 | if ( $this->{basemapping}->handlesUser( $cUID, $login, $wikiname ) ); | ||||
213 | |||||
214 | 595 | 1.45ms | 595 | 52.3ms | return $this->{mapping} # spent 52.3ms making 595 calls to Foswiki::Users::TopicUserMapping::handlesUser, avg 88µs/call |
215 | if ( $this->{mapping}->handlesUser( $cUID, $login, $wikiname ) ); | ||||
216 | |||||
217 | # The base mapping and the selected mapping claim not to know about | ||||
218 | # this user. Use the base mapping unless the caller has explicitly | ||||
219 | # requested otherwise. | ||||
220 | 432 | 265µs | return $this->{basemapping} unless ($noFallBack); | ||
221 | |||||
222 | 377 | 753µs | return; | ||
223 | } | ||||
224 | |||||
225 | =begin TML | ||||
226 | |||||
227 | ---++ ObjectMethod supportsRegistration () -> boolean | ||||
228 | |||||
229 | #return 1 if the main UserMapper supports registration (ie can create new users) | ||||
230 | |||||
231 | =cut | ||||
232 | |||||
233 | # spent 7µs (6+900ns) within Foswiki::Users::supportsRegistration which was called:
# once (6µs+900ns) by Foswiki::Users::new at line 119 | ||||
234 | 1 | 800ns | my ($this) = @_; | ||
235 | 1 | 4µs | 1 | 900ns | return $this->{mapping}->supportsRegistration(); # spent 900ns making 1 call to Foswiki::Users::TopicUserMapping::supportsRegistration |
236 | } | ||||
237 | |||||
238 | =begin TML | ||||
239 | |||||
240 | ---++ ObjectMethod validateRegistrationField ( $field, $value ) -> text | ||||
241 | |||||
242 | Return the registration formfield sanitized by the mapper, or oops thrown to block the registration. | ||||
243 | |||||
244 | =cut | ||||
245 | |||||
246 | sub validateRegistrationField { | ||||
247 | my ($this) = shift; | ||||
248 | return $this->{mapping}->validateRegistrationField(@_); | ||||
249 | } | ||||
250 | |||||
251 | =begin TML | ||||
252 | |||||
253 | ---++ ObjectMethod initialiseUser ($login) -> $cUID | ||||
254 | |||||
255 | Given a login (which must have been authenticated) determine the cUID that | ||||
256 | corresponds to that user. This method is used from Foswiki.pm to map the | ||||
257 | $REMOTE_USER to a cUID. | ||||
258 | |||||
259 | =cut | ||||
260 | |||||
261 | # spent 98.2ms (112µs+98.1) within Foswiki::Users::initialiseUser which was called:
# once (112µs+98.1ms) by Foswiki::new at line 1939 of /var/www/foswiki11/lib/Foswiki.pm | ||||
262 | 1 | 2µs | my ( $this, $login ) = @_; | ||
263 | |||||
264 | # For compatibility with older ways of building login managers, | ||||
265 | # plugins can provide an alternate login name. | ||||
266 | 1 | 8µs | 1 | 97.9ms | my $plogin = # spent 97.9ms making 1 call to Foswiki::Plugins::load |
267 | $this->{session}->{plugins}->load( $Foswiki::cfg{DisableAllPlugins} ); | ||||
268 | |||||
269 | #Monitor::MARK("Plugins loaded"); | ||||
270 | |||||
271 | 1 | 1µs | $login = $plogin if $plogin; | ||
272 | |||||
273 | 1 | 300ns | my $cUID; | ||
274 | 1 | 2µs | if ( defined($login) && $login ne '' ) { | ||
275 | |||||
276 | # In the case of a user mapper that accepts any identifier as | ||||
277 | # a cUID, | ||||
278 | 1 | 5µs | 1 | 160µs | $cUID = $this->getCanonicalUserID($login); # spent 160µs making 1 call to Foswiki::Users::getCanonicalUserID |
279 | |||||
280 | # see BugsItem4771 - it seems that authenticated, but unmapped | ||||
281 | # users have rights too | ||||
282 | 1 | 1µs | if ( !defined($cUID) ) { | ||
283 | |||||
284 | # There is no known canonical user ID for this login name. | ||||
285 | # Generate a cUID for the login, and add it anyway. There is | ||||
286 | # a risk that the generated cUID will overlap a cUID generated | ||||
287 | # by a custom mapper, but since (1) the user has to be | ||||
288 | # authenticated to get here and (2) the custom user mapper | ||||
289 | # is specific to the login process used, that risk should be | ||||
290 | # small (unless the author of the custom mapper screws up) | ||||
291 | 1 | 4µs | 1 | 10µs | $cUID = mapLogin2cUID($login); # spent 10µs making 1 call to Foswiki::Users::mapLogin2cUID |
292 | |||||
293 | 1 | 2µs | $this->{cUID2Login}->{$cUID} = $login; | ||
294 | 1 | 1µs | $this->{cUID2WikiName}->{$cUID} = $login; | ||
295 | |||||
296 | # needs to be WikiName safe | ||||
297 | 1 | 11µs | $this->{cUID2WikiName}->{$cUID} =~ s/$Foswiki::cfg{NameFilter}//go; | ||
298 | 1 | 2µs | $this->{cUID2WikiName}->{$cUID} =~ s/\.//go; | ||
299 | |||||
300 | 1 | 1µs | $this->{login2cUID}->{$login} = $cUID; | ||
301 | 1 | 2µs | $this->{wikiName2cUID}->{ $this->{cUID2WikiName}->{$cUID} } = $cUID; | ||
302 | } | ||||
303 | } | ||||
304 | |||||
305 | # if we get here without a login id, we are a guest. Get the guest | ||||
306 | # cUID. | ||||
307 | 1 | 100ns | $cUID ||= $this->getCanonicalUserID( $Foswiki::cfg{DefaultUserLogin} ); | ||
308 | |||||
309 | 1 | 4µs | return $cUID; | ||
310 | } | ||||
311 | |||||
312 | # global used by test harness to give predictable results | ||||
313 | 2 | 241µs | 2 | 50µs | # spent 31µs (12+19) within Foswiki::Users::BEGIN@313 which was called:
# once (12µs+19µs) by Foswiki::BEGIN@636 at line 313 # spent 31µs making 1 call to Foswiki::Users::BEGIN@313
# spent 19µs making 1 call to vars::import |
314 | |||||
315 | =begin TML | ||||
316 | |||||
317 | ---++ randomPassword() | ||||
318 | Static function that returns a random password. This function is not used | ||||
319 | in this module; it is provided as a service for other modules, such as | ||||
320 | custom mappers and registration modules. | ||||
321 | |||||
322 | =cut | ||||
323 | |||||
324 | sub randomPassword { | ||||
325 | |||||
326 | my $pwlen = | ||||
327 | ( $Foswiki::cfg{MinPasswordLength} > 8 ) | ||||
328 | ? $Foswiki::cfg{MinPasswordLength} | ||||
329 | : 8; | ||||
330 | my @chars = ( 'a' .. 'z', 'A' .. 'Z', 0 .. 9, '_', '.', '/' ); | ||||
331 | my $newpw; | ||||
332 | |||||
333 | foreach ( 1 .. $pwlen ) { | ||||
334 | $newpw .= $chars[ rand @chars ]; | ||||
335 | } | ||||
336 | return $newpw; | ||||
337 | |||||
338 | } | ||||
339 | |||||
340 | =begin TML | ||||
341 | |||||
342 | ---++ ObjectMethod addUser($login, $wikiname, $password, $emails) -> $cUID | ||||
343 | |||||
344 | * =$login= - user login name. If =undef=, =$wikiname= will be used as | ||||
345 | the login name. | ||||
346 | * =$wikiname= - user wikiname. If =undef=, the user mapper will be asked | ||||
347 | to provide it. | ||||
348 | * =$password= - password. If undef, a password will be generated. | ||||
349 | |||||
350 | Add a new Foswiki user identity, returning the canonical user id for the new | ||||
351 | user. Used ONLY for user registration. | ||||
352 | |||||
353 | The user is added to the password system (if there is one, and if it accepts | ||||
354 | changes). If the user already exists in the password system, then the password | ||||
355 | is checked and an exception thrown if it doesn't match. If there is no | ||||
356 | existing user, and no password is given, a random password is generated. | ||||
357 | |||||
358 | $login can be undef; $wikiname must always have a value. | ||||
359 | |||||
360 | The return value is the canonical user id that is used | ||||
361 | by Foswiki to identify the user. | ||||
362 | |||||
363 | =cut | ||||
364 | |||||
365 | sub addUser { | ||||
366 | my ( $this, $login, $wikiname, $password, $emails ) = @_; | ||||
367 | my $removeOnFail = 0; | ||||
368 | |||||
369 | ASSERT( $login || $wikiname ) if DEBUG; # must have at least one | ||||
370 | |||||
371 | # create a new user and get the canonical user ID from the user mapping | ||||
372 | # manager. | ||||
373 | my $cUID = | ||||
374 | $this->{mapping}->addUser( $login, $wikiname, $password, $emails ); | ||||
375 | |||||
376 | # update the cached values | ||||
377 | $this->{cUID2Login}->{$cUID} = $login; | ||||
378 | $this->{cUID2WikiName}->{$cUID} = $wikiname; | ||||
379 | |||||
380 | $this->{login2cUID}->{$login} = $cUID; | ||||
381 | $this->{wikiName2cUID}->{$wikiname} = $cUID; | ||||
382 | |||||
383 | return $cUID; | ||||
384 | } | ||||
385 | |||||
386 | =begin TML | ||||
387 | |||||
388 | ---++ StaticMethod mapLogin2cUID( $login ) -> $cUID | ||||
389 | |||||
390 | This function maps an arbitrary string into a valid cUID. The transformation | ||||
391 | is reversible, but the function is not idempotent (a cUID passed to this | ||||
392 | function will NOT be returned unchanged). The generated cUID will be unique | ||||
393 | for the given login name. | ||||
394 | |||||
395 | This static function is designed to be called from custom user mappers that | ||||
396 | support 1:1 login-to-cUID mappings. | ||||
397 | |||||
398 | =cut | ||||
399 | |||||
400 | # spent 9.38ms (8.75+635µs) within Foswiki::Users::mapLogin2cUID which was called 1067 times, avg 9µs/call:
# 1066 times (8.74ms+634µs) by Foswiki::Users::TopicUserMapping::login2cUID at line 189 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 9µs/call
# once (9µs+700ns) by Foswiki::Users::initialiseUser at line 291 | ||||
401 | 1067 | 224µs | my $cUID = shift; | ||
402 | |||||
403 | 1067 | 736µs | 1067 | 635µs | ASSERT( defined($cUID) ) if DEBUG; # spent 635µs making 1067 calls to Assert::ASSERTS_OFF, avg 595ns/call |
404 | |||||
405 | # use bytes to ignore character encoding | ||||
406 | 2 | 52µs | 2 | 15µs | # spent 13µs (11+2) within Foswiki::Users::BEGIN@406 which was called:
# once (11µs+2µs) by Foswiki::BEGIN@636 at line 406 # spent 13µs making 1 call to Foswiki::Users::BEGIN@406
# spent 2µs making 1 call to bytes::import |
407 | 1067 | 574µs | $cUID =~ s/([^a-zA-Z0-9])/'_'.sprintf('%02x', ord($1))/ge; | ||
408 | 2 | 1.56ms | 2 | 17µs | # spent 14µs (12+2) within Foswiki::Users::BEGIN@408 which was called:
# once (12µs+2µs) by Foswiki::BEGIN@636 at line 408 # spent 14µs making 1 call to Foswiki::Users::BEGIN@408
# spent 2µs making 1 call to bytes::unimport |
409 | 1067 | 2.11ms | return $cUID; | ||
410 | } | ||||
411 | |||||
412 | =begin TML | ||||
413 | |||||
414 | ---++ ObjectMethod getCGISession() | ||||
415 | Get the currect CGI session object | ||||
416 | |||||
417 | =cut | ||||
418 | |||||
419 | # spent 30µs (26+4) within Foswiki::Users::getCGISession which was called:
# once (26µs+4µs) by Foswiki::getCGISession at line 1276 of /var/www/foswiki11/lib/Foswiki.pm | ||||
420 | 1 | 700ns | my $this = shift; | ||
421 | 1 | 26µs | 1 | 4µs | return $this->{loginManager}->getCGISession(); # spent 4µs making 1 call to Foswiki::LoginManager::getCGISession |
422 | } | ||||
423 | |||||
424 | =begin TML | ||||
425 | |||||
426 | ---++ ObjectMethod getLoginManager() -> $loginManager | ||||
427 | |||||
428 | Get the Foswiki::LoginManager object associated with this session, if there is | ||||
429 | one. May return undef. | ||||
430 | |||||
431 | =cut | ||||
432 | |||||
433 | # spent 35µs within Foswiki::Users::getLoginManager which was called 10 times, avg 4µs/call:
# 10 times (35µs+0s) by Foswiki::getLoginManager at line 1289 of /var/www/foswiki11/lib/Foswiki.pm, avg 4µs/call | ||||
434 | 10 | 5µs | my $this = shift; | ||
435 | 10 | 44µs | return $this->{loginManager}; | ||
436 | } | ||||
437 | |||||
438 | =begin TML | ||||
439 | |||||
440 | ---++ ObjectMethod getCanonicalUserID( $identifier ) -> $cUID | ||||
441 | |||||
442 | Works out the Foswiki canonical user identifier for the user who either | ||||
443 | (1) logs in with the login name $identifier or (2) has the wikiname | ||||
444 | $identifier. | ||||
445 | |||||
446 | The canonical user ID is an alphanumeric string that is unique | ||||
447 | to the login name, and can be mapped back to a login name and the | ||||
448 | corresponding wiki name using the methods of this class. | ||||
449 | |||||
450 | Note that if the login name to wiki name mapping is not 1:1, this | ||||
451 | method will map a wikiname to one of the login names that corresponds | ||||
452 | to the wiki name, but there is no guarantee which one. | ||||
453 | |||||
454 | Returns undef if the user does not exist. | ||||
455 | |||||
456 | =cut | ||||
457 | |||||
458 | # This function was previously known as forceCUID. It differs from that | ||||
459 | # implementation in that it does *not* accept a CUID as parameter, which | ||||
460 | # if why it has been renamed. | ||||
461 | # spent 98.5ms (6.94+91.6) within Foswiki::Users::getCanonicalUserID which was called 381 times, avg 259µs/call:
# 374 times (6.83ms+52.5ms) by Foswiki::Users::isInUserList at line 648, avg 159µs/call
# 3 times (39µs+56µs) by Foswiki::Render::renderRevisionInfo at line 1758 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 32µs/call
# once (26µs+38.8ms) by Foswiki::LoginManager::userLoggedIn at line 695 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (25µs+135µs) by Foswiki::Users::initialiseUser at line 278
# once (13µs+57µs) by Foswiki::Users::TopicUserMapping::_expandUserList at line 1754 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm
# once (10µs+800ns) by Foswiki::Func::getCanonicalUserID at line 902 of /var/www/foswiki11/lib/Foswiki/Func.pm | ||||
462 | 381 | 217µs | my ( $this, $identifier ) = @_; | ||
463 | 381 | 57µs | my $cUID; | ||
464 | |||||
465 | 381 | 444µs | 381 | 422µs | ASSERT( defined $identifier ) if DEBUG; # spent 422µs making 381 calls to Assert::ASSERTS_OFF, avg 1µs/call |
466 | |||||
467 | # Someone we already know? | ||||
468 | |||||
469 | 381 | 497µs | if ( defined( $this->{login2cUID}->{$identifier} ) ) { | ||
470 | $cUID = $this->{login2cUID}->{$identifier}; | ||||
471 | } | ||||
472 | elsif ( defined( $this->{wikiName2cUID}->{$identifier} ) ) { | ||||
473 | $cUID = $this->{wikiName2cUID}->{$identifier}; | ||||
474 | } | ||||
475 | else { | ||||
476 | |||||
477 | # See if a mapping recognises the identifier as a login name | ||||
478 | 378 | 707µs | 378 | 63.4ms | my $mapping = $this->_getMapping( undef, $identifier, undef, 1 ); # spent 63.4ms making 378 calls to Foswiki::Users::_getMapping, avg 168µs/call |
479 | 378 | 75µs | if ($mapping) { | ||
480 | 1 | 19µs | 2 | 30µs | if ( $mapping->can('login2cUID') ) { # spent 28µs making 1 call to Foswiki::Users::TopicUserMapping::login2cUID
# spent 2µs making 1 call to UNIVERSAL::can |
481 | $cUID = $mapping->login2cUID($identifier); | ||||
482 | } | ||||
483 | elsif ( $mapping->can('getCanonicalUserID') ) { | ||||
484 | |||||
485 | # Old name of login2cUID. Name changed to avoid confusion | ||||
486 | # with Foswiki::Users::getCanonicalUserID. See | ||||
487 | # Codev.UserMapperChangesBetween420And421 for more. | ||||
488 | $cUID = $mapping->getCanonicalUserID($identifier); | ||||
489 | } | ||||
490 | else { | ||||
491 | die( | ||||
492 | "Broken user mapping $mapping; does not implement login2cUID" | ||||
493 | ); | ||||
494 | } | ||||
495 | } | ||||
496 | |||||
497 | 378 | 168µs | unless ($cUID) { | ||
498 | |||||
499 | # Finally see if it's a valid user wikiname | ||||
500 | |||||
501 | # Strip users web id (legacy, probably specific to | ||||
502 | # TopicUserMappingContrib but may be used by other mappers | ||||
503 | # that support user topics) | ||||
504 | 377 | 1.10ms | 377 | 4.22ms | my ( $dummy, $nid ) = # spent 4.22ms making 377 calls to Foswiki::normalizeWebTopicName, avg 11µs/call |
505 | $this->{session}->normalizeWebTopicName( '', $identifier ); | ||||
506 | 377 | 292µs | $identifier = $nid if ( $dummy eq $Foswiki::cfg{UsersWebName} ); | ||
507 | |||||
508 | 377 | 645µs | 377 | 23.5ms | my $found = $this->findUserByWikiName($identifier); # spent 23.5ms making 377 calls to Foswiki::Users::findUserByWikiName, avg 62µs/call |
509 | 377 | 573µs | $cUID = $found->[0] if ( $found && scalar(@$found) ); | ||
510 | } | ||||
511 | } | ||||
512 | 381 | 1.04ms | return $cUID; | ||
513 | } | ||||
514 | |||||
515 | =begin TML | ||||
516 | |||||
517 | ---++ ObjectMethod findUserByWikiName( $wn ) -> \@users | ||||
518 | * =$wn= - wikiname to look up | ||||
519 | Return a list of canonical user names for the users that have this wikiname. | ||||
520 | Since a single wikiname might be used by multiple login ids, we need a list. | ||||
521 | |||||
522 | If $wn is the name of a group, the group will *not* be expanded. | ||||
523 | |||||
524 | =cut | ||||
525 | |||||
526 | # spent 33.8ms (10.3+23.5) within Foswiki::Users::findUserByWikiName which was called 533 times, avg 63µs/call:
# 377 times (9.14ms+14.4ms) by Foswiki::Users::getCanonicalUserID at line 508, avg 62µs/call
# 156 times (1.18ms+9.07ms) by Foswiki::Users::TopicUserMapping::_expandUserList at line 1747 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 66µs/call | ||||
527 | 533 | 275µs | my ( $this, $wn ) = @_; | ||
528 | 533 | 450µs | 533 | 394µs | ASSERT($wn) if DEBUG; # spent 394µs making 533 calls to Assert::ASSERTS_OFF, avg 740ns/call |
529 | |||||
530 | # Trim the (pointless) userweb, if present | ||||
531 | 533 | 659µs | $wn =~ s/^($Foswiki::cfg{UsersWebName}|%USERSWEB%|%MAINWEB%)\.//; | ||
532 | 533 | 790µs | 533 | 11.6ms | my $mapping = $this->_getMapping( undef, undef, $wn ); # spent 11.6ms making 533 calls to Foswiki::Users::_getMapping, avg 22µs/call |
533 | |||||
534 | #my $mapping = $this->_getMapping( $wn, $wn, $wn ); # why not? | ||||
535 | 533 | 1.78ms | 533 | 11.4ms | return $mapping->findUserByWikiName($wn); # spent 9.79ms making 378 calls to Foswiki::Users::BaseUserMapping::findUserByWikiName, avg 26µs/call
# spent 1.66ms making 155 calls to Foswiki::Users::TopicUserMapping::findUserByWikiName, avg 11µs/call |
536 | } | ||||
537 | |||||
538 | =begin TML | ||||
539 | |||||
540 | ---++ ObjectMethod findUserByEmail( $email ) -> \@users | ||||
541 | * =$email= - email address to look up | ||||
542 | Return a list of canonical user names for the users that have this email | ||||
543 | registered with the user mapping managers. | ||||
544 | |||||
545 | =cut | ||||
546 | |||||
547 | sub findUserByEmail { | ||||
548 | my ( $this, $email ) = @_; | ||||
549 | ASSERT($email) if DEBUG; | ||||
550 | |||||
551 | my $users = $this->{mapping}->findUserByEmail($email); | ||||
552 | push @{$users}, @{ $this->{basemapping}->findUserByEmail($email) }; | ||||
553 | |||||
554 | return $users; | ||||
555 | } | ||||
556 | |||||
557 | =begin TML | ||||
558 | |||||
559 | ---++ ObjectMethod getEmails($name) -> @emailAddress | ||||
560 | |||||
561 | If $name is a cUID, return their email addresses. If it is a group, | ||||
562 | return the addresses of everyone in the group. | ||||
563 | |||||
564 | The password manager and user mapping manager are both consulted for emails | ||||
565 | for each user (where they are actually found is implementation defined). | ||||
566 | |||||
567 | Duplicates are removed from the list. | ||||
568 | |||||
569 | =cut | ||||
570 | |||||
571 | sub getEmails { | ||||
572 | my ( $this, $name ) = @_; | ||||
573 | |||||
574 | return () unless ($name); | ||||
575 | if ( $this->{mapping}->isGroup($name) ) { | ||||
576 | return $this->{mapping}->getEmails($name); | ||||
577 | } | ||||
578 | |||||
579 | return $this->_getMapping($name)->getEmails($name); | ||||
580 | } | ||||
581 | |||||
582 | =begin TML | ||||
583 | |||||
584 | ---++ ObjectMethod setEmails($cUID, @emails) | ||||
585 | |||||
586 | Set the email address(es) for the given user. | ||||
587 | The password manager is tried first, and if it doesn't want to know the | ||||
588 | user mapping manager is tried. | ||||
589 | |||||
590 | =cut | ||||
591 | |||||
592 | sub setEmails { | ||||
593 | my $this = shift; | ||||
594 | my $cUID = shift; | ||||
595 | my @emails = @_; | ||||
596 | return $this->_getMapping($cUID)->setEmails( $cUID, @emails ); | ||||
597 | } | ||||
598 | |||||
599 | =begin TML | ||||
600 | |||||
601 | ---++ ObjectMethod isAdmin( $cUID ) -> $boolean | ||||
602 | |||||
603 | True if the user is an admin | ||||
604 | * is $Foswiki::cfg{SuperAdminGroup} | ||||
605 | * is a member of the $Foswiki::cfg{SuperAdminGroup} | ||||
606 | |||||
607 | =cut | ||||
608 | |||||
609 | # spent 4.58ms (2.10+2.48) within Foswiki::Users::isAdmin which was called 585 times, avg 8µs/call:
# 409 times (1.06ms+0s) by Foswiki::Meta::haveAccess at line 1747 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 3µs/call
# 94 times (520µs+0s) by Foswiki::WebFilter::ok at line 42 of /var/www/foswiki11/lib/Foswiki/WebFilter.pm, avg 6µs/call
# 41 times (386µs+27µs) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 53 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 10µs/call
# 40 times (94µs+0s) by Foswiki::Store::SearchAlgorithms::Forking::query at line 158 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 2µs/call
# once (40µs+2.45ms) by Foswiki::new at line 1971 of /var/www/foswiki11/lib/Foswiki.pm | ||||
610 | 585 | 407µs | my ( $this, $cUID ) = @_; | ||
611 | |||||
612 | 585 | 127µs | return 0 unless defined $cUID; | ||
613 | |||||
614 | 585 | 1.98ms | return $this->{isAdmin}->{$cUID} | ||
615 | if ( defined( $this->{isAdmin}->{$cUID} ) ); | ||||
616 | |||||
617 | 2 | 10µs | 2 | 83µs | my $mapping = $this->_getMapping($cUID); # spent 83µs making 2 calls to Foswiki::Users::_getMapping, avg 42µs/call |
618 | 2 | 6µs | my $otherMapping = | ||
619 | ( $mapping eq $this->{basemapping} ) | ||||
620 | ? $this->{mapping} | ||||
621 | : $this->{basemapping}; | ||||
622 | |||||
623 | 2 | 2µs | if ( $mapping eq $otherMapping ) { | ||
624 | return $mapping->isAdmin($cUID); | ||||
625 | } | ||||
626 | 2 | 20µs | 3 | 2.39ms | $this->{isAdmin}->{$cUID} = # spent 2.27ms making 2 calls to Foswiki::Users::TopicUserMapping::isAdmin, avg 1.14ms/call
# spent 122µs making 1 call to Foswiki::Users::BaseUserMapping::isAdmin |
627 | ( $mapping->isAdmin($cUID) || $otherMapping->isAdmin($cUID) ); | ||||
628 | 2 | 12µs | return $this->{isAdmin}->{$cUID}; | ||
629 | } | ||||
630 | |||||
631 | =begin TML | ||||
632 | |||||
633 | ---++ ObjectMethod isInUserList( $cUID, \@list ) -> $boolean | ||||
634 | |||||
635 | Return true if $cUID is in a list of user *wikinames*, *logins* and group ids. | ||||
636 | |||||
637 | The list may contain the conventional web specifiers (which are ignored). | ||||
638 | |||||
639 | =cut | ||||
640 | |||||
641 | # spent 310ms (3.65+306) within Foswiki::Users::isInUserList which was called 325 times, avg 953µs/call:
# 322 times (3.61ms+63.5ms) by Foswiki::Meta::haveAccess at line 1797 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 208µs/call
# 3 times (44µs+243ms) by Foswiki::Meta::haveAccess at line 1811 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 80.9ms/call | ||||
642 | 325 | 206µs | my ( $this, $cUID, $userlist ) = @_; | ||
643 | |||||
644 | 325 | 85µs | return 0 unless defined $userlist && defined $cUID; | ||
645 | |||||
646 | 325 | 311µs | foreach my $ident (@$userlist) { | ||
647 | |||||
648 | 374 | 644µs | 374 | 59.3ms | my $identCUID = $this->getCanonicalUserID($ident); # spent 59.3ms making 374 calls to Foswiki::Users::getCanonicalUserID, avg 159µs/call |
649 | |||||
650 | 374 | 147µs | if ( defined $identCUID ) { | ||
651 | return 1 if ( $identCUID eq $cUID ); | ||||
652 | } | ||||
653 | 374 | 1.08ms | 377 | 247ms | if ( $this->isGroup($ident) ) { # spent 226ms making 374 calls to Foswiki::Users::isGroup, avg 605µs/call
# spent 20.5ms making 3 calls to Foswiki::Users::isInGroup, avg 6.84ms/call |
654 | return 1 if ( $this->isInGroup( $cUID, $ident ) ); | ||||
655 | } | ||||
656 | } | ||||
657 | 325 | 6.76ms | return 0; | ||
658 | } | ||||
659 | |||||
660 | =begin TML | ||||
661 | |||||
662 | ---++ ObjectMethod getLoginName($cUID) -> $login | ||||
663 | |||||
664 | Get the login name of a user. Returns undef if the user is not known. | ||||
665 | |||||
666 | =cut | ||||
667 | |||||
668 | # spent 250µs (175+75) within Foswiki::Users::getLoginName which was called 42 times, avg 6µs/call:
# 36 times (123µs+0s) by Foswiki::Plugin::__ANON__[/var/www/foswiki11/lib/Foswiki/Plugin.pm:241] at line 234 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 3µs/call
# 3 times (29µs+75µs) by Foswiki::Render::renderRevisionInfo at line 1772 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 35µs/call
# 2 times (13µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm:20] at line 16 of /var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm, avg 6µs/call
# once (10µs+0s) by Foswiki::logEvent at line 2249 of /var/www/foswiki11/lib/Foswiki.pm | ||||
669 | 42 | 28µs | my ( $this, $cUID ) = @_; | ||
670 | |||||
671 | 42 | 12µs | return unless defined($cUID); | ||
672 | |||||
673 | 42 | 190µs | return $this->{cUID2Login}->{$cUID} | ||
674 | if ( defined( $this->{cUID2Login}->{$cUID} ) ); | ||||
675 | |||||
676 | 1 | 2µs | 1 | 1µs | ASSERT( $this->{basemapping} ); # spent 1µs making 1 call to Assert::dummyASSERT |
677 | 1 | 2µs | 1 | 13µs | my $mapping = $this->_getMapping($cUID); # spent 13µs making 1 call to Foswiki::Users::_getMapping |
678 | 1 | 400ns | my $login; | ||
679 | 1 | 3µs | 1 | 61µs | if ( $cUID && $mapping ) { # spent 61µs making 1 call to Foswiki::Users::TopicUserMapping::getLoginName |
680 | $login = $mapping->getLoginName($cUID); | ||||
681 | } | ||||
682 | |||||
683 | 1 | 1µs | if ( defined $login ) { | ||
684 | 1 | 2µs | $this->{cUID2Login}->{$cUID} = $login; | ||
685 | 1 | 2µs | $this->{login2cUID}->{$login} = $cUID; | ||
686 | } | ||||
687 | |||||
688 | 1 | 4µs | return $login; | ||
689 | } | ||||
690 | |||||
691 | =begin TML | ||||
692 | |||||
693 | ---++ ObjectMethod getWikiName($cUID) -> $wikiName | ||||
694 | |||||
695 | Get the wikiname to display for a canonical user identifier. | ||||
696 | |||||
697 | Can return undef if the user is not in the mapping system | ||||
698 | (or the special case from initialiseUser) | ||||
699 | |||||
700 | =cut | ||||
701 | |||||
702 | # spent 136µs (100+36) within Foswiki::Users::getWikiName which was called 14 times, avg 10µs/call:
# 5 times (65µs+36µs) by Foswiki::Users::webDotWikiName at line 744, avg 20µs/call
# 5 times (19µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm:36] at line 31 of /var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm, avg 4µs/call
# 3 times (7µs+0s) by Foswiki::Render::renderRevisionInfo at line 1771 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 2µs/call
# once (9µs+0s) by Foswiki::new at line 1962 of /var/www/foswiki11/lib/Foswiki.pm | ||||
703 | 14 | 12µs | my ( $this, $cUID ) = @_; | ||
704 | 14 | 4µs | return 'UnknownUser' unless defined($cUID); | ||
705 | 14 | 72µs | return $this->{cUID2WikiName}->{$cUID} | ||
706 | if ( defined( $this->{cUID2WikiName}->{$cUID} ) ); | ||||
707 | |||||
708 | 1 | 300ns | my $wikiname; | ||
709 | 1 | 1µs | 1 | 14µs | my $mapping = $this->_getMapping($cUID); # spent 14µs making 1 call to Foswiki::Users::_getMapping |
710 | 1 | 4µs | 1 | 22µs | $wikiname = $mapping->getWikiName($cUID) if $mapping; # spent 22µs making 1 call to Foswiki::Users::TopicUserMapping::getWikiName |
711 | |||||
712 | #don't cache unknown users - it really makes a mess later. | ||||
713 | 1 | 1µs | if ( !defined($wikiname) ) { | ||
714 | if ( $Foswiki::cfg{RenderLoggedInButUnknownUsers} ) { | ||||
715 | $wikiname = "UnknownUser (<nop>$cUID)"; | ||||
716 | } | ||||
717 | else { | ||||
718 | $wikiname = $cUID; | ||||
719 | } | ||||
720 | } | ||||
721 | else { | ||||
722 | |||||
723 | # remove the web part | ||||
724 | # SMELL: is this really needed? | ||||
725 | 1 | 25µs | $wikiname =~ s/^($Foswiki::cfg{UsersWebName}|%MAINWEB%|%USERSWEB%)\.//; | ||
726 | |||||
727 | 1 | 3µs | $this->{cUID2WikiName}->{$cUID} = $wikiname; | ||
728 | 1 | 2µs | $this->{wikiName2cUID}->{$wikiname} = $cUID; | ||
729 | } | ||||
730 | 1 | 5µs | return $wikiname; | ||
731 | } | ||||
732 | |||||
733 | =begin TML | ||||
734 | |||||
735 | ---++ ObjectMethod webDotWikiName($cUID) -> $webDotWiki | ||||
736 | |||||
737 | Return the fully qualified wikiname of the user | ||||
738 | |||||
739 | =cut | ||||
740 | |||||
741 | # spent 151µs (50+101) within Foswiki::Users::webDotWikiName which was called 5 times, avg 30µs/call:
# 3 times (23µs+90µs) by Foswiki::Render::renderRevisionInfo at line 1770 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 38µs/call
# 2 times (27µs+11µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm:45] at line 39 of /var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm, avg 19µs/call | ||||
742 | 5 | 6µs | my ( $this, $cUID ) = @_; | ||
743 | |||||
744 | 5 | 42µs | 5 | 101µs | return $Foswiki::cfg{UsersWebName} . '.' . $this->getWikiName($cUID); # spent 101µs making 5 calls to Foswiki::Users::getWikiName, avg 20µs/call |
745 | } | ||||
746 | |||||
747 | =begin TML | ||||
748 | |||||
749 | ---++ ObjectMethod userExists($cUID) -> $boolean | ||||
750 | |||||
751 | Determine if the user already exists or not. A user exists if they are | ||||
752 | known to to the user mapper. | ||||
753 | |||||
754 | =cut | ||||
755 | |||||
756 | sub userExists { | ||||
757 | my ( $this, $cUID ) = @_; | ||||
758 | return $this->_getMapping($cUID)->userExists($cUID); | ||||
759 | } | ||||
760 | |||||
761 | =begin TML | ||||
762 | |||||
763 | ---++ ObjectMethod eachUser() -> Foswiki::Iterator of cUIDs | ||||
764 | |||||
765 | Get an iterator over the list of all the registered users *not* including | ||||
766 | groups. | ||||
767 | |||||
768 | list of canonical_ids ??? | ||||
769 | |||||
770 | Use it as follows: | ||||
771 | <verbatim> | ||||
772 | my $iterator = $umm->eachUser(); | ||||
773 | while ($iterator->hasNext()) { | ||||
774 | my $user = $iterator->next(); | ||||
775 | ... | ||||
776 | } | ||||
777 | </verbatim> | ||||
778 | |||||
779 | =cut | ||||
780 | |||||
781 | sub eachUser { | ||||
782 | my $this = shift; | ||||
783 | my @list = | ||||
784 | ( $this->{basemapping}->eachUser(@_), $this->{mapping}->eachUser(@_) ); | ||||
785 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
786 | |||||
787 | return shift->{mapping}->eachUser(@_); | ||||
788 | } | ||||
789 | |||||
790 | =begin TML | ||||
791 | |||||
792 | ---++ ObjectMethod eachGroup() -> $iterator | ||||
793 | |||||
794 | Get an iterator over the list of all the group names. | ||||
795 | |||||
796 | =cut | ||||
797 | |||||
798 | sub eachGroup { | ||||
799 | my $this = shift; | ||||
800 | my @list = | ||||
801 | ( $this->{basemapping}->eachGroup(@_), $this->{mapping}->eachGroup(@_) ); | ||||
802 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
803 | } | ||||
804 | |||||
805 | =begin TML | ||||
806 | |||||
807 | ---++ ObjectMethod eachGroupMember($group) -> $iterator | ||||
808 | |||||
809 | Return a iterator of user ids that are members of this group. | ||||
810 | Should only be called on groups. | ||||
811 | |||||
812 | Note that groups may be defined recursively, so a group may contain other | ||||
813 | groups. This method should *only* return users i.e. all contained groups | ||||
814 | should be fully expanded. | ||||
815 | |||||
816 | =cut | ||||
817 | |||||
818 | sub eachGroupMember { | ||||
819 | my $this = shift; | ||||
820 | my @list = ( | ||||
821 | $this->{basemapping}->eachGroupMember(@_), | ||||
822 | $this->{mapping}->eachGroupMember(@_) | ||||
823 | ); | ||||
824 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
825 | } | ||||
826 | |||||
827 | =begin TML | ||||
828 | |||||
829 | ---++ ObjectMethod isGroup($name) -> boolean | ||||
830 | |||||
831 | Establish if a $name refers to a group or not. If $name is not | ||||
832 | a group name it will probably be a canonical user id, though that | ||||
833 | should not be assumed. | ||||
834 | |||||
835 | =cut | ||||
836 | |||||
837 | # spent 226ms (2.64+224) within Foswiki::Users::isGroup which was called 374 times, avg 605µs/call:
# 374 times (2.64ms+224ms) by Foswiki::Users::isInUserList at line 653, avg 605µs/call | ||||
838 | 374 | 108µs | my $this = shift; | ||
839 | 374 | 1.86ms | 748 | 224ms | return ( $this->{basemapping}->isGroup(@_) ) # spent 223ms making 374 calls to Foswiki::Users::TopicUserMapping::isGroup, avg 596µs/call
# spent 629µs making 374 calls to Foswiki::Users::BaseUserMapping::isGroup, avg 2µs/call |
840 | || ( $this->{mapping}->isGroup(@_) ); | ||||
841 | } | ||||
842 | |||||
843 | =begin TML | ||||
844 | |||||
845 | ---++ ObjectMethod isInGroup( $cUID, $group, $options) -> $boolean | ||||
846 | |||||
847 | Test if the user identified by $cUID is in the given group. Options | ||||
848 | is a hash array of options effecting the search. Available options are: | ||||
849 | |||||
850 | * =expand => 1= 0/1 - should nested groups be expanded when searching for the user. Default is 1, to expand nested groups. | ||||
851 | |||||
852 | =cut | ||||
853 | |||||
854 | # spent 20.5ms (76µs+20.4) within Foswiki::Users::isInGroup which was called 3 times, avg 6.84ms/call:
# 3 times (76µs+20.4ms) by Foswiki::Users::isInUserList at line 653, avg 6.84ms/call | ||||
855 | 3 | 4µs | my ( $this, $cUID, $group, $options ) = @_; | ||
856 | 3 | 700ns | return unless ( defined($cUID) ); | ||
857 | |||||
858 | 3 | 2µs | my $expand = $options->{expand}; | ||
859 | 3 | 1µs | $expand = 1 unless ( defined $expand ); | ||
860 | |||||
861 | 3 | 5µs | 3 | 58µs | my $mapping = $this->_getMapping($cUID); # spent 58µs making 3 calls to Foswiki::Users::_getMapping, avg 19µs/call |
862 | 3 | 6µs | my $otherMapping = | ||
863 | ( $mapping eq $this->{basemapping} ) | ||||
864 | ? $this->{mapping} | ||||
865 | : $this->{basemapping}; | ||||
866 | 3 | 19µs | 3 | 20.2ms | return 1 if $mapping->isInGroup( $cUID, $group, { expand => $expand } ); # spent 20.2ms making 3 calls to Foswiki::UserMapping::isInGroup, avg 6.74ms/call |
867 | |||||
868 | 3 | 26µs | 3 | 154µs | return $otherMapping->isInGroup( $cUID, $group, { expand => $expand } ) # spent 154µs making 3 calls to Foswiki::UserMapping::isInGroup, avg 51µs/call |
869 | if ( $otherMapping ne $mapping ); | ||||
870 | } | ||||
871 | |||||
872 | =begin TML | ||||
873 | |||||
874 | ---++ ObjectMethod eachMembership($cUID) -> $iterator | ||||
875 | |||||
876 | Return an iterator over the groups that $cUID | ||||
877 | is a member of. | ||||
878 | |||||
879 | =cut | ||||
880 | |||||
881 | sub eachMembership { | ||||
882 | my ( $this, $cUID ) = @_; | ||||
883 | |||||
884 | my $mapping = $this->_getMapping($cUID); | ||||
885 | my $wikiname = $mapping->getWikiName($cUID); | ||||
886 | |||||
887 | #stop if the user has no wikiname (generally means BugsItem4771) | ||||
888 | unless ( defined($wikiname) ) { | ||||
889 | require Foswiki::ListIterator; | ||||
890 | return new Foswiki::ListIterator( \() ); | ||||
891 | } | ||||
892 | |||||
893 | my $otherMapping = | ||||
894 | ( $mapping eq $this->{basemapping} ) | ||||
895 | ? $this->{mapping} | ||||
896 | : $this->{basemapping}; | ||||
897 | if ( $mapping eq $otherMapping ) { | ||||
898 | |||||
899 | # only using BaseMapping. | ||||
900 | return $mapping->eachMembership($cUID); | ||||
901 | } | ||||
902 | |||||
903 | my @list = | ||||
904 | ( $mapping->eachMembership($cUID), $otherMapping->eachMembership($cUID) ); | ||||
905 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
906 | } | ||||
907 | |||||
908 | =begin TML | ||||
909 | |||||
910 | ---++ ObjectMethod groupAllowsView($group) -> boolean | ||||
911 | |||||
912 | returns 1 if the group is able to be modified by the current logged in user | ||||
913 | |||||
914 | =cut | ||||
915 | |||||
916 | sub groupAllowsView { | ||||
917 | my $this = shift; | ||||
918 | my $group = shift; | ||||
919 | my $mapping = $this->{mapping}; | ||||
920 | return $mapping->groupAllowsView($group); | ||||
921 | } | ||||
922 | |||||
923 | =begin TML | ||||
924 | |||||
925 | ---++ ObjectMethod groupAllowsChange($group, $cuid) -> boolean | ||||
926 | |||||
927 | returns 1 if the group is able to be modified by the current logged in user | ||||
928 | |||||
929 | =cut | ||||
930 | |||||
931 | sub groupAllowsChange { | ||||
932 | my $this = shift; | ||||
933 | my $group = shift; | ||||
934 | my $cuid = shift || $this->{session}->{user}; | ||||
935 | |||||
936 | return ( $this->{basemapping}->groupAllowsChange( $group, $cuid ) | ||||
937 | and $this->{mapping}->groupAllowsChange( $group, $cuid ) ); | ||||
938 | } | ||||
939 | |||||
940 | =begin TML | ||||
941 | |||||
942 | ---++ ObjectMethod addToGroup( $cuid, $group, $create ) -> $boolean | ||||
943 | adds the user specified by the cuid to the group. | ||||
944 | If the group does not exist, it will return false and do nothing, unless the create flag is set. | ||||
945 | |||||
946 | =cut | ||||
947 | |||||
948 | sub addUserToGroup { | ||||
949 | my ( $this, $cuid, $group, $create ) = @_; | ||||
950 | my $mapping = $this->{mapping}; | ||||
951 | return $mapping->addUserToGroup( $cuid, $group, $create ); | ||||
952 | } | ||||
953 | |||||
954 | =begin TML | ||||
955 | |||||
956 | ---++ ObjectMethod removeFromGroup( $cuid, $group ) -> $boolean | ||||
957 | |||||
958 | =cut | ||||
959 | |||||
960 | sub removeUserFromGroup { | ||||
961 | my ( $this, $cuid, $group ) = @_; | ||||
962 | my $mapping = $this->{mapping}; | ||||
963 | return $mapping->removeUserFromGroup( $cuid, $group ); | ||||
964 | } | ||||
965 | |||||
966 | =begin TML | ||||
967 | |||||
968 | ---++ ObjectMethod checkLogin( $login, $passwordU ) -> $boolean | ||||
969 | |||||
970 | Finds if the password is valid for the given user. This method is | ||||
971 | called using the login name rather than the $cUID so that it can be called | ||||
972 | with a user who can be authenticated, but may not be mappable to a | ||||
973 | cUID (yet). | ||||
974 | |||||
975 | Returns 1 on success, undef on failure. | ||||
976 | |||||
977 | TODO: add special check for BaseMapping admin user's login, and if | ||||
978 | its there (and we're in sudo_context?) use that.. | ||||
979 | |||||
980 | =cut | ||||
981 | |||||
982 | sub checkPassword { | ||||
983 | my ( $this, $login, $pw ) = @_; | ||||
984 | my $mapping = $this->_getMapping( undef, $login, undef, 0 ); | ||||
985 | return $mapping->checkPassword( $login, $pw ); | ||||
986 | } | ||||
987 | |||||
988 | =begin TML | ||||
989 | |||||
990 | ---++ ObjectMethod setPassword( $cUID, $newPassU, $oldPassU ) -> $boolean | ||||
991 | |||||
992 | If the $oldPassU matches matches the user's password, then it will | ||||
993 | replace it with $newPassU. | ||||
994 | |||||
995 | If $oldPassU is not correct and not 1, will return 0. | ||||
996 | |||||
997 | If $oldPassU is 1, will force the change irrespective of | ||||
998 | the existing password, adding the user if necessary. | ||||
999 | |||||
1000 | Otherwise returns 1 on success, undef on failure. | ||||
1001 | |||||
1002 | =cut | ||||
1003 | |||||
1004 | sub setPassword { | ||||
1005 | my ( $this, $cUID, $newPassU, $oldPassU ) = @_; | ||||
1006 | ASSERT($cUID) if DEBUG; | ||||
1007 | return $this->_getMapping($cUID) | ||||
1008 | ->setPassword( $this->getLoginName($cUID), $newPassU, $oldPassU ); | ||||
1009 | } | ||||
1010 | |||||
1011 | =begin TML | ||||
1012 | |||||
1013 | ---++ ObjectMethod passwordError($cUID) -> $string | ||||
1014 | |||||
1015 | Returns a string indicating the error that happened in the password handler | ||||
1016 | The cUID is used to determine which mapper is handling the user. If called | ||||
1017 | without a cUID, then the Base mapping is used. | ||||
1018 | |||||
1019 | TODO: these delayed error's should be replaced with Exceptions. | ||||
1020 | |||||
1021 | returns undef if no error | ||||
1022 | |||||
1023 | =cut | ||||
1024 | |||||
1025 | sub passwordError { | ||||
1026 | my ( $this, $cUID ) = @_; | ||||
1027 | return $this->_getMapping($cUID)->passwordError(); | ||||
1028 | } | ||||
1029 | |||||
1030 | =begin TML | ||||
1031 | |||||
1032 | ---++ ObjectMethod removeUser( $cUID ) -> $boolean | ||||
1033 | |||||
1034 | Delete the users entry. Removes the user from the password | ||||
1035 | manager and user mapping manager. Does *not* remove their personal | ||||
1036 | topics, which may still be linked. | ||||
1037 | |||||
1038 | =cut | ||||
1039 | |||||
1040 | sub removeUser { | ||||
1041 | my ( $this, $cUID ) = @_; | ||||
1042 | $this->_getMapping($cUID)->removeUser($cUID); | ||||
1043 | } | ||||
1044 | |||||
1045 | 1 | 2µs | 1; | ||
1046 | __END__ |