Add a warning about the security hole :-(
[raven/abandoned/asp.git] / Ucam_Webauth.vbs
CommitLineData
f560b040
MV
1<%\r
2\r
3' This VBScript class implements a Raven v3 agent for the University of Cambridge\r
4' Web Authentication System.\r
5'\r
6' See http://raven.cam.ac.uk/project/ for more details\r
7'\r
8' Loosely based on the PHP module for Raven\r
9' https://wiki.cam.ac.uk/raven/PHP_library\r
10'\r
11' Copyright (c) 2004, 2005, 2008, 2014 University of Cambridge\r
12'\r
13' This module is free software; you can redistribute it and/or modify\r
14' it under the terms of the GNU Lesser General Public License as\r
15' published by the Free Software Foundation; either version 2.1 of the\r
16' License, or (at your option) any later version.\r
17'\r
18' The module is distributed in the hope that it will be useful, but\r
19' WITHOUT ANY WARRANTY; without even the implied warranty of\r
20' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
21' Lesser General Public License for more details.\r
22'\r
23' You should have received a copy of the GNU Lesser General Public\r
24' License along with this toolkit; if not, write to the Free Software\r
25' Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\r
26' USA\r
27'\r
28' $Id: ucam_webauth.vbs, v1.0 2014/04/05 08:13:00 sh801 \r
29'\r
30' Version 1.0\r
31\r
32 \r
33Class Ucam_Webauth\r
34\r
35 ' ****************************************\r
36 ' \r
37 ' ----------------------------------------\r
38 ' ---------- class Ucam_Webauth ----------\r
39 ' ----------------------------------------\r
40 ' \r
41 ' ****************************************\r
42 '\r
43 ' Methods are listed in order of importance\r
44 ' with MAIN functions at top and lower- \r
45 ' level functions towards the end.\r
46 '\r
47 ' ****************************************\r
48\r
49\r
50 ' 'status_codes' is associative array of status codes of the form {"CODE" => "Description", ..}\r
51\r
52 Private status_codes \r
53\r
54 ' ****************************************\r
55 ' Default values for key parameters\r
56 ' ****************************************\r
57\r
58 Private PROTOCOL_VERSION\r
59 Private AUTHENTICATION_RESPONSE_VERSION\r
60 Private DEFAULT_AUTH_SERVICE\r
61 Private DEFAULT_KEY_DIR\r
62 Private DEFAULT_COOKIE_NAME\r
63 Private DEFAULT_TIMEOUT_MESSAGE\r
64 Private DEFAULT_HOSTNAME\r
65 Private WLS_LOGOUT\r
66 Private DEFAULT_LOG_FILE\r
67 Private AUTHENTICATIONCOOKIE_REDIRECT_WLS\r
68\r
69 ' ****************************************\r
70 ' Constants for tracking state\r
71 ' ****************************************\r
72 '\r
73 ' The 'Authenticate' function is called multiple \r
74 ' times for a successful authentication so we \r
75 ' need to track where we are in the authentication \r
76 ' process with some constants. \r
77\r
78 Private STATE_ERROR\r
79 Private STATE_NEW_AUTHENTICATION\r
80 Private STATE_WLS_RESPONSE_RECEIVED\r
81 private STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
82\r
83 ' ****************************************\r
84 ' Constants for returning state\r
85 ' ****************************************\r
86 '\r
87 ' The 'Authenticate' function needs to \r
88 ' return relevant information as to where \r
89 ' it currently is in the authentication process.\r
90\r
91 Public AUTHENTICATE_INCOMPLETE\r
92 Public AUTHENTICATE_COMPLETE_ERROR\r
93 Public AUTHENTICATE_COMPLETE_AUTHENTICATED\r
94 Public AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED\r
95\r
96 ' ****************************************\r
97 ' Index numbers for the 'Authentication response' fields\r
98 ' ****************************************\r
99 '\r
100 ' See Raven specification documentation for descriptions of each parameter\r
101\r
102 Private AUTHENTICATION_RESPONSE_VER\r
103 Private AUTHENTICATION_RESPONSE_STATUS\r
104 Private AUTHENTICATION_RESPONSE_MSG\r
105 Private AUTHENTICATION_RESPONSE_ISSUE\r
106 Private AUTHENTICATION_RESPONSE_EXPIRE\r
107 Private AUTHENTICATION_RESPONSE_ID\r
108 Private AUTHENTICATION_RESPONSE_PRINCIPAL\r
109 Private AUTHENTICATION_RESPONSE_PTAGS\r
110 Private AUTHENTICATION_RESPONSE_AUTH\r
111 Private AUTHENTICATION_RESPONSE_SSO\r
112 Private AUTHENTICATION_RESPONSE_PARAMS\r
113 Private AUTHENTICATION_RESPONSE_SIG\r
114 Private AUTHENTICATION_RESPONSE_SIZE ' Size of required array\r
115\r
116 Private WLS_RESPONSE_VER \r
117 Private WLS_RESPONSE_STATUS \r
118 Private WLS_RESPONSE_MSG \r
119 Private WLS_RESPONSE_ISSUE \r
120 Private WLS_RESPONSE_ID \r
121 Private WLS_RESPONSE_URL \r
122 Private WLS_RESPONSE_PRINCIPAL \r
123 Private WLS_RESPONSE_PTAGS\r
124 Private WLS_RESPONSE_AUTH\r
125 Private WLS_RESPONSE_SSO\r
126 Private WLS_RESPONSE_LIFE\r
127 Private WLS_RESPONSE_PARAMS\r
128 Private WLS_RESPONSE_KID\r
129 Private WLS_RESPONSE_SIG\r
130 Private WLS_RESPONSE_SIZE ' Size of required array\r
131\r
132 ' ****************************************\r
133 ' General private member variables\r
134 ' ****************************************\r
135\r
136 Private m_response_timeout\r
137 Private m_authrequest_skew\r
138 Private m_max_session_life\r
139 Private m_redirected\r
140 Private m_use_authrequest_iact\r
141 Private m_authrequest_iact\r
142 Private m_authrequest_fail\r
143 Private m_authrequest_desc\r
144 Private m_authrequest_aauth\r
145 Private m_authrequest_params\r
146 Private m_authentication_response_string\r
147 Private m_authentication_cookie\r
148 Private m_auth_service\r
149 Private m_hostname\r
150 Private m_key_dir\r
151 Private m_timeout_message\r
152 Private m_cookie_key\r
153 Private m_cookie_path\r
154 Private m_cookie_name\r
155 Private m_cookie_domain\r
156 Private m_log_file\r
157 Private m_authentication_response\r
158\r
159 ' ****************************************\r
160 ' \r
161 ' ----------------------------------------\r
162 ' ----------- MAIN FUNCTIONS ------------- \r
163 ' ----------------------------------------\r
164 '\r
165 ' **************************************** \r
166\r
167 Private Sub Class_Initialize\r
168 \r
169 ' Initialize all constants as it's not possible \r
170 ' to declare initial values in class definition, above.\r
171 \r
172 PROTOCOL_VERSION = "3"\r
173 AUTHENTICATION_RESPONSE_VERSION = "3"\r
174 DEFAULT_AUTH_SERVICE = "https://raven.cam.ac.uk/auth/authenticate.html"\r
175 DEFAULT_KEY_DIR = "/etc/httpd/conf/webauth_keys"\r
176 DEFAULT_COOKIE_NAME = "Ucam-WebAuth-Session"\r
177 DEFAULT_TIMEOUT_MESSAGE = "your logon to the site has expired"\r
178 DEFAULT_HOSTNAME = "" ' must be supplied explicitly\r
179 WLS_LOGOUT = "Not-authenticated"\r
180 DEFAULT_LOG_FILE = "log.txt"\r
181 AUTHENTICATIONCOOKIE_REDIRECT_WLS = "REDIRECT_WLS"\r
182\r
183 STATE_ERROR = -1\r
184 STATE_NEW_AUTHENTICATION = 0\r
185 STATE_WLS_RESPONSE_RECEIVED = 1\r
186 STATE_WAA_AUTHENTICATIONCOOKIE_SET = 2\r
187\r
188 AUTHENTICATE_INCOMPLETE = 0\r
189 AUTHENTICATE_COMPLETE_ERROR = -1\r
190 AUTHENTICATE_COMPLETE_AUTHENTICATED = 1\r
191 AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED = 2\r
192\r
193 AUTHENTICATION_RESPONSE_VER = 0\r
194 AUTHENTICATION_RESPONSE_STATUS = 1\r
195 AUTHENTICATION_RESPONSE_MSG = 2\r
196 AUTHENTICATION_RESPONSE_ISSUE = 3\r
197 AUTHENTICATION_RESPONSE_EXPIRE = 4\r
198 AUTHENTICATION_RESPONSE_ID = 5\r
199 AUTHENTICATION_RESPONSE_PRINCIPAL = 6\r
200 AUTHENTICATION_RESPONSE_PTAGS = 7\r
201 AUTHENTICATION_RESPONSE_AUTH = 8\r
202 AUTHENTICATION_RESPONSE_SSO = 9\r
203 AUTHENTICATION_RESPONSE_PARAMS = 10\r
204 AUTHENTICATION_RESPONSE_SIG = 11\r
205 AUTHENTICATION_RESPONSE_SIZE = 12 ' Size of required array\r
206\r
207 WLS_RESPONSE_VER = 0\r
208 WLS_RESPONSE_STATUS = 1\r
209 WLS_RESPONSE_MSG = 2\r
210 WLS_RESPONSE_ISSUE = 3\r
211 WLS_RESPONSE_ID = 4\r
212 WLS_RESPONSE_URL = 5\r
213 WLS_RESPONSE_PRINCIPAL = 6\r
214 WLS_RESPONSE_PTAGS = 7\r
215 WLS_RESPONSE_AUTH = 8\r
216 WLS_RESPONSE_SSO = 9\r
217 WLS_RESPONSE_LIFE = 10\r
218 WLS_RESPONSE_PARAMS = 11\r
219 WLS_RESPONSE_KID = 12\r
220 WLS_RESPONSE_SIG = 13\r
221 WLS_RESPONSE_SIZE = 14 ' Size of required array\r
222 \r
223 ' Set up 'status_codes' associative array\r
224 ' See Raven specification documentation for descriptions of each parameter\r
225\r
226 Set status_codes = CreateObject("Scripting.Dictionary")\r
227\r
228 status_codes.Add "200", "Successful authentication"\r
229 status_codes.Add "410", "The user cancelled the authentication request"\r
230 status_codes.Add "510", "No mutually acceptable authentication types available"\r
231 status_codes.Add "520", "Unsupported protocol version"\r
232 status_codes.Add "530", "General request parameter error"\r
233 status_codes.Add "540", "Interaction would be required"\r
234 status_codes.Add "560", "WAA not authorised" \r
235 status_codes.Add "570", "Authentication declined" \r
236\r
237 ' Set up array for holding authentication response parameters\r
238\r
239 ReDim m_authentication_response(AUTHENTICATION_RESPONSE_SIZE)\r
240\r
241 End Sub\r
242 \r
243 \r
244 Public Default Function Construct(ByVal args)\r
245\r
246 ' ****************************************\r
247 ' Constructor for Ucam_Webauth\r
248 ' \r
249 ' We split the constructor that takes \r
250 ' parameters from the initializer as \r
251 ' VBScript doesn't allow initializers \r
252 ' to take parameters.\r
253 ' \r
254 ' Arguments\r
255 ' ================\r
256 ' args: An associative array of arguments as name,value pairs, eg. {"auth_service" => "http://..", "hostname" => "www...", "log_file" => }.\r
257 '\r
258 ' To supply arguments:\r
259 ' Set args = CreateObject("Scripting.Dictionary") \r
260 ' args.Add auth_service", "https://..."\r
261 ' args.Add hostname", "www..."\r
262 ' args.Add log_file", "C:/logfile.txt"\r
263 ' args.Add key_dir", "C:/raven"\r
264 ' args.Add cookie_key", "Random string"\r
265 '\r
266 ' ****************************************\r
267\r
268\r
269 ' Set up default values\r
270\r
271 log_file = DEFAULT_LOG_FILE\r
272 response_timeout = 30\r
273 key_dir = DEFAULT_KEY_DIR\r
274 max_session_life = 2 * 60 * 60\r
275 timeout_message = DEFAULT_TIMEOUT_MESSAGE\r
276 hostname = DEFAULT_HOSTNAME\r
277 cookie_name = DEFAULT_COOKIE_NAME\r
278 cookie_path = "" ' *** SHOULD BE PATH RELATIVE PATH TO SCRIPT BY DEFAULT ***\r
279 cookie_domain = ""\r
280 auth_service = DEFAULT_AUTH_SERVICE\r
281 authrequest_skew = 5\r
282 authrequest_fail = False\r
283 authrequest_iact = False\r
284 use_authrequest_iact = False\r
285\r
286 ' If specific arguments are provided, then override default values\r
287\r
288 If (args.Exists("log_file")) Then log_file = args("log_file")\r
289 If (args.Exists("response_timeout")) Then response_timeout = Int(args("response_timeout"))\r
290 If (args.Exists("key_dir")) Then key_dir = args("key_dir")\r
291 If (args.Exists("max_session_life")) Then max_session_life = Int(args("max_session_life"))\r
292 If (args.Exists("timeout_message")) Then timeout_message = args("timeout_message")\r
293 If (args.Exists("hostname")) Then hostname = args("hostname")\r
294 If (args.Exists("cookie_key")) Then cookie_key = args("cookie_key")\r
295 If (args.Exists("cookie_name")) Then cookie_name = args("cookie_name")\r
296 If (args.Exists("cookie_path")) Then cookie_path = args("cookie_path")\r
297 If (args.Exists("cookie_domain")) Then cookie_domain = args("cookie_domain")\r
298 If (args.Exists("auth_service")) Then auth_service = args("auth_service")\r
299 If (args.Exists("authrequest_desc")) Then authrequest_desc = args("authrequest_desc")\r
300 If (args.Exists("authrequest_params")) Then authrequest_params = args("authrequest_params")\r
301 If (args.Exists("authrequest_skew")) Then authrequest_skew = Int(args("authrequest_skew"))\r
302 If (args.Exists("authrequest_fail")) Then authrequest_fail = CBool(args("authrequest_fail"))\r
303 If (args.Exists("authrequest_iact")) Then \r
304 authrequest_iact = CBool(args("authrequest_iact"))\r
305 use_authrequest_iact = True\r
306 End If\r
307 \r
308 End Function\r
309\r
310 ' ****************************************\r
311 ' \r
312 ' ----------------------------------------\r
313 ' -- PRIMARY FUNCTION - Authenticate() ---\r
314 ' ----------------------------------------\r
315 '\r
316 ' **************************************** \r
317\r
318 Public Function Authenticate()\r
319\r
320 ' ****************************************\r
321 ' Authenticate()\r
322 '\r
323 ' This function is called three times in \r
324 ' order to complete the authentication process.\r
325 '\r
326 ' STEP 1: A fresh user requests an Authenticated \r
327 ' resource with the URL 'X'. 'Authenticate' \r
328 ' redirects the user's browser to a Web Login \r
329 ' Service (WLS) via 'SendAuthenticationRequest()'.\r
330 '\r
331 ' STEP 2: The WLS processes the user's user id\r
332 ' and password and then redirects the user's \r
333 ' browser back to the client's Web Application \r
334 ' Agent (WAA) with a specific set of parameters \r
335 ' in a 'WLS-Response' GET variable. \r
336 ' 'Authenticate' is called again and validates \r
337 ' these values using 'ProcessAuthenticationRequest()'. \r
338 ' If they all check out, it creates a \r
339 ' local authentication cookie on the user's \r
340 ' browser and redirects the user's browser \r
341 ' back to the original URL 'X'.\r
342 '\r
343 ' STEP 3: We return to our original page, except \r
344 ' this time we have a local authentication cookie \r
345 ' set. 'Authenticate' calls \r
346 ' 'ProcessAuthenticationCookie' which checks \r
347 ' this cookie is valid and if the status code \r
348 ' of the cookie is '200', the user was successfully \r
349 ' verified at the WLS - \r
350 ' 'AUTHENTICATE_COMPLETE_AUTHENTICATED' is then \r
351 ' returned to the user.\r
352 '\r
353 ' ****************************************\r
354 \r
355 \r
356 ' First off, perform a sanity check on basic variables\r
357\r
358 If (CheckSetup() = False) Then\r
359 ResetState()\r
360 Authenticate = AUTHENTICATE_COMPLETE_ERROR\r
361 Exit Function\r
362 End If\r
363 \r
364 ' Now work out where we are in the authentication process:\r
365 ' \r
366 ' STATE_NEW_AUTHENTICATION\r
367 ' A completely fresh authentication attempt.\r
368 '\r
369 ' STATE_WLS_RESPONSE_RECEIVED\r
370 ' The user has already been redirected to the WLS, which has \r
371 ' then redirected them back here. They may have successfully \r
372 ' authenticated or simply pressed cancel. As long as it's a \r
373 ' valid, signed WLS-Response - regardless of whether it's a \r
374 ' successful authentication or not - we set a new \r
375 ' authentication cookie which indicates to the code \r
376 ' that the user has been processed by the WLS.\r
377 '\r
378 ' STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
379 ' We have a valid authentication cookie and just need to \r
380 ' check what the status of that is. The user may have \r
381 ' successfully authenticated, the authentication token \r
382 ' may have expired, or the user may have skipped out \r
383 ' the authentication process. In the event of expiration, \r
384 ' 'ProcessAuthenticationCookie' redirects the user back \r
385 ' to the WLS.\r
386 '\r
387 ' STATE_ERROR\r
388 ' There was an error somewhere along the way.\r
389 ' If this happens, it's not a simple case of \r
390 ' an invalid authentication but something more serious\r
391 ' that falls outside the expected process flow.\r
392\r
393 state = GetCurrentState()\r
394\r
395 Select Case state\r
396 \r
397 Case STATE_NEW_AUTHENTICATION\r
398 \r
399 Authenticate = SendAuthenticationRequest("")\r
400 Exit Function\r
401 \r
402 Case STATE_WLS_RESPONSE_RECEIVED\r
403 \r
404 Authenticate = ProcessAuthenticationResponse()\r
405 Exit Function\r
406 \r
407 Case STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
408 \r
409 Authenticate = ProcessAuthenticationCookie()\r
410 Exit Function\r
411 \r
412 Case Else ' This includes the case STATE_ERROR\r
413 \r
414 write_log("STATE_ERROR received: " & status() & ": " & msg()) \r
415 ResetState() \r
416 Authenticate = AUTHENTICATE_COMPLETE_ERROR\r
417 Exit Function\r
418 \r
419 End Select\r
420 \r
421 End Function\r
422 \r
423\r
424 ' ****************************************\r
425 ' \r
426 ' ----------------------------------------\r
427 ' ---- SECONDARY FUNCTIONS TRIGGERED -----\r
428 ' ------- FROM 'Authenticate()' ----------\r
429 ' ----------------------------------------\r
430 '\r
431 ' 1. SendAuthenticationRequest()\r
432 ' 2. ProcessAuthenticationResponse()\r
433 ' 3. ProcessAuthenticationCookie()\r
434 '\r
435 ' **************************************** \r
436\r
437 Public Function SendAuthenticationRequest(msg)\r
438\r
439 ' ****************************************\r
440 ' 1. SendAuthenticationRequest()\r
441 '\r
442 ' Send an authentication request from the WAA to the WLS. \r
443 '\r
444 ' ****************************************\r
445 \r
446 \r
447 ' Write a long line of astericks to make log easier to read.\r
448 \r
449 write_log("****************************************************************") \r
450 write_log("SendAuthenticationRequest: Starting...")\r
451 \r
452 ' If the hostname from the request (Host: header) does not match the\r
453 ' server's preferred name for itself (which should be what's configured\r
454 ' as hostname), cookies are likely to break "randomly" (or more\r
455 ' accurately, the cookie may not be sent by the browser since it"s for\r
456 ' a different hostname) as a result of following links that use the\r
457 ' preferred name, or server-level redirects e.g. to fix "directory"\r
458 ' URLs lacking the trailing "/". Attempt to avoid that by redirecting\r
459 ' to an equivalent URL using the configured hostname.\r
460\r
461 http_host = Request.ServerVariables("HTTP_HOST")\r
462 \r
463 If ((http_host <> "") And (LCase(hostname) <> LCase(http_host))) Then \r
464 write_log("SendAuthenticationRequest: Redirect to tidy up hostname mismatch") \r
465 Redirect(url()) \r
466 SendAuthenticationRequest = AUTHENTICATE_INCOMPLETE \r
467 Exit Function\r
468 End If\r
469 \r
470 ' We set the authentication cookie to 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
471 ' to keep a track of state.\r
472 \r
473 write_log("SendAuthenticationRequest: Setting pre-session cookie")\r
474 \r
475 authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS\r
476 \r
477 ' Build the full 'Authentication Request' URL that will \r
478 ' redirect the user to the WLS. \r
479 ' \r
480 ' Full information about each of these parameters can be \r
481 ' found in Raven v3 documentation.\r
482 \r
483 wls_redirect = auth_service\r
484 wls_redirect = wls_redirect & "?ver=" & PROTOCOL_VERSION\r
485 wls_redirect = wls_redirect & "&url=" & Server.URLEncode(url())\r
486\r
487 If (authrequest_desc <> "") Then wls_redirect = wls_redirect & "&desc=" & Server.URLEncode(authrequest_desc)\r
488 If (authrequest_aauth <> "") Then wls_redirect = wls_redirect & "&aauth=" & Server.URLEncode(authrequest_aauth)\r
489 \r
490 If use_authrequest_iact Then\r
491 If authrequest_iact Then\r
492 wls_redirect = wls_redirect & "&iact=yes"\r
493 Else\r
494 wls_redirect = wls_redirect & "&iact=no"\r
495 End If\r
496 End If\r
497 \r
498 If (msg <> "") Then wls_redirect = wls_redirect & "&msg=" & Server.URLEncode(msg)\r
499 if (authrequest_params <> "") Then wls_redirect = wls_redirect & "&params=" & Server.URLEncode(authrequest_params)\r
500\r
501 wls_redirect = wls_redirect & "&date=" & Server.URLEncode(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow())))\r
502\r
503 ' If (clock_skew <> 0) THen wls_redirect = wls_redirect & "&skew=" & Server.URLEncode(Convert.ToString(clock_skew)) ' 'skew' parameter deprecated in v3\r
504\r
505 If (authrequest_fail = True) Then wls_redirect = wls_redirect & "&fail=yes"\r
506\r
507 write_log("SendAuthenticationRequest: Redirecting to WLS with URL=" & wls_redirect)\r
508 \r
509 Redirect(wls_redirect)\r
510 \r
511 SendAuthenticationRequest = AUTHENTICATE_INCOMPLETE\r
512 \r
513 End Function\r
514 \r
515 \r
516 Public Function ProcessAuthenticationResponse()\r
517\r
518 ' ****************************************\r
519 ' 2. ProcessAuthenticationResponse()\r
520 '\r
521 ' Process the authentication response received from the WLS. \r
522 '\r
523 ' ****************************************\r
524\r
525 write_log("ProcessAuthenticationResponse: Starting...")\r
526 write_log("ProcessAuthenticationResponse: WLS response=" & authentication_response_string)\r
527\r
528 wls_response = Split(authentication_response_string, "!")\r
529 \r
530 set_status "200", ""\r
531 \r
532 \r
533 If (UBound(wls_response) < 1) Then\r
534 \r
535 ' Response is too short to have been signed or have a status.\r
536 \r
537 set_status "620", "WLS response has too few parameters"\r
538 ResetState()\r
539 ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
540 Exit Function\r
541\r
542 End If\r
543 \r
544 ' We only check signature if status = "200".\r
545\r
546 If (wls_response(WLS_RESPONSE_STATUS) = "200") Then\r
547\r
548 ' Get signature and key_id off the end of the wls_response array\r
549 ' and collapse the remaining array into a string. \r
550 ' It's this string that will have been signed by the WLS \r
551 ' and whose signature we then verify using the WLS\r
552 ' public certificate on our server.\r
553 \r
554 signature = wls_response(UBound(wls_response))\r
555 key_id = wls_response(UBound(wls_response) - 1)\r
556 Redim Preserve wls_response (UBound(wls_response) - 2)\r
557 wls_response_signedstring = Join(wls_response, "!")\r
558 \r
559 ' write_log("Signature=" & signature)\r
560 ' write_log("Signed string=" & wls_response_signedstring)\r
561 \r
562 If (check_signature(wls_response_signedstring, signature, key_id) = False) Then\r
563 \r
564 ' Signature is not correct for the wls_response\r
565 \r
566 set_status "606", "Invalid WLS wls_response signature"\r
567 ResetState()\r
568 ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
569 Exit Function\r
570 \r
571 End If\r
572 \r
573 write_log("ProcessAuthenticationResponse: Signature is correct.")\r
574 \r
575 End If\r
576 \r
577\r
578 ' Expand 'wls_response' array to maximum size just in case it's too small \r
579 ' and subsequent calls to wls_response(WLS_RESPONSE_XXX) raise 'IndexOutOfRangeException'\r
580 \r
581 Redim Preserve wls_response (WLS_RESPONSE_SIZE)\r
582 \r
583 \r
584 ' Remove the query part of our current url \r
585 ' and the url provided by the WLS and check \r
586 ' they match.\r
587 \r
588 Set rgx = New RegExp\r
589 rgx.Global = True\r
590 rgx.IgnoreCase = False\r
591 rgx.Pattern = "\?.*$"\r
592 this_url = rgx.Replace(url(), "")\r
593 \r
594 If (wls_response(WLS_RESPONSE_URL) = "") Then\r
595 set_status "607", "Null URL in response ticket doesn't match this URL: " & this_url\r
596 ResetState() \r
597 ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
598 Exit Function \r
599 End If\r
600 \r
601 response_url = wls_response(WLS_RESPONSE_URL) \r
602 response_url = rgx.Replace(response_url, "")\r
603 \r
604 If (this_url <> response_url) Then\r
605 set_status "607", "URL in response ticket doesn't match this URL: " & response_url & " != " & this_url\r
606 ResetState()\r
607 ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
608 Exit Function\r
609 End If\r
610 \r
611 \r
612 ' Go through the possible different response codes \r
613 ' from the WLS and set our status accordingly.\r
614 \r
615 If (wls_response(WLS_RESPONSE_STATUS) = "410") Then\r
616 \r
617 set_status "410", status_codes("410")\r
618 \r
619 ElseIf ((wls_response(WLS_RESPONSE_VER) <> PROTOCOL_VERSION) And (wls_response(WLS_RESPONSE_STATUS) <> "520")) Then\r
620 \r
621 set_status "608", "Wrong protocol version in authentication service reply"\r
622 \r
623 ElseIf (wls_response(WLS_RESPONSE_STATUS) <> "200") Then\r
624 \r
625 ' If status code != "200" then we have an error of some description.\r
626 ' First off, check that it's an error for which we have an error code / msg.\r
627 \r
628 If (status_codes.Exists(wls_response(WLS_RESPONSE_STATUS)) = False) Then\r
629 write_log("No status code for error " & wls_response(WLS_RESPONSE_STATUS)) \r
630 ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
631 Exit Function \r
632 End If\r
633 \r
634 ' If we have an error code / msg for the error, then set status to that code / msg.\r
635 \r
636 set_status wls_response(WLS_RESPONSE_STATUS), status_codes(wls_response(WLS_RESPONSE_STATUS))\r
637 \r
638 ' If the authentication response provided a response message then set status msg to that.\r
639 \r
640 If (wls_response(WLS_RESPONSE_MSG) <> "") Then m_authentication_response(AUTHENTICATION_RESPONSE_MSG) = wls_response(WLS_RESPONSE_MSG)\r
641\r
642 Else\r
643\r
644 ' Status code must be '200' to get here. \r
645 ' But we need to check the issue time of the \r
646 ' authentication response is close to our current time.\r
647\r
648 timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow()) \r
649 timestamp_issue = iso2time(wls_response(WLS_RESPONSE_ISSUE))\r
650 \r
651 If (timestamp_issue = 0) Then\r
652 \r
653 set_status "609", "Unable to read issue time in authentication service reply"\r
654\r
655 ElseIf (timestamp_issue > (timestamp_now + authrequest_skew + 1)) Then\r
656\r
657 set_status "610", "Authentication service reply apparently issued in the future: " & wls_response(WLS_RESPONSE_ISSUE)\r
658\r
659 ElseIf ((timestamp_now - authrequest_skew - 1) > (timestamp_issue + response_timeout)) Then\r
660 \r
661 set_status "611", "Stale authentication service reply issue at " & wls_response(WLS_RESPONSE_ISSUE)\r
662\r
663 End If\r
664 \r
665 End If\r
666\r
667 \r
668 ' Calculate session expiry time\r
669 \r
670 expiry = max_session_life\r
671 \r
672 If (wls_response(WLS_RESPONSE_LIFE) <> "") Then\r
673 \r
674 wls_token_life = Int(wls_response(WLS_RESPONSE_LIFE))\r
675 \r
676 If ((wls_token_life > 0) And (wls_token_life < expiry)) Then expiry = wls_token_life\r
677 \r
678 End If\r
679 \r
680 \r
681 ' Populate authentication response with information collected so far\r
682 \r
683 m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE) = CStr(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow())))\r
684 m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE) = CStr(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow()) + expiry))\r
685 m_authentication_response(AUTHENTICATION_RESPONSE_ID) = wls_response(WLS_RESPONSE_ID)\r
686 m_authentication_response(AUTHENTICATION_RESPONSE_PRINCIPAL) = wls_response(WLS_RESPONSE_PRINCIPAL)\r
687 m_authentication_response(AUTHENTICATION_RESPONSE_AUTH) = wls_response(WLS_RESPONSE_AUTH)\r
688 m_authentication_response(AUTHENTICATION_RESPONSE_SSO) = wls_response(WLS_RESPONSE_SSO)\r
689 m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS) = wls_response(WLS_RESPONSE_PARAMS)\r
690 m_authentication_response(AUTHENTICATION_RESPONSE_PTAGS) = wls_response(WLS_RESPONSE_PTAGS)\r
691 m_authentication_response(AUTHENTICATION_RESPONSE_VER) = AUTHENTICATION_RESPONSE_VERSION\r
692\r
693\r
694 ' Collapse parameters of authentication_response into a string \r
695 ' then create HMAC hash code of this string and append this code \r
696 ' onto the string to form the value of our authentication cookie.\r
697 \r
698 authentication_cookie_value = ""\r
699 \r
700 For i = 0 To (AUTHENTICATION_RESPONSE_PARAMS - 1)\r
701 If (m_authentication_response(i) <> "") Then authentication_cookie_value = authentication_cookie_value & m_authentication_response(i)\r
702 authentication_cookie_value = authentication_cookie_value & "!"\r
703 Next\r
704\r
705 If (m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS) <> "") Then\r
706 authentication_cookie_value = authentication_cookie_value & m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS)\r
707 End If\r
708\r
709 hmac_signature = hmac_sha1(cookie_key, authentication_cookie_value)\r
710 authentication_cookie_value = authentication_cookie_value & "!" & hmac_signature\r
711 \r
712 write_log("ProcessAuthenticationResponse: Setting cookie=" & authentication_cookie_value)\r
713 \r
714 authentication_cookie = authentication_cookie_value\r
715\r
716 ' Now the authentication cookie's in place, we \r
717 ' can redirect user back to the page they started from.\r
718 ' As long as our authentication cookie doesn't expire, \r
719 ' we then only need to call 'ProcessAuthenticationCookie' \r
720 ' to check the cookie is valid - ie. we don't need to \r
721 ' keep returning to the WLS for every single \r
722 ' authentication request.\r
723 \r
724 write_log("ProcessAuthenticationResponse: Session cookie established, redirecting...")\r
725 \r
726 Redirect(wls_response(WLS_RESPONSE_URL))\r
727 \r
728 ProcessAuthenticationResponse = AUTHENTICATE_INCOMPLETE\r
729 \r
730 End Function\r
731 \r
732\r
733 Public Function ProcessAuthenticationCookie()\r
734\r
735 ' ****************************************\r
736 ' 3. ProcessAuthenticationCookie()\r
737 '\r
738 ' Check the signature of the cookie is valid and if so,\r
739 ' process/interpret the values of the authentication cookie. \r
740 '\r
741 ' ****************************************\r
742 \r
743 write_log("ProcessAuthenticationCookie: Starting...")\r
744\r
745 ' Do some quick checks to ensure the authentication \r
746 ' cookie looks like a valid response from WLS.\r
747\r
748 If (authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) Then\r
749 write_log("ProcessAuthenticationCookie: Processing authentication cookie when it's still set to REDIRECT_WLS.")\r
750 set_status "612", "Processing authentication cookie when its still set to REDIRECT_WLS"\r
751 ResetState()\r
752 ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
753 Exit Function\r
754 End If\r
755\r
756 If (CheckValidAuthenticationCookie(authentication_cookie) = False) Then\r
757 write_log("ProcessAuthenticationCookie: Authentication cookie looks invalid.")\r
758 set_status "613", "Authentication cookie invalid"\r
759 ResetState()\r
760 ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
761 Exit Function \r
762 End If\r
763\r
764 write_log("ProcessAuthenticationCookie: Interpreting authentication cookie=" & authentication_cookie)\r
765\r
766 ' Split up authentication cookie into _authentication_response array \r
767 ' of response parameters using '!' as the delimiter.\r
768\r
769 m_authentication_response = Split(url_decode(authentication_cookie), "!")\r
770\r
771 ' ****************************************\r
772 ' Check authentication cookie has been correctly signed\r
773 ' ****************************************\r
774\r
775 ' Get signature from last element of authentication response array.\r
776\r
777 signature = m_authentication_response(UBound(m_authentication_response))\r
778\r
779 ' Copy m_authentication_response into a separate array \r
780 ' then remove the last element of that array \r
781 ' and bundle together as a string. \r
782\r
783 Dim values_for_verify()\r
784 ReDim values_for_verify(UBound(m_authentication_response) - 1)\r
785 \r
786 For i = 0 To (UBound(values_for_verify))\r
787 values_for_verify(i) = m_authentication_response(i)\r
788 Next\r
789\r
790 values_for_verify_string = Join(values_for_verify, "!")\r
791\r
792 ' Check whether the hash of this shorter string matches the signature \r
793 ' we generated in the previous stage of the authentication process. \r
794 \r
795 If (False = hmac_sha1_verify(cookie_key, values_for_verify_string, signature)) Then\r
796 write_log("ProcessAuthenticationCookie: AUTHENTICATION FAILED, session cookie signature invalid")\r
797 set_status "614", "Session cookie signature invalid"\r
798 ResetState()\r
799 ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
800 Exit Function \r
801 End If\r
802\r
803 write_log("ProcessAuthenticationCookie: Existing authentication cookie verified")\r
804\r
805 ' ****************************************\r
806 ' Check authentication cookie hasn't expired\r
807 ' ****************************************\r
808 \r
809 timestamp_issue = iso2time(m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE))\r
810 timestamp_expire = iso2time(m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE))\r
811 timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow()) ' Get current time as Unix timestamp\r
812\r
813 If ((timestamp_issue > timestamp_now) Or (timestamp_now >= timestamp_expire)) Then\r
814\r
815 ' Session has expired so send new authentication request to WLS.\r
816\r
817 write_log("ProcessAuthenticationCookie: Local session cookie expired. Issue/now/expire: " & Cstr(timestamp_issue) & "/" & CStr(timestamp_now) & "/" & CStr(timestamp_expire))\r
818\r
819 ' this.ResetState(); This won't work as we need to set the cookie during 'SendAuthenticationRequest'\r
820 \r
821 ProcessAuthenticationCookie = SendAuthenticationRequest(timeout_message)\r
822 Exit Function\r
823 \r
824 End If\r
825\r
826 ' ****************************************\r
827 ' Authentication process is COMPLETE \r
828 ' though the user may not have been \r
829 ' successfully authenticated. \r
830 ' ****************************************\r
831\r
832 If (m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) <> "200") Then\r
833 write_log("ProcessAuthenticationCookie: AUTHENTICATION COMPLETE but not successfully authenticated.")\r
834 write_log("****************************************************************")\r
835 ResetState()\r
836 ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED\r
837 Exit Function\r
838 End If\r
839 \r
840 write_log("ProcessAuthenticationCookie: AUTHENTICATION COMPLETE and user authenticated.")\r
841 write_log("****************************************************************") \r
842 ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_AUTHENTICATED\r
843 \r
844 End Function\r
845 \r
846\r
847 ' ****************************************\r
848 ' \r
849 ' ----------------------------------------\r
850 ' --- AUTHENTICATE()-SPECIFIC FUNCTIONS --\r
851 ' ----------------------------------------\r
852 '\r
853 ' **************************************** \r
854\r
855 Public Function CheckSetup()\r
856\r
857 ' ****************************************\r
858 ' CheckSetup()\r
859 '\r
860 ' Check the essential variables are in place.\r
861 '\r
862 ' ****************************************\r
863\r
864 request_method = Request.ServerVariables("REQUEST_METHOD")\r
865 \r
866 ' Check 'cookie_key' is defined, the key we will be using to create hash of cookie value.\r
867 \r
868 If (cookie_key = "") Then\r
869 set_status "601", "No key defined for session cookie"\r
870 CheckSetup = False\r
871 Exit Function \r
872 End If\r
873\r
874 ' Log a warning if being used to authenticate POST requests.\r
875 \r
876 If (request_method = "POST") Then\r
877 write_log("Ucam_Webauth agent invoked for POST request, which it doesn't really support")\r
878 End If\r
879 \r
880 ' Check that the hostname is set explicitly (since we cannot trust\r
881 ' the Host: header); if it returns false (i.e. not set).\r
882\r
883 If (hostname = "") Then\r
884 write_log("hostname not set in Ucam_Webauth object, but is mandatory")\r
885 set_status "602", "Ucam_Webauth configuration error - mandatory hostname not defined"\r
886 CheckSetup = False\r
887 Exit Function\r
888 End If\r
889 \r
890 ' If we have got this far without problems, then everything is good.\r
891\r
892 CheckSetup = True\r
893 \r
894 End Function\r
895 \r
896\r
897 Public Sub ResetState()\r
898\r
899 ' Reset state as if a new user has just loaded a \r
900 ' fresh browser window. Unfortunately we can't reset \r
901 ' any cookies that the remote WLS may have set.\r
902 ' This will not completely log you out of Raven as \r
903 ' the Raven WLS also stores a session cookie that \r
904 ' you cannot delete remotely. So accessing Raven \r
905 ' after logout may elicit a "You are already logged \r
906 ' in" from the Raven WLS. \r
907 '\r
908 ' As both local and WLS cookies are session cookies, the safest \r
909 ' thing to do is to quit the browser to remove both session cookies. \r
910 ' Note that some browsers with 'Restore session' functionality, \r
911 ' eg. Firefox, may not remove session cookies properly.\r
912 ' <returns>'true' whatever happens.</returns>\r
913 \r
914 ' By setting the expiry to '1', we ensure the \r
915 ' authentication cookie is removed straightaway.\r
916 \r
917 setcookie full_cookie_name(), "", 1, cookie_path, cookie_domain, using_https(), False\r
918\r
919 End Sub \r
920\r
921\r
922 Public Function GetCurrentState()\r
923\r
924 ' If no authentication cookie and no WLS-response, then we're \r
925 ' starting fresh so return 'STAGE_AUTHENTICATION_NEW'\r
926 \r
927 If ((authentication_cookie = "") And (authentication_response_string = "")) Then\r
928 GetCurrentState = STATE_NEW_AUTHENTICATION\r
929 Exit Function\r
930 End If\r
931 \r
932 ' If no cookie and a non-empty WLS-Response, then either (i) we have \r
933 ' returned from the WLS without the previous cookie that we set staying intact.\r
934 ' So there must have been a problem setting that earlier cookie.\r
935 ' Or (ii) a 'WLS-Response' GET variable was supplied to our initial\r
936 ' page to begin with, which is going to cause confusion. \r
937 ' This may be due to reloading the post-WLS page after an error.\r
938 \r
939 If ((authentication_cookie = "") And (authentication_response_string <> "")) Then\r
940 set_status "610", "Either browser is not accepting session cookie or you supplied WLS-Response variable to initial page."\r
941 \r
942 ' Don't do any redirecting back to the original \r
943 ' page as it might catch us in an infinite loop. \r
944 ' Instead show a page to the user with the \r
945 ' option to click on a particular link or \r
946 ' put something in code to go to a specific \r
947 ' safe page.\r
948 \r
949 GetCurrentState = STATE_ERROR\r
950 Exit Function\r
951 End If\r
952 \r
953 ' If authentication cookie = 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
954 ' and WLS-Response is non-empty, then we've been redirected here \r
955 ' by the WLS (though you could simulate this redirection manually by \r
956 ' interrupting the WLS process and manually pasting in a URL with a \r
957 ' WLS-Response GET variable.)\r
958 \r
959 If ((authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) And (authentication_response_string <> "")) Then \r
960 GetCurrentState = STATE_WLS_RESPONSE_RECEIVED\r
961 Exit Function\r
962 End If \r
963\r
964 \r
965 ' If authentication cookie = 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
966 ' and WLS-Response is empty, then the WLS is not working correctly.\r
967 ' So we trigger another authentication request.\r
968 ' Ideally we'd 'ResetState()' but this seems to create \r
969 ' confusion when we subsequently set the authentication \r
970 ' cookie to 'AUTHENTICATIONCOOKIE_REDIRECT_WLS' again - \r
971 ' so we leave it as is, with authentication cookie still \r
972 ' with this value.\r
973 \r
974 If ((authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) And (authentication_response_string = "")) Then\r
975 GetCurrentState = STATE_NEW_AUTHENTICATION\r
976 Exit Function\r
977 End If\r
978 \r
979 \r
980 ' If authentication cookie != "" and != 'AUTHENTICATIONCOOKIE_REDIRECT_WLS' \r
981 ' then there's a possibility we have a legitimate authentication cookie.\r
982 ' Run 'CheckValidAuthenticationCookie' to check it looks in the \r
983 ' right format.\r
984 \r
985 If ((authentication_cookie <> "") And (authentication_cookie <> AUTHENTICATIONCOOKIE_REDIRECT_WLS)) Then\r
986\r
987 If (CheckValidAuthenticationCookie(authentication_cookie)) Then\r
988 GetCurrentState = STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
989 Exit Function \r
990 End If \r
991 \r
992 set_status "604", "Authentication cookie invalid"\r
993 GetCurrentState = STATE_ERROR\r
994 Exit Function\r
995 End If\r
996 \r
997 ' If none of the conditions have been satisfied so far, \r
998 ' there must have been an error along the way. \r
999 \r
1000 If (status() <> "200") Then set_status "605", "Miscellaneous error while getting current state."\r
1001 \r
1002 GetCurrentState = STATE_ERROR\r
1003 \r
1004 End Function\r
1005 \r
1006\r
1007 Public Function CheckValidAuthenticationCookie(ByVal vAuthenticationCookie)\r
1008\r
1009 ' A quick check to ensure the cookie value looks the \r
1010 ' right format to be an authentication cookie. \r
1011 ' ie. it has the correct number of values, delimited by '!'.\r
1012\r
1013 If (vAuthenticationCookie = "") Then\r
1014 CheckValidAuthenticationCookie = False\r
1015 Exit Function\r
1016 End If\r
1017 \r
1018 ' Split up authentication cookie into Array\r
1019 ' using '!' as the delimiter.\r
1020 \r
1021 authentication_response = Split(url_decode(vAuthenticationCookie), "!")\r
1022\r
1023 If (UBound(authentication_response) <> (AUTHENTICATION_RESPONSE_SIZE - 1)) Then\r
1024 CheckValidAuthenticationCookie = False\r
1025 Exit Function\r
1026 End If \r
1027 \r
1028 CheckValidAuthenticationCookie = True\r
1029 \r
1030 End Function\r
1031 \r
1032 \r
1033 Public Sub Redirect(url)\r
1034 \r
1035 ' Redirect user's browser making \r
1036 ' sure to set redirected flag accordingly\r
1037 \r
1038 Response.Redirect(url)\r
1039 redirected = True\r
1040 \r
1041 End Sub\r
1042\r
1043\r
1044 ' ****************************************\r
1045 ' \r
1046 ' ----------------------------------------\r
1047 ' ------- MISCELLANEOUS FUNCTIONS -------- \r
1048 ' ----------------------------------------\r
1049 '\r
1050 ' ****************************************\r
1051 \r
1052 Public Sub write_log(ByVal message )\r
1053\r
1054 ' Write a message to the log file with a timestamp prefix on every line\r
1055 ' \r
1056 ' Note relative paths, eg. 'logfile.txt', will be relative \r
1057 ' to the IIS server directories where permissions to create\r
1058 ' new files may not be available. So provide an absolute\r
1059 ' path in the initial arguments to Ucam_Webauth ("log_file" => Path) \r
1060 \r
1061 Set objFSO = CreateObject("Scripting.FileSystemObject")\r
1062\r
1063 If (objFSO.FileExists(log_file) = False) Then\r
1064 Set objFile = objFSO.CreateTextFile(log_file)\r
1065 Else\r
1066 Set objFile = objFSO.OpenTextFile(log_file, 8)\r
1067 End If\r
1068\r
1069 date_prefix = "[" & lpad(Year(Date()), 4) & "-" & lpad(Month(Date()),2) & "-" & lpad(Day(Date()),2) & " " & _\r
1070 lpad(Hour(Time()), 2) & ":" & lpad(Minute(Time()),2) & ":" & lpad(Second(Time()),2) & "] " \r
1071\r
1072 objFile.WriteLine(date_prefix & message)\r
1073 objFile.Close\r
1074\r
1075 End Sub\r
1076\r
1077 \r
1078 Public Sub set_status(response_status, response_msg) \r
1079\r
1080 ' Quick function to set 'status' and 'msg' in a single line. \r
1081 ' Makes the code look a little neater.\r
1082 \r
1083 m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) = response_status\r
1084 m_authentication_response(AUTHENTICATION_RESPONSE_MSG) = response_msg\r
1085 \r
1086 End Sub\r
1087 \r
1088\r
1089 Public Function using_https() \r
1090\r
1091 ' Determines whether we're using https or Not\r
1092\r
1093 using_https = False\r
1094\r
1095 If (Request.ServerVariables("HTTPS") <> "") Then\r
1096 servertype = Request.ServerVariables("HTTPS")\r
1097 If (servertype = "on") Then using_https = True\r
1098 End If\r
1099 \r
1100 End Function\r
1101 \r
1102\r
1103 Public Function url() \r
1104\r
1105 ' Get the url to redirect the browser to after a successful authentication attempt.\r
1106 ' \r
1107 ' This is typically identical to the url that first calls this script. \r
1108 ' But due to the possibility of faking 'HOST' variables in a server response, \r
1109 ' the 'hostname' must be supplied as a setup / default parameter in the code. \r
1110 '\r
1111 ' In versions 2 and 3, we must include the query component (GET parameters) of the \r
1112 ' original calling url if they exist.\r
1113 \r
1114 \r
1115 ' Strip out port number from hostname\r
1116\r
1117 Set rgx = New RegExp\r
1118 rgx.Global = True\r
1119 rgx.IgnoreCase = False\r
1120 rgx.Pattern = ":[0-9]+$"\r
1121\r
1122 basichostname = rgx.Replace(hostname, "")\r
1123 port = Request.ServerVariables("SERVER_PORT")\r
1124 protocol = "http://"\r
1125\r
1126 If (using_https()) Then\r
1127 protocol = "https://"\r
1128 If (port = "443") Then port = ""\r
1129 Else\r
1130 If (port = "80") Then port = ""\r
1131 End If\r
1132\r
1133 finalurl = protocol & basichostname\r
1134 If (port <> "") Then finalurl = finalurl & ":" & port\r
1135 \r
1136 ' Remove any possible WLS-Response variables \r
1137 ' from query part of URL to avoid \r
1138 ' confusion and just in case we've \r
1139 ' called 'SendAuthenticationRequest' \r
1140 ' after WLS returned incorrect WLS-Response \r
1141 ' 'GET' - which could lead to multiple \r
1142 ' 'WLS-Response=&WLS-Response=...'\r
1143 ' coming back from WLS server.\r
1144 \r
1145 url_query = Request.ServerVariables("REQUEST_URI")\r
1146 rgx.Pattern = "&WLS-Response=[^&]*"\r
1147 url_query = rgx.Replace(url_query, "")\r
1148 rgx.Pattern = "\?WLS-Response=[^&]*"\r
1149 url_query = rgx.Replace(url_query, "?")\r
1150 rgx.Pattern = "\?&"\r
1151 url_query = rgx.Replace(url_query, "?") \r
1152 rgx.Pattern = "\?$"\r
1153 url_query = rgx.Replace(url_query, "") \r
1154 \r
1155 url = finalurl & url_query\r
1156 \r
1157 End Function\r
1158\r
1159 \r
1160 Public Function full_cookie_name() \r
1161\r
1162 ' Get name of cookie, typically 'Ucam-WebAuth-Session'\r
1163 ' If 'https', then distinguish the name of the cookie by suffixing '-S'\r
1164\r
1165 full_cookie_name = cookie_name\r
1166\r
1167 If (using_https()) Then full_cookie_name = cookie_name & "-S"\r
1168 \r
1169 End Function\r
1170 \r
1171\r
1172 Public Sub setcookie(ByVal name , ByVal value , ByVal expire , ByVal path , ByVal domain , ByVal secure , ByVal httponly )\r
1173 \r
1174 ' Sets cookie.\r
1175 ' \r
1176 ' name: Name of cookie.\r
1177 ' value: Value of cookie.\r
1178 ' expire: Expiry of cookie. Don't set it to make it a session cookie.\r
1179 ' path: Path of cookie.\r
1180 ' domain: Domain.\r
1181 ' secure: Only allow on secure domains.\r
1182 ' httponly: Only allow on http non-secure domains.\r
1183 \r
1184 If (expire <> 0) Then\r
1185 If (expire = 1) Then\r
1186 expire_datetime = DateAdd("s", 1, UTCNow())\r
1187 Else\r
1188 timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow())\r
1189 \r
1190 If (expire < timestamp_now) Then\r
1191 write_log("setcookie: Setting expire to past so don't bother setting cookie.")\r
1192 Exit Sub\r
1193 End If\r
1194 \r
1195 expire_datetime = DateAdd("s", expire, "01/01/1970 00:00:00")\r
1196 End If \r
1197 End If\r
1198\r
1199 Response.Cookies(name) = value\r
1200\r
1201 ' Whats correct value for Expires field when expire = 0?\r
1202 \r
1203 If (expire_datetime <> 0) Then\r
1204 Response.Cookies(name).Expires = expire_datetime\r
1205 End If\r
1206\r
1207 ' Problems setting 'httponly' in VBScript as \r
1208 ' VBScript encodes everything to do with cookies. \r
1209 ' So if 'httponly' is required, a different \r
1210 ' way of setting cookies by directly setting \r
1211 ' the header with 'Set-Cookie' will be necessary. \r
1212 \r
1213 ' If (httponly) Then \r
1214 ' Response.Cookies(name).Path = path & "; HttpOnly"\r
1215 ' Else \r
1216 ' Response.Cookies(name).Path = path \r
1217 ' End If\r
1218\r
1219 Response.Cookies(name).Path = path \r
1220 \r
1221 If (domain <> "") Then Response.Cookies(name).Domain = domain\r
1222 \r
1223 Response.Cookies(name).Secure = secure\r
1224\r
1225 ' Response.Cookies.Add(cookie)\r
1226 End Sub\r
1227\r
1228\r
1229 Public Function time2iso(t) \r
1230\r
1231 ' Convert a Unix timestamp into the format required by Raven. \r
1232 ' Format based on RFC 3339, but see Raven documentation for \r
1233 ' a full description.\r
1234\r
1235 unUDate = DateAdd("s", t, "01/01/1970 00:00:00")\r
1236\r
1237 time2iso = (lpad(Year(unUDate), 4) & lpad(Month(unUDate),2) & lpad(Day(unUDate),2) & "T" &_\r
1238 lpad(Hour(unUDate), 2) & lpad(Minute(unUDate),2) & lpad(Second(unUDate),2) & "Z") \r
1239 \r
1240 End Function\r
1241\r
1242\r
1243 Public Function iso2time(t) \r
1244\r
1245 ' Convert a time in Raven format into a Unix timestamp \r
1246 ' ie. the number of seconds since epoch.\r
1247\r
1248 iso2time = 0\r
1249 \r
1250 if (Len(t) <> 16) Then Exit Function \r
1251 \r
1252 On Error Resume Next\r
1253 \r
1254 sYear = Mid(t,1,4)\r
1255 sMonth = Mid(t, 5, 2)\r
1256 sDay = Mid(t, 7, 2)\r
1257 sHour = Mid(t, 10, 2)\r
1258 sMinute = Mid(t, 12, 2)\r
1259 sSecond = Mid(t, 14, 2)\r
1260 \r
1261 var_origin = CDate("01/01/1970 00:00:00")\r
1262 var_date = CDate(sDay & "/" & sMonth & "/" & sYear & " " & sHour & ":" & sMinute & ":" & sSecond)\r
1263 \r
1264 iso2time = DateDiff("s", var_origin, var_date) \r
1265 \r
1266 On Error GoTo 0\r
1267 \r
1268 End Function\r
1269\r
1270\r
1271 Public Function load_key(ByVal key_id ) \r
1272\r
1273 ' Returns content of a certificate key as a string\r
1274\r
1275 key_filename = key_dir & "/" & key_id & ".crt"\r
1276\r
1277 Set fso = CreateObject("Scripting.FileSystemObject")\r
1278 Set file = fso.getFile(key_filename)\r
1279 If isNull(file) Then\r
1280 Exit Function\r
1281 End If\r
1282 \r
1283 Set ts = file.OpenAsTextStream()\r
1284 s = Space(file.size)\r
1285 a = Split(s," ")\r
1286\r
1287 i = 0\r
1288 ' Do not replace the following block by readBinary = by ts.readAll(), \r
1289 ' it would result in broken output, because that method is not intended for binary data \r
1290 While Not ts.atEndOfStream\r
1291 a(i) = ts.read(1)\r
1292 i = i + 1\r
1293 Wend\r
1294 ts.close\r
1295\r
1296 load_key = Join(a,"")\r
1297 \r
1298 End Function\r
1299\r
1300\r
1301 Public Function check_signature(ByVal data , ByVal sig , ByVal key_id ) \r
1302\r
1303 ' Checks the 'signature' provided by the WLS when it signed 'data' \r
1304 ' is a valid signature for the data. This ensures the data has not been \r
1305 ' tampered with.\r
1306\r
1307 key_str = load_key(key_id)\r
1308\r
1309 ' We make a call to a some Javascript libraries to do the verification\r
1310 \r
1311 check_signature = JavascriptCertVerify(data, wls_decode(sig), key_str)\r
1312 \r
1313 End Function\r
1314\r
1315\r
1316 Public Function wls_encode(plainTextBytes) \r
1317\r
1318 ' Encode a byte array of data in a way that can be \r
1319 ' easily sent to the WLS\r
1320\r
1321 Set rgx = New RegExp\r
1322 rgx.Global = True\r
1323 rgx.IgnoreCase = False\r
1324 rgx.Pattern = "\+": plainTextBytes = rgx.Replace(plainTextBytes, "_")\r
1325 rgx.Pattern = "/": plainTextBytes = rgx.Replace(plainTextBytes, ".")\r
1326 rgx.Pattern = "=": plainTextBytes = rgx.Replace(plainTextBytes, "_")\r
1327\r
1328 wls_encode = plainTextBytes\r
1329 \r
1330 End Function\r
1331\r
1332\r
1333 Public Function wls_decode(ByVal sig )\r
1334\r
1335 ' Decode a string of data received from the WLS \r
1336 ' into a string with data as hex doubledigits (as used by javascript security library)\r
1337 \r
1338 Set rgx = New RegExp\r
1339 rgx.Global = True\r
1340 rgx.IgnoreCase = False\r
1341 rgx.Pattern = "-": sig = rgx.Replace(sig, "+")\r
1342 rgx.Pattern = "\.": sig = rgx.Replace(sig, "/")\r
1343 rgx.Pattern = "_": sig = rgx.Replace(sig, "=")\r
1344 \r
1345 sig_base64 = base64_decode(sig)\r
1346 \r
1347 sig_hex = ""\r
1348 For i = 1 To LenB(sig_base64)\r
1349 sig_hex = sig_hex & Right(String(2, "0") & LCase(Hex(AscB(MidB(sig_base64, i, 1)))), 2)\r
1350 Next\r
1351\r
1352 wls_decode = sig_hex\r
1353 \r
1354 End Function\r
1355\r
1356\r
1357 Public Function hmac_sha1(ByVal key , ByVal data ) \r
1358\r
1359 ' Create HMACSHA1 hash value for 'data' using public 'key'.\r
1360 '\r
1361 ' key: raw content of a certificate file as string.\r
1362 ' data: data to create hash value from as string.\r
1363 \r
1364 hmac_sha1 = wls_encode(b64_hmac_sha1(key, data))\r
1365 \r
1366 End Function\r
1367\r
1368\r
1369 Public Function hmac_sha1_verify(ByVal key , ByVal data , ByVal sig ) \r
1370\r
1371 ' Verify the 'data' has been signed by public 'key'\r
1372 ' \r
1373 ' Compute HMACSHA1 hash value for 'data' using public 'key'\r
1374 ' then compare the value to 'sig'(nature).\r
1375 ' \r
1376 ' key: Full text for public key.\r
1377 ' data: Data to be verified.\r
1378 ' signature: Signature of signed data (ie. hash value generated by us earlier).\r
1379 \r
1380 hmac_sha1_verify = (sig = hmac_sha1(key, data))\r
1381 \r
1382 End Function\r
1383\r
1384\r
1385 ' ****************************************\r
1386 ' \r
1387 ' ----------------------------------------\r
1388 ' ------- MISCELLANEOUS FUNCTIONS -------- \r
1389 ' ------- SPECIFIC TO ASP VERSION --------\r
1390 ' ----------------------------------------\r
1391 '\r
1392 ' ****************************************\r
1393\r
1394 Function lpad(strInput, length)\r
1395\r
1396 ' Left pad string with zeros.\r
1397 \r
1398 lpad = Right(String(length, "0") & strInput, length)\r
1399 \r
1400 End Function\r
1401\r
1402\r
1403 Public Function url_decode(ByVal url_encoded)\r
1404\r
1405 ' Decodes URL-encoded string \r
1406\r
1407 url_decode = ""\r
1408 \r
1409 If (url_encoded = "") Then Exit Function\r
1410\r
1411 Dim aSplit\r
1412 Dim sOutput\r
1413 Dim I\r
1414 If IsNull(url_encoded) Then\r
1415 Exit Function\r
1416 End If\r
1417 \r
1418 ' convert all pluses to spaces\r
1419 sOutput = REPLACE(url_encoded, "+", " ")\r
1420 \r
1421 ' next convert %hexdigits to the character\r
1422 aSplit = Split(sOutput, "%")\r
1423 \r
1424 If IsArray(aSplit) Then\r
1425 sOutput = aSplit(0)\r
1426 For I = 0 to UBound(aSplit) - 1\r
1427 sOutput = sOutput & _\r
1428 Chr("&H" & Left(aSplit(i + 1), 2)) &_\r
1429 Right(aSplit(i + 1), Len(aSplit(i + 1)) - 2)\r
1430 Next\r
1431 End If\r
1432 \r
1433 url_decode = sOutput\r
1434 \r
1435 End Function\r
1436\r
1437 \r
1438 Public Function UTCNow()\r
1439\r
1440 ' Gets the UTC current time\r
1441 ' The UTC time is the standard time the Raven server is operating with.\r
1442 \r
1443 Set dateTime = CreateObject("WbemScripting.SWbemDateTime") \r
1444 dateTime.SetVarDate (now())\r
1445 UTCNow = dateTime.GetVarDate (false)\r
1446 \r
1447 End Function\r
1448\r
1449\r
1450 Public Function base64_decode(strB64)\r
1451\r
1452 ' Base64 decodes a string\r
1453 \r
1454 strXML = "<B64DECODE xmlns:dt=" & Chr(34) & _\r
1455 "urn:schemas-microsoft-com:datatypes" & Chr(34) & " " & _\r
1456 "dt:dt=" & Chr(34) & "bin.base64" & Chr(34) & ">" & _\r
1457 strB64 & "</B64DECODE>"\r
1458 Set oXMLDoc = CreateObject("MSXML2.DOMDocument.3.0")\r
1459 oXMLDoc.LoadXML(strXML)\r
1460 \r
1461 base64_decode = oXMLDoc.selectsinglenode("B64DECODE").nodeTypedValue\r
1462 \r
1463 set oXMLDoc = Nothing\r
1464 \r
1465 End Function\r
1466 \r
1467\r
1468 ' ****************************************\r
1469 ' \r
1470 ' Special get/set methods to enable \r
1471 ' seamless access to cookies or query \r
1472 ' variables as if they were ordinary \r
1473 ' member variables.\r
1474 '\r
1475 ' ****************************************\r
1476\r
1477 ' Get/set authentication_cookie\r
1478 ' 'authentication_cookie' is used to get and set \r
1479 ' the value of the authentication cookie.\r
1480\r
1481 Public Property Get authentication_cookie\r
1482\r
1483 ' If the current value of the private variable \r
1484 ' m_authentication_cookie is null then we check \r
1485 ' to see what the value of the actual cookie is \r
1486 ' and use that to set the variable accordingly.\r
1487\r
1488 If (m_authentication_cookie = "") Then\r
1489 On Error Resume Next\r
1490 m_authentication_cookie = Request.Cookies(full_cookie_name())\r
1491 On Error GoTo 0\r
1492 End If\r
1493\r
1494 authentication_cookie = m_authentication_cookie\r
1495\r
1496 End Property \r
1497 \r
1498 Public Property Let authentication_cookie(v_authentication_cookie)\r
1499\r
1500 ' Reset the private variable _authentication_cookie \r
1501 ' so the system is forced to query the cookie directly\r
1502 ' next time it wants to check the value through \r
1503 ' authentication_cookie.\r
1504\r
1505 m_authentication_cookie = ""\r
1506 \r
1507 setcookie full_cookie_name(), v_authentication_cookie, 0, cookie_path, cookie_domain, using_https(), False\r
1508 \r
1509 End Property\r
1510\r
1511\r
1512 Public Property Get authentication_response_string()\r
1513\r
1514 ' Get authentication_response_string\r
1515 ' \r
1516 ' Checks to see if there is a 'WLS-Response' \r
1517 ' variable set and uses this as the value \r
1518 ' for authentication_response_string\r
1519\r
1520 ' If the value is already set, we just return it straightaway\r
1521 \r
1522 If (m_authentication_response_string <> "") Then\r
1523 authentication_response_string = m_authentication_response_string\r
1524 Exit Property\r
1525 End If\r
1526 \r
1527 ' If the value is not set, we look for the value of 'WLS-Response' in 'QUERY_STRING'\r
1528 \r
1529 query_string = Request.ServerVariables("QUERY_STRING")\r
1530 \r
1531 If (query_string = "") Then\r
1532 authentication_response_string = m_authentication_response_string\r
1533 Exit Property\r
1534 End If\r
1535 \r
1536\r
1537 ' We're processing urls with possible name-value pairs\r
1538 ' in addition to WLS-Response=... so we need to extract all \r
1539 ' name-value pairs and check specifically for WLS-Response. \r
1540 \r
1541 namevaluepairs = Split(query_string, "&")\r
1542 \r
1543 For Each namevalue In namevaluepairs\r
1544 \r
1545 pair = Split(namevalue, "=")\r
1546 \r
1547 If (UBound(pair) = 1) Then \r
1548 If (pair(0) = "WLS-Response") Then \r
1549 authentication_response_string = url_decode(pair(1))\r
1550 Exit Property \r
1551 End If\r
1552 End If\r
1553 Next\r
1554\r
1555 authentication_response_string = "" \r
1556 \r
1557 End Property\r
1558 \r
1559\r
1560 ' ****************************************\r
1561 ' \r
1562 ' Get/set methods to enable public access \r
1563 ' to private variables.\r
1564 '\r
1565 ' ****************************************\r
1566\r
1567 ' Get/set auth_service\r
1568\r
1569 Public Property Get auth_service\r
1570 auth_service = m_auth_service\r
1571 End Property \r
1572 Public Property Let auth_service(v_auth_service)\r
1573 m_auth_service = v_auth_service\r
1574 End Property\r
1575\r
1576 ' Get/set authrequest_desc\r
1577\r
1578 Public Property Get authrequest_desc\r
1579 authrequest_desc = m_description\r
1580 End Property \r
1581 Public Property Let authrequest_desc(v_authrequest_desc)\r
1582 m_authrequest_desc = v_authrequest_desc\r
1583 End Property\r
1584\r
1585 ' Get/set authrequest_skew\r
1586\r
1587 Public Property Get authrequest_skew\r
1588 authrequest_skew = m_authrequest_skew\r
1589 End Property \r
1590 Public Property Let authrequest_skew(v_authrequest_skew)\r
1591 m_authrequest_skew = v_authrequest_skew\r
1592 End Property\r
1593\r
1594 ' Get/set authrequest_fail\r
1595\r
1596 Public Property Get authrequest_fail\r
1597 authrequest_fail = m_authrequest_fail\r
1598 End Property \r
1599 Public Property Let authrequest_fail(v_authrequest_fail)\r
1600 m_authrequest_fail = v_authrequest_fail\r
1601 End Property\r
1602\r
1603 ' Get/set authrequest_iact\r
1604\r
1605 Public Property Get authrequest_iact\r
1606 authrequest_iact = m_authrequest_iact\r
1607 End Property \r
1608 Public Property Let authrequest_iact(v_authrequest_iact)\r
1609 m_authrequest_iact = v_authrequest_iact\r
1610 End Property\r
1611\r
1612 ' Get/set use_authrequest_iact\r
1613\r
1614 Public Property Get use_authrequest_iact\r
1615 use_authrequest_iact = m_use_authrequest_iact\r
1616 End Property \r
1617 Public Property Let use_authrequest_iact(v_use_authrequest_iact)\r
1618 m_use_authrequest_iact = v_use_authrequest_iact\r
1619 End Property\r
1620\r
1621 ' Get/set authrequest_aauth\r
1622\r
1623 Public Property Get authrequest_aauth\r
1624 authrequest_aauth = m_authrequest_aauth\r
1625 End Property \r
1626 Public Property Let authrequest_aauth(v_authrequest_aauth)\r
1627 m_authrequest_aauth = v_authrequest_aauth\r
1628 End Property\r
1629\r
1630 ' Get/set authrequest_params\r
1631\r
1632 Public Property Get authrequest_params\r
1633 authrequest_params = m_authrequest_params\r
1634 End Property \r
1635 Public Property Let authrequest_params(v_authrequest_params)\r
1636 m_authrequest_params = v_authrequest_params\r
1637 End Property\r
1638 ' Get/set cookie_key\r
1639\r
1640 Public Property Get cookie_key\r
1641 cookie_key = m_cookie_key\r
1642 End Property \r
1643 Public Property Let cookie_key(v_cookie_key)\r
1644 m_cookie_key = v_cookie_key\r
1645 End Property\r
1646\r
1647 ' Get/set redirected\r
1648 ' \r
1649 ' 'redirected' is a flag that says \r
1650 ' whether a redirect has been sent \r
1651 ' which is useful to check before \r
1652 ' attempting to output any information \r
1653 ' to the browser.\r
1654\r
1655 Public Property Get redirected\r
1656 redirected = m_redirected\r
1657 End Property \r
1658 Public Property Let redirected(v_redirected)\r
1659 m_redirected = v_redirected\r
1660 End Property\r
1661\r
1662 ' Get/set cookie_path\r
1663\r
1664 Public Property Get cookie_path\r
1665 cookie_path = m_cookie_path\r
1666 End Property \r
1667 Public Property Let cookie_path(v_cookie_path)\r
1668 m_cookie_path = v_cookie_path\r
1669 End Property\r
1670 \r
1671 ' Get/set response_timeout\r
1672\r
1673 Public Property Get response_timeout\r
1674 response_timeout = m_response_timeout\r
1675 End Property \r
1676 Public Property Let response_timeout(v_response_timeout)\r
1677 m_response_timeout = v_response_timeout\r
1678 End Property\r
1679\r
1680 ' Get/set hostname\r
1681\r
1682 Public Property Get hostname\r
1683 hostname = m_hostname\r
1684 End Property \r
1685 Public Property Let hostname(v_hostname)\r
1686 m_hostname = v_hostname\r
1687 End Property\r
1688\r
1689 ' Get/set key_dir\r
1690\r
1691 Public Property Get key_dir\r
1692 key_dir = m_key_dir\r
1693 End Property\r
1694 Public Property Let key_dir(v_key_dir)\r
1695 m_key_dir = v_key_dir\r
1696 End Property\r
1697\r
1698 ' Get/set max_session_life\r
1699\r
1700 Public Property Get max_session_life\r
1701 max_session_life = m_max_session_life\r
1702 End Property \r
1703 Public Property Let max_session_life(v_max_session_life)\r
1704 m_max_session_life = v_max_session_life\r
1705 End Property\r
1706\r
1707 ' Get/set timeout_message\r
1708\r
1709 Public Property Get timeout_message\r
1710 timeout_message = m_timeout_message\r
1711 End Property \r
1712 Public Property Let timeout_message(v_timeout_message)\r
1713 m_timeout_message = v_timeout_message\r
1714 End Property\r
1715\r
1716 ' Get/set cookie_name\r
1717\r
1718 Public Property Get cookie_name\r
1719 cookie_name = m_cookie_name\r
1720 End Property \r
1721 Public Property Let cookie_name(v_cookie_name)\r
1722 m_cookie_name = v_cookie_name\r
1723 End Property\r
1724\r
1725 ' Get/set cookie_domain\r
1726\r
1727 Public Property Get cookie_domain\r
1728 cookie_domain = m_cookie_domain\r
1729 End Property \r
1730 Public Property Let cookie_domain(v_cookie_domain)\r
1731 m_cookie_domain = v_cookie_domain\r
1732 End Property\r
1733\r
1734 ' Get/set log_file\r
1735\r
1736 Public Property Get log_file\r
1737 log_file = m_log_file\r
1738 End Property \r
1739 Public Property Let log_file(v_log_file)\r
1740 m_log_file = v_log_file\r
1741 End Property\r
1742 \r
1743 ' ****************************************\r
1744 ' \r
1745 ' Read-only methods to retrieve \r
1746 ' authentication response values.\r
1747 '\r
1748 ' See Raven documentation for a full \r
1749 ' explanation of each parameter.\r
1750 '\r
1751 ' ****************************************\r
1752 \r
1753 Public Function status() \r
1754\r
1755 ' Read-only status\r
1756\r
1757 status = ""\r
1758\r
1759 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_STATUS) Then\r
1760 status = m_authentication_response(AUTHENTICATION_RESPONSE_STATUS)\r
1761 End If\r
1762\r
1763 End Function\r
1764\r
1765 Public Function success() \r
1766\r
1767 ' Read-only success\r
1768\r
1769 success = False\r
1770\r
1771 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_STATUS) Then\r
1772 success = (m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) = "200")\r
1773 End If\r
1774 \r
1775 End Function\r
1776\r
1777 Public Function msg() \r
1778\r
1779 ' Read-only msg\r
1780\r
1781 msg = ""\r
1782\r
1783 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_MSG) Then\r
1784 msg = m_authentication_response(AUTHENTICATION_RESPONSE_MSG)\r
1785 End If\r
1786 \r
1787 End Function\r
1788 \r
1789 Public Function issue() \r
1790\r
1791 ' Read-only issue\r
1792\r
1793 issue = ""\r
1794\r
1795 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_ISSUE) Then\r
1796 issue = m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE)\r
1797 End If\r
1798\r
1799 End Function\r
1800\r
1801 Public Function expire() \r
1802\r
1803 ' Read-only expire\r
1804\r
1805 expire = ""\r
1806\r
1807 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_EXPIRE) Then\r
1808 expire = m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE)\r
1809 End If\r
1810 \r
1811 End Function\r
1812\r
1813 Public Function id() \r
1814\r
1815 ' Read-only id\r
1816\r
1817 id = ""\r
1818\r
1819 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_ID) Then\r
1820 id = m_authentication_response(AUTHENTICATION_RESPONSE_ID)\r
1821 End If\r
1822 \r
1823 End Function\r
1824\r
1825 Public Function principal() \r
1826\r
1827 ' Read-only principal\r
1828 ' ie. the user id of the authenticated user\r
1829\r
1830 principal = ""\r
1831\r
1832 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PRINCIPAL) Then\r
1833 principal = m_authentication_response(AUTHENTICATION_RESPONSE_PRINCIPAL)\r
1834 End If\r
1835\r
1836 End Function\r
1837\r
1838 Public Function auth() \r
1839 \r
1840 ' Read-only auth\r
1841\r
1842 auth = ""\r
1843\r
1844 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_AUTH) Then\r
1845 auth = m_authentication_response(AUTHENTICATION_RESPONSE_AUTH)\r
1846 End If\r
1847\r
1848 End Function\r
1849 \r
1850 Public Function sso() \r
1851\r
1852 ' Read-only sso\r
1853\r
1854 sso = ""\r
1855\r
1856 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_SSO) Then\r
1857 sso = m_authentication_response(AUTHENTICATION_RESPONSE_SSO)\r
1858 End If\r
1859\r
1860 End Function\r
1861 \r
1862 Public Function webauth_params() \r
1863\r
1864 ' Read-only params\r
1865\r
1866 webauth_params = ""\r
1867\r
1868 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PARAMS) Then\r
1869 webauth_params = m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS)\r
1870 End If\r
1871\r
1872 End Function\r
1873 \r
1874 Public Function ptags() \r
1875\r
1876 ' Read-only ptags\r
1877 ' ie. whether user is 'current' staff/student \r
1878 ' or another type of user.\r
1879\r
1880 ptags = ""\r
1881\r
1882 If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PTAGS) Then\r
1883 ptags = m_authentication_response(AUTHENTICATION_RESPONSE_PTAGS)\r
1884 End If\r
1885\r
1886 End Function \r
1887 \r
1888End Class\r
1889\r
1890%>\r
1891\r
1892<script runat="server" language="JavaScript" src="js/core.js"></script>\r
1893<script runat="server" language="JavaScript" src="js/md5.js"></script>\r
1894<script runat="server" language="JavaScript" src="js/sha1.js"></script>\r
1895<script runat="server" language="JavaScript" src="js/sha256.js"></script>\r
1896<script runat="server" language="JavaScript" src="js/ripemd160.js"></script>\r
1897<script runat="server" language="JavaScript" src="js/x64-core.js"></script>\r
1898<script runat="server" language="JavaScript" src="js/sha512.js"></script>\r
1899<script runat="server" language="JavaScript" src="js/jsbn.js"></script>\r
1900<script runat="server" language="JavaScript" src="js/jsbn2.js"></script>\r
1901<script runat="server" language="JavaScript" src="js/rsa.js"></script>\r
1902<script runat="server" language="JavaScript" src="js/rsa2.js"></script>\r
1903<script runat="server" language="JavaScript" src="js/crypto-1.1.js"></script>\r
1904<script runat="server" language="JavaScript" src="js/x509-1.1.js"></script>\r
1905<script runat="server" language="JavaScript" src="js/base64.js"></script>\r
1906<script runat="server" language="JavaScript" src="js/asn1hex-1.1.js"></script>\r
1907<script runat="server" language="JavaScript" src="js/rsapem-1.1.js"></script>\r
1908<script runat="server" language="JavaScript" src="js/rsasign-1.2.js"></script>\r
1909<script runat="server" language="JavaScript" src="js/hex_sha1_js.js"></script>\r
1910<script runat="server" language="JavaScript" >\r
1911\r
1912// Javascript cryptographic libraries above adapted for ASP use from \r
1913// client libraries at http://kjur.github.io/jsrsasign/index.html \r
1914// These libraries are used in 'JavascriptCertVerify' (Javascript) \r
1915// and 'hmac_sha1' functions. \r
1916 \r
1917function JavascriptCertVerify(sMsg, sSignature, sCertificateValue) \r
1918{\r
1919 // Javascript function to verify message has \r
1920 // been signed with particular certificate.\r
1921 \r
1922 var bytes = [];\r
1923 var x509 = new X509();\r
1924\r
1925 x509.readCertPEM(sCertificateValue);\r
1926\r
1927 return x509.subjectPublicKeyRSA.verifyString(sMsg, sSignature);\r
1928}\r
1929\r
1930</script>\r