Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm |
Statements | Executed 28224 statements in 200ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
12164 | 1 | 1 | 204ms | 3.82s | isGroup | Foswiki::Users::
1 | 1 | 1 | 12.7ms | 61.6ms | new | Foswiki::Users::
1 | 1 | 1 | 7.26ms | 7.76ms | BEGIN@64 | Foswiki::Users::
410 | 1 | 1 | 6.44ms | 8.79ms | mapLogin2cUID | Foswiki::Users::
114 | 5 | 1 | 3.48ms | 94.8ms | _getMapping | Foswiki::Users::
63 | 2 | 2 | 1.92ms | 72.9ms | findUserByWikiName | Foswiki::Users::
39 | 5 | 5 | 1.64ms | 34.1ms | getCanonicalUserID | Foswiki::Users::
589 | 4 | 1 | 1.27ms | 1.27ms | CORE:subst (opcode) | Foswiki::Users::
58 | 3 | 3 | 951µs | 85.1ms | isAdmin | Foswiki::Users::
42 | 6 | 5 | 811µs | 5.98ms | getWikiName | Foswiki::Users::
1 | 1 | 1 | 708µs | 1.49ms | BEGIN@63 | Foswiki::Users::
179 | 3 | 1 | 456µs | 456µs | CORE:regcomp (opcode) | Foswiki::Users::
27 | 4 | 4 | 324µs | 831µs | getLoginName | Foswiki::Users::
20 | 1 | 1 | 294µs | 294µs | isInUserList | Foswiki::Users::
10 | 2 | 2 | 249µs | 373µs | webDotWikiName | Foswiki::Users::
1 | 1 | 1 | 155µs | 3.25ms | finish | Foswiki::Users::
12 | 1 | 1 | 106µs | 106µs | getLoginManager | Foswiki::Users::
2 | 1 | 1 | 94µs | 10.1ms | eachGroupMember | Foswiki::Users::
1 | 1 | 1 | 68µs | 46.6ms | initialiseUser | Foswiki::Users::
1 | 1 | 1 | 40µs | 50µs | getCGISession | Foswiki::Users::
8 | 1 | 1 | 36µs | 36µs | CORE:substcont (opcode) | Foswiki::Users::
1 | 1 | 1 | 26µs | 99µs | BEGIN@300 | Foswiki::Users::
1 | 1 | 1 | 24µs | 32µs | BEGIN@59 | Foswiki::Users::
1 | 1 | 1 | 21µs | 137ms | loadSession | Foswiki::Users::
1 | 1 | 1 | 20µs | 26µs | BEGIN@388 | Foswiki::Users::
1 | 1 | 1 | 18µs | 24µs | BEGIN@390 | Foswiki::Users::
1 | 1 | 1 | 16µs | 20µs | supportsRegistration | Foswiki::Users::
1 | 1 | 1 | 16µs | 53µs | BEGIN@61 | Foswiki::Users::
1 | 1 | 1 | 16µs | 34µs | BEGIN@60 | 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 | 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 | isInGroup | 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::
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 | 50µs | 2 | 39µs | # spent 32µs (24+7) within Foswiki::Users::BEGIN@59 which was called:
# once (24µs+7µs) by Foswiki::BEGIN@613 at line 59 # spent 32µs making 1 call to Foswiki::Users::BEGIN@59
# spent 8µs making 1 call to strict::import |
60 | 2 | 48µs | 2 | 52µs | # spent 34µs (16+18) within Foswiki::Users::BEGIN@60 which was called:
# once (16µs+18µs) by Foswiki::BEGIN@613 at line 60 # spent 34µs making 1 call to Foswiki::Users::BEGIN@60
# spent 18µs making 1 call to warnings::import |
61 | 2 | 50µs | 2 | 89µs | # spent 53µs (16+37) within Foswiki::Users::BEGIN@61 which was called:
# once (16µs+37µs) by Foswiki::BEGIN@613 at line 61 # spent 53µs making 1 call to Foswiki::Users::BEGIN@61
# spent 37µs making 1 call to Assert::import |
62 | |||||
63 | 2 | 149µs | 1 | 1.49ms | # spent 1.49ms (708µs+778µs) within Foswiki::Users::BEGIN@63 which was called:
# once (708µs+778µs) by Foswiki::BEGIN@613 at line 63 # spent 1.49ms making 1 call to Foswiki::Users::BEGIN@63 |
64 | 2 | 1.39ms | 1 | 7.76ms | # spent 7.76ms (7.26+497µs) within Foswiki::Users::BEGIN@64 which was called:
# once (7.26ms+497µs) by Foswiki::BEGIN@613 at line 64 # spent 7.76ms 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 61.6ms (12.7+48.9) within Foswiki::Users::new which was called:
# once (12.7ms+48.9ms) by Foswiki::new at line 1701 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
78 | 1 | 3µs | my ( $class, $session ) = @_; | ||
79 | 1 | 15µs | my $this = bless( { session => $session }, $class ); | ||
80 | |||||
81 | # Do a dynamic 'use locale' for this module | ||||
82 | 1 | 2µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
83 | require locale; | ||||
84 | import locale(); | ||||
85 | } | ||||
86 | |||||
87 | # making basemapping | ||||
88 | 1 | 3µs | my $implBaseUserMappingManager = $Foswiki::cfg{BaseUserMappingManager} | ||
89 | || 'Foswiki::Users::BaseUserMapping'; | ||||
90 | 1 | 29µs | eval "require $implBaseUserMappingManager"; # spent 135µs executing statements in string eval | ||
91 | 1 | 2µs | die $@ if $@; | ||
92 | 1 | 12µs | 1 | 186µs | $this->{basemapping} = $implBaseUserMappingManager->new($session); # spent 186µs making 1 call to Foswiki::Users::BaseUserMapping::new |
93 | |||||
94 | 1 | 3µs | my $implUserMappingManager = $Foswiki::cfg{UserMappingManager}; | ||
95 | 1 | 2µs | $implUserMappingManager = 'Foswiki::Users::TopicUserMapping' | ||
96 | if ( $implUserMappingManager eq 'none' ); | ||||
97 | |||||
98 | 1 | 3µs | if ( $implUserMappingManager eq 'Foswiki::Users::BaseUserMapping' ) { | ||
99 | $this->{mapping} = $this->{basemapping}; #TODO: probly make undef.. | ||||
100 | } | ||||
101 | else { | ||||
102 | 1 | 31µs | eval "require $implUserMappingManager"; # spent 142µs executing statements in string eval | ||
103 | 1 | 2µs | die $@ if $@; | ||
104 | 1 | 14µs | 1 | 18.8ms | $this->{mapping} = $implUserMappingManager->new($session); # spent 18.8ms making 1 call to Foswiki::Users::TopicUserMapping::new |
105 | } | ||||
106 | |||||
107 | 1 | 9µs | 1 | 10.7ms | $this->{loginManager} = Foswiki::LoginManager::makeLoginManager($session); # spent 10.7ms 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 | 3µs | $this->{cUID2WikiName} = {}; | ||
114 | 1 | 2µs | $this->{cUID2Login} = {}; | ||
115 | 1 | 2µs | $this->{isAdmin} = {}; | ||
116 | |||||
117 | # the UI for rego supported/not is different from rego temporarily | ||||
118 | # turned off | ||||
119 | 1 | 9µs | 1 | 20µs | if ( $this->supportsRegistration() ) { # spent 20µs making 1 call to Foswiki::Users::supportsRegistration |
120 | 1 | 6µs | 1 | 8µs | $session->enterContext('registration_supported'); # spent 8µs making 1 call to Foswiki::enterContext |
121 | 1 | 7µs | 1 | 7µs | $session->enterContext('registration_enabled') # spent 7µs making 1 call to Foswiki::enterContext |
122 | if $Foswiki::cfg{Register}{EnableNewUserRegistration}; | ||||
123 | } | ||||
124 | |||||
125 | 1 | 11µ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 137ms (21µs+137) within Foswiki::Users::loadSession which was called:
# once (21µs+137ms) by Foswiki::new at line 1727 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
139 | 1 | 2µ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 | 11µs | 1 | 137ms | my $remoteUser = $this->{loginManager}->loadSession( $defaultUser, $this ); # spent 137ms making 1 call to Foswiki::LoginManager::loadSession |
145 | |||||
146 | 1 | 10µ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 3.25ms (155µs+3.10) within Foswiki::Users::finish which was called:
# once (155µs+3.10ms) by Foswiki::finish at line 2100 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
160 | 1 | 2µs | my $this = shift; | ||
161 | |||||
162 | 1 | 16µs | 1 | 1.75ms | $this->{loginManager}->finish() if $this->{loginManager}; # spent 1.75ms making 1 call to Foswiki::LoginManager::finish |
163 | 1 | 14µs | 1 | 107µs | $this->{basemapping}->finish() if $this->{basemapping}; # spent 107µs making 1 call to Foswiki::Users::BaseUserMapping::finish |
164 | |||||
165 | 1 | 17µs | 1 | 1.24ms | $this->{mapping}->finish() # spent 1.24ms making 1 call to Foswiki::Users::TopicUserMapping::finish |
166 | if $this->{mapping} | ||||
167 | && $this->{mapping} ne $this->{basemapping}; | ||||
168 | |||||
169 | 1 | 13µs | undef $this->{loginManager}; | ||
170 | 1 | 12µs | undef $this->{basemapping}; | ||
171 | 1 | 64µs | undef $this->{mapping}; | ||
172 | 1 | 2µs | undef $this->{session}; | ||
173 | 1 | 3µs | undef $this->{cUID2WikiName}; | ||
174 | 1 | 3µs | undef $this->{cUID2Login}; | ||
175 | 1 | 2µs | undef $this->{wikiName2cUID}; | ||
176 | 1 | 2µs | undef $this->{login2cUID}; | ||
177 | 1 | 12µ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 94.8ms (3.48+91.3) within Foswiki::Users::_getMapping which was called 114 times, avg 832µs/call:
# 63 times (1.85ms+65.1ms) by Foswiki::Users::findUserByWikiName at line 514, avg 1.06ms/call
# 32 times (985µs+25.7ms) by Foswiki::Users::getCanonicalUserID at line 460, avg 834µs/call
# 16 times (514µs+408µs) by Foswiki::Users::getWikiName at line 691, avg 58µs/call
# 2 times (92µs+86µs) by Foswiki::Users::isAdmin at line 599, avg 89µs/call
# once (35µs+27µs) by Foswiki::Users::getLoginName at line 659 | ||||
200 | 114 | 234µs | my ( $this, $cUID, $login, $wikiname, $noFallBack ) = @_; | ||
201 | |||||
202 | 114 | 178µs | $login = '' unless defined $login; | ||
203 | 114 | 152µs | $wikiname = '' unless defined $wikiname; | ||
204 | |||||
205 | 114 | 1.35ms | 228 | 462µs | $wikiname =~ s/^($Foswiki::cfg{UsersWebName}|%USERSWEB%|%MAINWEB%)\.//; # spent 285µs making 114 calls to Foswiki::Users::CORE:regcomp, avg 2µs/call
# spent 177µs making 114 calls to Foswiki::Users::CORE:subst, avg 2µs/call |
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 | 114 | 641µs | 114 | 1.28ms | return $this->{basemapping} # spent 1.28ms making 114 calls to Foswiki::Users::BaseUserMapping::handlesUser, avg 11µs/call |
212 | if ( $this->{basemapping}->handlesUser( $cUID, $login, $wikiname ) ); | ||||
213 | |||||
214 | 114 | 761µs | 114 | 89.6ms | return $this->{mapping} # spent 89.6ms making 114 calls to Foswiki::Users::TopicUserMapping::handlesUser, avg 786µ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 | 90 | 352µs | return $this->{basemapping} unless ($noFallBack); | ||
221 | |||||
222 | 30 | 135µ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 20µs (16+4) within Foswiki::Users::supportsRegistration which was called:
# once (16µs+4µs) by Foswiki::Users::new at line 119 | ||||
234 | 1 | 2µs | my ($this) = @_; | ||
235 | 1 | 12µs | 1 | 4µs | return $this->{mapping}->supportsRegistration(); # spent 4µs making 1 call to Foswiki::Users::TopicUserMapping::supportsRegistration |
236 | } | ||||
237 | |||||
238 | =begin TML | ||||
239 | |||||
240 | ---++ ObjectMethod initialiseUser ($login) -> $cUID | ||||
241 | |||||
242 | Given a login (which must have been authenticated) determine the cUID that | ||||
243 | corresponds to that user. This method is used from Foswiki.pm to map the | ||||
244 | $REMOTE_USER to a cUID. | ||||
245 | |||||
246 | =cut | ||||
247 | |||||
248 | # spent 46.6ms (68µs+46.6) within Foswiki::Users::initialiseUser which was called:
# once (68µs+46.6ms) by Foswiki::new at line 1863 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
249 | 1 | 5µs | my ( $this, $login ) = @_; | ||
250 | |||||
251 | # For compatibility with older ways of building login managers, | ||||
252 | # plugins can provide an alternate login name. | ||||
253 | 1 | 20µs | 1 | 46.0ms | my $plogin = # spent 46.0ms making 1 call to Foswiki::Plugins::load |
254 | $this->{session}->{plugins}->load( $Foswiki::cfg{DisableAllPlugins} ); | ||||
255 | |||||
256 | #Monitor::MARK("Plugins loaded"); | ||||
257 | |||||
258 | 1 | 2µs | $login = $plogin if $plogin; | ||
259 | |||||
260 | 1 | 3µs | my $cUID; | ||
261 | 1 | 4µs | if ( defined($login) && $login ne '' ) { | ||
262 | |||||
263 | # In the case of a user mapper that accepts any identifier as | ||||
264 | # a cUID, | ||||
265 | 1 | 11µs | 1 | 617µs | $cUID = $this->getCanonicalUserID($login); # spent 617µs making 1 call to Foswiki::Users::getCanonicalUserID |
266 | |||||
267 | # see BugsItem4771 - it seems that authenticated, but unmapped | ||||
268 | # users have rights too | ||||
269 | 1 | 2µs | if ( !defined($cUID) ) { | ||
270 | |||||
271 | # There is no known canonical user ID for this login name. | ||||
272 | # Generate a cUID for the login, and add it anyway. There is | ||||
273 | # a risk that the generated cUID will overlap a cUID generated | ||||
274 | # by a custom mapper, but since (1) the user has to be | ||||
275 | # authenticated to get here and (2) the custom user mapper | ||||
276 | # is specific to the login process used, that risk should be | ||||
277 | # small (unless the author of the custom mapper screws up) | ||||
278 | $cUID = mapLogin2cUID($login); | ||||
279 | |||||
280 | $this->{cUID2Login}->{$cUID} = $login; | ||||
281 | $this->{cUID2WikiName}->{$cUID} = $login; | ||||
282 | |||||
283 | # needs to be WikiName safe | ||||
284 | $this->{cUID2WikiName}->{$cUID} =~ s/$Foswiki::cfg{NameFilter}//go; | ||||
285 | $this->{cUID2WikiName}->{$cUID} =~ s/\.//go; | ||||
286 | |||||
287 | $this->{login2cUID}->{$login} = $cUID; | ||||
288 | $this->{wikiName2cUID}->{ $this->{cUID2WikiName}->{$cUID} } = $cUID; | ||||
289 | } | ||||
290 | } | ||||
291 | |||||
292 | # if we get here without a login id, we are a guest. Get the guest | ||||
293 | # cUID. | ||||
294 | 1 | 1µs | $cUID ||= $this->getCanonicalUserID( $Foswiki::cfg{DefaultUserLogin} ); | ||
295 | |||||
296 | 1 | 13µs | return $cUID; | ||
297 | } | ||||
298 | |||||
299 | # global used by test harness to give predictable results | ||||
300 | 2 | 406µs | 2 | 172µs | # spent 99µs (26+73) within Foswiki::Users::BEGIN@300 which was called:
# once (26µs+73µs) by Foswiki::BEGIN@613 at line 300 # spent 99µs making 1 call to Foswiki::Users::BEGIN@300
# spent 73µs making 1 call to vars::import |
301 | |||||
302 | =begin TML | ||||
303 | |||||
304 | ---++ randomPassword() | ||||
305 | Static function that returns a random password. This function is not used | ||||
306 | in this module; it is provided as a service for other modules, such as | ||||
307 | custom mappers and registration modules. | ||||
308 | |||||
309 | =cut | ||||
310 | |||||
311 | sub randomPassword { | ||||
312 | return $password | ||||
313 | || join( | ||||
314 | "", | ||||
315 | ( ".", "/", 0 .. 9, "A" .. "Z", "a" .. "z" )[ | ||||
316 | rand(64), rand(64), rand(64), rand(64), | ||||
317 | rand(64), rand(64), rand(64), rand(64) | ||||
318 | ] | ||||
319 | ); | ||||
320 | } | ||||
321 | |||||
322 | =begin TML | ||||
323 | |||||
324 | ---++ ObjectMethod addUser($login, $wikiname, $password, $emails) -> $cUID | ||||
325 | |||||
326 | * =$login= - user login name. If =undef=, =$wikiname= will be used as | ||||
327 | the login name. | ||||
328 | * =$wikiname= - user wikiname. If =undef=, the user mapper will be asked | ||||
329 | to provide it. | ||||
330 | * =$password= - password. If undef, a password will be generated. | ||||
331 | |||||
332 | Add a new Foswiki user identity, returning the canonical user id for the new | ||||
333 | user. Used ONLY for user registration. | ||||
334 | |||||
335 | The user is added to the password system (if there is one, and if it accepts | ||||
336 | changes). If the user already exists in the password system, then the password | ||||
337 | is checked and an exception thrown if it doesn't match. If there is no | ||||
338 | existing user, and no password is given, a random password is generated. | ||||
339 | |||||
340 | $login can be undef; $wikiname must always have a value. | ||||
341 | |||||
342 | The return value is the canonical user id that is used | ||||
343 | by Foswiki to identify the user. | ||||
344 | |||||
345 | =cut | ||||
346 | |||||
347 | sub addUser { | ||||
348 | my ( $this, $login, $wikiname, $password, $emails ) = @_; | ||||
349 | my $removeOnFail = 0; | ||||
350 | |||||
351 | ASSERT( $login || $wikiname ) if DEBUG; # must have at least one | ||||
352 | |||||
353 | # create a new user and get the canonical user ID from the user mapping | ||||
354 | # manager. | ||||
355 | my $cUID = | ||||
356 | $this->{mapping}->addUser( $login, $wikiname, $password, $emails ); | ||||
357 | |||||
358 | # update the cached values | ||||
359 | $this->{cUID2Login}->{$cUID} = $login; | ||||
360 | $this->{cUID2WikiName}->{$cUID} = $wikiname; | ||||
361 | |||||
362 | $this->{login2cUID}->{$login} = $cUID; | ||||
363 | $this->{wikiName2cUID}->{$wikiname} = $cUID; | ||||
364 | |||||
365 | return $cUID; | ||||
366 | } | ||||
367 | |||||
368 | =begin TML | ||||
369 | |||||
370 | ---++ StaticMethod mapLogin2cUID( $login ) -> $cUID | ||||
371 | |||||
372 | This function maps an arbitrary string into a valid cUID. The transformation | ||||
373 | is reversible, but the function is not idempotent (a cUID passed to this | ||||
374 | function will NOT be returned unchanged). The generated cUID will be unique | ||||
375 | for the given login name. | ||||
376 | |||||
377 | This static function is designed to be called from custom user mappers that | ||||
378 | support 1:1 login-to-cUID mappings. | ||||
379 | |||||
380 | =cut | ||||
381 | |||||
382 | # spent 8.79ms (6.44+2.35) within Foswiki::Users::mapLogin2cUID which was called 410 times, avg 21µs/call:
# 410 times (6.44ms+2.35ms) by Foswiki::Users::TopicUserMapping::login2cUID at line 189 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 21µs/call | ||||
383 | 410 | 598µs | my $cUID = shift; | ||
384 | |||||
385 | 410 | 1.77ms | 410 | 1.32ms | ASSERT( defined($cUID) ) if DEBUG; # spent 1.32ms making 410 calls to Assert::ASSERTS_OFF, avg 3µs/call |
386 | |||||
387 | # use bytes to ignore character encoding | ||||
388 | 2 | 89µs | 2 | 33µs | # spent 26µs (20+6) within Foswiki::Users::BEGIN@388 which was called:
# once (20µs+6µs) by Foswiki::BEGIN@613 at line 388 # spent 26µs making 1 call to Foswiki::Users::BEGIN@388
# spent 6µs making 1 call to bytes::import |
389 | 414 | 2.80ms | 418 | 1.02ms | $cUID =~ s/([^a-zA-Z0-9])/'_'.sprintf('%02x', ord($1))/ge; # spent 985µs making 410 calls to Foswiki::Users::CORE:subst, avg 2µs/call
# spent 36µs making 8 calls to Foswiki::Users::CORE:substcont, avg 5µs/call |
390 | 2 | 2.94ms | 2 | 31µs | # spent 24µs (18+6) within Foswiki::Users::BEGIN@390 which was called:
# once (18µs+6µs) by Foswiki::BEGIN@613 at line 390 # spent 24µs making 1 call to Foswiki::Users::BEGIN@390
# spent 6µs making 1 call to bytes::unimport |
391 | 410 | 2.12ms | return $cUID; | ||
392 | } | ||||
393 | |||||
394 | =begin TML | ||||
395 | |||||
396 | ---++ ObjectMethod getCGISession() | ||||
397 | Get the currect CGI session object | ||||
398 | |||||
399 | =cut | ||||
400 | |||||
401 | # spent 50µs (40+10) within Foswiki::Users::getCGISession which was called:
# once (40µs+10µs) by Foswiki::getCGISession at line 1246 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
402 | 1 | 2µs | my $this = shift; | ||
403 | 1 | 36µs | 1 | 10µs | return $this->{loginManager}->getCGISession(); # spent 10µs making 1 call to Foswiki::LoginManager::getCGISession |
404 | } | ||||
405 | |||||
406 | =begin TML | ||||
407 | |||||
408 | ---++ ObjectMethod getLoginManager() -> $loginManager | ||||
409 | |||||
410 | Get the Foswiki::LoginManager object associated with this session, if there is | ||||
411 | one. May return undef. | ||||
412 | |||||
413 | =cut | ||||
414 | |||||
415 | # spent 106µs within Foswiki::Users::getLoginManager which was called 12 times, avg 9µs/call:
# 12 times (106µs+0s) by Foswiki::getLoginManager at line 1259 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 9µs/call | ||||
416 | 12 | 20µs | my $this = shift; | ||
417 | 12 | 119µs | return $this->{loginManager}; | ||
418 | } | ||||
419 | |||||
420 | =begin TML | ||||
421 | |||||
422 | ---++ ObjectMethod getCanonicalUserID( $identifier ) -> $cUID | ||||
423 | |||||
424 | Works out the Foswiki canonical user identifier for the user who either | ||||
425 | (1) logs in with the login name $identifier or (2) has the wikiname | ||||
426 | $identifier. | ||||
427 | |||||
428 | The canonical user ID is an alphanumeric string that is unique | ||||
429 | to the login name, and can be mapped back to a login name and the | ||||
430 | corresponding wiki name using the methods of this class. | ||||
431 | |||||
432 | Note that if the login name to wiki name mapping is not 1:1, this | ||||
433 | method will map a wikiname to one of the login names that corresponds | ||||
434 | to the wiki name, but there is no guarantee which one. | ||||
435 | |||||
436 | Returns undef if the user does not exist. | ||||
437 | |||||
438 | =cut | ||||
439 | |||||
440 | # This function was previously known as forceCUID. It differs from that | ||||
441 | # implementation in that it does *not* accept a CUID as parameter, which | ||||
442 | # if why it has been renamed. | ||||
443 | # spent 34.1ms (1.64+32.5) within Foswiki::Users::getCanonicalUserID which was called 39 times, avg 875µs/call:
# 30 times (1.36ms+11.6ms) by Foswiki::Users::TopicUserMapping::_expandUserList at line 1650 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 433µs/call
# 6 times (139µs+20µs) by Foswiki::Render::renderRevisionInfo at line 1735 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 26µs/call
# once (66µs+20.2ms) by Foswiki::LoginManager::userLoggedIn at line 602 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm
# once (57µs+560µs) by Foswiki::Users::initialiseUser at line 265
# once (22µs+3µs) by Foswiki::Func::getCanonicalUserID at line 863 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm | ||||
444 | 39 | 78µs | my ( $this, $identifier ) = @_; | ||
445 | 39 | 49µs | my $cUID; | ||
446 | |||||
447 | 39 | 174µs | 39 | 131µs | ASSERT( defined $identifier ) if DEBUG; # spent 131µs making 39 calls to Assert::ASSERTS_OFF, avg 3µs/call |
448 | |||||
449 | # Someone we already know? | ||||
450 | |||||
451 | 39 | 151µs | if ( defined( $this->{login2cUID}->{$identifier} ) ) { | ||
452 | 7 | 17µs | $cUID = $this->{login2cUID}->{$identifier}; | ||
453 | } | ||||
454 | elsif ( defined( $this->{wikiName2cUID}->{$identifier} ) ) { | ||||
455 | $cUID = $this->{wikiName2cUID}->{$identifier}; | ||||
456 | } | ||||
457 | else { | ||||
458 | |||||
459 | # See if a mapping recognises the identifier as a login name | ||||
460 | 32 | 170µs | 32 | 26.7ms | my $mapping = $this->_getMapping( undef, $identifier, undef, 1 ); # spent 26.7ms making 32 calls to Foswiki::Users::_getMapping, avg 834µs/call |
461 | 32 | 45µs | if ($mapping) { | ||
462 | 2 | 36µs | 2 | 10µs | if ( $mapping->can('login2cUID') ) { # spent 10µs making 2 calls to UNIVERSAL::can, avg 5µs/call |
463 | 2 | 13µs | 2 | 434µs | $cUID = $mapping->login2cUID($identifier); # spent 434µs making 2 calls to Foswiki::Users::TopicUserMapping::login2cUID, avg 217µs/call |
464 | } | ||||
465 | elsif ( $mapping->can('getCanonicalUserID') ) { | ||||
466 | |||||
467 | # Old name of login2cUID. Name changed to avoid confusion | ||||
468 | # with Foswiki::Users::getCanonicalUserID. See | ||||
469 | # Codev.UserMapperChangesBetween420And421 for more. | ||||
470 | $cUID = $mapping->getCanonicalUserID($identifier); | ||||
471 | } | ||||
472 | else { | ||||
473 | die( | ||||
474 | "Broken user mapping $mapping; does not implement login2cUID" | ||||
475 | ); | ||||
476 | } | ||||
477 | } | ||||
478 | |||||
479 | 32 | 84µs | unless ($cUID) { | ||
480 | |||||
481 | # Finally see if it's a valid user wikiname | ||||
482 | |||||
483 | # Strip users web id (legacy, probably specific to | ||||
484 | # TopicUserMappingContrib but may be used by other mappers | ||||
485 | # that support user topics) | ||||
486 | 30 | 211µs | 30 | 1.27ms | my ( $dummy, $nid ) = # spent 1.27ms making 30 calls to Foswiki::normalizeWebTopicName, avg 42µs/call |
487 | $this->{session}->normalizeWebTopicName( '', $identifier ); | ||||
488 | 30 | 60µs | $identifier = $nid if ( $dummy eq $Foswiki::cfg{UsersWebName} ); | ||
489 | |||||
490 | 30 | 175µs | 30 | 3.92ms | my $found = $this->findUserByWikiName($identifier); # spent 3.92ms making 30 calls to Foswiki::Users::findUserByWikiName, avg 131µs/call |
491 | 30 | 62µs | $cUID = $found->[0] if ( $found && scalar(@$found) ); | ||
492 | } | ||||
493 | } | ||||
494 | 39 | 221µs | return $cUID; | ||
495 | } | ||||
496 | |||||
497 | =begin TML | ||||
498 | |||||
499 | ---++ ObjectMethod findUserByWikiName( $wn ) -> \@users | ||||
500 | * =$wn= - wikiname to look up | ||||
501 | Return a list of canonical user names for the users that have this wikiname. | ||||
502 | Since a single wikiname might be used by multiple login ids, we need a list. | ||||
503 | |||||
504 | If $wn is the name of a group, the group will *not* be expanded. | ||||
505 | |||||
506 | =cut | ||||
507 | |||||
508 | # spent 72.9ms (1.92+71.0) within Foswiki::Users::findUserByWikiName which was called 63 times, avg 1.16ms/call:
# 33 times (1.03ms+68.0ms) by Foswiki::Users::TopicUserMapping::_expandUserList at line 1642 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 2.09ms/call
# 30 times (890µs+3.03ms) by Foswiki::Users::getCanonicalUserID at line 490, avg 131µs/call | ||||
509 | 63 | 104µs | my ( $this, $wn ) = @_; | ||
510 | 63 | 276µs | 63 | 210µs | ASSERT($wn) if DEBUG; # spent 210µs making 63 calls to Assert::ASSERTS_OFF, avg 3µs/call |
511 | |||||
512 | # Trim the (pointless) userweb, if present | ||||
513 | 63 | 698µs | 126 | 237µs | $wn =~ s/^($Foswiki::cfg{UsersWebName}|%USERSWEB%|%MAINWEB%)\.//; # spent 136µs making 63 calls to Foswiki::Users::CORE:regcomp, avg 2µs/call
# spent 101µs making 63 calls to Foswiki::Users::CORE:subst, avg 2µs/call |
514 | 63 | 329µs | 63 | 66.9ms | my $mapping = $this->_getMapping( undef, undef, $wn ); # spent 66.9ms making 63 calls to Foswiki::Users::_getMapping, avg 1.06ms/call |
515 | |||||
516 | #my $mapping = $this->_getMapping( $wn, $wn, $wn ); # why not? | ||||
517 | 63 | 575µs | 63 | 3.62ms | return $mapping->findUserByWikiName($wn); # spent 2.12ms making 3 calls to Foswiki::Users::TopicUserMapping::findUserByWikiName, avg 705µs/call
# spent 1.50ms making 60 calls to Foswiki::Users::BaseUserMapping::findUserByWikiName, avg 25µs/call |
518 | } | ||||
519 | |||||
520 | =begin TML | ||||
521 | |||||
522 | ---++ ObjectMethod findUserByEmail( $email ) -> \@users | ||||
523 | * =$email= - email address to look up | ||||
524 | Return a list of canonical user names for the users that have this email | ||||
525 | registered with the user mapping managers. | ||||
526 | |||||
527 | =cut | ||||
528 | |||||
529 | sub findUserByEmail { | ||||
530 | my ( $this, $email ) = @_; | ||||
531 | ASSERT($email) if DEBUG; | ||||
532 | |||||
533 | my $users = $this->{mapping}->findUserByEmail($email); | ||||
534 | push @{$users}, @{ $this->{basemapping}->findUserByEmail($email) }; | ||||
535 | |||||
536 | return $users; | ||||
537 | } | ||||
538 | |||||
539 | =begin TML | ||||
540 | |||||
541 | ---++ ObjectMethod getEmails($name) -> @emailAddress | ||||
542 | |||||
543 | If $name is a cUID, return their email addresses. If it is a group, | ||||
544 | return the addresses of everyone in the group. | ||||
545 | |||||
546 | The password manager and user mapping manager are both consulted for emails | ||||
547 | for each user (where they are actually found is implementation defined). | ||||
548 | |||||
549 | Duplicates are removed from the list. | ||||
550 | |||||
551 | =cut | ||||
552 | |||||
553 | sub getEmails { | ||||
554 | my ( $this, $name ) = @_; | ||||
555 | |||||
556 | return () unless ($name); | ||||
557 | if ( $this->{mapping}->isGroup($name) ) { | ||||
558 | return $this->{mapping}->getEmails($name); | ||||
559 | } | ||||
560 | |||||
561 | return $this->_getMapping($name)->getEmails($name); | ||||
562 | } | ||||
563 | |||||
564 | =begin TML | ||||
565 | |||||
566 | ---++ ObjectMethod setEmails($cUID, @emails) | ||||
567 | |||||
568 | Set the email address(es) for the given user. | ||||
569 | The password manager is tried first, and if it doesn't want to know the | ||||
570 | user mapping manager is tried. | ||||
571 | |||||
572 | =cut | ||||
573 | |||||
574 | sub setEmails { | ||||
575 | my $this = shift; | ||||
576 | my $cUID = shift; | ||||
577 | my @emails = @_; | ||||
578 | return $this->_getMapping($cUID)->setEmails( $cUID, @emails ); | ||||
579 | } | ||||
580 | |||||
581 | =begin TML | ||||
582 | |||||
583 | ---++ ObjectMethod isAdmin( $cUID ) -> $boolean | ||||
584 | |||||
585 | True if the user is an admin | ||||
586 | * is $Foswiki::cfg{SuperAdminGroup} | ||||
587 | * is a member of the $Foswiki::cfg{SuperAdminGroup} | ||||
588 | |||||
589 | =cut | ||||
590 | |||||
591 | # spent 85.1ms (951µs+84.2) within Foswiki::Users::isAdmin which was called 58 times, avg 1.47ms/call:
# 56 times (886µs+84.1ms) by Foswiki::Access::TopicACLAccess::haveAccess at line 80 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Access/TopicACLAccess.pm, avg 1.52ms/call
# once (47µs+128µs) by Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator at line 199 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm
# once (18µs+0s) by Foswiki::Func::isAnAdmin at line 1085 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm | ||||
592 | 58 | 204µs | my ( $this, $cUID ) = @_; | ||
593 | |||||
594 | 58 | 140µs | return 0 unless defined $cUID; | ||
595 | |||||
596 | 58 | 517µs | return $this->{isAdmin}->{$cUID} | ||
597 | if ( defined( $this->{isAdmin}->{$cUID} ) ); | ||||
598 | |||||
599 | 2 | 18µs | 2 | 179µs | my $mapping = $this->_getMapping($cUID); # spent 179µs making 2 calls to Foswiki::Users::_getMapping, avg 89µs/call |
600 | 2 | 8µs | my $otherMapping = | ||
601 | ( $mapping eq $this->{basemapping} ) | ||||
602 | ? $this->{mapping} | ||||
603 | : $this->{basemapping}; | ||||
604 | |||||
605 | 2 | 4µs | if ( $mapping eq $otherMapping ) { | ||
606 | return $mapping->isAdmin($cUID); | ||||
607 | } | ||||
608 | 2 | 42µs | 3 | 84.0ms | $this->{isAdmin}->{$cUID} = # spent 83.8ms making 2 calls to Foswiki::Users::TopicUserMapping::isAdmin, avg 41.9ms/call
# spent 234µs making 1 call to Foswiki::Users::BaseUserMapping::isAdmin |
609 | ( $mapping->isAdmin($cUID) || $otherMapping->isAdmin($cUID) ); | ||||
610 | 2 | 22µs | return $this->{isAdmin}->{$cUID}; | ||
611 | } | ||||
612 | |||||
613 | =begin TML | ||||
614 | |||||
615 | ---++ ObjectMethod isInUserList( $cUID, \@list ) -> $boolean | ||||
616 | |||||
617 | Return true if $cUID is in a list of user *wikinames*, *logins* and group ids. | ||||
618 | |||||
619 | The list may contain the conventional web specifiers (which are ignored). | ||||
620 | |||||
621 | =cut | ||||
622 | |||||
623 | # spent 294µs within Foswiki::Users::isInUserList which was called 20 times, avg 15µs/call:
# 20 times (294µs+0s) by Foswiki::Access::TopicACLAccess::haveAccess at line 131 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Access/TopicACLAccess.pm, avg 15µs/call | ||||
624 | 20 | 59µs | my ( $this, $cUID, $userlist ) = @_; | ||
625 | |||||
626 | 20 | 30µs | return 0 unless defined $userlist && defined $cUID; | ||
627 | |||||
628 | 20 | 83µs | foreach my $ident (@$userlist) { | ||
629 | |||||
630 | my $identCUID = $this->getCanonicalUserID($ident); | ||||
631 | |||||
632 | if ( defined $identCUID ) { | ||||
633 | return 1 if ( $identCUID eq $cUID ); | ||||
634 | } | ||||
635 | if ( $this->isGroup($ident) ) { | ||||
636 | return 1 if ( $this->isInGroup( $cUID, $ident ) ); | ||||
637 | } | ||||
638 | } | ||||
639 | 20 | 124µs | return 0; | ||
640 | } | ||||
641 | |||||
642 | =begin TML | ||||
643 | |||||
644 | ---++ ObjectMethod getLoginName($cUID) -> $login | ||||
645 | |||||
646 | Get the login name of a user. Returns undef if the user is not known. | ||||
647 | |||||
648 | =cut | ||||
649 | |||||
650 | # spent 831µs (324+507) within Foswiki::Users::getLoginName which was called 27 times, avg 31µs/call:
# 19 times (238µs+507µs) by Foswiki::Plugin::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugin.pm:235] at line 228 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugin.pm, avg 39µs/call
# 6 times (51µs+0s) by Foswiki::Render::renderRevisionInfo at line 1749 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 9µs/call
# once (21µs+0s) by Foswiki::logEvent at line 2171 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
# once (14µs+0s) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm:16] at line 11 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm | ||||
651 | 27 | 54µs | my ( $this, $cUID ) = @_; | ||
652 | |||||
653 | 27 | 38µs | return unless defined($cUID); | ||
654 | |||||
655 | 27 | 232µs | return $this->{cUID2Login}->{$cUID} | ||
656 | if ( defined( $this->{cUID2Login}->{$cUID} ) ); | ||||
657 | |||||
658 | 1 | 6µs | 1 | 5µs | ASSERT( $this->{basemapping} ); # spent 5µs making 1 call to Assert::dummyASSERT |
659 | 1 | 8µs | 1 | 62µs | my $mapping = $this->_getMapping($cUID); # spent 62µs making 1 call to Foswiki::Users::_getMapping |
660 | 1 | 1µs | my $login; | ||
661 | 1 | 3µs | if ( $cUID && $mapping ) { | ||
662 | 1 | 6µs | 1 | 441µs | $login = $mapping->getLoginName($cUID); # spent 441µs making 1 call to Foswiki::Users::TopicUserMapping::getLoginName |
663 | } | ||||
664 | |||||
665 | 1 | 2µs | if ( defined $login ) { | ||
666 | 1 | 6µs | $this->{cUID2Login}->{$cUID} = $login; | ||
667 | 1 | 4µs | $this->{login2cUID}->{$login} = $cUID; | ||
668 | } | ||||
669 | |||||
670 | 1 | 10µs | return $login; | ||
671 | } | ||||
672 | |||||
673 | =begin TML | ||||
674 | |||||
675 | ---++ ObjectMethod getWikiName($cUID) -> $wikiName | ||||
676 | |||||
677 | Get the wikiname to display for a canonical user identifier. | ||||
678 | |||||
679 | Can return undef if the user is not in the mapping system | ||||
680 | (or the special case from initialiseUser) | ||||
681 | |||||
682 | =cut | ||||
683 | |||||
684 | # spent 5.98ms (811µs+5.17) within Foswiki::Users::getWikiName which was called 42 times, avg 142µs/call:
# 18 times (507µs+4.48ms) by Foswiki::Func::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm:1252] at line 1251 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 277µs/call
# 10 times (124µs+0s) by Foswiki::Users::webDotWikiName at line 726, avg 12µs/call
# 6 times (46µs+0s) by Foswiki::Render::renderRevisionInfo at line 1748 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 8µs/call
# 4 times (38µs+0s) by Foswiki::Func::getWikiName at line 899 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 10µs/call
# 3 times (28µs+0s) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm:31] at line 26 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm, avg 9µs/call
# once (69µs+681µs) by Foswiki::new at line 1886 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
685 | 42 | 91µs | my ( $this, $cUID ) = @_; | ||
686 | 42 | 58µs | return 'UnknownUser' unless defined($cUID); | ||
687 | 42 | 256µs | return $this->{cUID2WikiName}->{$cUID} | ||
688 | if ( defined( $this->{cUID2WikiName}->{$cUID} ) ); | ||||
689 | |||||
690 | 16 | 18µs | my $wikiname; | ||
691 | 16 | 86µs | 16 | 922µs | my $mapping = $this->_getMapping($cUID); # spent 922µs making 16 calls to Foswiki::Users::_getMapping, avg 58µs/call |
692 | 16 | 110µs | 16 | 4.20ms | $wikiname = $mapping->getWikiName($cUID) if $mapping; # spent 4.20ms making 16 calls to Foswiki::Users::TopicUserMapping::getWikiName, avg 263µs/call |
693 | |||||
694 | #don't cache unknown users - it really makes a mess later. | ||||
695 | 16 | 46µs | if ( !defined($wikiname) ) { | ||
696 | 14 | 44µs | if ( $Foswiki::cfg{RenderLoggedInButUnknownUsers} ) { | ||
697 | $wikiname = "UnknownUser (<nop>$cUID)"; | ||||
698 | } | ||||
699 | else { | ||||
700 | 14 | 23µs | $wikiname = $cUID; | ||
701 | } | ||||
702 | } | ||||
703 | else { | ||||
704 | |||||
705 | # remove the web part | ||||
706 | # SMELL: is this really needed? | ||||
707 | 2 | 63µs | 4 | 40µs | $wikiname =~ s/^($Foswiki::cfg{UsersWebName}|%MAINWEB%|%USERSWEB%)\.//; # spent 35µs making 2 calls to Foswiki::Users::CORE:regcomp, avg 18µs/call
# spent 4µs making 2 calls to Foswiki::Users::CORE:subst, avg 2µs/call |
708 | |||||
709 | 2 | 13µs | $this->{cUID2WikiName}->{$cUID} = $wikiname; | ||
710 | 2 | 8µs | $this->{wikiName2cUID}->{$wikiname} = $cUID; | ||
711 | } | ||||
712 | 16 | 107µs | return $wikiname; | ||
713 | } | ||||
714 | |||||
715 | =begin TML | ||||
716 | |||||
717 | ---++ ObjectMethod webDotWikiName($cUID) -> $webDotWiki | ||||
718 | |||||
719 | Return the fully qualified wikiname of the user | ||||
720 | |||||
721 | =cut | ||||
722 | |||||
723 | # spent 373µs (249+124) within Foswiki::Users::webDotWikiName which was called 10 times, avg 37µs/call:
# 6 times (110µs+60µs) by Foswiki::Render::renderRevisionInfo at line 1747 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 28µs/call
# 4 times (139µs+64µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm:40] at line 34 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm, avg 51µs/call | ||||
724 | 10 | 26µs | my ( $this, $cUID ) = @_; | ||
725 | |||||
726 | 10 | 190µs | 10 | 124µs | return $Foswiki::cfg{UsersWebName} . '.' . $this->getWikiName($cUID); # spent 124µs making 10 calls to Foswiki::Users::getWikiName, avg 12µs/call |
727 | } | ||||
728 | |||||
729 | =begin TML | ||||
730 | |||||
731 | ---++ ObjectMethod userExists($cUID) -> $boolean | ||||
732 | |||||
733 | Determine if the user already exists or not. A user exists if they are | ||||
734 | known to to the user mapper. | ||||
735 | |||||
736 | =cut | ||||
737 | |||||
738 | sub userExists { | ||||
739 | my ( $this, $cUID ) = @_; | ||||
740 | return $this->_getMapping($cUID)->userExists($cUID); | ||||
741 | } | ||||
742 | |||||
743 | =begin TML | ||||
744 | |||||
745 | ---++ ObjectMethod eachUser() -> Foswiki::Iterator of cUIDs | ||||
746 | |||||
747 | Get an iterator over the list of all the registered users *not* including | ||||
748 | groups. | ||||
749 | |||||
750 | list of canonical_ids ??? | ||||
751 | |||||
752 | Use it as follows: | ||||
753 | <verbatim> | ||||
754 | my $iterator = $umm->eachUser(); | ||||
755 | while ($iterator->hasNext()) { | ||||
756 | my $user = $iterator->next(); | ||||
757 | ... | ||||
758 | } | ||||
759 | </verbatim> | ||||
760 | |||||
761 | =cut | ||||
762 | |||||
763 | sub eachUser { | ||||
764 | my $this = shift; | ||||
765 | my @list = | ||||
766 | ( $this->{basemapping}->eachUser(@_), $this->{mapping}->eachUser(@_) ); | ||||
767 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
768 | |||||
769 | return shift->{mapping}->eachUser(@_); | ||||
770 | } | ||||
771 | |||||
772 | =begin TML | ||||
773 | |||||
774 | ---++ ObjectMethod eachGroup() -> $iterator | ||||
775 | |||||
776 | Get an iterator over the list of all the group names. | ||||
777 | |||||
778 | =cut | ||||
779 | |||||
780 | sub eachGroup { | ||||
781 | my $this = shift; | ||||
782 | my @list = | ||||
783 | ( $this->{basemapping}->eachGroup(@_), $this->{mapping}->eachGroup(@_) ); | ||||
784 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
785 | } | ||||
786 | |||||
787 | =begin TML | ||||
788 | |||||
789 | ---++ ObjectMethod eachGroupMember($group) -> $iterator | ||||
790 | |||||
791 | Return a iterator of user ids that are members of this group. | ||||
792 | Should only be called on groups. | ||||
793 | |||||
794 | Note that groups may be defined recursively, so a group may contain other | ||||
795 | groups. This method should *only* return users i.e. all contained groups | ||||
796 | should be fully expanded. | ||||
797 | |||||
798 | =cut | ||||
799 | |||||
800 | # spent 10.1ms (94µs+9.96) within Foswiki::Users::eachGroupMember which was called 2 times, avg 5.03ms/call:
# 2 times (94µs+9.96ms) by Foswiki::Func::eachGroupMember at line 1247 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 5.03ms/call | ||||
801 | 2 | 3µs | my $this = shift; | ||
802 | 2 | 43µs | 4 | 9.90ms | my @list = ( # spent 9.81ms making 2 calls to Foswiki::Users::TopicUserMapping::eachGroupMember, avg 4.90ms/call
# spent 90µs making 2 calls to Foswiki::Users::BaseUserMapping::eachGroupMember, avg 45µs/call |
803 | $this->{basemapping}->eachGroupMember(@_), | ||||
804 | $this->{mapping}->eachGroupMember(@_) | ||||
805 | ); | ||||
806 | 2 | 46µs | 2 | 62µs | return new Foswiki::AggregateIterator( \@list, 1 ); # spent 62µs making 2 calls to Foswiki::AggregateIterator::new, avg 31µs/call |
807 | } | ||||
808 | |||||
809 | =begin TML | ||||
810 | |||||
811 | ---++ ObjectMethod isGroup($name) -> boolean | ||||
812 | |||||
813 | Establish if a $name refers to a group or not. If $name is not | ||||
814 | a group name it will probably be a canonical user id, though that | ||||
815 | should not be assumed. | ||||
816 | |||||
817 | =cut | ||||
818 | |||||
819 | # spent 3.82s (204ms+3.62) within Foswiki::Users::isGroup which was called 12164 times, avg 314µs/call:
# 12164 times (204ms+3.62s) by Foswiki::Func::eachGroupMember at line 1246 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 314µs/call | ||||
820 | 12164 | 18.2ms | my $this = shift; | ||
821 | 12164 | 159ms | 24328 | 3.62s | return ( $this->{basemapping}->isGroup(@_) ) # spent 3.53s making 12164 calls to Foswiki::Users::TopicUserMapping::isGroup, avg 290µs/call
# spent 87.9ms making 12164 calls to Foswiki::Users::BaseUserMapping::isGroup, avg 7µs/call |
822 | || ( $this->{mapping}->isGroup(@_) ); | ||||
823 | } | ||||
824 | |||||
825 | =begin TML | ||||
826 | |||||
827 | ---++ ObjectMethod isInGroup( $cUID, $group, $options) -> $boolean | ||||
828 | |||||
829 | Test if the user identified by $cUID is in the given group. Options | ||||
830 | is a hash array of options effecting the search. Available options are: | ||||
831 | |||||
832 | * =expand => 1= 0/1 - should nested groups be expanded when searching for the user. Default is 1, to expand nested groups. | ||||
833 | |||||
834 | =cut | ||||
835 | |||||
836 | sub isInGroup { | ||||
837 | my ( $this, $cUID, $group, $options ) = @_; | ||||
838 | return unless ( defined($cUID) ); | ||||
839 | |||||
840 | my $expand = $options->{expand}; | ||||
841 | $expand = 1 unless ( defined $expand ); | ||||
842 | |||||
843 | my $mapping = $this->_getMapping($cUID); | ||||
844 | my $otherMapping = | ||||
845 | ( $mapping eq $this->{basemapping} ) | ||||
846 | ? $this->{mapping} | ||||
847 | : $this->{basemapping}; | ||||
848 | return 1 if $mapping->isInGroup( $cUID, $group, { expand => $expand } ); | ||||
849 | |||||
850 | return $otherMapping->isInGroup( $cUID, $group, { expand => $expand } ) | ||||
851 | if ( $otherMapping ne $mapping ); | ||||
852 | } | ||||
853 | |||||
854 | =begin TML | ||||
855 | |||||
856 | ---++ ObjectMethod eachMembership($cUID) -> $iterator | ||||
857 | |||||
858 | Return an iterator over the groups that $cUID | ||||
859 | is a member of. | ||||
860 | |||||
861 | =cut | ||||
862 | |||||
863 | sub eachMembership { | ||||
864 | my ( $this, $cUID ) = @_; | ||||
865 | |||||
866 | my $mapping = $this->_getMapping($cUID); | ||||
867 | my $wikiname = $mapping->getWikiName($cUID); | ||||
868 | |||||
869 | #stop if the user has no wikiname (generally means BugsItem4771) | ||||
870 | unless ( defined($wikiname) ) { | ||||
871 | require Foswiki::ListIterator; | ||||
872 | return new Foswiki::ListIterator( \() ); | ||||
873 | } | ||||
874 | |||||
875 | my $otherMapping = | ||||
876 | ( $mapping eq $this->{basemapping} ) | ||||
877 | ? $this->{mapping} | ||||
878 | : $this->{basemapping}; | ||||
879 | if ( $mapping eq $otherMapping ) { | ||||
880 | |||||
881 | # only using BaseMapping. | ||||
882 | return $mapping->eachMembership($cUID); | ||||
883 | } | ||||
884 | |||||
885 | my @list = | ||||
886 | ( $mapping->eachMembership($cUID), $otherMapping->eachMembership($cUID) ); | ||||
887 | return new Foswiki::AggregateIterator( \@list, 1 ); | ||||
888 | } | ||||
889 | |||||
890 | =begin TML | ||||
891 | |||||
892 | ---++ ObjectMethod groupAllowsView($group) -> boolean | ||||
893 | |||||
894 | returns 1 if the group is able to be modified by the current logged in user | ||||
895 | |||||
896 | =cut | ||||
897 | |||||
898 | sub groupAllowsView { | ||||
899 | my $this = shift; | ||||
900 | my $group = shift; | ||||
901 | my $mapping = $this->{mapping}; | ||||
902 | return $mapping->groupAllowsView($group); | ||||
903 | } | ||||
904 | |||||
905 | =begin TML | ||||
906 | |||||
907 | ---++ ObjectMethod groupAllowsChange($group, $cuid) -> boolean | ||||
908 | |||||
909 | returns 1 if the group is able to be modified by the current logged in user | ||||
910 | |||||
911 | =cut | ||||
912 | |||||
913 | sub groupAllowsChange { | ||||
914 | my $this = shift; | ||||
915 | my $group = shift; | ||||
916 | my $cuid = shift || $this->{session}->{user}; | ||||
917 | |||||
918 | return ( $this->{basemapping}->groupAllowsChange( $group, $cuid ) | ||||
919 | and $this->{mapping}->groupAllowsChange( $group, $cuid ) ); | ||||
920 | } | ||||
921 | |||||
922 | =begin TML | ||||
923 | |||||
924 | ---++ ObjectMethod addToGroup( $cuid, $group, $create ) -> $boolean | ||||
925 | adds the user specified by the cuid to the group. | ||||
926 | If the group does not exist, it will return false and do nothing, unless the create flag is set. | ||||
927 | |||||
928 | =cut | ||||
929 | |||||
930 | sub addUserToGroup { | ||||
931 | my ( $this, $cuid, $group, $create ) = @_; | ||||
932 | my $mapping = $this->{mapping}; | ||||
933 | return $mapping->addUserToGroup( $cuid, $group, $create ); | ||||
934 | } | ||||
935 | |||||
936 | =begin TML | ||||
937 | |||||
938 | ---++ ObjectMethod removeFromGroup( $cuid, $group ) -> $boolean | ||||
939 | |||||
940 | =cut | ||||
941 | |||||
942 | sub removeUserFromGroup { | ||||
943 | my ( $this, $cuid, $group ) = @_; | ||||
944 | my $mapping = $this->{mapping}; | ||||
945 | return $mapping->removeUserFromGroup( $cuid, $group ); | ||||
946 | } | ||||
947 | |||||
948 | =begin TML | ||||
949 | |||||
950 | ---++ ObjectMethod checkLogin( $login, $passwordU ) -> $boolean | ||||
951 | |||||
952 | Finds if the password is valid for the given user. This method is | ||||
953 | called using the login name rather than the $cUID so that it can be called | ||||
954 | with a user who can be authenticated, but may not be mappable to a | ||||
955 | cUID (yet). | ||||
956 | |||||
957 | Returns 1 on success, undef on failure. | ||||
958 | |||||
959 | TODO: add special check for BaseMapping admin user's login, and if | ||||
960 | its there (and we're in sudo_context?) use that.. | ||||
961 | |||||
962 | =cut | ||||
963 | |||||
964 | sub checkPassword { | ||||
965 | my ( $this, $login, $pw ) = @_; | ||||
966 | my $mapping = $this->_getMapping( undef, $login, undef, 0 ); | ||||
967 | return $mapping->checkPassword( $login, $pw ); | ||||
968 | } | ||||
969 | |||||
970 | =begin TML | ||||
971 | |||||
972 | ---++ ObjectMethod setPassword( $cUID, $newPassU, $oldPassU ) -> $boolean | ||||
973 | |||||
974 | If the $oldPassU matches matches the user's password, then it will | ||||
975 | replace it with $newPassU. | ||||
976 | |||||
977 | If $oldPassU is not correct and not 1, will return 0. | ||||
978 | |||||
979 | If $oldPassU is 1, will force the change irrespective of | ||||
980 | the existing password, adding the user if necessary. | ||||
981 | |||||
982 | Otherwise returns 1 on success, undef on failure. | ||||
983 | |||||
984 | =cut | ||||
985 | |||||
986 | sub setPassword { | ||||
987 | my ( $this, $cUID, $newPassU, $oldPassU ) = @_; | ||||
988 | ASSERT($cUID) if DEBUG; | ||||
989 | return $this->_getMapping($cUID) | ||||
990 | ->setPassword( $this->getLoginName($cUID), $newPassU, $oldPassU ); | ||||
991 | } | ||||
992 | |||||
993 | =begin TML | ||||
994 | |||||
995 | ---++ ObjectMethod passwordError() -> $string | ||||
996 | |||||
997 | Returns a string indicating the error that happened in the password handlers | ||||
998 | TODO: these delayed error's should be replaced with Exceptions. | ||||
999 | |||||
1000 | returns undef if no error | ||||
1001 | |||||
1002 | =cut | ||||
1003 | |||||
1004 | sub passwordError { | ||||
1005 | my ($this) = @_; | ||||
1006 | return $this->_getMapping()->passwordError(); | ||||
1007 | } | ||||
1008 | |||||
1009 | =begin TML | ||||
1010 | |||||
1011 | ---++ ObjectMethod removeUser( $cUID ) -> $boolean | ||||
1012 | |||||
1013 | Delete the users entry. Removes the user from the password | ||||
1014 | manager and user mapping manager. Does *not* remove their personal | ||||
1015 | topics, which may still be linked. | ||||
1016 | |||||
1017 | =cut | ||||
1018 | |||||
1019 | sub removeUser { | ||||
1020 | my ( $this, $cUID ) = @_; | ||||
1021 | $this->_getMapping($cUID)->removeUser($cUID); | ||||
1022 | } | ||||
1023 | |||||
1024 | 1 | 5µs | 1; | ||
1025 | __END__ | ||||
# spent 456µs within Foswiki::Users::CORE:regcomp which was called 179 times, avg 3µs/call:
# 114 times (285µs+0s) by Foswiki::Users::_getMapping at line 205, avg 2µs/call
# 63 times (136µs+0s) by Foswiki::Users::findUserByWikiName at line 513, avg 2µs/call
# 2 times (35µs+0s) by Foswiki::Users::getWikiName at line 707, avg 18µs/call | |||||
# spent 1.27ms within Foswiki::Users::CORE:subst which was called 589 times, avg 2µs/call:
# 410 times (985µs+0s) by Foswiki::Users::mapLogin2cUID at line 389, avg 2µs/call
# 114 times (177µs+0s) by Foswiki::Users::_getMapping at line 205, avg 2µs/call
# 63 times (101µs+0s) by Foswiki::Users::findUserByWikiName at line 513, avg 2µs/call
# 2 times (4µs+0s) by Foswiki::Users::getWikiName at line 707, avg 2µs/call | |||||
# spent 36µs within Foswiki::Users::CORE:substcont which was called 8 times, avg 5µs/call:
# 8 times (36µs+0s) by Foswiki::Users::mapLogin2cUID at line 389, avg 5µs/call |