554 lines
30 KiB
Plaintext
554 lines
30 KiB
Plaintext
Function HTTP_Authentication_Services(@Service, @Params)
|
|
/***********************************************************************************************************************
|
|
|
|
This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
|
|
permission from SRP Computer Solutions, Inc.
|
|
|
|
Name : HTTP_Authentication_Services
|
|
|
|
Description : Handler program for all HTTP authentication.
|
|
|
|
Notes : Authentication techniques will vary depending upon the application so the code in the
|
|
AuthenticateRequest service will need to be customized as necessary.
|
|
|
|
Parameters :
|
|
Service [in] -- Name of the service being requested
|
|
Param1-10 [in/out] -- Additional request parameter holders
|
|
Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure
|
|
|
|
History : (Date, Initials, Notes)
|
|
02/25/15 dmb [SRPFW-91] Original programmer.
|
|
06/10/15 dmb [SRPFW-91] Add checks to make sure Username and Password are populated before attempting to
|
|
authenticate against the USERS table. This prevents easy authentication if the USERS table
|
|
isn't being managed well.
|
|
02/25/16 dmb [SRPFW-108] Add support for the GetEnableAuthenticateFlag service. If disabled, then automatically
|
|
authenticate the user.
|
|
02/25/16 dmb [SRPFW-108] Add support for the GetRealmValue service. Use this instead of hard-coding the
|
|
realm.
|
|
12/01/16 dmb Update the AuthenticateRequest service to verify authentication requirements of the current
|
|
URL using the URLRequiresAuthentication service.
|
|
07/01/17 dmb [SRPFW-184] Refactor using Enhanced BASIC+ syntax.
|
|
10/22/18 dmb [SRPFW-253] Add support for checking for whitelisted IPs in the AuthenticateRequest service.
|
|
10/31/18 dmb [SRPFW-254] Add GetWebAccountPassword, SetWebAccountPassword, and ValidateWebAccountPassword
|
|
services.
|
|
10/31/18 dmb [SRPFW-254] Update the AuthenticateRequest service to use the ValidateWebAccountPassword
|
|
service rather than relying upon a hardcoded USERS table.
|
|
11/01/18 dmb [SRPFW-256] Update NewPasswordTimeToLive$ equate to use the GetNewPasswordTimeToLive service
|
|
rather than the hardcoded value.
|
|
11/01/18 dmb [SRPFW-256] Update OldPasswordTimeToLive$ equate to use the GetOldPasswordTimeToLive service
|
|
rather than the hardcoded value.
|
|
11/09/18 dmb [SRPFW-256] Update ValidateWebAccountPassword service to implement the containment action if
|
|
too many failed password attempts have been attempted.
|
|
11/20/18 dmb [SRPFW-256] Add GetWebAccountEnabledStatus service. Update the AuthenticateRequest service
|
|
to use it before attempting to validate the password.
|
|
11/21/18 dmb [SRPFW-257] Add ResetWebAccountPassword service.
|
|
11/21/18 dmb [SRPFW-257] Update SetWebAccountPassword service to support a flag that ignores expiration
|
|
date.
|
|
11/23/18 dmb [SRPFW-257] Add SetAuthenticatedAccountID and GetAuthenticatedAccountID services.
|
|
12/12/18 dmb [SRPFW-257] Add SetAuthenticatedPassword and GetAuthenticatedPassword services.
|
|
06/24/19 dmb [SRPFW-276] Update the ValidateWebAccountPassword service to reset the invalid password
|
|
attempt counter for an account if a valid password is passed in.
|
|
12/09/19 dmb [SRPFW-296] Update all calls to Memory_Services to use a specific cache name.
|
|
06/30/20 dmb [SRPFW-313] Update the AuthenticateRequest service to return a 403 status code rather than
|
|
a 511 status code if the IP making the request is not permitted.
|
|
07/27/20 dmb [SRPFW-313] Replace references to the IPIsPermitted service with the IsIPPermitted service.
|
|
|
|
***********************************************************************************************************************/
|
|
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
$insert APP_INSERTS
|
|
$insert SERVICE_SETUP
|
|
$insert HTTP_INSERTS
|
|
|
|
Equ SecondsPerHour$ to 60 * 60 ; // 60 minutes * 60 seconds = 3600
|
|
Equ SecondsPerDay$ to 24 * SecondsPerHour$ ; // 24 hours * 60 minutes * 60 seconds = 86400
|
|
Equ NewPasswordTimeToLive$ to HTTP_Services('GetNewPasswordTimeToLive') * SecondsPerHour$ ; // Convert hours to seconds
|
|
Equ OldPasswordTimeToLive$ to HTTP_Services('GetOldPasswordTimeToLive') * SecondsPerHour$ ; // Convert hours to seconds
|
|
Equ CacheName$ to 'SRPHTTPFramework'
|
|
|
|
Declare function Database_Services, RTI_CreateGUID
|
|
Declare subroutine Database_Services
|
|
|
|
GoToService else
|
|
Error_Services('Add', Service : ' is not a valid service request within the HTTP Authentication services module.')
|
|
end
|
|
|
|
Return Response OR ''
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Service Parameter Options
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Options BOOLEAN = True$, False$
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Services
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// AuthenticateRequest
|
|
//
|
|
// Returns a boolean value indicating the success of the authentication attempt. Default method is built around
|
|
// HTTP Basic Authentication.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service AuthenticateRequest()
|
|
|
|
// All response headers that need to be set, regardless of authentication, should be handled here.
|
|
// 1. Access-Control-Allow-Origin must always be returned for CORS purposes.
|
|
HTTP_Services('SetResponseHeaderField', 'Access-Control-Allow-Origin', '*')
|
|
|
|
EnableAuthentication = HTTP_Services('GetEnableAuthenticationFlag')
|
|
FullEndPointURL = HTTP_Services('GetFullEndPointURL')
|
|
URLRequiresAuthentication = HTTP_Services('URLRequiresAuthentication', FullEndPointURL)
|
|
|
|
// Set the default status code and phrase if authentication fails.
|
|
StatusCode = 401
|
|
StatusPhrase = ''
|
|
|
|
If EnableAuthentication AND URLRequiresAuthentication then
|
|
HTTPMethod = HTTP_Services('GetHTTPRequestMethod')
|
|
HTTPRemoteAddr = HTTP_Services('GetHTTPRemoteAddr')
|
|
|
|
// Verify that the client IP is permitted. If there are no whitelisted IPs, then all IPs are permitted.
|
|
IsIPPermitted = HTTP_Services('IsIPPermitted', HTTPRemoteAddr)
|
|
If IsIPPermitted EQ True$ then
|
|
If HTTPMethod _EQC 'OPTIONS' then
|
|
// OPTIONS methods are never authenticated. Allow the user to be provisionally authenticated since the method
|
|
// will remains as OPTIONS throughout the entire API.
|
|
UserAuthenticated = True$
|
|
end else
|
|
// Assume the user is not authenticated until otherwise proven.
|
|
UserAuthenticated = False$
|
|
|
|
// The follow code provides a skeleton for support HTTP Basic authorization. This is a REST friendly
|
|
// authentication protocol and is documented in the core HTTP specification. Because REST does not preserve the
|
|
// state, all requests are authenticated regardless of previous authentication successes. HTTP Basic should
|
|
// only be used if https:// is being used. Otherwise, the credentials are being passed through as plain text.
|
|
|
|
|
|
// HTTP Basic uses the Authorization request header. However, the Authorization request header field does not
|
|
// always work with web server products when being passed to a third-party service. So, if the standard header
|
|
// returns nothing then check the custom X-Authorization request header.
|
|
AuthorizationB64 = HTTP_Services('GetRequestHeaderField', 'Authorization')
|
|
If AuthorizationB64 EQ '' then AuthorizationB64 = HTTP_Services('GetRequestHeaderField', 'X-Authorization')
|
|
|
|
If AuthorizationB64 NE '' then
|
|
// All HTTP Basic credentials should be Base64 encoded (in addition to encrypted via https://). Decode
|
|
// the credentials.
|
|
Authorization = SRP_Decode(AuthorizationB64[7, 999], 'BASE64')
|
|
|
|
// HTTP Basic credentials are always colon (:) delimited. Typically this will come through as
|
|
// Username:Password, but there could be other formats if the application requires it. For instance, for
|
|
// applications supporting multiple customers wherein each customer has their own group of users, the
|
|
// format could look like this CustomerID/Username:Password. This provides, in a sense, a three-part
|
|
// identifier. The following parsing logic would need to be adjusted as needed.
|
|
Username = Authorization[1, ':']
|
|
Password = Authorization[Col2() + 1, 999]
|
|
EnabledStatus = HTTP_Authentication_Services('GetWebAccountEnabledStatus', Username)
|
|
If EnabledStatus EQ True$ then
|
|
// Only authenticate if a username and password is provided. This prevents authenticating in the event
|
|
// the USERS row is missing a password or the USERS table has a blank row.
|
|
If (Username NE '') AND (Password NE '') then
|
|
// Below is where you would place your logic to validate the username, password, and any other credentials
|
|
// that were passed in. This code uses the default HTTP Framework WEB_ACCOUNTS table.
|
|
|
|
UserAuthenticated = HTTP_Authentication_Services('ValidateWebAccountPassword', Username, Password, False$)
|
|
|
|
// A successful login should set the WWW-Authenticate response header field with the appropriate value. The
|
|
// credentials are stored in memory so they can be retrieved by other services as needed.
|
|
If UserAuthenticated then
|
|
UserAuthenticated = True$
|
|
HTTP_Authentication_Services('SetAuthenticatedAccountID', Username)
|
|
HTTP_Authentication_Services('SetAuthenticatedPassword', Password)
|
|
// The realm attribute is a part of the HTTP authentication specification and is used to help identify all
|
|
// resources that belong to the same authentication. Typically this will be the same value for all requests
|
|
// within the same application. The branded name or OpenInsight name of the application would be a good
|
|
// example to use here.
|
|
Realm = HTTP_Services('GetRealmValue')
|
|
HTTP_Services('SetResponseHeaderField', 'WWW-Authenticate', 'xBasic realm="' : Realm : '"')
|
|
end
|
|
end
|
|
end else
|
|
// IP address making the request is not permitted. Do not authenticate the user.
|
|
StatusCode = 403
|
|
StatusPhrase = 'Account ' : Username : ' is disabled.'
|
|
UserAuthenticated = False$
|
|
end
|
|
end
|
|
end
|
|
end else
|
|
// IP address making the request is not permitted. Do not authenticate the user.
|
|
StatusCode = 403
|
|
StatusPhrase = HTTPRemoteAddr : ' is not a permitted IP address.'
|
|
UserAuthenticated = False$
|
|
end
|
|
end else
|
|
// Force the user to be authenticated since authentication is not enabled.
|
|
UserAuthenticated = True$
|
|
end
|
|
|
|
// Non-authenticated requests should have a 401 status code returned.
|
|
If Not(UserAuthenticated) then
|
|
HTTP_Services('SetResponseError', '', '', StatusCode, StatusPhrase, FullEndpointURL)
|
|
end
|
|
|
|
Response = UserAuthenticated
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// CleanUp
|
|
//
|
|
// Runs any clean up processes as needed to prepare the engine for the next request.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service CleanUp()
|
|
|
|
// This service is called from HTTP_MCP before sending the response back to the caller. Any application specific
|
|
// logic that stores data in memory or attaches customer specific database tables should be properly closed out
|
|
// to avoid subsequent requests from having innappropriate access.
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetWebAccountEnabledStatus
|
|
//
|
|
// Gets the enabled status for the indicated web account.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetWebAccountEnabledStatus(AccountID)
|
|
|
|
EnabledStatus = ''
|
|
|
|
If AccountID NE '' then
|
|
WebAccountRow = Database_Services('ReadDataRow', 'WEB_ACCOUNTS', AccountID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.WEB_ACCOUNTS')
|
|
@ID = AccountID
|
|
@RECORD = WebAccountRow
|
|
EnabledStatus = {ACCOUNT_ENABLED}
|
|
If EnabledStatus NE True$ then EnabledStatus = False$ ; // Always default to disabled unless explicitly enabled.
|
|
end
|
|
end else
|
|
Error_Services('Add', 'AccountID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = EnabledStatus
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetWebAccountPassword
|
|
//
|
|
// Gets the current password for the indicated web account. If the CreateIfNew flag is set to True$, a new password will
|
|
// be generated if no password currently exists. This new password will be added to the web account.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetWebAccountPassword(AccountID, CreateIfNew)
|
|
|
|
Password = ''
|
|
|
|
If CreateIfNew NE True$ then CreateIfNew = False$
|
|
|
|
If AccountID NE '' then
|
|
WebAccountRow = Database_Services('ReadDataRow', 'WEB_ACCOUNTS', AccountID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.WEB_ACCOUNTS')
|
|
@ID = AccountID
|
|
@RECORD = WebAccountRow
|
|
Begin Case
|
|
Case ({CURRENT_PASSWORD} EQ '') AND (CreateIfNew EQ True$)
|
|
Password = HTTP_Authentication_Services('ResetWebAccountPassword', AccountID, CurrentPassword)
|
|
|
|
Case ({CURRENT_PASSWORD} EQ '') AND (CreateIfNew EQ False$)
|
|
Error_Services('Add', 'No password exists for Account ID ' : AccountID)
|
|
|
|
Case Otherwise$
|
|
Password = {CURRENT_PASSWORD}
|
|
|
|
End Case
|
|
end
|
|
end else
|
|
Error_Services('Add', 'AccountID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = Password
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ResetWebAccountPassword
|
|
//
|
|
// Resets the current password (or creates a new one) for the indicated web account. This new password will be added to
|
|
// the web account.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ResetWebAccountPassword(AccountID, CurrentPassword)
|
|
|
|
Password = ''
|
|
|
|
If AccountID NE '' then
|
|
WebAccountRow = Database_Services('ReadDataRow', 'WEB_ACCOUNTS', AccountID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.WEB_ACCOUNTS')
|
|
@ID = AccountID
|
|
@RECORD = WebAccountRow
|
|
// Password is based on a random GUID and then encoded as Base64.
|
|
Password = RTI_CreateGUID('B')
|
|
HTTP_Authentication_Services('SetWebAccountPassword', AccountID, CurrentPassword, Password, True$)
|
|
If Error_Services('HasError') then Password = ''
|
|
end
|
|
end else
|
|
Error_Services('Add', 'AccountID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = Password
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ValidateWebAccountPassword
|
|
//
|
|
// Validates the password for the indicated web account. If the CurrentOnly argument is set to True$, then only the
|
|
// current password associated with the web account will be validated. Otherwise, the old password will also be valided
|
|
// using the expiration date and time associated.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ValidateWebAccountPassword(AccountID, Password, CurrentOnly)
|
|
|
|
Valid = False$ ; // Assume False$ for now.
|
|
ErrorMessage = ''
|
|
|
|
If CurrentOnly NE True$ then CurrentOnly = False$
|
|
|
|
If (AccountID NE '') AND (Password NE '') then
|
|
WebAccountRow = Database_Services('ReadDataRow', 'WEB_ACCOUNTS', AccountID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.WEB_ACCOUNTS')
|
|
@ID = AccountID
|
|
@RECORD = WebAccountRow
|
|
ThisSeconds = Date() * SecondsPerDay$ + Time()
|
|
Begin Case
|
|
Case Password EQ {CURRENT_PASSWORD}
|
|
ExpireSeconds = {CURRENT_PASSWORD_EXPIRE_DATE} * SecondsPerDay$ + {CURRENT_PASSWORD_EXPIRE_TIME}
|
|
If ThisSeconds LE ExpireSeconds then
|
|
Valid = True$
|
|
end else
|
|
ErrorMessage = 'Password is expired. A new one needs to be requested.'
|
|
end
|
|
|
|
Case (Password EQ {OLD_PASSWORD}) AND (CurrentOnly EQ False$)
|
|
ExpireSeconds = {OLD_PASSWORD_EXPIRE_DATE} * SecondsPerDay$ + {OLD_PASSWORD_EXPIRE_TIME}
|
|
If ThisSeconds LE ExpireSeconds then
|
|
Valid = True$
|
|
end else
|
|
ErrorMessage = 'Password is expired. A new one needs to be requested.'
|
|
end
|
|
|
|
Case Otherwise$
|
|
ErrorMessage = 'Password is invalid.'
|
|
|
|
End Case
|
|
|
|
If ErrorMessage EQ '' then
|
|
// Reset the number of invalid password attempts for the account.
|
|
{INVALID_PASSWORD_ATTEMPTS} = 0
|
|
Database_Services('WriteDataRow', 'WEB_ACCOUNTS', @ID, @RECORD, True$, False$, True$)
|
|
end else
|
|
// Update the total invalid password attempts for this server.
|
|
Attempts = HTTP_Services('GetTotalInvalidPasswordAttempts')
|
|
Attempts += 1
|
|
HTTP_Services('SetTotalInvalidPasswordAttempts', Attempts)
|
|
// Update the total invalid password attempts for this account.
|
|
InvalidPasswordAttempts = {INVALID_PASSWORD_ATTEMPTS} + 1
|
|
{INVALID_PASSWORD_ATTEMPTS} = InvalidPasswordAttempts
|
|
Database_Services('WriteDataRow', 'WEB_ACCOUNTS', @ID, @RECORD, True$, False$, True$)
|
|
InvalidPasswordLimit = HTTP_Services('GetInvalidPasswordLimit')
|
|
If InvalidPasswordAttempts GE InvalidPasswordLimit then
|
|
ContainmentAction = HTTP_Services('GetContainmentAction')
|
|
Begin Case
|
|
Case ContainmentAction _EQC 'Disable Server'
|
|
HTTP_Services('SetServerEnabled', False$)
|
|
Case ContainmentAction _EQC 'Quarantine Account'
|
|
{ACCOUNT_ENABLED} = False$
|
|
WebAccountRow = @RECORD
|
|
Database_Services('WriteDataRow', 'WEB_ACCOUNTS', AccountID, WebAccountRow, True$, False$, True$)
|
|
End Case
|
|
ActionDetails = ''
|
|
ActionDetails<1> = Fmt('Containment Action:', 'L#35') : ContainmentAction
|
|
ActionDetails<2> = Fmt('Invalid Password Limit:', 'L#35') : InvalidPasswordLimit
|
|
ActionDetails<3> = Fmt('Total Invalid Password Attempts:', 'L#35') : Attempts
|
|
ActionDetails<4> = Fmt('Account ID:', 'L#35') : AccountID
|
|
ActionDetails<5> = Fmt('Total Account Invalid Attempts:', 'L#35') : InvalidPasswordAttempts
|
|
HTTP_Authentication_Services('ContainmentActionNotification', ActionDetails)
|
|
end
|
|
Error_Services('Add', ErrorMessage)
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'AccountID or Password argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = Valid
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// SetWebAccountPassword
|
|
//
|
|
// Sets a new password for the indicated web account. If no current password already exists, then the new password will
|
|
// be added to the web account automatically. Otherwise, the current password will be verified before allowing a new
|
|
// password to be set.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service SetWebAccountPassword(AccountID, CurrentPassword, NewPassword, OverrideExpireDate)
|
|
|
|
If OverrideExpireDate NE True$ then OverrideExpireDate = False$
|
|
|
|
If (AccountID NE '') AND (NewPassword NE '') then
|
|
WebAccountRow = Database_Services('ReadDataRow', 'WEB_ACCOUNTS', AccountID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.WEB_ACCOUNTS')
|
|
@ID = AccountID
|
|
@RECORD = WebAccountRow
|
|
If {CURRENT_PASSWORD} EQ '' then
|
|
// This is a new password for this web account. Accept the new password.
|
|
CreateDate = Date()
|
|
CreateTime = Time()
|
|
CreateSeconds = CreateDate * SecondsPerDay$ + CreateTime
|
|
ExpireSeconds = CreateSeconds + NewPasswordTimeToLive$
|
|
ExpireDate = Int(ExpireSeconds / SecondsPerDay$)
|
|
ExpireTime = Mod(ExpireSeconds, SecondsPerDay$)
|
|
{CURRENT_PASSWORD} = NewPassword
|
|
{CURRENT_PASSWORD_CREATE_DATE} = CreateDate
|
|
{CURRENT_PASSWORD_CREATE_TIME} = CreateTime
|
|
{CURRENT_PASSWORD_EXPIRE_DATE} = ExpireDate
|
|
{CURRENT_PASSWORD_EXPIRE_TIME} = ExpireTime
|
|
WebAccountRow = @RECORD
|
|
Database_Services('WriteDataRow', 'WEB_ACCOUNTS', AccountID, WebAccountRow, True$, False$, True$)
|
|
end else
|
|
// A current password already exists.
|
|
Valid = HTTP_Authentication_Services('ValidateWebAccountPassword', AccountID, CurrentPassword, True$) OR (OverrideExpireDate EQ True$)
|
|
If Valid EQ True$ then
|
|
Begin Case
|
|
Case CurrentPassword EQ NewPassword
|
|
// New password must be different than the current password.
|
|
Error_Services('Add', 'New password must be different than the current password.')
|
|
|
|
Case Otherwise$
|
|
// Current password is valid and new password is different.
|
|
|
|
// Make the current password the old passowrd. Reset the expiration date and time as
|
|
// needed.
|
|
CurrentPassword = {CURRENT_PASSWORD}
|
|
CurrentPasswordCreateDate = {CURRENT_PASSWORD_CREATE_DATE}
|
|
CurrentPasswordCreateTime = {CURRENT_PASSWORD_CREATE_TIME}
|
|
{OLD_PASSWORD} = CurrentPassword
|
|
{OLD_PASSWORD_CREATE_DATE} = CurrentPasswordCreateDate
|
|
{OLD_PASSWORD_CREATE_TIME} = CurrentPasswordCreateTime
|
|
ThisSeconds = Date() * SecondsPerDay$ + Time()
|
|
ExpireSeconds = ThisSeconds + OldPasswordTimeToLive$
|
|
ExpireDate = Int(ExpireSeconds / SecondsPerDay$)
|
|
ExpireTime = Mod(ExpireSeconds, SecondsPerDay$)
|
|
{OLD_PASSWORD_EXPIRE_DATE} = ExpireDate
|
|
{OLD_PASSWORD_EXPIRE_TIME} = ExpireTime
|
|
|
|
// Set the new password information.
|
|
CreateDate = Date()
|
|
CreateTime = Time()
|
|
CreateSeconds = CreateDate * SecondsPerDay$ + CreateTime
|
|
ExpireSeconds = CreateSeconds + NewPasswordTimeToLive$
|
|
ExpireDate = Int(ExpireSeconds / SecondsPerDay$)
|
|
ExpireTime = Mod(ExpireSeconds, SecondsPerDay$)
|
|
{CURRENT_PASSWORD} = NewPassword
|
|
{CURRENT_PASSWORD_CREATE_DATE} = CreateDate
|
|
{CURRENT_PASSWORD_CREATE_TIME} = CreateTime
|
|
{CURRENT_PASSWORD_EXPIRE_DATE} = ExpireDate
|
|
{CURRENT_PASSWORD_EXPIRE_TIME} = ExpireTime
|
|
WebAccountRow = @RECORD
|
|
Database_Services('WriteDataRow', 'WEB_ACCOUNTS', AccountID, WebAccountRow, True$, False$, True$)
|
|
End Case
|
|
end
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'AccountID or NewPassword argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// SetAuthenticatedAccountID
|
|
//
|
|
// Sets the account ID that was successfully authenticated for this request.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service SetAuthenticatedAccountID(AccountID)
|
|
|
|
If AccountID NE '' then
|
|
Memory_Services('SetValue', ServiceModule : '*AuthenticatedAccountID', AccountID, CacheName$)
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetAuthenticatedAccountID
|
|
//
|
|
// Gets the successfully authenticated account ID for this request.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetAuthenticatedAccountID()
|
|
|
|
AccountID = Memory_Services('GetValue', ServiceModule : '*AuthenticatedAccountID', '', '', CacheName$)
|
|
|
|
Response = AccountID
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// SetAuthenticatedPassword
|
|
//
|
|
// Sets the password that was successfully authenticated for this request.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service SetAuthenticatedPassword(Password)
|
|
|
|
If Password NE '' then
|
|
Memory_Services('SetValue', ServiceModule : '*AuthenticatedPassword', Password, CacheName$)
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetAuthenticatedPassword
|
|
//
|
|
// Gets the successfully authenticated password for this request.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetAuthenticatedPassword()
|
|
|
|
Password = Memory_Services('GetValue', ServiceModule : '*AuthenticatedPassword', '', '', CacheName$)
|
|
|
|
Response = Password
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ContainmentActionNotification
|
|
//
|
|
// Handles notification protocols when a containment breach has occured. This handler is mostly a placeholder for
|
|
// developers to add their own custom protocol action.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ContainmentActionNotification(ActionDetails)
|
|
|
|
end service
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Internal GoSubs
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|