Intro
I will try implementing HTTP Authentication with 'Basic' HTTP Authentication.
After authentication, I will set a session key as a cookie value.
Note:
This sample was created simply to see how "Basic" authentication works.
In practice, security measures must be applied.
'Basic' HTTP Authentication
'Basic' HTTP Authentication uses a pair of ID and password for authentication.
And it's based on "Challenge-response authentication".
- [Client] Access the protected resources
- [Server] Because the client does not have the credentials、The server returns a 401 status code and "WWW-Authenticate".
- [Client] Send valid ID and password
- [Server] The authentication is succeeded and the server will return the protected resources
2. Returning a 401 status code and "WWW-Authenticate"
At first I will see how web browsers work when the server returns the 401 statu code.
main.go
package main
import (
"log"
"net/http"
)
func main() {
// It only returns 401 status code now.
http.HandleFunc("/auth/", func(w http.ResponseWriter, r *http.Request) {
// TODO: Validate the user authentication info
// At least one "WWW-Authenticate" is required.
// Otherwise, web browsers just show the default 401 error page.
w.Header().Set("WWW-Authenticate", "Basic realm=\"localhost\"")
w.WriteHeader(401)
})
log.Fatal(http.ListenAndServe("localhost:8083", nil))
}
Result
4. Get the client user-pass(ID and password)
After the client input its ID and password, the server can get them from HTTP request header.
The web brower sets them into HTTP request header as "user-pass".
The "user-pass" is generated in the following format and encoded in Base64.
{ID}:{Password}
The web browser registers it with the "Authorization" key along with the Scheme.
Basic {user-pass}
The server can split them into the Scheme(Basic), the ID, and the password.
main.go
...
import (
"encoding/base64"
"log"
"net/http"
"strings"
)
...
func signin(r *http.Request) {
// Get user-pass
authText := r.Header.Get("Authorization")
splitted := strings.Split(authText, " ")
if len(splitted) >= 2 {
log.Printf("Authorization: %s UserPass: %s", splitted[0], splitted[1])
decoded, err := base64.StdEncoding.DecodeString(splitted[1])
if err == nil {
userPass := string(decoded)
splitTarget := strings.Index(userPass, ":")
if splitTarget < 0 {
log.Println("Invalid")
return
}
userId := userPass[0:splitTarget]
pass := userPass[splitTarget+1:]
log.Printf("USER ID:%s Password:%s", userId, pass)
} else {
log.Println(err.Error())
}
} else {
log.Println("Invalid")
}
}
Results
Authorization: Basic UserPass: ZmZmZ2hqazpkZmdoamts
USER ID:fffghjk Password:dfghjkl
Saving the authentication info
After authentication, how should I keep my credentials?
For example, ASP.NET Core Identity registers authentication information in cookies by default.
I will try registering in cookies in this time.
According to my ASP.NET Core application run, the cookie set after authentication was as follows.
Cookie: .AspNetCore.Identity.Application=CfDJ8PAT8IN6xqxGqh9UWuW_Iif6kvwPRUoA5MEVumnp6qYnZySdcFGwZhWqaznPiKtjbsiyfYLzPmyKHs_wSDYZqSp61aiv-wzRYg5zuisGsOyVpSbKrCUkxUMSTQIrXFdNeVMdb7QDQYJahbbdgjSmZc5kOAuqK8WQh1fCQ0GxbE4XrvwEDClLm-SSRyOC72Ne76uBnGRHPzuGOFXUMklWeRcRWLPEd3ZOwMkwChKkSMA7xJjHAPtCnx0LLkZJ30YmfsbRPJ6qBWiSCoq-ChVzWZLKog0mR4SLBz7K_dEbUfdfMeAi52sXiJkk8rHSaHxxDymF4KJu8-Qg6xZ4e--02xCc-dFedut7Q2NXQPXD7PXY_wV-VB0x60KRQYNc_UeZDvuZWPZi-vgICqgraMFHoynKLEQgRbmTYU6SVRb_MX920fccmtySo8y5-xZ6P_Drmko1hqNyyZKamMKxqHxXXXX
Because I couldn't find a standard specification for storing authentication information in cookies, I figured I had to decide for myself what the key and value of the cookie would be.
Set cookies
expiration := time.Now()
expiration = expiration.AddDate(0, 0, 1)
cookie := http.Cookie{Name: "WebAuthSample", Value: uuid.New().String(), Expires: expiration}
http.SetCookie(w, &cookie)
Get cookies
func getAuthenticationInfo(r *http.Request) string {
for _, c := range r.Cookies() {
if c.Name != "WebAuthSample" {
continue
}
// If the client has a valid cookie, it can retrieve the value.
return c.String()
}
return ""
}
TODO
The server-side application should maintain the ID and cookie values of clients who have completed the authentication process, and check the authentication status when the client accesses protected resources.