Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm |
Statements | Executed 227 statements in 9.02ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 2.17ms | 10.7ms | makeLoginManager | Foswiki::LoginManager::
1 | 1 | 1 | 383µs | 137ms | loadSession | Foswiki::LoginManager::
5 | 1 | 1 | 173µs | 291µs | endRenderingHandler | Foswiki::LoginManager::
1 | 1 | 1 | 159µs | 159µs | CORE:readdir (opcode) | Foswiki::LoginManager::
1 | 1 | 1 | 154µs | 221µs | new | Foswiki::LoginManager::
2 | 1 | 1 | 139µs | 10.1ms | _LOGOUT | Foswiki::LoginManager::
1 | 1 | 1 | 136µs | 1.75ms | finish | Foswiki::LoginManager::
1 | 1 | 1 | 115µs | 21.7ms | userLoggedIn | Foswiki::LoginManager::
1 | 1 | 1 | 114µs | 317µs | expireDeadSessions | Foswiki::LoginManager::
11 | 3 | 1 | 82µs | 82µs | CORE:subst (opcode) | Foswiki::LoginManager::
2 | 1 | 1 | 72µs | 616µs | _LOGOUTURL | Foswiki::LoginManager::
1 | 1 | 1 | 54µs | 522µs | _addSessionCookieToResponse | Foswiki::LoginManager::
1 | 1 | 1 | 42µs | 1.56ms | complete | Foswiki::LoginManager::
2 | 1 | 1 | 38µs | 80µs | _LOGIN | Foswiki::LoginManager::
9 | 5 | 1 | 38µs | 38µs | __ANON__[:208] | Foswiki::LoginManager::
1 | 1 | 1 | 35µs | 54µs | checkAccess | Foswiki::LoginManager::
1 | 1 | 1 | 25µs | 33µs | BEGIN@51 | Foswiki::LoginManager::
1 | 1 | 1 | 20µs | 368µs | BEGIN@54 | Foswiki::LoginManager::
1 | 1 | 1 | 16µs | 35µs | BEGIN@52 | Foswiki::LoginManager::
1 | 1 | 1 | 16µs | 16µs | CORE:open_dir (opcode) | Foswiki::LoginManager::
1 | 1 | 1 | 16µs | 52µs | BEGIN@53 | Foswiki::LoginManager::
4 | 1 | 1 | 15µs | 15µs | CORE:match (opcode) | Foswiki::LoginManager::
1 | 1 | 1 | 10µs | 10µs | getCGISession | Foswiki::LoginManager::
1 | 1 | 1 | 9µs | 9µs | BEGIN@56 | Foswiki::LoginManager::
1 | 1 | 1 | 8µs | 8µs | CORE:stat (opcode) | Foswiki::LoginManager::
1 | 1 | 1 | 4µs | 4µs | getUser | Foswiki::LoginManager::
1 | 1 | 1 | 4µs | 4µs | CORE:closedir (opcode) | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _AUTHENTICATED | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _CANLOGIN | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _IP2SID | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _LOGINURL | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _SESSION_VARIABLE | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _dispLogon | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _myScriptURLRE | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _real_trace | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _rewriteFORM | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _rewriteURL | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | _skinSelect | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | clearSessionValue | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | forceAuthentication | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | getSessionValue | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | getSessionValues | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | isValidLoginName | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | loginUrl | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | rewriteRedirectUrl | Foswiki::LoginManager::
0 | 0 | 0 | 0s | 0s | setSessionValue | Foswiki::LoginManager::
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::LoginManager | ||||
6 | |||||
7 | The package is also a Factory for login managers and also the base class | ||||
8 | for all login managers. | ||||
9 | |||||
10 | On it's own, an object of this class is used when you specify 'none' in | ||||
11 | the security setup section of | ||||
12 | [[%SCRIPTURL{"configure"}%][configure]]. When it is used, | ||||
13 | logins are not supported. If you want to authenticate users then you should | ||||
14 | consider TemplateLogin or ApacheLogin, which are subclasses of this class. | ||||
15 | |||||
16 | If you are building a new login manager, then you should write a new subclass | ||||
17 | of this class, implementing the methods marked as *VIRTUAL*. There are already | ||||
18 | examples in the =lib/Foswiki/LoginManager= directory. | ||||
19 | |||||
20 | The class has extensive tracing, which is enabled by | ||||
21 | $Foswiki::cfg{Trace}{LoginManager}. The tracing is done in such a way as to | ||||
22 | let the perl optimiser optimise out the trace function as a no-op if tracing | ||||
23 | is disabled. | ||||
24 | |||||
25 | Here's an overview of how it works: | ||||
26 | |||||
27 | Early in Foswiki::new, the login manager is created. The creation of the login manager does two things: | ||||
28 | 1 If sessions are in use, it loads CGI::Session but doesn't initialise the session yet. | ||||
29 | 1 Creates the login manager object | ||||
30 | Slightly later in Foswiki::new, loginManager->loadSession is called. | ||||
31 | 1 Calls loginManager->getUser to get the username *before* the session is created | ||||
32 | * Foswiki::LoginManager::ApacheLogin looks at REMOTE_USER (only for authenticated scripts) | ||||
33 | * Foswiki::LoginManager::TemplateLogin just returns undef | ||||
34 | 1 If the NO_FOSWIKI_SESSION environment variable is defined, then no session is created and the username is returned. This might be defined for search engine bots, depending on how the web server is configured | ||||
35 | 1 Reads the FOSWIKISID cookie to get the SID (or the FOSWIKISID parameters in the CGI query if cookies aren't available, or IP2SID mapping if that's enabled). | ||||
36 | 1 Creates the CGI::Session object, and the session is thereby read. | ||||
37 | 1 If the username still isn't known, reads it from the cookie. Thus Foswiki::LoginManager::ApacheLogin overrides the cookie using REMOTE_USER, and Foswiki::LoginManager::TemplateLogin *always* uses the session. | ||||
38 | |||||
39 | Later again in Foswiki::new, plugins are given a chance to *override* the username found from the loginManager. | ||||
40 | |||||
41 | The last step in Foswiki::new is to find the user, using whatever user mapping manager is in place. | ||||
42 | |||||
43 | ---++ ObjectData =twiki= | ||||
44 | |||||
45 | The Foswiki object this login manager is attached to. | ||||
46 | |||||
47 | =cut | ||||
48 | |||||
49 | package Foswiki::LoginManager; | ||||
50 | |||||
51 | 2 | 46µs | 2 | 40µs | # spent 33µs (25+8) within Foswiki::LoginManager::BEGIN@51 which was called:
# once (25µs+8µs) by Foswiki::Users::BEGIN@64 at line 51 # spent 33µs making 1 call to Foswiki::LoginManager::BEGIN@51
# spent 8µs making 1 call to strict::import |
52 | 2 | 44µs | 2 | 53µs | # spent 35µs (16+18) within Foswiki::LoginManager::BEGIN@52 which was called:
# once (16µs+18µs) by Foswiki::Users::BEGIN@64 at line 52 # spent 35µs making 1 call to Foswiki::LoginManager::BEGIN@52
# spent 18µs making 1 call to warnings::import |
53 | 2 | 50µs | 2 | 88µs | # spent 52µs (16+36) within Foswiki::LoginManager::BEGIN@53 which was called:
# once (16µs+36µs) by Foswiki::Users::BEGIN@64 at line 53 # spent 52µs making 1 call to Foswiki::LoginManager::BEGIN@53
# spent 36µs making 1 call to Assert::import |
54 | 2 | 47µs | 2 | 716µs | # spent 368µs (20+348) within Foswiki::LoginManager::BEGIN@54 which was called:
# once (20µs+348µs) by Foswiki::Users::BEGIN@64 at line 54 # spent 368µs making 1 call to Foswiki::LoginManager::BEGIN@54
# spent 348µs making 1 call to Error::import |
55 | |||||
56 | 2 | 6.96ms | 1 | 9µs | # spent 9µs within Foswiki::LoginManager::BEGIN@56 which was called:
# once (9µs+0s) by Foswiki::Users::BEGIN@64 at line 56 # spent 9µs making 1 call to Foswiki::LoginManager::BEGIN@56 |
57 | |||||
58 | # Marker chars | ||||
59 | 1 | 2µs | our $M1 = chr(5); | ||
60 | 1 | 1µs | our $M2 = chr(6); | ||
61 | 1 | 2µs | our $M3 = chr(7); | ||
62 | |||||
63 | # Some session keys are secret (not to be given to the browser) and | ||||
64 | # others read only (not to be changed from the browser) | ||||
65 | 1 | 5µs | our %secretSK = ( STRIKEONESECRET => 1, VALID_ACTIONS => 1 ); | ||
66 | 1 | 5µs | our %readOnlySK = ( %secretSK, AUTHUSER => 1, SUDOFROMAUTHUSER => 1 ); | ||
67 | |||||
68 | =begin TML | ||||
69 | |||||
70 | ---++ StaticMethod makeLoginManager( $session ) -> $Foswiki::LoginManager | ||||
71 | |||||
72 | Factory method, used to generate a new Foswiki::LoginManager object | ||||
73 | for the given session. | ||||
74 | |||||
75 | =cut | ||||
76 | |||||
77 | # spent 10.7ms (2.17+8.57) within Foswiki::LoginManager::makeLoginManager which was called:
# once (2.17ms+8.57ms) by Foswiki::Users::new at line 107 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm | ||||
78 | 1 | 2µs | my $session = shift; | ||
79 | |||||
80 | 1 | 5µs | 1 | 4µs | ASSERT( $session->isa('Foswiki') ) if DEBUG; # spent 4µs making 1 call to Assert::ASSERTS_OFF |
81 | |||||
82 | #user is trying to sudo login - use BaseUserMapping | ||||
83 | 1 | 9µs | 1 | 62µs | if ( $session->{request}->param('sudo') ) { # spent 62µs making 1 call to Foswiki::Request::param |
84 | |||||
85 | #promote / login to internal wiki admin | ||||
86 | $session->enterContext('sudo_login'); | ||||
87 | } | ||||
88 | |||||
89 | 1 | 10µs | 1 | 8µs | if ( $Foswiki::cfg{UseClientSessions} # spent 8µs making 1 call to Foswiki::inContext |
90 | && !$session->inContext('command_line') ) | ||||
91 | { | ||||
92 | |||||
93 | 1 | 2µs | my $use = 'use Foswiki::LoginManager::Session'; | ||
94 | 1 | 3µs | if ( $Foswiki::cfg{Sessions}{UseIPMatching} ) { | ||
95 | $use .= ' qw(-ip_match)'; | ||||
96 | } | ||||
97 | 1 | 2µs | $use .= '; use CGI::Cookie ()'; | ||
98 | 1 | 54µs | eval $use; # spent 183µs executing statements in string eval # includes 496µs spent executing 2 calls to 2 subs defined therein. | ||
99 | 1 | 1µs | throw Error::Simple($@) if $@; | ||
100 | 1 | 4µs | if ( $Foswiki::LoginManager::Session::VERSION eq '4.10' ) { | ||
101 | |||||
102 | # 4.10 is broken; see Item1989 | ||||
103 | $Foswiki::LoginManager::Session::NAME = 'FOSWIKISID'; | ||||
104 | } | ||||
105 | else { | ||||
106 | 1 | 12µs | 1 | 10µs | Foswiki::LoginManager::Session->name('FOSWIKISID'); # spent 10µs making 1 call to CGI::Session::name |
107 | } | ||||
108 | } | ||||
109 | |||||
110 | 1 | 1µs | my $mgr; | ||
111 | 1 | 4µs | if ( $Foswiki::cfg{LoginManager} eq 'none' ) { | ||
112 | |||||
113 | # No login manager; just use default behaviours | ||||
114 | $mgr = new Foswiki::LoginManager($session); | ||||
115 | } | ||||
116 | else { | ||||
117 | |||||
118 | # Rename from old "Client" to new "LoginManager" - see TWikibug:Item3375 | ||||
119 | 1 | 14µs | 1 | 4µs | $Foswiki::cfg{LoginManager} =~ s/::Client::/::LoginManager::/; # spent 4µs making 1 call to Foswiki::LoginManager::CORE:subst |
120 | 1 | 2µs | my $loginManager = $Foswiki::cfg{LoginManager}; | ||
121 | 1 | 7µs | 1 | 8µs | if ( $session->inContext('sudo_login') ) # spent 8µs making 1 call to Foswiki::inContext |
122 | { #TODO: move selection into BaseUserMapper | ||||
123 | $loginManager = 'Foswiki::LoginManager::TemplateLogin'; | ||||
124 | } | ||||
125 | 1 | 33µs | eval "require $loginManager"; # spent 127µs executing statements in string eval | ||
126 | 1 | 2µs | die $@ if $@; | ||
127 | 1 | 10µs | 1 | 275µs | $mgr = $loginManager->new($session); # spent 275µs making 1 call to Foswiki::LoginManager::TemplateLogin::new |
128 | } | ||||
129 | 1 | 7µs | return $mgr; | ||
130 | } | ||||
131 | |||||
132 | =begin TML | ||||
133 | |||||
134 | ---++ ClassMethod new ($session, $impl) | ||||
135 | |||||
136 | Construct the user management object | ||||
137 | |||||
138 | =cut | ||||
139 | |||||
140 | # protected: Construct new client object. | ||||
141 | # spent 221µs (154+67) within Foswiki::LoginManager::new which was called:
# once (154µs+67µs) by Foswiki::LoginManager::TemplateLogin::new at line 36 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager/TemplateLogin.pm | ||||
142 | 1 | 2µs | my ( $class, $session ) = @_; | ||
143 | 1 | 14µs | my $this = bless( | ||
144 | { | ||||
145 | session => $session, | ||||
146 | twiki => $session, # backwards compatibility | ||||
147 | _haveCookie => 0, | ||||
148 | }, | ||||
149 | $class | ||||
150 | ); | ||||
151 | |||||
152 | 1 | 6µs | 1 | 12µs | $session->leaveContext('can_login'); # spent 12µs making 1 call to Foswiki::leaveContext |
153 | 15 | 65µs | map { $this->{_authScripts}{$_} = 1; } | ||
154 | split( /[\s,]+/, $Foswiki::cfg{AuthScripts} ); | ||||
155 | |||||
156 | # register tag handlers and values | ||||
157 | 1 | 8µs | 1 | 11µs | Foswiki::registerTagHandler( 'LOGINURL', \&_LOGINURL ); # spent 11µs making 1 call to Foswiki::registerTagHandler |
158 | 1 | 6µs | 1 | 8µs | Foswiki::registerTagHandler( 'LOGIN', \&_LOGIN ); # spent 8µs making 1 call to Foswiki::registerTagHandler |
159 | 1 | 6µs | 1 | 8µs | Foswiki::registerTagHandler( 'LOGOUT', \&_LOGOUT ); # spent 8µs making 1 call to Foswiki::registerTagHandler |
160 | 1 | 5µs | 1 | 7µs | Foswiki::registerTagHandler( 'LOGOUTURL', \&_LOGOUTURL ); # spent 7µs making 1 call to Foswiki::registerTagHandler |
161 | 1 | 6µs | 1 | 7µs | Foswiki::registerTagHandler( 'SESSION_VARIABLE', \&_SESSION_VARIABLE ); # spent 7µs making 1 call to Foswiki::registerTagHandler |
162 | 1 | 5µs | 1 | 7µs | Foswiki::registerTagHandler( 'AUTHENTICATED', \&_AUTHENTICATED ); # spent 7µs making 1 call to Foswiki::registerTagHandler |
163 | 1 | 5µs | 1 | 7µs | Foswiki::registerTagHandler( 'CANLOGIN', \&_CANLOGIN ); # spent 7µs making 1 call to Foswiki::registerTagHandler |
164 | |||||
165 | 1 | 8µs | return $this; | ||
166 | } | ||||
167 | |||||
168 | =begin TML | ||||
169 | |||||
170 | ---++ ObjectMethod finish() | ||||
171 | Break circular references. | ||||
172 | |||||
173 | =cut | ||||
174 | |||||
175 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
176 | # whether they are references or not. That way this method is "golden | ||||
177 | # documentation" of the live fields in the object. | ||||
178 | # spent 1.75ms (136µs+1.61) within Foswiki::LoginManager::finish which was called:
# once (136µs+1.61ms) by Foswiki::Users::finish at line 162 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm | ||||
179 | 1 | 2µs | my $this = shift; | ||
180 | 1 | 14µs | 1 | 1.56ms | $this->complete(); # call to flush the session if not already done # spent 1.56ms making 1 call to Foswiki::LoginManager::complete |
181 | 1 | 8µs | undef $this->{_authScripts}; | ||
182 | 1 | 29µs | undef $this->{_cgisession}; | ||
183 | 1 | 62µs | 2 | 54µs | undef $this->{_haveCookie}; # spent 48µs making 1 call to CGI::Session::DESTROY
# spent 7µs making 1 call to CGI::Session::Driver::file::DESTROY |
184 | 1 | 3µs | undef $this->{_MYSCRIPTURL}; | ||
185 | 1 | 8µs | undef $this->{session}; | ||
186 | } | ||||
187 | |||||
188 | =begin TML | ||||
189 | |||||
190 | ---++ ClassMethod _real_trace ($session, $impl) | ||||
191 | |||||
192 | Construct the user management object | ||||
193 | |||||
194 | =cut | ||||
195 | |||||
196 | sub _real_trace { | ||||
197 | my ( $this, $mess ) = @_; | ||||
198 | my $id = | ||||
199 | 'SESSION ' . ( $this->{_cgisession} ? $this->{_cgisession}->id() : '?' ); | ||||
200 | $id .= '(c)' if $this->{_haveCookie}; | ||||
201 | print STDERR "$id: $mess\n"; | ||||
202 | } | ||||
203 | |||||
204 | 1 | 5µs | if ( $Foswiki::cfg{Trace}{LoginManager} ) { | ||
205 | *_trace = \&_real_trace; | ||||
206 | } | ||||
207 | else { | ||||
208 | 10 | 64µs | # spent 38µs within Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208] which was called 9 times, avg 4µs/call:
# 5 times (18µs+0s) by Foswiki::LoginManager::loadSession at line 466, avg 4µs/call
# once (6µs+0s) by Foswiki::LoginManager::userLoggedIn at line 622
# once (5µs+0s) by Foswiki::LoginManager::loadSession at line 355
# once (5µs+0s) by Foswiki::LoginManager::loadSession at line 271
# once (4µs+0s) by Foswiki::LoginManager::loadSession at line 294 | ||
209 | } | ||||
210 | |||||
211 | =begin TML | ||||
212 | |||||
213 | ---++ ClassMethod _IP2SID ($session, $impl) | ||||
214 | |||||
215 | read/write IP to SID map, return SID | ||||
216 | |||||
217 | =cut | ||||
218 | |||||
219 | sub _IP2SID { | ||||
220 | my ( $this, $sid ) = @_; | ||||
221 | |||||
222 | my $ip = $this->{session}->{request}->address; | ||||
223 | |||||
224 | return unless $ip; # no IP address, can't map | ||||
225 | |||||
226 | my %ips; | ||||
227 | my $IPMAP; | ||||
228 | if ( open( $IPMAP, '<', $Foswiki::cfg{WorkingDir} . '/tmp/ip2sid' ) ) { | ||||
229 | local $/ = undef; | ||||
230 | %ips = map { split( /:/, $_ ) } split( /\r?\n/, <$IPMAP> ); | ||||
231 | close($IPMAP); | ||||
232 | } | ||||
233 | if ($sid) { | ||||
234 | |||||
235 | # known SID, map the IP addr to it | ||||
236 | $ips{$ip} = $sid; | ||||
237 | open( $IPMAP, '>', $Foswiki::cfg{WorkingDir} . '/tmp/ip2sid' ) | ||||
238 | || die | ||||
239 | "Failed to open ip2sid map for write. Ask your administrator to make sure that the {Sessions}{Dir} is writable by the webserver user."; | ||||
240 | print $IPMAP map { "$_:$ips{$_}\n" } keys %ips; | ||||
241 | close($IPMAP); | ||||
242 | } | ||||
243 | else { | ||||
244 | |||||
245 | # Return the SID for this IP address | ||||
246 | $sid = $ips{$ip}; | ||||
247 | } | ||||
248 | return $sid; | ||||
249 | } | ||||
250 | |||||
251 | =begin TML | ||||
252 | |||||
253 | ---++ ObjectMethod loadSession($defaultUser, $pwchecker) -> $login | ||||
254 | |||||
255 | Get the client session data, using the cookie and/or the request URL. | ||||
256 | Set up appropriate session variables in the twiki object and return | ||||
257 | the login name. | ||||
258 | |||||
259 | $pwchecker is a pointer to an object that implements checkPassword | ||||
260 | |||||
261 | $defaultUser is a username to use if one is not available from other | ||||
262 | sources. The username passed when you create a Foswiki instance is | ||||
263 | passed in here. | ||||
264 | |||||
265 | =cut | ||||
266 | |||||
267 | # spent 137ms (383µs+136) within Foswiki::LoginManager::loadSession which was called:
# once (383µs+136ms) by Foswiki::Users::loadSession at line 144 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm | ||||
268 | 1 | 2µs | my ( $this, $defaultUser, $pwchecker ) = @_; | ||
269 | 1 | 2µs | my $session = $this->{session}; | ||
270 | |||||
271 | 1 | 6µs | 1 | 5µs | _trace( $this, "LOAD SESSION\n" ); # spent 5µs making 1 call to Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208] |
272 | |||||
273 | 1 | 3µs | $defaultUser = $Foswiki::cfg{DefaultUserLogin} | ||
274 | unless ( defined($defaultUser) ); | ||||
275 | |||||
276 | # Try and get the user from the webserver. This is referred to as | ||||
277 | # the "webserver user". the webserver user is authenticated by some | ||||
278 | # means beyond foswiki e.g. Basic Auth | ||||
279 | 1 | 10µs | 1 | 4µs | my $authUser = $this->getUser($this); # spent 4µs making 1 call to Foswiki::LoginManager::getUser |
280 | 1 | 2µs | _trace( $this, "Webserver says user is $authUser" ) if ($authUser); | ||
281 | |||||
282 | # If the NO_FOSWIKI_SESSION environment varaible is defined, then | ||||
283 | # do not create the session. This might be defined if the request | ||||
284 | # is made by a search engine bot, depending on how the web server | ||||
285 | # is configured | ||||
286 | 1 | 2µs | return $authUser if $ENV{NO_FOSWIKI_SESSION}; | ||
287 | |||||
288 | 1 | 8µs | 1 | 8µs | if ( $Foswiki::cfg{UseClientSessions} # spent 8µs making 1 call to Foswiki::inContext |
289 | && !$session->inContext('command_line') ) | ||||
290 | { | ||||
291 | |||||
292 | 1 | 8µs | 1 | 52µs | $this->{_haveCookie} = $session->{request}->header('Cookie'); # spent 52µs making 1 call to Foswiki::Request::header |
293 | |||||
294 | 1 | 9µs | 1 | 4µs | _trace( $this, # spent 4µs making 1 call to Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208] |
295 | $this->{_haveCookie} | ||||
296 | ? "Cookie $this->{_haveCookie}" | ||||
297 | : "No cookie " ); | ||||
298 | |||||
299 | # Item3568: CGI::Session from 4.0 already does the -d and creates the | ||||
300 | # sessions directory if it does not exist. For performance reasons we | ||||
301 | # only test for and create session file directory for older | ||||
302 | # CGI::Session | ||||
303 | 1 | 4µs | my $sessionDir = "$Foswiki::cfg{WorkingDir}/tmp"; | ||
304 | 1 | 5µs | if ( $Foswiki::LoginManager::Session::VERSION < 4.0 ) { | ||
305 | unless ( | ||||
306 | -d $sessionDir | ||||
307 | || ( mkdir( $Foswiki::cfg{WorkingDir} ) | ||||
308 | && mkdir($sessionDir) ) | ||||
309 | ) | ||||
310 | { | ||||
311 | die "Could not create $sessionDir for storing sessions"; | ||||
312 | } | ||||
313 | } | ||||
314 | |||||
315 | # First, see if there is a cookied session, creating a new session | ||||
316 | # if necessary. | ||||
317 | 1 | 4µs | if ( $Foswiki::cfg{Sessions}{MapIP2SID} ) { | ||
318 | |||||
319 | # map the end user IP address to a session ID | ||||
320 | |||||
321 | my $sid = $this->_IP2SID(); | ||||
322 | if ($sid) { | ||||
323 | $this->{_cgisession} = | ||||
324 | Foswiki::LoginManager::Session->new( undef, $sid, | ||||
325 | { Directory => $sessionDir } ); | ||||
326 | } | ||||
327 | else { | ||||
328 | |||||
329 | # The IP address was not mapped; create a new session | ||||
330 | |||||
331 | $this->{_cgisession} = | ||||
332 | Foswiki::LoginManager::Session->new( undef, undef, | ||||
333 | { Directory => $sessionDir } ); | ||||
334 | _trace( $this, "New IP2SID session" ); | ||||
335 | $this->_IP2SID( $this->{_cgisession}->id() ); | ||||
336 | } | ||||
337 | } | ||||
338 | else { | ||||
339 | |||||
340 | # IP mapping is off; use the request cookie | ||||
341 | |||||
342 | 1 | 14µs | 1 | 114ms | $this->{_cgisession} = # spent 114ms making 1 call to CGI::Session::new |
343 | Foswiki::LoginManager::Session->new( undef, $session->{request}, | ||||
344 | { Directory => $sessionDir } ); | ||||
345 | } | ||||
346 | |||||
347 | 1 | 2µs | die Foswiki::LoginManager::Session->errstr() | ||
348 | unless $this->{_cgisession}; | ||||
349 | |||||
350 | # Get the authorised user stored in the session | ||||
351 | |||||
352 | 1 | 18µs | 2 | 54µs | my $sessionUser = Foswiki::Sandbox::untaintUnchecked( # spent 29µs making 1 call to CGI::Session::param
# spent 25µs making 1 call to Foswiki::Sandbox::untaintUnchecked |
353 | $this->{_cgisession}->param('AUTHUSER') ); | ||||
354 | |||||
355 | 1 | 8µs | 1 | 5µs | _trace( $this, "AUTHUSER is $sessionUser" ) if defined $sessionUser; # spent 5µs making 1 call to Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208] |
356 | |||||
357 | # An admin user stored in the session can override the webserver | ||||
358 | # user; handy for sudo | ||||
359 | |||||
360 | 1 | 3µs | $authUser = $sessionUser | ||
361 | if ( !defined($authUser) | ||||
362 | || $sessionUser && $sessionUser eq $Foswiki::cfg{AdminUserLogin} ); | ||||
363 | } | ||||
364 | |||||
365 | 1 | 1µs | if ( !$authUser ) { | ||
366 | |||||
367 | # if we couldn't get the login manager or the http session to tell | ||||
368 | # us who the user is, check the username and password URI params. | ||||
369 | |||||
370 | my $login = $session->{request}->param('username'); | ||||
371 | my $pass = $session->{request}->param('password'); | ||||
372 | if ( $login && defined $pass && $pwchecker ) { | ||||
373 | my $validation = $pwchecker->checkPassword( $login, $pass ); | ||||
374 | unless ($validation) { | ||||
375 | my $res = $session->{response}; | ||||
376 | my $err = "ERROR: (401) Can't login as $login"; | ||||
377 | |||||
378 | # Item1953: You might think that this is needed: | ||||
379 | # $res->header( -type => 'text/html', -status => '401' ); | ||||
380 | # throw Foswiki::EngineException( 401, $err, $res ); | ||||
381 | # but it would be wrong, because it would require the | ||||
382 | # exception to be handled before the session object is | ||||
383 | # properly initialised, which would cause an error. | ||||
384 | # Instead, we do this, and let the caller handle the error. | ||||
385 | undef $login; | ||||
386 | } | ||||
387 | $authUser = $login || $defaultUser; | ||||
388 | _trace( $this, "URI params say user is $authUser" ); | ||||
389 | } | ||||
390 | else { | ||||
391 | |||||
392 | # Last ditch attempt; if a user was passed in to this function, | ||||
393 | # then use it (it is normally {remoteUser} from the session | ||||
394 | # object) | ||||
395 | $authUser = $defaultUser; | ||||
396 | _trace( $this, "Falling back to $authUser" ) if $authUser; | ||||
397 | |||||
398 | } | ||||
399 | } | ||||
400 | |||||
401 | # We should have a user at this point; or $defaultUser if there | ||||
402 | # was no better information available. | ||||
403 | |||||
404 | # is this a logout? | ||||
405 | 1 | 10µs | 1 | 54µs | if ( ( $authUser && $authUser ne $Foswiki::cfg{DefaultUserLogin} ) # spent 54µs making 1 call to Foswiki::Request::param |
406 | && ( $session->{request} && $session->{request}->param('logout') ) ) | ||||
407 | { | ||||
408 | |||||
409 | # SMELL: is there any way to get evil data into the CGI session such | ||||
410 | # that this untaint is less than safe? | ||||
411 | my $sudoUser = Foswiki::Sandbox::untaintUnchecked( | ||||
412 | $this->{_cgisession}->param('SUDOFROMAUTHUSER') ); | ||||
413 | |||||
414 | if ($sudoUser) { | ||||
415 | _trace( $this, "User is logging out to $sudoUser" ); | ||||
416 | $session->logEvent( 'sudo logout', '', | ||||
417 | 'from ' . ( $authUser || '' ), $sudoUser ); | ||||
418 | $this->{_cgisession}->clear('SUDOFROMAUTHUSER'); | ||||
419 | $authUser = $sudoUser; | ||||
420 | } | ||||
421 | else { | ||||
422 | _trace( $this, "User is logging out" ); | ||||
423 | $session->logEvent( 'logout', ' ', | ||||
424 | "AUTHENTICATION LOGOUT - $authUser - " ); | ||||
425 | |||||
426 | #TODO: consider if we should risk passing on the urlparams on logout | ||||
427 | my $path_info = $session->{request}->path_info(); | ||||
428 | if ( my $topic = $session->{request}->param('topic') ) | ||||
429 | { #we should at least respect the ?topic= request | ||||
430 | my $topicRequest = Foswiki::Sandbox::untaintUnchecked( | ||||
431 | $session->{request}->param('topic') ); | ||||
432 | my ( $web, $topic ) = | ||||
433 | $this->{session} | ||||
434 | ->normalizeWebTopicName( undef, $topicRequest ); | ||||
435 | $path_info = '/' . $web . '/' . $topic; | ||||
436 | } | ||||
437 | |||||
438 | my $redirectUrl; | ||||
439 | if ($path_info) { | ||||
440 | $redirectUrl = $session->{request}->url() . $path_info; | ||||
441 | } | ||||
442 | else { | ||||
443 | $redirectUrl = $session->{request}->referer(); | ||||
444 | } | ||||
445 | |||||
446 | #lets avoid infinite loops | ||||
447 | $session->{request}->delete('logout'); | ||||
448 | $authUser = $defaultUser; | ||||
449 | $session->redirect( $redirectUrl, 0 ); | ||||
450 | } | ||||
451 | } | ||||
452 | 1 | 7µs | 1 | 12µs | $session->{request}->delete('logout'); # spent 12µs making 1 call to Foswiki::Request::delete |
453 | |||||
454 | 1 | 12µs | 1 | 21.7ms | $this->userLoggedIn($authUser); # spent 21.7ms making 1 call to Foswiki::LoginManager::userLoggedIn |
455 | |||||
456 | 1 | 34µs | if ( $this->{_cgisession} ) { | ||
457 | 1 | 14µs | 2 | 52µs | $session->{prefs}->setInternalPreferences( # spent 29µs making 1 call to Foswiki::Prefs::setInternalPreferences
# spent 23µs making 1 call to CGI::Session::id |
458 | SESSIONID => $this->{_cgisession}->id(), | ||||
459 | SESSIONVAR => $CGI::Session::NAME | ||||
460 | ); | ||||
461 | |||||
462 | # Restore CGI Session parameters | ||||
463 | 1 | 10µs | 1 | 103µs | for ( $this->{_cgisession}->param ) { # spent 103µs making 1 call to CGI::Session::param |
464 | 5 | 29µs | 5 | 94µs | my $value = $this->{_cgisession}->param($_); # spent 94µs making 5 calls to CGI::Session::param, avg 19µs/call |
465 | 5 | 27µs | 5 | 75µs | $session->{prefs}->setInternalPreferences( $_ => $value ); # spent 75µs making 5 calls to Foswiki::Prefs::setInternalPreferences, avg 15µs/call |
466 | 5 | 47µs | 5 | 18µs | $this->_trace( "Setting internal preference $_ to " # spent 18µs making 5 calls to Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208], avg 4µs/call |
467 | . ( $value ? $value : 'null' ) ); | ||||
468 | } | ||||
469 | |||||
470 | # May end up doing this several times; but this is the only place | ||||
471 | # if should really need to be done, unless someone allocates a | ||||
472 | # new response object. | ||||
473 | 1 | 10µs | 1 | 522µs | $this->_addSessionCookieToResponse(); # spent 522µs making 1 call to Foswiki::LoginManager::_addSessionCookieToResponse |
474 | } | ||||
475 | |||||
476 | 1 | 8µs | return $authUser; | ||
477 | } | ||||
478 | |||||
479 | =begin TML | ||||
480 | |||||
481 | ---++ ObjectMethod checkAccess() | ||||
482 | |||||
483 | Check if the script being run in this session is authorised for execution. | ||||
484 | If not, throw an access control exception. | ||||
485 | |||||
486 | =cut | ||||
487 | |||||
488 | # spent 54µs (35+19) within Foswiki::LoginManager::checkAccess which was called:
# once (35µs+19µs) by Foswiki::UI::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm:318] at line 315 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm | ||||
489 | |||||
490 | 1 | 3µs | return unless ( $Foswiki::cfg{UseClientSessions} ); | ||
491 | |||||
492 | 1 | 2µs | my $this = shift; | ||
493 | 1 | 2µs | my $session = $this->{session}; | ||
494 | |||||
495 | 1 | 10µs | 1 | 13µs | return if $session->inContext('command_line'); # spent 13µs making 1 call to Foswiki::inContext |
496 | |||||
497 | 1 | 11µs | 1 | 7µs | unless ( $session->inContext('authenticated') # spent 7µs making 1 call to Foswiki::inContext |
498 | || $Foswiki::cfg{LoginManager} eq 'none' ) | ||||
499 | { | ||||
500 | |||||
501 | # This checks the *base_action* which is the action in the | ||||
502 | # request *before* any request cache was restored. Otherwise | ||||
503 | # you can end up with an infinite loop - see | ||||
504 | # Foswiki:Development.FoswikiRedirectCache | ||||
505 | my $action = $session->{request}->base_action(); | ||||
506 | |||||
507 | if ( defined $action && $this->{_authScripts}{$action} ) { | ||||
508 | my $topic = $session->{topicName}; | ||||
509 | my $web = $session->{webName}; | ||||
510 | require Foswiki::AccessControlException; | ||||
511 | throw Foswiki::AccessControlException( $action, $session->{user}, | ||||
512 | $web, $topic, $action . ' requires authentication' ); | ||||
513 | } | ||||
514 | } | ||||
515 | } | ||||
516 | |||||
517 | =begin TML | ||||
518 | |||||
519 | ---++ ObjectMethod complete() | ||||
520 | |||||
521 | Complete processing after the client's HTTP request has been responded | ||||
522 | to. Flush the user's session (if any) to disk. | ||||
523 | |||||
524 | =cut | ||||
525 | |||||
526 | # spent 1.56ms (42µs+1.52) within Foswiki::LoginManager::complete which was called:
# once (42µs+1.52ms) by Foswiki::LoginManager::finish at line 180 | ||||
527 | 1 | 2µs | my $this = shift; | ||
528 | |||||
529 | 1 | 4µs | if ( $this->{_cgisession} ) { | ||
530 | 1 | 9µs | 1 | 1.17ms | $this->{_cgisession}->flush(); # spent 1.17ms making 1 call to CGI::Session::flush |
531 | 1 | 12µs | 1 | 25µs | die $this->{_cgisession}->errstr() # spent 25µs making 1 call to CGI::Session::ErrorHandler::errstr |
532 | if $this->{_cgisession}->errstr(); | ||||
533 | } | ||||
534 | |||||
535 | 1 | 4µs | return unless ( $Foswiki::cfg{Sessions}{ExpireAfter} > 0 ); | ||
536 | |||||
537 | 1 | 16µs | 1 | 317µs | expireDeadSessions(); # spent 317µs making 1 call to Foswiki::LoginManager::expireDeadSessions |
538 | } | ||||
539 | |||||
540 | =begin TML | ||||
541 | |||||
542 | ---++ StaticMethod expireDeadSessions() | ||||
543 | |||||
544 | Delete sessions and passthrough files that are sitting around but are really expired. | ||||
545 | This *assumes* that the sessions are stored as files. | ||||
546 | |||||
547 | This is a static method, but requires Foswiki::cfg. It is designed to be | ||||
548 | run from a session or from a cron job. | ||||
549 | |||||
550 | =cut | ||||
551 | |||||
552 | # spent 317µs (114+202) within Foswiki::LoginManager::expireDeadSessions which was called:
# once (114µs+202µs) by Foswiki::LoginManager::complete at line 537 | ||||
553 | 1 | 3µs | my $time = time() || 0; | ||
554 | 1 | 3µs | my $exp = $Foswiki::cfg{Sessions}{ExpireAfter} || 36000; # 10 hours | ||
555 | 1 | 2µs | $exp = -$exp if $exp < 0; | ||
556 | |||||
557 | 1 | 30µs | 1 | 16µs | opendir( D, "$Foswiki::cfg{WorkingDir}/tmp" ) || return; # spent 16µs making 1 call to Foswiki::LoginManager::CORE:open_dir |
558 | 1 | 183µs | 1 | 159µs | foreach my $file ( readdir(D) ) { # spent 159µs making 1 call to Foswiki::LoginManager::CORE:readdir |
559 | |||||
560 | # Validate | ||||
561 | 4 | 40µs | 4 | 15µs | next unless $file =~ /^((passthru|cgisess)_[0-9a-f]{32})$/; # spent 15µs making 4 calls to Foswiki::LoginManager::CORE:match, avg 4µs/call |
562 | 1 | 4µs | $file = $1; # untaint validated file name | ||
563 | |||||
564 | 1 | 27µs | 1 | 8µs | my @stat = stat("$Foswiki::cfg{WorkingDir}/tmp/$file"); # spent 8µs making 1 call to Foswiki::LoginManager::CORE:stat |
565 | |||||
566 | # CGI::Session updates the session file each time a browser views a | ||||
567 | # topic setting the access and expiry time as values in the file. This | ||||
568 | # also sets the mtime (modification time) for the file which is all | ||||
569 | # we need. We know that the expiry time is mtime + | ||||
570 | # $Foswiki::cfg{Sessions}{ExpireAfter} so we do not need to waste | ||||
571 | # execution time opening and reading the file. We just check the | ||||
572 | # mtime. As a fallback we also check ctime. Files are deleted when | ||||
573 | # they expire. | ||||
574 | 1 | 2µs | my $lat = $stat[9] || $stat[10] || 0; | ||
575 | 1 | 2µs | unlink "$Foswiki::cfg{WorkingDir}/tmp/$file" | ||
576 | if ( $time - $lat >= $exp ); | ||||
577 | 1 | 2µs | next; | ||
578 | } | ||||
579 | 1 | 18µs | 1 | 4µs | closedir D; # spent 4µs making 1 call to Foswiki::LoginManager::CORE:closedir |
580 | } | ||||
581 | |||||
582 | =begin TML | ||||
583 | |||||
584 | ---++ ObjectMethod userLoggedIn( $login, $wikiname) | ||||
585 | |||||
586 | Called when the user is known. It's invoked from Foswiki::UI::Register::finish | ||||
587 | for instance, | ||||
588 | 1 when the user follows the link in their verification email message | ||||
589 | 2 or when the session store is read | ||||
590 | 3 when the user authenticates (via templatelogin / sudo) | ||||
591 | |||||
592 | * =$login= - string login name | ||||
593 | * =$wikiname= - string wikiname | ||||
594 | |||||
595 | =cut | ||||
596 | |||||
597 | # spent 21.7ms (115µs+21.6) within Foswiki::LoginManager::userLoggedIn which was called:
# once (115µs+21.6ms) by Foswiki::LoginManager::loadSession at line 454 | ||||
598 | 1 | 2µs | my ( $this, $authUser, $wikiName ) = @_; | ||
599 | |||||
600 | 1 | 2µs | my $session = $this->{session}; | ||
601 | 1 | 4µs | if ( $session->{users} ) { | ||
602 | 1 | 8µs | 1 | 20.3ms | $session->{user} = $session->{users}->getCanonicalUserID($authUser); # spent 20.3ms making 1 call to Foswiki::Users::getCanonicalUserID |
603 | } | ||||
604 | return | ||||
605 | 1 | 9µs | 1 | 9µs | if $session->inContext('command_line') # spent 9µs making 1 call to Foswiki::inContext |
606 | || $session->{remoteUser} | ||||
607 | && $authUser | ||||
608 | && $authUser eq $session->{remoteUser}; # same user | ||||
609 | |||||
610 | 1 | 4µs | if ( $Foswiki::cfg{UseClientSessions} ) { | ||
611 | |||||
612 | # create new session if necessary | ||||
613 | 1 | 2µs | unless ( $this->{_cgisession} ) { | ||
614 | $this->{_cgisession} = | ||||
615 | Foswiki::LoginManager::Session->new( undef, $session->{request}, | ||||
616 | { Directory => "$Foswiki::cfg{WorkingDir}/tmp" } ); | ||||
617 | die Foswiki::LoginManager::Session->errstr() | ||||
618 | unless $this->{_cgisession}; | ||||
619 | } | ||||
620 | } | ||||
621 | 1 | 4µs | if ( $authUser && $authUser ne $Foswiki::cfg{DefaultUserLogin} ) { | ||
622 | 1 | 9µs | 1 | 6µs | _trace( $this, # spent 6µs making 1 call to Foswiki::LoginManager::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm:208] |
623 | 'Authenticated; converting from ' | ||||
624 | . ( $session->{remoteUser} || 'undef' ) . ' to ' | ||||
625 | . $authUser ); | ||||
626 | |||||
627 | # SMELL: right now anyone that makes a template login url can log | ||||
628 | # in multiple times - should i forbid it | ||||
629 | 1 | 3µs | if ( $Foswiki::cfg{UseClientSessions} ) { | ||
630 | 1 | 2µs | if ( defined( $session->{remoteUser} ) | ||
631 | && $session->inContext('sudo_login') ) | ||||
632 | { | ||||
633 | $session->logEvent( 'sudo login', '', | ||||
634 | 'from ' . ( $session->{remoteUser} || '' ), $authUser ); | ||||
635 | $this->{_cgisession} | ||||
636 | ->param( 'SUDOFROMAUTHUSER', $session->{remoteUser} ); | ||||
637 | } | ||||
638 | |||||
639 | # SMELL: these are bare logins, so if and when there are | ||||
640 | # multiple usermappings, this would need to include cUID.. | ||||
641 | 1 | 8µs | 1 | 96µs | $this->{_cgisession}->param( 'AUTHUSER', $authUser ); # spent 96µs making 1 call to CGI::Session::param |
642 | } | ||||
643 | 1 | 7µs | 1 | 11µs | $session->enterContext('authenticated'); # spent 11µs making 1 call to Foswiki::enterContext |
644 | } | ||||
645 | else { | ||||
646 | _trace( $this, "Session is NOT authenticated" ); | ||||
647 | |||||
648 | # if we are not authenticated, expire any existing session | ||||
649 | $this->{_cgisession}->clear( ['AUTHUSER'] ) | ||||
650 | if ( $Foswiki::cfg{UseClientSessions} ); | ||||
651 | $session->leaveContext('authenticated'); | ||||
652 | } | ||||
653 | 1 | 10µs | if ( $Foswiki::cfg{UseClientSessions} ) { | ||
654 | |||||
655 | # flush the session, to try to fix Item1820 and Item2234 | ||||
656 | 1 | 14µs | 1 | 1.17ms | $this->{_cgisession}->flush(); # spent 1.17ms making 1 call to CGI::Session::flush |
657 | 1 | 10µs | 1 | 16µs | die $this->{_cgisession}->errstr() if $this->{_cgisession}->errstr(); # spent 16µs making 1 call to CGI::Session::ErrorHandler::errstr |
658 | } | ||||
659 | } | ||||
660 | |||||
661 | =begin TML | ||||
662 | |||||
663 | ---++ ObjectMethod _myScriptURLRE ($thisl) | ||||
664 | |||||
- - | |||||
667 | =cut | ||||
668 | |||||
669 | # get an RE that matches a local script URL | ||||
670 | sub _myScriptURLRE { | ||||
671 | my $this = shift; | ||||
672 | |||||
673 | my $s = $this->{_MYSCRIPTURL}; | ||||
674 | unless ($s) { | ||||
675 | $s = quotemeta( $this->{session}->getScriptUrl( 1, $M1, $M2, $M3 ) ); | ||||
676 | $s =~ s@\\$M1@[^/]*?@go; | ||||
677 | $s =~ s@\\$M2@[^/]*?@go; | ||||
678 | $s =~ s@\\$M3@[^#\?/]*@go; | ||||
679 | |||||
680 | # now add alternates for the various script-specific overrides | ||||
681 | foreach my $v ( values %{ $Foswiki::cfg{ScriptUrlPaths} } ) { | ||||
682 | my $over = $v; | ||||
683 | |||||
684 | # escape non-alphabetics | ||||
685 | $over =~ s/(\W)/\\$1/g; | ||||
686 | $s .= '|' . $over; | ||||
687 | } | ||||
688 | $this->{_MYSCRIPTURL} = "($s)"; | ||||
689 | } | ||||
690 | return $s; | ||||
691 | } | ||||
692 | |||||
693 | =begin TML | ||||
694 | |||||
695 | ---++ ObjectMethod _rewriteURL ($this, $url) -> $url | ||||
696 | |||||
697 | =cut | ||||
698 | |||||
699 | # Rewrite a URL inserting the session id | ||||
700 | sub _rewriteURL { | ||||
701 | my ( $this, $url ) = @_; | ||||
702 | |||||
703 | return $url unless $url; | ||||
704 | |||||
705 | my $sessionId = $this->{_cgisession}->id(); | ||||
706 | return $url unless $sessionId; | ||||
707 | return $url if $url =~ m/\?$Foswiki::LoginManager::Session::NAME=/; | ||||
708 | |||||
709 | my $s = _myScriptURLRE($this); | ||||
710 | |||||
711 | # If the URL has no colon in it, or it matches the local script | ||||
712 | # URL, it must be an internal URL and therefore needs the session. | ||||
713 | if ( $url !~ /:/ || $url =~ /^$s/ ) { | ||||
714 | |||||
715 | # strip off the anchor | ||||
716 | my $anchor = ''; | ||||
717 | if ( $url =~ s/(#.*)// ) { | ||||
718 | $anchor = $1; | ||||
719 | } | ||||
720 | |||||
721 | # strip off existing params | ||||
722 | my $params = "?$Foswiki::LoginManager::Session::NAME=$sessionId"; | ||||
723 | |||||
724 | # implicit untaint is OK because recombined with url later | ||||
725 | if ( $url =~ s/\?(.*)$// ) { | ||||
726 | $params .= ';' . $1; | ||||
727 | } | ||||
728 | |||||
729 | # rebuild the URL | ||||
730 | $url .= $params . $anchor; | ||||
731 | } # otherwise leave it untouched | ||||
732 | |||||
733 | return $url; | ||||
734 | } | ||||
735 | |||||
736 | =begin TML | ||||
737 | |||||
738 | ---++ ObjectMethod _rewriteFORM ($thisl) | ||||
739 | |||||
740 | |||||
741 | =cut | ||||
742 | |||||
743 | # Catch all FORMs and add a hidden Session ID variable. | ||||
744 | # Only do this if the form is pointing to an internal link. | ||||
745 | # This occurs if there are no colons in its target, if it has | ||||
746 | # no target, or if its target matches a getScriptUrl URL. | ||||
747 | # '$rest' is the bit of the initial form tag up to the closing > | ||||
748 | sub _rewriteFORM { | ||||
749 | my ( $this, $url, $rest ) = @_; | ||||
750 | |||||
751 | return $url . $rest unless $this->{_cgisession}; | ||||
752 | |||||
753 | my $s = _myScriptURLRE($this); | ||||
754 | |||||
755 | if ( $url !~ /:/ || $url =~ /^($s)/ ) { | ||||
756 | $rest .= CGI::hidden( | ||||
757 | -name => $Foswiki::LoginManager::Session::NAME, | ||||
758 | -value => $this->{_cgisession}->id() | ||||
759 | ); | ||||
760 | } | ||||
761 | return $url . $rest; | ||||
762 | } | ||||
763 | |||||
764 | =begin TML | ||||
765 | |||||
766 | ---++ ObjectMethod endRenderingHandler() | ||||
767 | |||||
768 | This handler is called by getRenderedVersion just before the plugins | ||||
769 | postRenderingHandler. So it is passed all HTML text just before it is | ||||
770 | printed. | ||||
771 | |||||
772 | *DEPRECATED* Use postRenderingHandler instead. | ||||
773 | |||||
774 | =cut | ||||
775 | |||||
776 | # spent 291µs (173+118) within Foswiki::LoginManager::endRenderingHandler which was called 5 times, avg 58µs/call:
# 5 times (173µs+118µs) by Foswiki::Render::getRenderedVersion at line 1443 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 58µs/call | ||||
777 | 5 | 13µs | return unless ( $Foswiki::cfg{UseClientSessions} ); | ||
778 | |||||
779 | 5 | 8µs | my $this = shift; | ||
780 | 5 | 36µs | 5 | 39µs | return if $this->{session}->inContext('command_line'); # spent 39µs making 5 calls to Foswiki::inContext, avg 8µs/call |
781 | |||||
782 | # If cookies are not turned on and transparent CGI session IDs are, | ||||
783 | # grab every URL that is an internal link and pass a CGI variable | ||||
784 | # with the session ID | ||||
785 | 5 | 13µs | unless ( $this->{_haveCookie} || !$Foswiki::cfg{Sessions}{IDsInURLs} ) { | ||
786 | |||||
787 | # rewrite internal links to include the transparent session ID | ||||
788 | # Doesn't catch Javascript, because there are just so many ways | ||||
789 | # to generate links from JS. | ||||
790 | # SMELL: this would probably be done better using javascript | ||||
791 | # that handles navigation away from this page, and uses the | ||||
792 | # rules to rewrite any relative URLs at that time. | ||||
793 | |||||
794 | # a href= rewriting | ||||
795 | $_[0] =~ | ||||
796 | s/(<a[^>]*(?<=\s)href=(["']))(.*?)(\2)/$1.$this->_rewriteURL($3).$4/geoi; | ||||
797 | |||||
798 | # form action= rewriting | ||||
799 | # SMELL: Forms that have no target are also implicit internal | ||||
800 | # links, but are not handled. Does this matter> | ||||
801 | $_[0] =~ | ||||
802 | s/(<form[^>]*(?<=\s)(?:action)=(["']))(.*?)(\2[^>]*>)/$1._rewriteFORM( $this,$3, $4)/geoi; | ||||
803 | } | ||||
804 | |||||
805 | # And, finally, the logon stuff | ||||
806 | 5 | 90µs | 5 | 57µs | $_[0] =~ s/%SESSIONLOGON%/_dispLogon( $this )/geo; # spent 57µs making 5 calls to Foswiki::LoginManager::CORE:subst, avg 11µs/call |
807 | 5 | 70µs | 5 | 22µs | $_[0] =~ s/%SKINSELECT%/_skinSelect( $this )/geo; # spent 22µs making 5 calls to Foswiki::LoginManager::CORE:subst, avg 4µs/call |
808 | } | ||||
809 | |||||
810 | # spent 522µs (54+468) within Foswiki::LoginManager::_addSessionCookieToResponse which was called:
# once (54µs+468µs) by Foswiki::LoginManager::loadSession at line 473 | ||||
811 | 1 | 2µs | my $this = shift; | ||
812 | |||||
813 | 1 | 30µs | 3 | 458µs | my $cookie = CGI::Cookie->new( # spent 431µs making 1 call to CGI::Cookie::new
# spent 21µs making 1 call to CGI::Session::id
# spent 6µs making 1 call to Foswiki::Request::secure |
814 | -name => $Foswiki::LoginManager::Session::NAME, | ||||
815 | -value => $this->{_cgisession}->id(), | ||||
816 | -path => '/', | ||||
817 | -domain => $Foswiki::cfg{Sessions}{CookieRealm} || '', | ||||
818 | -httponly => 1, | ||||
819 | -secure => $this->{session}->{request}->secure, | ||||
820 | ); | ||||
821 | |||||
822 | # An expiry time is only set if the session has the REMEMBER variable | ||||
823 | # in it. This is to prevent accidentally remembering cookies with | ||||
824 | # login managers where the authority is cached in the browser and | ||||
825 | # *not* in the session. Otherwise another user might be able to login | ||||
826 | # on the same machine and inherit the authorities of a prior user. | ||||
827 | 1 | 3µs | if ( $Foswiki::cfg{Sessions}{ExpireCookiesAfter} | ||
828 | && $this->getSessionValue('REMEMBER') ) | ||||
829 | { | ||||
830 | require Foswiki::Time; | ||||
831 | my $exp = Foswiki::Time::formatTime( | ||||
832 | time() + $Foswiki::cfg{Sessions}{ExpireCookiesAfter}, | ||||
833 | '$wday, $day-$month-$ye $hours:$minutes:$seconds GMT' | ||||
834 | ); | ||||
835 | |||||
836 | $cookie->expires($exp); | ||||
837 | } | ||||
838 | |||||
839 | 1 | 14µs | 1 | 10µs | $this->{session}->{response}->cookies( [$cookie] ); # spent 10µs making 1 call to Foswiki::Response::cookies |
840 | } | ||||
841 | |||||
842 | =begin TML | ||||
843 | |||||
844 | ---++ ObjectMethod rewriteRedirectUrl( $url ) ->$url | ||||
845 | |||||
846 | Rewrite the URL used in a redirect if necessary to include any session | ||||
847 | identification. | ||||
848 | * =$url= - target of the redirection. | ||||
849 | |||||
850 | =cut | ||||
851 | |||||
852 | sub rewriteRedirectUrl { | ||||
853 | |||||
854 | my ( $this, $url ) = @_; | ||||
855 | |||||
856 | return $url unless $this->{_cgisession}; | ||||
857 | |||||
858 | if ( $Foswiki::cfg{Sessions}{IDsInURLs} && !$this->{_haveCookie} ) { | ||||
859 | $url = _rewriteURL( $this, $url ); | ||||
860 | } | ||||
861 | |||||
862 | # This usually won't be important, but just in case they haven't | ||||
863 | # yet received the cookie and happen to be redirecting, be sure | ||||
864 | # they do have the cookie. | ||||
865 | $this->_addSessionCookieToResponse(); | ||||
866 | |||||
867 | return $url; | ||||
868 | } | ||||
869 | |||||
870 | =begin TML | ||||
871 | |||||
872 | ---++ ObjectMethod getSessionValues() -> \%values | ||||
873 | |||||
874 | Get a name->value hash of all the defined session variables | ||||
875 | |||||
876 | =cut | ||||
877 | |||||
878 | sub getSessionValues { | ||||
879 | my ($this) = @_; | ||||
880 | |||||
881 | return unless $this->{_cgisession}; | ||||
882 | |||||
883 | return $this->{_cgisession}->param_hashref(); | ||||
884 | } | ||||
885 | |||||
886 | =begin TML | ||||
887 | |||||
888 | ---++ ObjectMethod getCGISession() | ||||
889 | Get the currect CGI session object | ||||
890 | |||||
891 | =cut | ||||
892 | |||||
893 | # spent 10µs within Foswiki::LoginManager::getCGISession which was called:
# once (10µs+0s) by Foswiki::Users::getCGISession at line 403 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm | ||||
894 | 1 | 2µs | my $this = shift; | ||
895 | 1 | 17µs | return $this->{_cgisession}; | ||
896 | } | ||||
897 | |||||
898 | =begin TML | ||||
899 | |||||
900 | ---++ ObjectMethod getSessionValue( $name ) -> $value | ||||
901 | |||||
902 | Get the value of a session variable. | ||||
903 | |||||
904 | =cut | ||||
905 | |||||
906 | sub getSessionValue { | ||||
907 | my ( $this, $key ) = @_; | ||||
908 | return unless $this->{_cgisession}; | ||||
909 | |||||
910 | return $this->{_cgisession}->param($key); | ||||
911 | } | ||||
912 | |||||
913 | =begin TML | ||||
914 | |||||
915 | ---++ ObjectMethod setSessionValue( $name, $value ) | ||||
916 | |||||
917 | Set the value of a session variable. | ||||
918 | |||||
919 | =cut | ||||
920 | |||||
921 | sub setSessionValue { | ||||
922 | my ( $this, $key, $value ) = @_; | ||||
923 | |||||
924 | if ( $this->{_cgisession} | ||||
925 | && defined( $this->{_cgisession}->param( $key, $value ) ) ) | ||||
926 | { | ||||
927 | return 1; | ||||
928 | } | ||||
929 | |||||
930 | return; | ||||
931 | } | ||||
932 | |||||
933 | =begin TML | ||||
934 | |||||
935 | ---++ ObjectMethod clearSessionValue( $name ) -> $boolean | ||||
936 | |||||
937 | Clear the value of a session variable. | ||||
938 | We do not allow setting of AUTHUSER. | ||||
939 | |||||
940 | =cut | ||||
941 | |||||
942 | sub clearSessionValue { | ||||
943 | my ( $this, $key ) = @_; | ||||
944 | |||||
945 | # We do not allow clearing of AUTHUSER. | ||||
946 | if ( $this->{_cgisession} | ||||
947 | && $key ne 'AUTHUSER' | ||||
948 | && defined( $this->{_cgisession}->param($key) ) ) | ||||
949 | { | ||||
950 | $this->{_cgisession}->clear( [ $_[1] ] ); | ||||
951 | |||||
952 | return 1; | ||||
953 | } | ||||
954 | |||||
955 | return; | ||||
956 | } | ||||
957 | |||||
958 | =begin TML | ||||
959 | |||||
960 | ---++ ObjectMethod forceAuthentication() -> boolean | ||||
961 | |||||
962 | *VIRTUAL METHOD* implemented by subclasses | ||||
963 | |||||
964 | Triggered by an access control violation, this method tests | ||||
965 | to see if the current session is authenticated or not. If not, | ||||
966 | it does whatever is needed so that the user can log in, and returns 1. | ||||
967 | |||||
968 | If the user has an existing authenticated session, the function simply drops | ||||
969 | though and returns 0. | ||||
970 | |||||
971 | =cut | ||||
972 | |||||
973 | sub forceAuthentication { | ||||
974 | return 0; | ||||
975 | } | ||||
976 | |||||
977 | =begin TML | ||||
978 | |||||
979 | ---++ ObjectMethod loginUrl( ... ) -> $url | ||||
980 | |||||
981 | *VIRTUAL METHOD* implemented by subclasses | ||||
982 | |||||
983 | Return a full URL suitable for logging in. | ||||
984 | * =...= - url parameters to be added to the URL, in the format required by Foswiki::getScriptUrl() | ||||
985 | |||||
986 | =cut | ||||
987 | |||||
988 | sub loginUrl { | ||||
989 | return ''; | ||||
990 | } | ||||
991 | |||||
992 | =begin TML | ||||
993 | |||||
994 | ---++ ObjectMethod getUser() | ||||
995 | |||||
996 | Should be implemented by subclasses | ||||
997 | |||||
998 | If there is some other means of getting a username - for example, | ||||
999 | Apache has remote_user() - then return it. Otherwise, return undef and | ||||
1000 | the username stored in the session will be used. | ||||
1001 | |||||
1002 | This method of getting the user *assumes* that the identified user | ||||
1003 | has been authenticated in some way (for example, by the web server) | ||||
1004 | |||||
1005 | =cut | ||||
1006 | |||||
1007 | # spent 4µs within Foswiki::LoginManager::getUser which was called:
# once (4µs+0s) by Foswiki::LoginManager::loadSession at line 279 | ||||
1008 | 1 | 7µs | return; | ||
1009 | } | ||||
1010 | |||||
1011 | =begin TML | ||||
1012 | |||||
1013 | ---++ ObjectMethod isValidLoginName( $name ) -> $boolean | ||||
1014 | |||||
1015 | Check for a valid login name (not an existance check, just syntax). | ||||
1016 | Default behaviour is to check the login name against | ||||
1017 | $Foswiki::cfg{LoginNameFilterIn} | ||||
1018 | |||||
1019 | =cut | ||||
1020 | |||||
1021 | sub isValidLoginName { | ||||
1022 | my ( $this, $name ) = @_; | ||||
1023 | |||||
1024 | # this function was erroneously marked as static | ||||
1025 | ASSERT( !ref($name) ) if DEBUG; | ||||
1026 | return $name =~ /$Foswiki::cfg{LoginNameFilterIn}/; | ||||
1027 | } | ||||
1028 | |||||
1029 | =begin TML | ||||
1030 | |||||
1031 | ---++ ObjectMethod _LOGIN ($thisl) | ||||
1032 | |||||
1033 | |||||
1034 | =cut | ||||
1035 | |||||
1036 | # spent 80µs (38+42) within Foswiki::LoginManager::_LOGIN which was called 2 times, avg 40µs/call:
# 2 times (38µs+42µs) by Foswiki::_expandMacroOnTopicRendering at line 3066 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 40µs/call | ||||
1037 | |||||
1038 | #my( $session, $params, $topic, $web ) = @_; | ||||
1039 | 2 | 3µs | my $session = shift; | ||
1040 | 2 | 10µs | 2 | 29µs | my $this = $session->getLoginManager(); # spent 29µs making 2 calls to Foswiki::getLoginManager, avg 14µs/call |
1041 | |||||
1042 | 2 | 20µs | 2 | 13µs | return '' if $session->inContext('authenticated'); # spent 13µs making 2 calls to Foswiki::inContext, avg 7µs/call |
1043 | |||||
1044 | my $url = $this->loginUrl(); | ||||
1045 | if ($url) { | ||||
1046 | my $text = $session->templates->expandTemplate('LOG_IN'); | ||||
1047 | return CGI::a( { href => $url }, $text ); | ||||
1048 | } | ||||
1049 | return ''; | ||||
1050 | } | ||||
1051 | |||||
1052 | =begin TML | ||||
1053 | |||||
1054 | ---++ ObjectMethod _LOGOUTURL ($thisl) | ||||
1055 | |||||
1056 | |||||
1057 | =cut | ||||
1058 | |||||
1059 | # spent 616µs (72+544) within Foswiki::LoginManager::_LOGOUTURL which was called 2 times, avg 308µs/call:
# 2 times (72µs+544µs) by Foswiki::LoginManager::_LOGOUT at line 1084, avg 308µs/call | ||||
1060 | 2 | 5µs | my ( $session, $params, $topic, $web ) = @_; | ||
1061 | 2 | 11µs | 2 | 28µs | my $this = $session->getLoginManager(); # spent 28µs making 2 calls to Foswiki::getLoginManager, avg 14µs/call |
1062 | |||||
1063 | 2 | 47µs | 6 | 516µs | return $session->getScriptUrl( # spent 480µs making 2 calls to Foswiki::getScriptUrl, avg 240µs/call
# spent 35µs making 4 calls to Foswiki::Prefs::getPreference, avg 9µs/call |
1064 | 0, 'view', | ||||
1065 | $session->{prefs}->getPreference('BASEWEB'), | ||||
1066 | $session->{prefs}->getPreference('BASETOPIC'), | ||||
1067 | 'logout' => 1 | ||||
1068 | ); | ||||
1069 | } | ||||
1070 | |||||
1071 | =begin TML | ||||
1072 | |||||
1073 | ---++ ObjectMethod _LOGOUT ($thisl) | ||||
1074 | |||||
1075 | |||||
1076 | =cut | ||||
1077 | |||||
1078 | # spent 10.1ms (139µs+9.92) within Foswiki::LoginManager::_LOGOUT which was called 2 times, avg 5.03ms/call:
# 2 times (139µs+9.92ms) by Foswiki::_expandMacroOnTopicRendering at line 3066 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 5.03ms/call | ||||
1079 | 2 | 5µs | my ( $session, $params, $topic, $web ) = @_; | ||
1080 | 2 | 18µs | 2 | 55µs | my $this = $session->getLoginManager(); # spent 55µs making 2 calls to Foswiki::getLoginManager, avg 28µs/call |
1081 | |||||
1082 | 2 | 13µs | 2 | 16µs | return '' unless $session->inContext('authenticated'); # spent 16µs making 2 calls to Foswiki::inContext, avg 8µs/call |
1083 | |||||
1084 | 2 | 17µs | 2 | 616µs | my $url = _LOGOUTURL(@_); # spent 616µs making 2 calls to Foswiki::LoginManager::_LOGOUTURL, avg 308µs/call |
1085 | 2 | 3µs | if ($url) { | ||
1086 | 2 | 31µs | 4 | 628µs | my $text = $session->templates->expandTemplate('LOG_OUT'); # spent 607µs making 2 calls to Foswiki::Templates::expandTemplate, avg 304µs/call
# spent 21µs making 2 calls to Foswiki::templates, avg 10µs/call |
1087 | 2 | 47µs | 2 | 7.48ms | return CGI::a( { href => $url }, $text ); # spent 7.34ms making 1 call to CGI::AUTOLOAD
# spent 131µs making 1 call to CGI::a |
1088 | } | ||||
1089 | return ''; | ||||
1090 | } | ||||
1091 | |||||
1092 | =begin TML | ||||
1093 | |||||
1094 | ---++ ObjectMethod _AUTHENTICATED ($thisl) | ||||
1095 | |||||
1096 | |||||
1097 | =cut | ||||
1098 | |||||
1099 | sub _AUTHENTICATED { | ||||
1100 | my ( $session, $params ) = @_; | ||||
1101 | my $this = $session->getLoginManager(); | ||||
1102 | |||||
1103 | if ( $session->inContext('authenticated') ) { | ||||
1104 | return $params->{then} || 1; | ||||
1105 | } | ||||
1106 | else { | ||||
1107 | return $params->{else} || 0; | ||||
1108 | } | ||||
1109 | } | ||||
1110 | |||||
1111 | =begin TML | ||||
1112 | |||||
1113 | ---++ ObjectMethod _CANLOGIN ($thisl) | ||||
1114 | |||||
1115 | =cut | ||||
1116 | |||||
1117 | sub _CANLOGIN { | ||||
1118 | my ( $session, $params ) = @_; | ||||
1119 | my $this = $session->getLoginManager(); | ||||
1120 | if ( $session->inContext('can_login') ) { | ||||
1121 | return $params->{then} || 1; | ||||
1122 | } | ||||
1123 | else { | ||||
1124 | return $params->{else} || 0; | ||||
1125 | } | ||||
1126 | } | ||||
1127 | |||||
1128 | =begin TML | ||||
1129 | |||||
1130 | ---++ ObjectMethod _SESSION_VARIABLE ($thisl) | ||||
1131 | |||||
1132 | =cut | ||||
1133 | |||||
1134 | sub _SESSION_VARIABLE { | ||||
1135 | my ( $session, $params ) = @_; | ||||
1136 | my $this = $session->getLoginManager(); | ||||
1137 | my $name = $params->{_DEFAULT}; | ||||
1138 | |||||
1139 | if ( defined $name ) { | ||||
1140 | if ( defined( $params->{set} ) ) { | ||||
1141 | unless ( $readOnlySK{$name} ) { | ||||
1142 | $this->setSessionValue( $name, $params->{set} ); | ||||
1143 | } | ||||
1144 | } | ||||
1145 | elsif ( defined( $params->{clear} ) ) { | ||||
1146 | unless ( $readOnlySK{$name} ) { | ||||
1147 | $this->clearSessionValue($name); | ||||
1148 | } | ||||
1149 | } | ||||
1150 | elsif ( !$secretSK{$name} ) { | ||||
1151 | my $val = $this->getSessionValue($name); | ||||
1152 | $val = '' unless defined $val; | ||||
1153 | return $val; | ||||
1154 | } | ||||
1155 | } | ||||
1156 | return ''; | ||||
1157 | } | ||||
1158 | |||||
1159 | =begin TML | ||||
1160 | |||||
1161 | ---++ ObjectMethod _LOGINURL ($thisl) | ||||
1162 | |||||
1163 | |||||
1164 | =cut | ||||
1165 | |||||
1166 | sub _LOGINURL { | ||||
1167 | my ( $session, $params ) = @_; | ||||
1168 | my $this = $session->{users}->getLoginManager(); | ||||
1169 | return $this->loginUrl(); | ||||
1170 | } | ||||
1171 | |||||
1172 | =begin TML | ||||
1173 | |||||
1174 | ---++ ObjectMethod _dispLogon ($thisl) | ||||
1175 | |||||
1176 | =cut | ||||
1177 | |||||
1178 | sub _dispLogon { | ||||
1179 | my $this = shift; | ||||
1180 | |||||
1181 | return '' unless $this->{_cgisession}; | ||||
1182 | |||||
1183 | my $session = $this->{session}; | ||||
1184 | my $topic = $session->{topicName}; | ||||
1185 | my $web = $session->{webName}; | ||||
1186 | my $sessionId = $this->{_cgisession}->id(); | ||||
1187 | |||||
1188 | my $urlToUse = $this->loginUrl(); | ||||
1189 | |||||
1190 | unless ( $this->{_haveCookie} || !$Foswiki::cfg{Sessions}{IDsInURLs} ) { | ||||
1191 | $urlToUse = _rewriteURL( $this, $urlToUse ); | ||||
1192 | } | ||||
1193 | |||||
1194 | my $text = $session->templates->expandTemplate('LOG_IN'); | ||||
1195 | return CGI::a( { class => 'foswikiAlert', href => $urlToUse }, $text ); | ||||
1196 | } | ||||
1197 | |||||
1198 | =begin TML | ||||
1199 | |||||
1200 | ---++ PrivateMethod _skinSelect () | ||||
1201 | |||||
1202 | Internal use only | ||||
1203 | TODO: what does it do? | ||||
1204 | |||||
1205 | =cut | ||||
1206 | |||||
1207 | sub _skinSelect { | ||||
1208 | my $this = shift; | ||||
1209 | my $session = $this->{session}; | ||||
1210 | my $skins = $session->{prefs}->getPreference('SKINS'); | ||||
1211 | my $skin = $session->getSkin(); | ||||
1212 | my @skins = split( /,/, $skins ); | ||||
1213 | unshift( @skins, 'default' ); | ||||
1214 | my $options = ''; | ||||
1215 | foreach my $askin (@skins) { | ||||
1216 | $askin =~ s/\s//go; | ||||
1217 | if ( $askin eq $skin ) { | ||||
1218 | $options .= | ||||
1219 | CGI::option( { selected => 'selected', name => $askin }, $askin ); | ||||
1220 | } | ||||
1221 | else { | ||||
1222 | $options .= CGI::option( { name => $askin }, $askin ); | ||||
1223 | } | ||||
1224 | } | ||||
1225 | return CGI::Select( { name => 'stickskin' }, $options ); | ||||
1226 | } | ||||
1227 | |||||
1228 | 1 | 12µs | 1; | ||
1229 | __END__ | ||||
# spent 4µs within Foswiki::LoginManager::CORE:closedir which was called:
# once (4µs+0s) by Foswiki::LoginManager::expireDeadSessions at line 579 | |||||
# spent 15µs within Foswiki::LoginManager::CORE:match which was called 4 times, avg 4µs/call:
# 4 times (15µs+0s) by Foswiki::LoginManager::expireDeadSessions at line 561, avg 4µs/call | |||||
# spent 16µs within Foswiki::LoginManager::CORE:open_dir which was called:
# once (16µs+0s) by Foswiki::LoginManager::expireDeadSessions at line 557 | |||||
# spent 159µs within Foswiki::LoginManager::CORE:readdir which was called:
# once (159µs+0s) by Foswiki::LoginManager::expireDeadSessions at line 558 | |||||
# spent 8µs within Foswiki::LoginManager::CORE:stat which was called:
# once (8µs+0s) by Foswiki::LoginManager::expireDeadSessions at line 564 | |||||
# spent 82µs within Foswiki::LoginManager::CORE:subst which was called 11 times, avg 7µs/call:
# 5 times (57µs+0s) by Foswiki::LoginManager::endRenderingHandler at line 806, avg 11µs/call
# 5 times (22µs+0s) by Foswiki::LoginManager::endRenderingHandler at line 807, avg 4µs/call
# once (4µs+0s) by Foswiki::LoginManager::makeLoginManager at line 119 |