Wapp

Implementing Basic authentication in Wapp
Login

Implementing Basic authentication in Wapp

(1) By geoff (geoffrey) on 2023-08-14 03:05:32 [source]

Basic authentication is widely supported by web browsers and is relatively simple to implement server-side.

See https://joeldare.com/why-im-using-http-basic-auth-in-2022.html for one programmer's opinion on where basic authentication can be useful currently.

Although Basic authentication is not provided by Wapp out of the box, not only is it straightforward to implement, but it would not be difficult to extend basic authentication to provide slightly more sophisticated authentication.

As shown below, basic-auth is a command to perform basic authentication. Basic authentication can only be secure when used exclusively via HTTPS, not HTTP, because username:password is passed in base64 encoding which is easily decoded, and has no real security advantage over plain-text.

Arguments to basic-auth:

authcmd is the name of the proc to decide whether the user/pswd/realm combination is authorised. A good way to proceed might be to access data in a user defined sqlite "login" table. This proc could then optionally take into account other information such as the time since last login. In this way we could get slightly more sophisticated basic authentication that vanilla basic authentication. Another possibility is to use authcmd to enable a hash of the password to be used server-side instead of a plain password (e.g. using exec argon2 ...). This might increase security slightly in the instance where the sqlite database becomes compromised. The authcmd proc will be called with user, pswd, realm as arguments. It must return 0 for failure and 1 for successful authentication.

realm is a realm string as per HTTP Basic Authentication

Return value:

The return value is 1 for successful authentication, or 0 for failure to authenticate

NOTES:

User (name) cannot contain ":".


source wapp.tcl

proc basic-auth {authcmd realm} {
  if {[wapp-param-exists .hdr:AUTHORIZATION]} {
    set plain [binary decode base64 \
	    [lindex [split [wapp-param .hdr:AUTHORIZATION] " "] 1]]
    set idx [string first ":" $plain]
    if {[$authcmd [string range $plain 0 $idx-1] \
	    [string range $plain $idx+1 end] $realm]} {
      return 1
    }
  }
  wapp-reply-code "401 Unauthorized"
  wapp-reply-extra WWW-Authenticate \
    "Basic realm=\"$realm\" charset=\"UTF-8\""
  return 0
}

# create one or more authcmds which should return "0" if
# authentication is rejected and "1" if it succeeds.

# This next variable is used as a simplistic simulation
# of time based login acceptance - after the third request
# by the client (which would include favicon.ico requests)
# login is declined, and providing user credentials is again
# requested (possibly assuming the browser user has not agreed
# to save the password in the browser, which I have not tested):
set authentications 3

proc my-auth-cmd {user pswd realm} {
  puts user=$user
  puts pswd=$pswd
  puts realm=$realm
  # Ordinarily, this next bit would either involve checking against
  # a basic authentication file in the script directory, or a table in an
  # sqlite database, but for simplicity a hard coded check is shown:
  if {$user eq "geoff" && $pswd eq "1234567" && $::authentications > 0} {
    incr ::authentications -1
    return 1
  } else {
    set ::authentications 3
    return 0
  }
}

proc wapp-default {} {
  # The call to "basic-auth" below could be placed in a relevant 
  # header proc used to generate the page header so that it did not
  # need to be explicity called (if desired):
  if {! [basic-auth my-auth-cmd "my realm"]} return
  
  wapp-trim {
    <html>
      <body>
        <p>Hello World</p>
      </body>
    </html>
  }
}

wapp-start $argv