+<%\r
+\r
+' This VBScript class implements a Raven v3 agent for the University of Cambridge\r
+' Web Authentication System.\r
+'\r
+' See http://raven.cam.ac.uk/project/ for more details\r
+'\r
+' Loosely based on the PHP module for Raven\r
+' https://wiki.cam.ac.uk/raven/PHP_library\r
+'\r
+' Copyright (c) 2004, 2005, 2008, 2014 University of Cambridge\r
+'\r
+' This module is free software; you can redistribute it and/or modify\r
+' it under the terms of the GNU Lesser General Public License as\r
+' published by the Free Software Foundation; either version 2.1 of the\r
+' License, or (at your option) any later version.\r
+'\r
+' The module is distributed in the hope that it will be useful, but\r
+' WITHOUT ANY WARRANTY; without even the implied warranty of\r
+' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+' Lesser General Public License for more details.\r
+'\r
+' You should have received a copy of the GNU Lesser General Public\r
+' License along with this toolkit; if not, write to the Free Software\r
+' Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\r
+' USA\r
+'\r
+' $Id: ucam_webauth.vbs, v1.0 2014/04/05 08:13:00 sh801 \r
+'\r
+' Version 1.0\r
+\r
+ \r
+Class Ucam_Webauth\r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' ---------- class Ucam_Webauth ----------\r
+ ' ----------------------------------------\r
+ ' \r
+ ' ****************************************\r
+ '\r
+ ' Methods are listed in order of importance\r
+ ' with MAIN functions at top and lower- \r
+ ' level functions towards the end.\r
+ '\r
+ ' ****************************************\r
+\r
+\r
+ ' 'status_codes' is associative array of status codes of the form {"CODE" => "Description", ..}\r
+\r
+ Private status_codes \r
+\r
+ ' ****************************************\r
+ ' Default values for key parameters\r
+ ' ****************************************\r
+\r
+ Private PROTOCOL_VERSION\r
+ Private AUTHENTICATION_RESPONSE_VERSION\r
+ Private DEFAULT_AUTH_SERVICE\r
+ Private DEFAULT_KEY_DIR\r
+ Private DEFAULT_COOKIE_NAME\r
+ Private DEFAULT_TIMEOUT_MESSAGE\r
+ Private DEFAULT_HOSTNAME\r
+ Private WLS_LOGOUT\r
+ Private DEFAULT_LOG_FILE\r
+ Private AUTHENTICATIONCOOKIE_REDIRECT_WLS\r
+\r
+ ' ****************************************\r
+ ' Constants for tracking state\r
+ ' ****************************************\r
+ '\r
+ ' The 'Authenticate' function is called multiple \r
+ ' times for a successful authentication so we \r
+ ' need to track where we are in the authentication \r
+ ' process with some constants. \r
+\r
+ Private STATE_ERROR\r
+ Private STATE_NEW_AUTHENTICATION\r
+ Private STATE_WLS_RESPONSE_RECEIVED\r
+ private STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
+\r
+ ' ****************************************\r
+ ' Constants for returning state\r
+ ' ****************************************\r
+ '\r
+ ' The 'Authenticate' function needs to \r
+ ' return relevant information as to where \r
+ ' it currently is in the authentication process.\r
+\r
+ Public AUTHENTICATE_INCOMPLETE\r
+ Public AUTHENTICATE_COMPLETE_ERROR\r
+ Public AUTHENTICATE_COMPLETE_AUTHENTICATED\r
+ Public AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED\r
+\r
+ ' ****************************************\r
+ ' Index numbers for the 'Authentication response' fields\r
+ ' ****************************************\r
+ '\r
+ ' See Raven specification documentation for descriptions of each parameter\r
+\r
+ Private AUTHENTICATION_RESPONSE_VER\r
+ Private AUTHENTICATION_RESPONSE_STATUS\r
+ Private AUTHENTICATION_RESPONSE_MSG\r
+ Private AUTHENTICATION_RESPONSE_ISSUE\r
+ Private AUTHENTICATION_RESPONSE_EXPIRE\r
+ Private AUTHENTICATION_RESPONSE_ID\r
+ Private AUTHENTICATION_RESPONSE_PRINCIPAL\r
+ Private AUTHENTICATION_RESPONSE_PTAGS\r
+ Private AUTHENTICATION_RESPONSE_AUTH\r
+ Private AUTHENTICATION_RESPONSE_SSO\r
+ Private AUTHENTICATION_RESPONSE_PARAMS\r
+ Private AUTHENTICATION_RESPONSE_SIG\r
+ Private AUTHENTICATION_RESPONSE_SIZE ' Size of required array\r
+\r
+ Private WLS_RESPONSE_VER \r
+ Private WLS_RESPONSE_STATUS \r
+ Private WLS_RESPONSE_MSG \r
+ Private WLS_RESPONSE_ISSUE \r
+ Private WLS_RESPONSE_ID \r
+ Private WLS_RESPONSE_URL \r
+ Private WLS_RESPONSE_PRINCIPAL \r
+ Private WLS_RESPONSE_PTAGS\r
+ Private WLS_RESPONSE_AUTH\r
+ Private WLS_RESPONSE_SSO\r
+ Private WLS_RESPONSE_LIFE\r
+ Private WLS_RESPONSE_PARAMS\r
+ Private WLS_RESPONSE_KID\r
+ Private WLS_RESPONSE_SIG\r
+ Private WLS_RESPONSE_SIZE ' Size of required array\r
+\r
+ ' ****************************************\r
+ ' General private member variables\r
+ ' ****************************************\r
+\r
+ Private m_response_timeout\r
+ Private m_authrequest_skew\r
+ Private m_max_session_life\r
+ Private m_redirected\r
+ Private m_use_authrequest_iact\r
+ Private m_authrequest_iact\r
+ Private m_authrequest_fail\r
+ Private m_authrequest_desc\r
+ Private m_authrequest_aauth\r
+ Private m_authrequest_params\r
+ Private m_authentication_response_string\r
+ Private m_authentication_cookie\r
+ Private m_auth_service\r
+ Private m_hostname\r
+ Private m_key_dir\r
+ Private m_timeout_message\r
+ Private m_cookie_key\r
+ Private m_cookie_path\r
+ Private m_cookie_name\r
+ Private m_cookie_domain\r
+ Private m_log_file\r
+ Private m_authentication_response\r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' ----------- MAIN FUNCTIONS ------------- \r
+ ' ----------------------------------------\r
+ '\r
+ ' **************************************** \r
+\r
+ Private Sub Class_Initialize\r
+ \r
+ ' Initialize all constants as it's not possible \r
+ ' to declare initial values in class definition, above.\r
+ \r
+ PROTOCOL_VERSION = "3"\r
+ AUTHENTICATION_RESPONSE_VERSION = "3"\r
+ DEFAULT_AUTH_SERVICE = "https://raven.cam.ac.uk/auth/authenticate.html"\r
+ DEFAULT_KEY_DIR = "/etc/httpd/conf/webauth_keys"\r
+ DEFAULT_COOKIE_NAME = "Ucam-WebAuth-Session"\r
+ DEFAULT_TIMEOUT_MESSAGE = "your logon to the site has expired"\r
+ DEFAULT_HOSTNAME = "" ' must be supplied explicitly\r
+ WLS_LOGOUT = "Not-authenticated"\r
+ DEFAULT_LOG_FILE = "log.txt"\r
+ AUTHENTICATIONCOOKIE_REDIRECT_WLS = "REDIRECT_WLS"\r
+\r
+ STATE_ERROR = -1\r
+ STATE_NEW_AUTHENTICATION = 0\r
+ STATE_WLS_RESPONSE_RECEIVED = 1\r
+ STATE_WAA_AUTHENTICATIONCOOKIE_SET = 2\r
+\r
+ AUTHENTICATE_INCOMPLETE = 0\r
+ AUTHENTICATE_COMPLETE_ERROR = -1\r
+ AUTHENTICATE_COMPLETE_AUTHENTICATED = 1\r
+ AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED = 2\r
+\r
+ AUTHENTICATION_RESPONSE_VER = 0\r
+ AUTHENTICATION_RESPONSE_STATUS = 1\r
+ AUTHENTICATION_RESPONSE_MSG = 2\r
+ AUTHENTICATION_RESPONSE_ISSUE = 3\r
+ AUTHENTICATION_RESPONSE_EXPIRE = 4\r
+ AUTHENTICATION_RESPONSE_ID = 5\r
+ AUTHENTICATION_RESPONSE_PRINCIPAL = 6\r
+ AUTHENTICATION_RESPONSE_PTAGS = 7\r
+ AUTHENTICATION_RESPONSE_AUTH = 8\r
+ AUTHENTICATION_RESPONSE_SSO = 9\r
+ AUTHENTICATION_RESPONSE_PARAMS = 10\r
+ AUTHENTICATION_RESPONSE_SIG = 11\r
+ AUTHENTICATION_RESPONSE_SIZE = 12 ' Size of required array\r
+\r
+ WLS_RESPONSE_VER = 0\r
+ WLS_RESPONSE_STATUS = 1\r
+ WLS_RESPONSE_MSG = 2\r
+ WLS_RESPONSE_ISSUE = 3\r
+ WLS_RESPONSE_ID = 4\r
+ WLS_RESPONSE_URL = 5\r
+ WLS_RESPONSE_PRINCIPAL = 6\r
+ WLS_RESPONSE_PTAGS = 7\r
+ WLS_RESPONSE_AUTH = 8\r
+ WLS_RESPONSE_SSO = 9\r
+ WLS_RESPONSE_LIFE = 10\r
+ WLS_RESPONSE_PARAMS = 11\r
+ WLS_RESPONSE_KID = 12\r
+ WLS_RESPONSE_SIG = 13\r
+ WLS_RESPONSE_SIZE = 14 ' Size of required array\r
+ \r
+ ' Set up 'status_codes' associative array\r
+ ' See Raven specification documentation for descriptions of each parameter\r
+\r
+ Set status_codes = CreateObject("Scripting.Dictionary")\r
+\r
+ status_codes.Add "200", "Successful authentication"\r
+ status_codes.Add "410", "The user cancelled the authentication request"\r
+ status_codes.Add "510", "No mutually acceptable authentication types available"\r
+ status_codes.Add "520", "Unsupported protocol version"\r
+ status_codes.Add "530", "General request parameter error"\r
+ status_codes.Add "540", "Interaction would be required"\r
+ status_codes.Add "560", "WAA not authorised" \r
+ status_codes.Add "570", "Authentication declined" \r
+\r
+ ' Set up array for holding authentication response parameters\r
+\r
+ ReDim m_authentication_response(AUTHENTICATION_RESPONSE_SIZE)\r
+\r
+ End Sub\r
+ \r
+ \r
+ Public Default Function Construct(ByVal args)\r
+\r
+ ' ****************************************\r
+ ' Constructor for Ucam_Webauth\r
+ ' \r
+ ' We split the constructor that takes \r
+ ' parameters from the initializer as \r
+ ' VBScript doesn't allow initializers \r
+ ' to take parameters.\r
+ ' \r
+ ' Arguments\r
+ ' ================\r
+ ' args: An associative array of arguments as name,value pairs, eg. {"auth_service" => "http://..", "hostname" => "www...", "log_file" => }.\r
+ '\r
+ ' To supply arguments:\r
+ ' Set args = CreateObject("Scripting.Dictionary") \r
+ ' args.Add auth_service", "https://..."\r
+ ' args.Add hostname", "www..."\r
+ ' args.Add log_file", "C:/logfile.txt"\r
+ ' args.Add key_dir", "C:/raven"\r
+ ' args.Add cookie_key", "Random string"\r
+ '\r
+ ' ****************************************\r
+\r
+\r
+ ' Set up default values\r
+\r
+ log_file = DEFAULT_LOG_FILE\r
+ response_timeout = 30\r
+ key_dir = DEFAULT_KEY_DIR\r
+ max_session_life = 2 * 60 * 60\r
+ timeout_message = DEFAULT_TIMEOUT_MESSAGE\r
+ hostname = DEFAULT_HOSTNAME\r
+ cookie_name = DEFAULT_COOKIE_NAME\r
+ cookie_path = "" ' *** SHOULD BE PATH RELATIVE PATH TO SCRIPT BY DEFAULT ***\r
+ cookie_domain = ""\r
+ auth_service = DEFAULT_AUTH_SERVICE\r
+ authrequest_skew = 5\r
+ authrequest_fail = False\r
+ authrequest_iact = False\r
+ use_authrequest_iact = False\r
+\r
+ ' If specific arguments are provided, then override default values\r
+\r
+ If (args.Exists("log_file")) Then log_file = args("log_file")\r
+ If (args.Exists("response_timeout")) Then response_timeout = Int(args("response_timeout"))\r
+ If (args.Exists("key_dir")) Then key_dir = args("key_dir")\r
+ If (args.Exists("max_session_life")) Then max_session_life = Int(args("max_session_life"))\r
+ If (args.Exists("timeout_message")) Then timeout_message = args("timeout_message")\r
+ If (args.Exists("hostname")) Then hostname = args("hostname")\r
+ If (args.Exists("cookie_key")) Then cookie_key = args("cookie_key")\r
+ If (args.Exists("cookie_name")) Then cookie_name = args("cookie_name")\r
+ If (args.Exists("cookie_path")) Then cookie_path = args("cookie_path")\r
+ If (args.Exists("cookie_domain")) Then cookie_domain = args("cookie_domain")\r
+ If (args.Exists("auth_service")) Then auth_service = args("auth_service")\r
+ If (args.Exists("authrequest_desc")) Then authrequest_desc = args("authrequest_desc")\r
+ If (args.Exists("authrequest_params")) Then authrequest_params = args("authrequest_params")\r
+ If (args.Exists("authrequest_skew")) Then authrequest_skew = Int(args("authrequest_skew"))\r
+ If (args.Exists("authrequest_fail")) Then authrequest_fail = CBool(args("authrequest_fail"))\r
+ If (args.Exists("authrequest_iact")) Then \r
+ authrequest_iact = CBool(args("authrequest_iact"))\r
+ use_authrequest_iact = True\r
+ End If\r
+ \r
+ End Function\r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' -- PRIMARY FUNCTION - Authenticate() ---\r
+ ' ----------------------------------------\r
+ '\r
+ ' **************************************** \r
+\r
+ Public Function Authenticate()\r
+\r
+ ' ****************************************\r
+ ' Authenticate()\r
+ '\r
+ ' This function is called three times in \r
+ ' order to complete the authentication process.\r
+ '\r
+ ' STEP 1: A fresh user requests an Authenticated \r
+ ' resource with the URL 'X'. 'Authenticate' \r
+ ' redirects the user's browser to a Web Login \r
+ ' Service (WLS) via 'SendAuthenticationRequest()'.\r
+ '\r
+ ' STEP 2: The WLS processes the user's user id\r
+ ' and password and then redirects the user's \r
+ ' browser back to the client's Web Application \r
+ ' Agent (WAA) with a specific set of parameters \r
+ ' in a 'WLS-Response' GET variable. \r
+ ' 'Authenticate' is called again and validates \r
+ ' these values using 'ProcessAuthenticationRequest()'. \r
+ ' If they all check out, it creates a \r
+ ' local authentication cookie on the user's \r
+ ' browser and redirects the user's browser \r
+ ' back to the original URL 'X'.\r
+ '\r
+ ' STEP 3: We return to our original page, except \r
+ ' this time we have a local authentication cookie \r
+ ' set. 'Authenticate' calls \r
+ ' 'ProcessAuthenticationCookie' which checks \r
+ ' this cookie is valid and if the status code \r
+ ' of the cookie is '200', the user was successfully \r
+ ' verified at the WLS - \r
+ ' 'AUTHENTICATE_COMPLETE_AUTHENTICATED' is then \r
+ ' returned to the user.\r
+ '\r
+ ' ****************************************\r
+ \r
+ \r
+ ' First off, perform a sanity check on basic variables\r
+\r
+ If (CheckSetup() = False) Then\r
+ ResetState()\r
+ Authenticate = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+ End If\r
+ \r
+ ' Now work out where we are in the authentication process:\r
+ ' \r
+ ' STATE_NEW_AUTHENTICATION\r
+ ' A completely fresh authentication attempt.\r
+ '\r
+ ' STATE_WLS_RESPONSE_RECEIVED\r
+ ' The user has already been redirected to the WLS, which has \r
+ ' then redirected them back here. They may have successfully \r
+ ' authenticated or simply pressed cancel. As long as it's a \r
+ ' valid, signed WLS-Response - regardless of whether it's a \r
+ ' successful authentication or not - we set a new \r
+ ' authentication cookie which indicates to the code \r
+ ' that the user has been processed by the WLS.\r
+ '\r
+ ' STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
+ ' We have a valid authentication cookie and just need to \r
+ ' check what the status of that is. The user may have \r
+ ' successfully authenticated, the authentication token \r
+ ' may have expired, or the user may have skipped out \r
+ ' the authentication process. In the event of expiration, \r
+ ' 'ProcessAuthenticationCookie' redirects the user back \r
+ ' to the WLS.\r
+ '\r
+ ' STATE_ERROR\r
+ ' There was an error somewhere along the way.\r
+ ' If this happens, it's not a simple case of \r
+ ' an invalid authentication but something more serious\r
+ ' that falls outside the expected process flow.\r
+\r
+ state = GetCurrentState()\r
+\r
+ Select Case state\r
+ \r
+ Case STATE_NEW_AUTHENTICATION\r
+ \r
+ Authenticate = SendAuthenticationRequest("")\r
+ Exit Function\r
+ \r
+ Case STATE_WLS_RESPONSE_RECEIVED\r
+ \r
+ Authenticate = ProcessAuthenticationResponse()\r
+ Exit Function\r
+ \r
+ Case STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
+ \r
+ Authenticate = ProcessAuthenticationCookie()\r
+ Exit Function\r
+ \r
+ Case Else ' This includes the case STATE_ERROR\r
+ \r
+ write_log("STATE_ERROR received: " & status() & ": " & msg()) \r
+ ResetState() \r
+ Authenticate = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+ \r
+ End Select\r
+ \r
+ End Function\r
+ \r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' ---- SECONDARY FUNCTIONS TRIGGERED -----\r
+ ' ------- FROM 'Authenticate()' ----------\r
+ ' ----------------------------------------\r
+ '\r
+ ' 1. SendAuthenticationRequest()\r
+ ' 2. ProcessAuthenticationResponse()\r
+ ' 3. ProcessAuthenticationCookie()\r
+ '\r
+ ' **************************************** \r
+\r
+ Public Function SendAuthenticationRequest(msg)\r
+\r
+ ' ****************************************\r
+ ' 1. SendAuthenticationRequest()\r
+ '\r
+ ' Send an authentication request from the WAA to the WLS. \r
+ '\r
+ ' ****************************************\r
+ \r
+ \r
+ ' Write a long line of astericks to make log easier to read.\r
+ \r
+ write_log("****************************************************************") \r
+ write_log("SendAuthenticationRequest: Starting...")\r
+ \r
+ ' If the hostname from the request (Host: header) does not match the\r
+ ' server's preferred name for itself (which should be what's configured\r
+ ' as hostname), cookies are likely to break "randomly" (or more\r
+ ' accurately, the cookie may not be sent by the browser since it"s for\r
+ ' a different hostname) as a result of following links that use the\r
+ ' preferred name, or server-level redirects e.g. to fix "directory"\r
+ ' URLs lacking the trailing "/". Attempt to avoid that by redirecting\r
+ ' to an equivalent URL using the configured hostname.\r
+\r
+ http_host = Request.ServerVariables("HTTP_HOST")\r
+ \r
+ If ((http_host <> "") And (LCase(hostname) <> LCase(http_host))) Then \r
+ write_log("SendAuthenticationRequest: Redirect to tidy up hostname mismatch") \r
+ Redirect(url()) \r
+ SendAuthenticationRequest = AUTHENTICATE_INCOMPLETE \r
+ Exit Function\r
+ End If\r
+ \r
+ ' We set the authentication cookie to 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
+ ' to keep a track of state.\r
+ \r
+ write_log("SendAuthenticationRequest: Setting pre-session cookie")\r
+ \r
+ authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS\r
+ \r
+ ' Build the full 'Authentication Request' URL that will \r
+ ' redirect the user to the WLS. \r
+ ' \r
+ ' Full information about each of these parameters can be \r
+ ' found in Raven v3 documentation.\r
+ \r
+ wls_redirect = auth_service\r
+ wls_redirect = wls_redirect & "?ver=" & PROTOCOL_VERSION\r
+ wls_redirect = wls_redirect & "&url=" & Server.URLEncode(url())\r
+\r
+ If (authrequest_desc <> "") Then wls_redirect = wls_redirect & "&desc=" & Server.URLEncode(authrequest_desc)\r
+ If (authrequest_aauth <> "") Then wls_redirect = wls_redirect & "&aauth=" & Server.URLEncode(authrequest_aauth)\r
+ \r
+ If use_authrequest_iact Then\r
+ If authrequest_iact Then\r
+ wls_redirect = wls_redirect & "&iact=yes"\r
+ Else\r
+ wls_redirect = wls_redirect & "&iact=no"\r
+ End If\r
+ End If\r
+ \r
+ If (msg <> "") Then wls_redirect = wls_redirect & "&msg=" & Server.URLEncode(msg)\r
+ if (authrequest_params <> "") Then wls_redirect = wls_redirect & "¶ms=" & Server.URLEncode(authrequest_params)\r
+\r
+ wls_redirect = wls_redirect & "&date=" & Server.URLEncode(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow())))\r
+\r
+ ' If (clock_skew <> 0) THen wls_redirect = wls_redirect & "&skew=" & Server.URLEncode(Convert.ToString(clock_skew)) ' 'skew' parameter deprecated in v3\r
+\r
+ If (authrequest_fail = True) Then wls_redirect = wls_redirect & "&fail=yes"\r
+\r
+ write_log("SendAuthenticationRequest: Redirecting to WLS with URL=" & wls_redirect)\r
+ \r
+ Redirect(wls_redirect)\r
+ \r
+ SendAuthenticationRequest = AUTHENTICATE_INCOMPLETE\r
+ \r
+ End Function\r
+ \r
+ \r
+ Public Function ProcessAuthenticationResponse()\r
+\r
+ ' ****************************************\r
+ ' 2. ProcessAuthenticationResponse()\r
+ '\r
+ ' Process the authentication response received from the WLS. \r
+ '\r
+ ' ****************************************\r
+\r
+ write_log("ProcessAuthenticationResponse: Starting...")\r
+ write_log("ProcessAuthenticationResponse: WLS response=" & authentication_response_string)\r
+\r
+ wls_response = Split(authentication_response_string, "!")\r
+ \r
+ set_status "200", ""\r
+ \r
+ \r
+ If (UBound(wls_response) < 1) Then\r
+ \r
+ ' Response is too short to have been signed or have a status.\r
+ \r
+ set_status "620", "WLS response has too few parameters"\r
+ ResetState()\r
+ ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+\r
+ End If\r
+ \r
+ ' We only check signature if status = "200".\r
+\r
+ If (wls_response(WLS_RESPONSE_STATUS) = "200") Then\r
+\r
+ ' Get signature and key_id off the end of the wls_response array\r
+ ' and collapse the remaining array into a string. \r
+ ' It's this string that will have been signed by the WLS \r
+ ' and whose signature we then verify using the WLS\r
+ ' public certificate on our server.\r
+ \r
+ signature = wls_response(UBound(wls_response))\r
+ key_id = wls_response(UBound(wls_response) - 1)\r
+ Redim Preserve wls_response (UBound(wls_response) - 2)\r
+ wls_response_signedstring = Join(wls_response, "!")\r
+ \r
+ ' write_log("Signature=" & signature)\r
+ ' write_log("Signed string=" & wls_response_signedstring)\r
+ \r
+ If (check_signature(wls_response_signedstring, signature, key_id) = False) Then\r
+ \r
+ ' Signature is not correct for the wls_response\r
+ \r
+ set_status "606", "Invalid WLS wls_response signature"\r
+ ResetState()\r
+ ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+ \r
+ End If\r
+ \r
+ write_log("ProcessAuthenticationResponse: Signature is correct.")\r
+ \r
+ End If\r
+ \r
+\r
+ ' Expand 'wls_response' array to maximum size just in case it's too small \r
+ ' and subsequent calls to wls_response(WLS_RESPONSE_XXX) raise 'IndexOutOfRangeException'\r
+ \r
+ Redim Preserve wls_response (WLS_RESPONSE_SIZE)\r
+ \r
+ \r
+ ' Remove the query part of our current url \r
+ ' and the url provided by the WLS and check \r
+ ' they match.\r
+ \r
+ Set rgx = New RegExp\r
+ rgx.Global = True\r
+ rgx.IgnoreCase = False\r
+ rgx.Pattern = "\?.*$"\r
+ this_url = rgx.Replace(url(), "")\r
+ \r
+ If (wls_response(WLS_RESPONSE_URL) = "") Then\r
+ set_status "607", "Null URL in response ticket doesn't match this URL: " & this_url\r
+ ResetState() \r
+ ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function \r
+ End If\r
+ \r
+ response_url = wls_response(WLS_RESPONSE_URL) \r
+ response_url = rgx.Replace(response_url, "")\r
+ \r
+ If (this_url <> response_url) Then\r
+ set_status "607", "URL in response ticket doesn't match this URL: " & response_url & " != " & this_url\r
+ ResetState()\r
+ ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+ End If\r
+ \r
+ \r
+ ' Go through the possible different response codes \r
+ ' from the WLS and set our status accordingly.\r
+ \r
+ If (wls_response(WLS_RESPONSE_STATUS) = "410") Then\r
+ \r
+ set_status "410", status_codes("410")\r
+ \r
+ ElseIf ((wls_response(WLS_RESPONSE_VER) <> PROTOCOL_VERSION) And (wls_response(WLS_RESPONSE_STATUS) <> "520")) Then\r
+ \r
+ set_status "608", "Wrong protocol version in authentication service reply"\r
+ \r
+ ElseIf (wls_response(WLS_RESPONSE_STATUS) <> "200") Then\r
+ \r
+ ' If status code != "200" then we have an error of some description.\r
+ ' First off, check that it's an error for which we have an error code / msg.\r
+ \r
+ If (status_codes.Exists(wls_response(WLS_RESPONSE_STATUS)) = False) Then\r
+ write_log("No status code for error " & wls_response(WLS_RESPONSE_STATUS)) \r
+ ProcessAuthenticationResponse = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function \r
+ End If\r
+ \r
+ ' If we have an error code / msg for the error, then set status to that code / msg.\r
+ \r
+ set_status wls_response(WLS_RESPONSE_STATUS), status_codes(wls_response(WLS_RESPONSE_STATUS))\r
+ \r
+ ' If the authentication response provided a response message then set status msg to that.\r
+ \r
+ If (wls_response(WLS_RESPONSE_MSG) <> "") Then m_authentication_response(AUTHENTICATION_RESPONSE_MSG) = wls_response(WLS_RESPONSE_MSG)\r
+\r
+ Else\r
+\r
+ ' Status code must be '200' to get here. \r
+ ' But we need to check the issue time of the \r
+ ' authentication response is close to our current time.\r
+\r
+ timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow()) \r
+ timestamp_issue = iso2time(wls_response(WLS_RESPONSE_ISSUE))\r
+ \r
+ If (timestamp_issue = 0) Then\r
+ \r
+ set_status "609", "Unable to read issue time in authentication service reply"\r
+\r
+ ElseIf (timestamp_issue > (timestamp_now + authrequest_skew + 1)) Then\r
+\r
+ set_status "610", "Authentication service reply apparently issued in the future: " & wls_response(WLS_RESPONSE_ISSUE)\r
+\r
+ ElseIf ((timestamp_now - authrequest_skew - 1) > (timestamp_issue + response_timeout)) Then\r
+ \r
+ set_status "611", "Stale authentication service reply issue at " & wls_response(WLS_RESPONSE_ISSUE)\r
+\r
+ End If\r
+ \r
+ End If\r
+\r
+ \r
+ ' Calculate session expiry time\r
+ \r
+ expiry = max_session_life\r
+ \r
+ If (wls_response(WLS_RESPONSE_LIFE) <> "") Then\r
+ \r
+ wls_token_life = Int(wls_response(WLS_RESPONSE_LIFE))\r
+ \r
+ If ((wls_token_life > 0) And (wls_token_life < expiry)) Then expiry = wls_token_life\r
+ \r
+ End If\r
+ \r
+ \r
+ ' Populate authentication response with information collected so far\r
+ \r
+ m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE) = CStr(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow())))\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE) = CStr(time2iso(DateDiff("s", "01/01/1970 00:00:00", UTCNow()) + expiry))\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_ID) = wls_response(WLS_RESPONSE_ID)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_PRINCIPAL) = wls_response(WLS_RESPONSE_PRINCIPAL)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_AUTH) = wls_response(WLS_RESPONSE_AUTH)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_SSO) = wls_response(WLS_RESPONSE_SSO)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS) = wls_response(WLS_RESPONSE_PARAMS)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_PTAGS) = wls_response(WLS_RESPONSE_PTAGS)\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_VER) = AUTHENTICATION_RESPONSE_VERSION\r
+\r
+\r
+ ' Collapse parameters of authentication_response into a string \r
+ ' then create HMAC hash code of this string and append this code \r
+ ' onto the string to form the value of our authentication cookie.\r
+ \r
+ authentication_cookie_value = ""\r
+ \r
+ For i = 0 To (AUTHENTICATION_RESPONSE_PARAMS - 1)\r
+ If (m_authentication_response(i) <> "") Then authentication_cookie_value = authentication_cookie_value & m_authentication_response(i)\r
+ authentication_cookie_value = authentication_cookie_value & "!"\r
+ Next\r
+\r
+ If (m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS) <> "") Then\r
+ authentication_cookie_value = authentication_cookie_value & m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS)\r
+ End If\r
+\r
+ hmac_signature = hmac_sha1(cookie_key, authentication_cookie_value)\r
+ authentication_cookie_value = authentication_cookie_value & "!" & hmac_signature\r
+ \r
+ write_log("ProcessAuthenticationResponse: Setting cookie=" & authentication_cookie_value)\r
+ \r
+ authentication_cookie = authentication_cookie_value\r
+\r
+ ' Now the authentication cookie's in place, we \r
+ ' can redirect user back to the page they started from.\r
+ ' As long as our authentication cookie doesn't expire, \r
+ ' we then only need to call 'ProcessAuthenticationCookie' \r
+ ' to check the cookie is valid - ie. we don't need to \r
+ ' keep returning to the WLS for every single \r
+ ' authentication request.\r
+ \r
+ write_log("ProcessAuthenticationResponse: Session cookie established, redirecting...")\r
+ \r
+ Redirect(wls_response(WLS_RESPONSE_URL))\r
+ \r
+ ProcessAuthenticationResponse = AUTHENTICATE_INCOMPLETE\r
+ \r
+ End Function\r
+ \r
+\r
+ Public Function ProcessAuthenticationCookie()\r
+\r
+ ' ****************************************\r
+ ' 3. ProcessAuthenticationCookie()\r
+ '\r
+ ' Check the signature of the cookie is valid and if so,\r
+ ' process/interpret the values of the authentication cookie. \r
+ '\r
+ ' ****************************************\r
+ \r
+ write_log("ProcessAuthenticationCookie: Starting...")\r
+\r
+ ' Do some quick checks to ensure the authentication \r
+ ' cookie looks like a valid response from WLS.\r
+\r
+ If (authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) Then\r
+ write_log("ProcessAuthenticationCookie: Processing authentication cookie when it's still set to REDIRECT_WLS.")\r
+ set_status "612", "Processing authentication cookie when its still set to REDIRECT_WLS"\r
+ ResetState()\r
+ ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function\r
+ End If\r
+\r
+ If (CheckValidAuthenticationCookie(authentication_cookie) = False) Then\r
+ write_log("ProcessAuthenticationCookie: Authentication cookie looks invalid.")\r
+ set_status "613", "Authentication cookie invalid"\r
+ ResetState()\r
+ ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function \r
+ End If\r
+\r
+ write_log("ProcessAuthenticationCookie: Interpreting authentication cookie=" & authentication_cookie)\r
+\r
+ ' Split up authentication cookie into _authentication_response array \r
+ ' of response parameters using '!' as the delimiter.\r
+\r
+ m_authentication_response = Split(url_decode(authentication_cookie), "!")\r
+\r
+ ' ****************************************\r
+ ' Check authentication cookie has been correctly signed\r
+ ' ****************************************\r
+\r
+ ' Get signature from last element of authentication response array.\r
+\r
+ signature = m_authentication_response(UBound(m_authentication_response))\r
+\r
+ ' Copy m_authentication_response into a separate array \r
+ ' then remove the last element of that array \r
+ ' and bundle together as a string. \r
+\r
+ Dim values_for_verify()\r
+ ReDim values_for_verify(UBound(m_authentication_response) - 1)\r
+ \r
+ For i = 0 To (UBound(values_for_verify))\r
+ values_for_verify(i) = m_authentication_response(i)\r
+ Next\r
+\r
+ values_for_verify_string = Join(values_for_verify, "!")\r
+\r
+ ' Check whether the hash of this shorter string matches the signature \r
+ ' we generated in the previous stage of the authentication process. \r
+ \r
+ If (False = hmac_sha1_verify(cookie_key, values_for_verify_string, signature)) Then\r
+ write_log("ProcessAuthenticationCookie: AUTHENTICATION FAILED, session cookie signature invalid")\r
+ set_status "614", "Session cookie signature invalid"\r
+ ResetState()\r
+ ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_ERROR\r
+ Exit Function \r
+ End If\r
+\r
+ write_log("ProcessAuthenticationCookie: Existing authentication cookie verified")\r
+\r
+ ' ****************************************\r
+ ' Check authentication cookie hasn't expired\r
+ ' ****************************************\r
+ \r
+ timestamp_issue = iso2time(m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE))\r
+ timestamp_expire = iso2time(m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE))\r
+ timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow()) ' Get current time as Unix timestamp\r
+\r
+ If ((timestamp_issue > timestamp_now) Or (timestamp_now >= timestamp_expire)) Then\r
+\r
+ ' Session has expired so send new authentication request to WLS.\r
+\r
+ write_log("ProcessAuthenticationCookie: Local session cookie expired. Issue/now/expire: " & Cstr(timestamp_issue) & "/" & CStr(timestamp_now) & "/" & CStr(timestamp_expire))\r
+\r
+ ' this.ResetState(); This won't work as we need to set the cookie during 'SendAuthenticationRequest'\r
+ \r
+ ProcessAuthenticationCookie = SendAuthenticationRequest(timeout_message)\r
+ Exit Function\r
+ \r
+ End If\r
+\r
+ ' ****************************************\r
+ ' Authentication process is COMPLETE \r
+ ' though the user may not have been \r
+ ' successfully authenticated. \r
+ ' ****************************************\r
+\r
+ If (m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) <> "200") Then\r
+ write_log("ProcessAuthenticationCookie: AUTHENTICATION COMPLETE but not successfully authenticated.")\r
+ write_log("****************************************************************")\r
+ ResetState()\r
+ ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_NOT_AUTHENTICATED\r
+ Exit Function\r
+ End If\r
+ \r
+ write_log("ProcessAuthenticationCookie: AUTHENTICATION COMPLETE and user authenticated.")\r
+ write_log("****************************************************************") \r
+ ProcessAuthenticationCookie = AUTHENTICATE_COMPLETE_AUTHENTICATED\r
+ \r
+ End Function\r
+ \r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' --- AUTHENTICATE()-SPECIFIC FUNCTIONS --\r
+ ' ----------------------------------------\r
+ '\r
+ ' **************************************** \r
+\r
+ Public Function CheckSetup()\r
+\r
+ ' ****************************************\r
+ ' CheckSetup()\r
+ '\r
+ ' Check the essential variables are in place.\r
+ '\r
+ ' ****************************************\r
+\r
+ request_method = Request.ServerVariables("REQUEST_METHOD")\r
+ \r
+ ' Check 'cookie_key' is defined, the key we will be using to create hash of cookie value.\r
+ \r
+ If (cookie_key = "") Then\r
+ set_status "601", "No key defined for session cookie"\r
+ CheckSetup = False\r
+ Exit Function \r
+ End If\r
+\r
+ ' Log a warning if being used to authenticate POST requests.\r
+ \r
+ If (request_method = "POST") Then\r
+ write_log("Ucam_Webauth agent invoked for POST request, which it doesn't really support")\r
+ End If\r
+ \r
+ ' Check that the hostname is set explicitly (since we cannot trust\r
+ ' the Host: header); if it returns false (i.e. not set).\r
+\r
+ If (hostname = "") Then\r
+ write_log("hostname not set in Ucam_Webauth object, but is mandatory")\r
+ set_status "602", "Ucam_Webauth configuration error - mandatory hostname not defined"\r
+ CheckSetup = False\r
+ Exit Function\r
+ End If\r
+ \r
+ ' If we have got this far without problems, then everything is good.\r
+\r
+ CheckSetup = True\r
+ \r
+ End Function\r
+ \r
+\r
+ Public Sub ResetState()\r
+\r
+ ' Reset state as if a new user has just loaded a \r
+ ' fresh browser window. Unfortunately we can't reset \r
+ ' any cookies that the remote WLS may have set.\r
+ ' This will not completely log you out of Raven as \r
+ ' the Raven WLS also stores a session cookie that \r
+ ' you cannot delete remotely. So accessing Raven \r
+ ' after logout may elicit a "You are already logged \r
+ ' in" from the Raven WLS. \r
+ '\r
+ ' As both local and WLS cookies are session cookies, the safest \r
+ ' thing to do is to quit the browser to remove both session cookies. \r
+ ' Note that some browsers with 'Restore session' functionality, \r
+ ' eg. Firefox, may not remove session cookies properly.\r
+ ' <returns>'true' whatever happens.</returns>\r
+ \r
+ ' By setting the expiry to '1', we ensure the \r
+ ' authentication cookie is removed straightaway.\r
+ \r
+ setcookie full_cookie_name(), "", 1, cookie_path, cookie_domain, using_https(), False\r
+\r
+ End Sub \r
+\r
+\r
+ Public Function GetCurrentState()\r
+\r
+ ' If no authentication cookie and no WLS-response, then we're \r
+ ' starting fresh so return 'STAGE_AUTHENTICATION_NEW'\r
+ \r
+ If ((authentication_cookie = "") And (authentication_response_string = "")) Then\r
+ GetCurrentState = STATE_NEW_AUTHENTICATION\r
+ Exit Function\r
+ End If\r
+ \r
+ ' If no cookie and a non-empty WLS-Response, then either (i) we have \r
+ ' returned from the WLS without the previous cookie that we set staying intact.\r
+ ' So there must have been a problem setting that earlier cookie.\r
+ ' Or (ii) a 'WLS-Response' GET variable was supplied to our initial\r
+ ' page to begin with, which is going to cause confusion. \r
+ ' This may be due to reloading the post-WLS page after an error.\r
+ \r
+ If ((authentication_cookie = "") And (authentication_response_string <> "")) Then\r
+ set_status "610", "Either browser is not accepting session cookie or you supplied WLS-Response variable to initial page."\r
+ \r
+ ' Don't do any redirecting back to the original \r
+ ' page as it might catch us in an infinite loop. \r
+ ' Instead show a page to the user with the \r
+ ' option to click on a particular link or \r
+ ' put something in code to go to a specific \r
+ ' safe page.\r
+ \r
+ GetCurrentState = STATE_ERROR\r
+ Exit Function\r
+ End If\r
+ \r
+ ' If authentication cookie = 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
+ ' and WLS-Response is non-empty, then we've been redirected here \r
+ ' by the WLS (though you could simulate this redirection manually by \r
+ ' interrupting the WLS process and manually pasting in a URL with a \r
+ ' WLS-Response GET variable.)\r
+ \r
+ If ((authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) And (authentication_response_string <> "")) Then \r
+ GetCurrentState = STATE_WLS_RESPONSE_RECEIVED\r
+ Exit Function\r
+ End If \r
+\r
+ \r
+ ' If authentication cookie = 'AUTHENTICATIONCOOKIE_REDIRECT_WLS'\r
+ ' and WLS-Response is empty, then the WLS is not working correctly.\r
+ ' So we trigger another authentication request.\r
+ ' Ideally we'd 'ResetState()' but this seems to create \r
+ ' confusion when we subsequently set the authentication \r
+ ' cookie to 'AUTHENTICATIONCOOKIE_REDIRECT_WLS' again - \r
+ ' so we leave it as is, with authentication cookie still \r
+ ' with this value.\r
+ \r
+ If ((authentication_cookie = AUTHENTICATIONCOOKIE_REDIRECT_WLS) And (authentication_response_string = "")) Then\r
+ GetCurrentState = STATE_NEW_AUTHENTICATION\r
+ Exit Function\r
+ End If\r
+ \r
+ \r
+ ' If authentication cookie != "" and != 'AUTHENTICATIONCOOKIE_REDIRECT_WLS' \r
+ ' then there's a possibility we have a legitimate authentication cookie.\r
+ ' Run 'CheckValidAuthenticationCookie' to check it looks in the \r
+ ' right format.\r
+ \r
+ If ((authentication_cookie <> "") And (authentication_cookie <> AUTHENTICATIONCOOKIE_REDIRECT_WLS)) Then\r
+\r
+ If (CheckValidAuthenticationCookie(authentication_cookie)) Then\r
+ GetCurrentState = STATE_WAA_AUTHENTICATIONCOOKIE_SET\r
+ Exit Function \r
+ End If \r
+ \r
+ set_status "604", "Authentication cookie invalid"\r
+ GetCurrentState = STATE_ERROR\r
+ Exit Function\r
+ End If\r
+ \r
+ ' If none of the conditions have been satisfied so far, \r
+ ' there must have been an error along the way. \r
+ \r
+ If (status() <> "200") Then set_status "605", "Miscellaneous error while getting current state."\r
+ \r
+ GetCurrentState = STATE_ERROR\r
+ \r
+ End Function\r
+ \r
+\r
+ Public Function CheckValidAuthenticationCookie(ByVal vAuthenticationCookie)\r
+\r
+ ' A quick check to ensure the cookie value looks the \r
+ ' right format to be an authentication cookie. \r
+ ' ie. it has the correct number of values, delimited by '!'.\r
+\r
+ If (vAuthenticationCookie = "") Then\r
+ CheckValidAuthenticationCookie = False\r
+ Exit Function\r
+ End If\r
+ \r
+ ' Split up authentication cookie into Array\r
+ ' using '!' as the delimiter.\r
+ \r
+ authentication_response = Split(url_decode(vAuthenticationCookie), "!")\r
+\r
+ If (UBound(authentication_response) <> (AUTHENTICATION_RESPONSE_SIZE - 1)) Then\r
+ CheckValidAuthenticationCookie = False\r
+ Exit Function\r
+ End If \r
+ \r
+ CheckValidAuthenticationCookie = True\r
+ \r
+ End Function\r
+ \r
+ \r
+ Public Sub Redirect(url)\r
+ \r
+ ' Redirect user's browser making \r
+ ' sure to set redirected flag accordingly\r
+ \r
+ Response.Redirect(url)\r
+ redirected = True\r
+ \r
+ End Sub\r
+\r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' ------- MISCELLANEOUS FUNCTIONS -------- \r
+ ' ----------------------------------------\r
+ '\r
+ ' ****************************************\r
+ \r
+ Public Sub write_log(ByVal message )\r
+\r
+ ' Write a message to the log file with a timestamp prefix on every line\r
+ ' \r
+ ' Note relative paths, eg. 'logfile.txt', will be relative \r
+ ' to the IIS server directories where permissions to create\r
+ ' new files may not be available. So provide an absolute\r
+ ' path in the initial arguments to Ucam_Webauth ("log_file" => Path) \r
+ \r
+ Set objFSO = CreateObject("Scripting.FileSystemObject")\r
+\r
+ If (objFSO.FileExists(log_file) = False) Then\r
+ Set objFile = objFSO.CreateTextFile(log_file)\r
+ Else\r
+ Set objFile = objFSO.OpenTextFile(log_file, 8)\r
+ End If\r
+\r
+ date_prefix = "[" & lpad(Year(Date()), 4) & "-" & lpad(Month(Date()),2) & "-" & lpad(Day(Date()),2) & " " & _\r
+ lpad(Hour(Time()), 2) & ":" & lpad(Minute(Time()),2) & ":" & lpad(Second(Time()),2) & "] " \r
+\r
+ objFile.WriteLine(date_prefix & message)\r
+ objFile.Close\r
+\r
+ End Sub\r
+\r
+ \r
+ Public Sub set_status(response_status, response_msg) \r
+\r
+ ' Quick function to set 'status' and 'msg' in a single line. \r
+ ' Makes the code look a little neater.\r
+ \r
+ m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) = response_status\r
+ m_authentication_response(AUTHENTICATION_RESPONSE_MSG) = response_msg\r
+ \r
+ End Sub\r
+ \r
+\r
+ Public Function using_https() \r
+\r
+ ' Determines whether we're using https or Not\r
+\r
+ using_https = False\r
+\r
+ If (Request.ServerVariables("HTTPS") <> "") Then\r
+ servertype = Request.ServerVariables("HTTPS")\r
+ If (servertype = "on") Then using_https = True\r
+ End If\r
+ \r
+ End Function\r
+ \r
+\r
+ Public Function url() \r
+\r
+ ' Get the url to redirect the browser to after a successful authentication attempt.\r
+ ' \r
+ ' This is typically identical to the url that first calls this script. \r
+ ' But due to the possibility of faking 'HOST' variables in a server response, \r
+ ' the 'hostname' must be supplied as a setup / default parameter in the code. \r
+ '\r
+ ' In versions 2 and 3, we must include the query component (GET parameters) of the \r
+ ' original calling url if they exist.\r
+ \r
+ \r
+ ' Strip out port number from hostname\r
+\r
+ Set rgx = New RegExp\r
+ rgx.Global = True\r
+ rgx.IgnoreCase = False\r
+ rgx.Pattern = ":[0-9]+$"\r
+\r
+ basichostname = rgx.Replace(hostname, "")\r
+ port = Request.ServerVariables("SERVER_PORT")\r
+ protocol = "http://"\r
+\r
+ If (using_https()) Then\r
+ protocol = "https://"\r
+ If (port = "443") Then port = ""\r
+ Else\r
+ If (port = "80") Then port = ""\r
+ End If\r
+\r
+ finalurl = protocol & basichostname\r
+ If (port <> "") Then finalurl = finalurl & ":" & port\r
+ \r
+ ' Remove any possible WLS-Response variables \r
+ ' from query part of URL to avoid \r
+ ' confusion and just in case we've \r
+ ' called 'SendAuthenticationRequest' \r
+ ' after WLS returned incorrect WLS-Response \r
+ ' 'GET' - which could lead to multiple \r
+ ' 'WLS-Response=&WLS-Response=...'\r
+ ' coming back from WLS server.\r
+ \r
+ url_query = Request.ServerVariables("REQUEST_URI")\r
+ rgx.Pattern = "&WLS-Response=[^&]*"\r
+ url_query = rgx.Replace(url_query, "")\r
+ rgx.Pattern = "\?WLS-Response=[^&]*"\r
+ url_query = rgx.Replace(url_query, "?")\r
+ rgx.Pattern = "\?&"\r
+ url_query = rgx.Replace(url_query, "?") \r
+ rgx.Pattern = "\?$"\r
+ url_query = rgx.Replace(url_query, "") \r
+ \r
+ url = finalurl & url_query\r
+ \r
+ End Function\r
+\r
+ \r
+ Public Function full_cookie_name() \r
+\r
+ ' Get name of cookie, typically 'Ucam-WebAuth-Session'\r
+ ' If 'https', then distinguish the name of the cookie by suffixing '-S'\r
+\r
+ full_cookie_name = cookie_name\r
+\r
+ If (using_https()) Then full_cookie_name = cookie_name & "-S"\r
+ \r
+ End Function\r
+ \r
+\r
+ Public Sub setcookie(ByVal name , ByVal value , ByVal expire , ByVal path , ByVal domain , ByVal secure , ByVal httponly )\r
+ \r
+ ' Sets cookie.\r
+ ' \r
+ ' name: Name of cookie.\r
+ ' value: Value of cookie.\r
+ ' expire: Expiry of cookie. Don't set it to make it a session cookie.\r
+ ' path: Path of cookie.\r
+ ' domain: Domain.\r
+ ' secure: Only allow on secure domains.\r
+ ' httponly: Only allow on http non-secure domains.\r
+ \r
+ If (expire <> 0) Then\r
+ If (expire = 1) Then\r
+ expire_datetime = DateAdd("s", 1, UTCNow())\r
+ Else\r
+ timestamp_now = DateDiff("s", "01/01/1970 00:00:00", UTCNow())\r
+ \r
+ If (expire < timestamp_now) Then\r
+ write_log("setcookie: Setting expire to past so don't bother setting cookie.")\r
+ Exit Sub\r
+ End If\r
+ \r
+ expire_datetime = DateAdd("s", expire, "01/01/1970 00:00:00")\r
+ End If \r
+ End If\r
+\r
+ Response.Cookies(name) = value\r
+\r
+ ' Whats correct value for Expires field when expire = 0?\r
+ \r
+ If (expire_datetime <> 0) Then\r
+ Response.Cookies(name).Expires = expire_datetime\r
+ End If\r
+\r
+ ' Problems setting 'httponly' in VBScript as \r
+ ' VBScript encodes everything to do with cookies. \r
+ ' So if 'httponly' is required, a different \r
+ ' way of setting cookies by directly setting \r
+ ' the header with 'Set-Cookie' will be necessary. \r
+ \r
+ ' If (httponly) Then \r
+ ' Response.Cookies(name).Path = path & "; HttpOnly"\r
+ ' Else \r
+ ' Response.Cookies(name).Path = path \r
+ ' End If\r
+\r
+ Response.Cookies(name).Path = path \r
+ \r
+ If (domain <> "") Then Response.Cookies(name).Domain = domain\r
+ \r
+ Response.Cookies(name).Secure = secure\r
+\r
+ ' Response.Cookies.Add(cookie)\r
+ End Sub\r
+\r
+\r
+ Public Function time2iso(t) \r
+\r
+ ' Convert a Unix timestamp into the format required by Raven. \r
+ ' Format based on RFC 3339, but see Raven documentation for \r
+ ' a full description.\r
+\r
+ unUDate = DateAdd("s", t, "01/01/1970 00:00:00")\r
+\r
+ time2iso = (lpad(Year(unUDate), 4) & lpad(Month(unUDate),2) & lpad(Day(unUDate),2) & "T" &_\r
+ lpad(Hour(unUDate), 2) & lpad(Minute(unUDate),2) & lpad(Second(unUDate),2) & "Z") \r
+ \r
+ End Function\r
+\r
+\r
+ Public Function iso2time(t) \r
+\r
+ ' Convert a time in Raven format into a Unix timestamp \r
+ ' ie. the number of seconds since epoch.\r
+\r
+ iso2time = 0\r
+ \r
+ if (Len(t) <> 16) Then Exit Function \r
+ \r
+ On Error Resume Next\r
+ \r
+ sYear = Mid(t,1,4)\r
+ sMonth = Mid(t, 5, 2)\r
+ sDay = Mid(t, 7, 2)\r
+ sHour = Mid(t, 10, 2)\r
+ sMinute = Mid(t, 12, 2)\r
+ sSecond = Mid(t, 14, 2)\r
+ \r
+ var_origin = CDate("01/01/1970 00:00:00")\r
+ var_date = CDate(sDay & "/" & sMonth & "/" & sYear & " " & sHour & ":" & sMinute & ":" & sSecond)\r
+ \r
+ iso2time = DateDiff("s", var_origin, var_date) \r
+ \r
+ On Error GoTo 0\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function load_key(ByVal key_id ) \r
+\r
+ ' Returns content of a certificate key as a string\r
+\r
+ key_filename = key_dir & "/" & key_id & ".crt"\r
+\r
+ Set fso = CreateObject("Scripting.FileSystemObject")\r
+ Set file = fso.getFile(key_filename)\r
+ If isNull(file) Then\r
+ Exit Function\r
+ End If\r
+ \r
+ Set ts = file.OpenAsTextStream()\r
+ s = Space(file.size)\r
+ a = Split(s," ")\r
+\r
+ i = 0\r
+ ' Do not replace the following block by readBinary = by ts.readAll(), \r
+ ' it would result in broken output, because that method is not intended for binary data \r
+ While Not ts.atEndOfStream\r
+ a(i) = ts.read(1)\r
+ i = i + 1\r
+ Wend\r
+ ts.close\r
+\r
+ load_key = Join(a,"")\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function check_signature(ByVal data , ByVal sig , ByVal key_id ) \r
+\r
+ ' Checks the 'signature' provided by the WLS when it signed 'data' \r
+ ' is a valid signature for the data. This ensures the data has not been \r
+ ' tampered with.\r
+\r
+ key_str = load_key(key_id)\r
+\r
+ ' We make a call to a some Javascript libraries to do the verification\r
+ \r
+ check_signature = JavascriptCertVerify(data, wls_decode(sig), key_str)\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function wls_encode(plainTextBytes) \r
+\r
+ ' Encode a byte array of data in a way that can be \r
+ ' easily sent to the WLS\r
+\r
+ Set rgx = New RegExp\r
+ rgx.Global = True\r
+ rgx.IgnoreCase = False\r
+ rgx.Pattern = "\+": plainTextBytes = rgx.Replace(plainTextBytes, "_")\r
+ rgx.Pattern = "/": plainTextBytes = rgx.Replace(plainTextBytes, ".")\r
+ rgx.Pattern = "=": plainTextBytes = rgx.Replace(plainTextBytes, "_")\r
+\r
+ wls_encode = plainTextBytes\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function wls_decode(ByVal sig )\r
+\r
+ ' Decode a string of data received from the WLS \r
+ ' into a string with data as hex doubledigits (as used by javascript security library)\r
+ \r
+ Set rgx = New RegExp\r
+ rgx.Global = True\r
+ rgx.IgnoreCase = False\r
+ rgx.Pattern = "-": sig = rgx.Replace(sig, "+")\r
+ rgx.Pattern = "\.": sig = rgx.Replace(sig, "/")\r
+ rgx.Pattern = "_": sig = rgx.Replace(sig, "=")\r
+ \r
+ sig_base64 = base64_decode(sig)\r
+ \r
+ sig_hex = ""\r
+ For i = 1 To LenB(sig_base64)\r
+ sig_hex = sig_hex & Right(String(2, "0") & LCase(Hex(AscB(MidB(sig_base64, i, 1)))), 2)\r
+ Next\r
+\r
+ wls_decode = sig_hex\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function hmac_sha1(ByVal key , ByVal data ) \r
+\r
+ ' Create HMACSHA1 hash value for 'data' using public 'key'.\r
+ '\r
+ ' key: raw content of a certificate file as string.\r
+ ' data: data to create hash value from as string.\r
+ \r
+ hmac_sha1 = wls_encode(b64_hmac_sha1(key, data))\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function hmac_sha1_verify(ByVal key , ByVal data , ByVal sig ) \r
+\r
+ ' Verify the 'data' has been signed by public 'key'\r
+ ' \r
+ ' Compute HMACSHA1 hash value for 'data' using public 'key'\r
+ ' then compare the value to 'sig'(nature).\r
+ ' \r
+ ' key: Full text for public key.\r
+ ' data: Data to be verified.\r
+ ' signature: Signature of signed data (ie. hash value generated by us earlier).\r
+ \r
+ hmac_sha1_verify = (sig = hmac_sha1(key, data))\r
+ \r
+ End Function\r
+\r
+\r
+ ' ****************************************\r
+ ' \r
+ ' ----------------------------------------\r
+ ' ------- MISCELLANEOUS FUNCTIONS -------- \r
+ ' ------- SPECIFIC TO ASP VERSION --------\r
+ ' ----------------------------------------\r
+ '\r
+ ' ****************************************\r
+\r
+ Function lpad(strInput, length)\r
+\r
+ ' Left pad string with zeros.\r
+ \r
+ lpad = Right(String(length, "0") & strInput, length)\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function url_decode(ByVal url_encoded)\r
+\r
+ ' Decodes URL-encoded string \r
+\r
+ url_decode = ""\r
+ \r
+ If (url_encoded = "") Then Exit Function\r
+\r
+ Dim aSplit\r
+ Dim sOutput\r
+ Dim I\r
+ If IsNull(url_encoded) Then\r
+ Exit Function\r
+ End If\r
+ \r
+ ' convert all pluses to spaces\r
+ sOutput = REPLACE(url_encoded, "+", " ")\r
+ \r
+ ' next convert %hexdigits to the character\r
+ aSplit = Split(sOutput, "%")\r
+ \r
+ If IsArray(aSplit) Then\r
+ sOutput = aSplit(0)\r
+ For I = 0 to UBound(aSplit) - 1\r
+ sOutput = sOutput & _\r
+ Chr("&H" & Left(aSplit(i + 1), 2)) &_\r
+ Right(aSplit(i + 1), Len(aSplit(i + 1)) - 2)\r
+ Next\r
+ End If\r
+ \r
+ url_decode = sOutput\r
+ \r
+ End Function\r
+\r
+ \r
+ Public Function UTCNow()\r
+\r
+ ' Gets the UTC current time\r
+ ' The UTC time is the standard time the Raven server is operating with.\r
+ \r
+ Set dateTime = CreateObject("WbemScripting.SWbemDateTime") \r
+ dateTime.SetVarDate (now())\r
+ UTCNow = dateTime.GetVarDate (false)\r
+ \r
+ End Function\r
+\r
+\r
+ Public Function base64_decode(strB64)\r
+\r
+ ' Base64 decodes a string\r
+ \r
+ strXML = "<B64DECODE xmlns:dt=" & Chr(34) & _\r
+ "urn:schemas-microsoft-com:datatypes" & Chr(34) & " " & _\r
+ "dt:dt=" & Chr(34) & "bin.base64" & Chr(34) & ">" & _\r
+ strB64 & "</B64DECODE>"\r
+ Set oXMLDoc = CreateObject("MSXML2.DOMDocument.3.0")\r
+ oXMLDoc.LoadXML(strXML)\r
+ \r
+ base64_decode = oXMLDoc.selectsinglenode("B64DECODE").nodeTypedValue\r
+ \r
+ set oXMLDoc = Nothing\r
+ \r
+ End Function\r
+ \r
+\r
+ ' ****************************************\r
+ ' \r
+ ' Special get/set methods to enable \r
+ ' seamless access to cookies or query \r
+ ' variables as if they were ordinary \r
+ ' member variables.\r
+ '\r
+ ' ****************************************\r
+\r
+ ' Get/set authentication_cookie\r
+ ' 'authentication_cookie' is used to get and set \r
+ ' the value of the authentication cookie.\r
+\r
+ Public Property Get authentication_cookie\r
+\r
+ ' If the current value of the private variable \r
+ ' m_authentication_cookie is null then we check \r
+ ' to see what the value of the actual cookie is \r
+ ' and use that to set the variable accordingly.\r
+\r
+ If (m_authentication_cookie = "") Then\r
+ On Error Resume Next\r
+ m_authentication_cookie = Request.Cookies(full_cookie_name())\r
+ On Error GoTo 0\r
+ End If\r
+\r
+ authentication_cookie = m_authentication_cookie\r
+\r
+ End Property \r
+ \r
+ Public Property Let authentication_cookie(v_authentication_cookie)\r
+\r
+ ' Reset the private variable _authentication_cookie \r
+ ' so the system is forced to query the cookie directly\r
+ ' next time it wants to check the value through \r
+ ' authentication_cookie.\r
+\r
+ m_authentication_cookie = ""\r
+ \r
+ setcookie full_cookie_name(), v_authentication_cookie, 0, cookie_path, cookie_domain, using_https(), False\r
+ \r
+ End Property\r
+\r
+\r
+ Public Property Get authentication_response_string()\r
+\r
+ ' Get authentication_response_string\r
+ ' \r
+ ' Checks to see if there is a 'WLS-Response' \r
+ ' variable set and uses this as the value \r
+ ' for authentication_response_string\r
+\r
+ ' If the value is already set, we just return it straightaway\r
+ \r
+ If (m_authentication_response_string <> "") Then\r
+ authentication_response_string = m_authentication_response_string\r
+ Exit Property\r
+ End If\r
+ \r
+ ' If the value is not set, we look for the value of 'WLS-Response' in 'QUERY_STRING'\r
+ \r
+ query_string = Request.ServerVariables("QUERY_STRING")\r
+ \r
+ If (query_string = "") Then\r
+ authentication_response_string = m_authentication_response_string\r
+ Exit Property\r
+ End If\r
+ \r
+\r
+ ' We're processing urls with possible name-value pairs\r
+ ' in addition to WLS-Response=... so we need to extract all \r
+ ' name-value pairs and check specifically for WLS-Response. \r
+ \r
+ namevaluepairs = Split(query_string, "&")\r
+ \r
+ For Each namevalue In namevaluepairs\r
+ \r
+ pair = Split(namevalue, "=")\r
+ \r
+ If (UBound(pair) = 1) Then \r
+ If (pair(0) = "WLS-Response") Then \r
+ authentication_response_string = url_decode(pair(1))\r
+ Exit Property \r
+ End If\r
+ End If\r
+ Next\r
+\r
+ authentication_response_string = "" \r
+ \r
+ End Property\r
+ \r
+\r
+ ' ****************************************\r
+ ' \r
+ ' Get/set methods to enable public access \r
+ ' to private variables.\r
+ '\r
+ ' ****************************************\r
+\r
+ ' Get/set auth_service\r
+\r
+ Public Property Get auth_service\r
+ auth_service = m_auth_service\r
+ End Property \r
+ Public Property Let auth_service(v_auth_service)\r
+ m_auth_service = v_auth_service\r
+ End Property\r
+\r
+ ' Get/set authrequest_desc\r
+\r
+ Public Property Get authrequest_desc\r
+ authrequest_desc = m_description\r
+ End Property \r
+ Public Property Let authrequest_desc(v_authrequest_desc)\r
+ m_authrequest_desc = v_authrequest_desc\r
+ End Property\r
+\r
+ ' Get/set authrequest_skew\r
+\r
+ Public Property Get authrequest_skew\r
+ authrequest_skew = m_authrequest_skew\r
+ End Property \r
+ Public Property Let authrequest_skew(v_authrequest_skew)\r
+ m_authrequest_skew = v_authrequest_skew\r
+ End Property\r
+\r
+ ' Get/set authrequest_fail\r
+\r
+ Public Property Get authrequest_fail\r
+ authrequest_fail = m_authrequest_fail\r
+ End Property \r
+ Public Property Let authrequest_fail(v_authrequest_fail)\r
+ m_authrequest_fail = v_authrequest_fail\r
+ End Property\r
+\r
+ ' Get/set authrequest_iact\r
+\r
+ Public Property Get authrequest_iact\r
+ authrequest_iact = m_authrequest_iact\r
+ End Property \r
+ Public Property Let authrequest_iact(v_authrequest_iact)\r
+ m_authrequest_iact = v_authrequest_iact\r
+ End Property\r
+\r
+ ' Get/set use_authrequest_iact\r
+\r
+ Public Property Get use_authrequest_iact\r
+ use_authrequest_iact = m_use_authrequest_iact\r
+ End Property \r
+ Public Property Let use_authrequest_iact(v_use_authrequest_iact)\r
+ m_use_authrequest_iact = v_use_authrequest_iact\r
+ End Property\r
+\r
+ ' Get/set authrequest_aauth\r
+\r
+ Public Property Get authrequest_aauth\r
+ authrequest_aauth = m_authrequest_aauth\r
+ End Property \r
+ Public Property Let authrequest_aauth(v_authrequest_aauth)\r
+ m_authrequest_aauth = v_authrequest_aauth\r
+ End Property\r
+\r
+ ' Get/set authrequest_params\r
+\r
+ Public Property Get authrequest_params\r
+ authrequest_params = m_authrequest_params\r
+ End Property \r
+ Public Property Let authrequest_params(v_authrequest_params)\r
+ m_authrequest_params = v_authrequest_params\r
+ End Property\r
+ ' Get/set cookie_key\r
+\r
+ Public Property Get cookie_key\r
+ cookie_key = m_cookie_key\r
+ End Property \r
+ Public Property Let cookie_key(v_cookie_key)\r
+ m_cookie_key = v_cookie_key\r
+ End Property\r
+\r
+ ' Get/set redirected\r
+ ' \r
+ ' 'redirected' is a flag that says \r
+ ' whether a redirect has been sent \r
+ ' which is useful to check before \r
+ ' attempting to output any information \r
+ ' to the browser.\r
+\r
+ Public Property Get redirected\r
+ redirected = m_redirected\r
+ End Property \r
+ Public Property Let redirected(v_redirected)\r
+ m_redirected = v_redirected\r
+ End Property\r
+\r
+ ' Get/set cookie_path\r
+\r
+ Public Property Get cookie_path\r
+ cookie_path = m_cookie_path\r
+ End Property \r
+ Public Property Let cookie_path(v_cookie_path)\r
+ m_cookie_path = v_cookie_path\r
+ End Property\r
+ \r
+ ' Get/set response_timeout\r
+\r
+ Public Property Get response_timeout\r
+ response_timeout = m_response_timeout\r
+ End Property \r
+ Public Property Let response_timeout(v_response_timeout)\r
+ m_response_timeout = v_response_timeout\r
+ End Property\r
+\r
+ ' Get/set hostname\r
+\r
+ Public Property Get hostname\r
+ hostname = m_hostname\r
+ End Property \r
+ Public Property Let hostname(v_hostname)\r
+ m_hostname = v_hostname\r
+ End Property\r
+\r
+ ' Get/set key_dir\r
+\r
+ Public Property Get key_dir\r
+ key_dir = m_key_dir\r
+ End Property\r
+ Public Property Let key_dir(v_key_dir)\r
+ m_key_dir = v_key_dir\r
+ End Property\r
+\r
+ ' Get/set max_session_life\r
+\r
+ Public Property Get max_session_life\r
+ max_session_life = m_max_session_life\r
+ End Property \r
+ Public Property Let max_session_life(v_max_session_life)\r
+ m_max_session_life = v_max_session_life\r
+ End Property\r
+\r
+ ' Get/set timeout_message\r
+\r
+ Public Property Get timeout_message\r
+ timeout_message = m_timeout_message\r
+ End Property \r
+ Public Property Let timeout_message(v_timeout_message)\r
+ m_timeout_message = v_timeout_message\r
+ End Property\r
+\r
+ ' Get/set cookie_name\r
+\r
+ Public Property Get cookie_name\r
+ cookie_name = m_cookie_name\r
+ End Property \r
+ Public Property Let cookie_name(v_cookie_name)\r
+ m_cookie_name = v_cookie_name\r
+ End Property\r
+\r
+ ' Get/set cookie_domain\r
+\r
+ Public Property Get cookie_domain\r
+ cookie_domain = m_cookie_domain\r
+ End Property \r
+ Public Property Let cookie_domain(v_cookie_domain)\r
+ m_cookie_domain = v_cookie_domain\r
+ End Property\r
+\r
+ ' Get/set log_file\r
+\r
+ Public Property Get log_file\r
+ log_file = m_log_file\r
+ End Property \r
+ Public Property Let log_file(v_log_file)\r
+ m_log_file = v_log_file\r
+ End Property\r
+ \r
+ ' ****************************************\r
+ ' \r
+ ' Read-only methods to retrieve \r
+ ' authentication response values.\r
+ '\r
+ ' See Raven documentation for a full \r
+ ' explanation of each parameter.\r
+ '\r
+ ' ****************************************\r
+ \r
+ Public Function status() \r
+\r
+ ' Read-only status\r
+\r
+ status = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_STATUS) Then\r
+ status = m_authentication_response(AUTHENTICATION_RESPONSE_STATUS)\r
+ End If\r
+\r
+ End Function\r
+\r
+ Public Function success() \r
+\r
+ ' Read-only success\r
+\r
+ success = False\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_STATUS) Then\r
+ success = (m_authentication_response(AUTHENTICATION_RESPONSE_STATUS) = "200")\r
+ End If\r
+ \r
+ End Function\r
+\r
+ Public Function msg() \r
+\r
+ ' Read-only msg\r
+\r
+ msg = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_MSG) Then\r
+ msg = m_authentication_response(AUTHENTICATION_RESPONSE_MSG)\r
+ End If\r
+ \r
+ End Function\r
+ \r
+ Public Function issue() \r
+\r
+ ' Read-only issue\r
+\r
+ issue = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_ISSUE) Then\r
+ issue = m_authentication_response(AUTHENTICATION_RESPONSE_ISSUE)\r
+ End If\r
+\r
+ End Function\r
+\r
+ Public Function expire() \r
+\r
+ ' Read-only expire\r
+\r
+ expire = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_EXPIRE) Then\r
+ expire = m_authentication_response(AUTHENTICATION_RESPONSE_EXPIRE)\r
+ End If\r
+ \r
+ End Function\r
+\r
+ Public Function id() \r
+\r
+ ' Read-only id\r
+\r
+ id = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_ID) Then\r
+ id = m_authentication_response(AUTHENTICATION_RESPONSE_ID)\r
+ End If\r
+ \r
+ End Function\r
+\r
+ Public Function principal() \r
+\r
+ ' Read-only principal\r
+ ' ie. the user id of the authenticated user\r
+\r
+ principal = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PRINCIPAL) Then\r
+ principal = m_authentication_response(AUTHENTICATION_RESPONSE_PRINCIPAL)\r
+ End If\r
+\r
+ End Function\r
+\r
+ Public Function auth() \r
+ \r
+ ' Read-only auth\r
+\r
+ auth = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_AUTH) Then\r
+ auth = m_authentication_response(AUTHENTICATION_RESPONSE_AUTH)\r
+ End If\r
+\r
+ End Function\r
+ \r
+ Public Function sso() \r
+\r
+ ' Read-only sso\r
+\r
+ sso = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_SSO) Then\r
+ sso = m_authentication_response(AUTHENTICATION_RESPONSE_SSO)\r
+ End If\r
+\r
+ End Function\r
+ \r
+ Public Function webauth_params() \r
+\r
+ ' Read-only params\r
+\r
+ webauth_params = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PARAMS) Then\r
+ webauth_params = m_authentication_response(AUTHENTICATION_RESPONSE_PARAMS)\r
+ End If\r
+\r
+ End Function\r
+ \r
+ Public Function ptags() \r
+\r
+ ' Read-only ptags\r
+ ' ie. whether user is 'current' staff/student \r
+ ' or another type of user.\r
+\r
+ ptags = ""\r
+\r
+ If (UBound(m_authentication_response) >= AUTHENTICATION_RESPONSE_PTAGS) Then\r
+ ptags = m_authentication_response(AUTHENTICATION_RESPONSE_PTAGS)\r
+ End If\r
+\r
+ End Function \r
+ \r
+End Class\r
+\r
+%>\r
+\r
+<script runat="server" language="JavaScript" src="js/core.js"></script>\r
+<script runat="server" language="JavaScript" src="js/md5.js"></script>\r
+<script runat="server" language="JavaScript" src="js/sha1.js"></script>\r
+<script runat="server" language="JavaScript" src="js/sha256.js"></script>\r
+<script runat="server" language="JavaScript" src="js/ripemd160.js"></script>\r
+<script runat="server" language="JavaScript" src="js/x64-core.js"></script>\r
+<script runat="server" language="JavaScript" src="js/sha512.js"></script>\r
+<script runat="server" language="JavaScript" src="js/jsbn.js"></script>\r
+<script runat="server" language="JavaScript" src="js/jsbn2.js"></script>\r
+<script runat="server" language="JavaScript" src="js/rsa.js"></script>\r
+<script runat="server" language="JavaScript" src="js/rsa2.js"></script>\r
+<script runat="server" language="JavaScript" src="js/crypto-1.1.js"></script>\r
+<script runat="server" language="JavaScript" src="js/x509-1.1.js"></script>\r
+<script runat="server" language="JavaScript" src="js/base64.js"></script>\r
+<script runat="server" language="JavaScript" src="js/asn1hex-1.1.js"></script>\r
+<script runat="server" language="JavaScript" src="js/rsapem-1.1.js"></script>\r
+<script runat="server" language="JavaScript" src="js/rsasign-1.2.js"></script>\r
+<script runat="server" language="JavaScript" src="js/hex_sha1_js.js"></script>\r
+<script runat="server" language="JavaScript" >\r
+\r
+// Javascript cryptographic libraries above adapted for ASP use from \r
+// client libraries at http://kjur.github.io/jsrsasign/index.html \r
+// These libraries are used in 'JavascriptCertVerify' (Javascript) \r
+// and 'hmac_sha1' functions. \r
+ \r
+function JavascriptCertVerify(sMsg, sSignature, sCertificateValue) \r
+{\r
+ // Javascript function to verify message has \r
+ // been signed with particular certificate.\r
+ \r
+ var bytes = [];\r
+ var x509 = new X509();\r
+\r
+ x509.readCertPEM(sCertificateValue);\r
+\r
+ return x509.subjectPublicKeyRSA.verifyString(sMsg, sSignature);\r
+}\r
+\r
+</script>\r