Using Basic authorization in a WebHandler of an application end point

I Love Xbase++ (ILX)
The portal for Xbase++ developers worldwide

Andreas Herdt

Member
I am here to help you!
Feb 1, 2021
31
4
8
Customer Identifier
E104394

Background​

In the basic authentication scheme, username and password are transferred base64 encoded in the Authorization header of the HTTP request. So in the WebHandler this header must be accessed and the username and password must be extracted from the header value and checked.

The Authorization header follows the following convention:
Code:
Header: "Authorization"
Value : "Basic <credentials>" // "<credentials>" is a Base64-encoded
                              // string with the client's credentials
                              // specified as "<user>:<password>".
So the first thing to do is to extract the <credentials> part, decode it (base64) and separate username and password. If the authorization fails, the corresponding HTTP status code 401 is set and the WebHandler method terminates appropriately.

Example​

The task of authorization is implemented in the BasicAuthorization() class in the code example below. The usage is illustrated here using the CurrentTime:get() method from the documentation of the WebHandler class:
Xbase++:
METHOD CurrentTime:get()
   ...
   IF .NOT. BasicAuthorization():verify( ::HttpRequest, ::HttpResponse )
      RETURN "Access denied"
   ENDIF
   ...
RETURN cResponse
The following curl commands can be used to check the functionality:
Code:
// positive test
curl http://localhost:81/CurrentTime/get -u "login:password"

// invalid password curl
curl http://localhost:81/CurrentTime/get -u "login:invalid"

// no credentials
curl http://localhost:81/CurrentTime/get
The BasicAuthorization() class in the example here implements the logic to access the Authorization header of the HttpRequest() object. In case of an error, the HTTP status code 401 of the HTTP response is set. The method HttpResponse:setStatus() used for this is unfortunately not yet documented in the Xbase++ documentation.
Xbase++:
//////////////////////////////////////////////////////////////////////
///
/// <summary>
/// The class BasicAuthorization verifies credentials according to
/// an HttpRequest object. On error the HttpResponse object gets the
/// status code 401 set.
/// </summary>
///
///
/// <remarks>
/// The class method :verifyCredentials() needs to be extended according
/// to your infrastructure.
/// </remarks>
///
///
/// <copyright>
/// Alaska Software. All Rights Reserved.
/// </copyright>
///
//////////////////////////////////////////////////////////////////////

/// <summary>
/// </summary>
CLASS BasicAuthorization
   PROTECTED:
      CLASS METHOD extractCredentials
      CLASS METHOD verifyCredentials
   EXPORTED:
      CLASS METHOD verify
ENDCLASS

/// <summary>
/// Verify basic authorization according the httprequest Authorization header.
/// Set status code and message on failure.
/// </summary>
CLASS METHOD BasicAuthorization:verify( oHttpRequest, oHttpResponse )
   LOCAL cAuthorizationHeader
   LOCAL cUser, cPass

   cAuthorizationHeader := oHttpRequest:getHeader( "Authorization" )

   cUser := cPass := NIL
   IF .NOT. ::extractCredentials( cAuthorizationHeader, @cUser, @cPass )
      oHttpResponse:setStatus( 401, "Unauthorized" )
      RETURN .F.
   ENDIF

   IF .NOT. ::verifyCredentials( cUser, cPass )
      oHttpResponse:setStatus( 401, "Unauthorized" )
      RETURN .F.
   ENDIF

RETURN .T.

/// <summary>
/// Extract username and password from Authorization header.
/// </summary>
/// <param name="cAuthorization">The HTTP Authorization header value.</param>
/// <param name="cResultUser">Return the username in this reference parameter.</param>
/// <param name="cResultPass">Return the password in this reference parameter.</param>
/// <returns>
/// Return the logical value true (.T.) when authorization
/// succeeded. Return false(.F.) otherwise.
/// </returns>
CLASS METHOD BasicAuthorization:extractCredentials( cAuthorization, cResultUser, cResultPass )
   LOCAL cUserPass
   LOCAL nColPos

   // Initialize the return values passed by reference
   cResultUser := ""
   cResultPass := ""

   // Credentials are prefixed by "Basic "
   IF .NOT. "basic " == Lower( SubStr( cAuthorization, 1, 6 ) )
      RETURN .F.
   ENDIF

   // Username and password are base64 encoded
   cUserPass := Base642Bin( SubStr( cAuthorization, 7 ) )
   // and seperated by a colon
   nColPos := At( ":", cUserPass )

   IF 0 == nColPos
      RETURN .F.
   ENDIF

   cResultUser := SubStr( cUserPass, 1, nColPos - 1 )
   cResultPass := SubStr( cUserPass, nColPos + 1 )

RETURN .T.

/// <summary>
/// Verify credentials
/// </summary>
/// <returns>
/// Returns the logical value true (.T.) when credentials are valid and
/// false (.F.) otherwise.
/// </returns>
/// <remarks>Modify this method according your infrastructure</remarks>
CLASS METHOD BasicAuthorization:verifyCredentials( cUser, cPass )

   IF .NOT. "login" == cUser
      RETURN .F.
   ENDIF

   IF .NOT. "password" == cPass
      RETURN .F.
   ENDIF

RETURN .T.
See also:
Xbase++ documentation: Class WebHandler
Xbase++ documentation: Class HttpEndpoint
Homepage Homepage curl.exe
RFC 7617: The 'Basic' HTTP Authentication Scheme
 
Last edited: