Sesame-Disk / cool-storage-api

3 stars 0 forks source link

Token bearer problem #17

Closed ezielramos closed 2 years ago

ezielramos commented 2 years ago

How to solve authentication problem ?

Story points: 3

ezielramos commented 2 years ago

Some options to implement token authentication

First how we create the token ?

First choice :

import ( "crypto/md5" "encoding/hex" "fmt" "log"

"golang.org/x/crypto/bcrypt"

)

// GenerateToken returns a unique token based on the provided email string func GenerateToken(email string) string { hash, err := bcrypt.GenerateFromPassword([]byte(email), bcrypt.DefaultCost) if err != nil { log.Fatal(err) } fmt.Println("Hash to store:", string(hash))

hasher := md5.New()
hasher.Write(hash)
return hex.EncodeToString(hasher.Sum(nil))

}

func main() { fmt.Println("token:", GenerateToken("bob@webserver.com")) }

- this code generate a short token
- output: 

$ go run main.go Hash to store: $2a$10$B23cv7lDpbY3iVvfZ7GYE.e4691ow8i7l6CQXkmz315fbg4jLzoue token: 90a514ab93e2c32fdd1072154b26a100

###  Option 3: base64

package main

import ( "encoding/base64" "fmt" "log"

"golang.org/x/crypto/bcrypt"

)

// GenerateToken returns a unique token based on the provided email string func GenerateToken(email string) string { hash, err := bcrypt.GenerateFromPassword([]byte(email), bcrypt.DefaultCost) if err != nil { log.Fatal(err) } fmt.Println("Hash to store:", string(hash))

return base64.StdEncoding.EncodeToString(hash)

}

func main() { fmt.Println("token:", GenerateToken("bob@webserver.com")) }

- output:

$ go run main.go Hash to store: $2a$10$cbVMU9U665VSqpfwrNZWOeU5cIDOe5iBJ8ZVa2yJCTsnk9MEZHvRq token: JDJhJDEwJGNiVk1VOVU2NjVWU3FwZndyTlpXT2VVNWNJRE9lNWlCSjhaVmEyeUpDVHNuazlNRVpIdlJx

- option 2 and 3 are from: https://stackoverflow.com/a/45267661
### Option 4 IBM
/go-sdk-core

import "github.com/IBM/go-sdk-core/v5/core" ... // Create the authenticator. authenticator, err := core.NewBasicAuthenticator("myuser", "mypassword") if err != nil { panic(err) }

- description link: https://github.com/IBM/go-sdk-core/blob/main/Authentication.md
### Option 5 Implement Token-based Authentication with Golang and MySQL 8 Server:
- Token-based authentication is a form of access control protocol. To implement it, you require users to verify their identity (For instance, by providing their usernames and passwords). Then, you issue the users with a time-based secret that they can use to access your application.
- Prerequisites: A Linux server, A non-root sudo user, A MySQL database,The Golang package
- Follow this link for the description and complete implementation: https://www.vultr.com/docs/implement-tokenbased-authentication-with-golang-and-mysql-8-server/#:~:text=Introduction,use%20to%20access%20your%20application.
- This is how look authentications.go

package main

import (
"database/sql" _ "github.com/go-sql-driver/mysql" "golang.org/x/crypto/bcrypt" "time" "crypto/rand" "encoding/base64" "errors" )

func generateToken(username string, password string) (map[string]interface{}, error) {

db, err := sql.Open("mysql", "sample_db_user:EXAMPLE_PASSWORD@tcp(127.0.0.1:3306)/sample_db")                                                       
if err != nil {
    return nil, err
}            

queryString := "select user_id, password from system_users where username = ?"

stmt, err := db.Prepare(queryString) 

if err != nil {
    return nil, err
}

defer stmt.Close()

userId := 0
accountPassword := ""              

err = stmt.QueryRow(username).Scan(&userId, &accountPassword)

if err != nil {

    if err == sql.ErrNoRows {
        return nil, errors.New("Invalid username or password.\r\n")
    }

   return nil, err
}

err = bcrypt.CompareHashAndPassword([]byte(accountPassword), []byte(password))

if err != nil {
    return nil, errors.New("Invalid username or password.\r\n")
}

queryString = "insert into authentication_tokens(user_id, auth_token, generated_at, expires_at) values (?, ?, ?, ?)"
stmt, err = db.Prepare(queryString) 

if err != nil {
    return nil, err
}

defer stmt.Close() 

randomToken := make([]byte, 32)

_, err = rand.Read(randomToken)

if err != nil { return nil, err
}

authToken   := base64.URLEncoding.EncodeToString(randomToken)

const timeLayout = "2006-01-02 15:04:05"

dt := time.Now()
expirtyTime := time.Now().Add(time.Minute * 60)

generatedAt := dt.Format(timeLayout)
expiresAt   := expirtyTime.Format(timeLayout)

_, err = stmt.Exec(userId, authToken, generatedAt, expiresAt)  

if err != nil {
    return nil, err
}

tokenDetails := map[string]interface{}{
    "token_type":   "Bearer",
    "auth_token" :  authToken,
    "generated_at": generatedAt,
    "expires_at":   expiresAt,
}

return tokenDetails, nil

}

func validateToken(authToken string) (map[string]interface{}, error) {

db, err := sql.Open("mysql", "sample_db_user:EXAMPLE_PASSWORD@tcp(127.0.0.1:3306)/sample_db") 

if err != nil {
    return nil, err
}      

queryString := `select 
            system_users.user_id,
            username,
            generated_at,
            expires_at                         
        from authentication_tokens
        left join system_users
        on authentication_tokens.user_id = system_users.user_id
        where auth_token = ?`

stmt, err := db.Prepare(queryString) 

if err != nil {
    return nil, err
}

defer stmt.Close()

userId      := 0
username    := ""
generatedAt := ""
expiresAt   := ""      

err = stmt.QueryRow(authToken).Scan(&userId, &username, &generatedAt, &expiresAt)

if err != nil {

    if err == sql.ErrNoRows {
        return nil, errors.New("Invalid access token.\r\n")
    }

   return nil, err
}

const timeLayout = "2006-01-02 15:04:05"

expiryTime, _  := time.Parse(timeLayout, expiresAt)
currentTime, _ := time.Parse(timeLayout, time.Now().Format(timeLayout))

if expiryTime.Before(currentTime) {
    return nil, errors.New("The token is expired.\r\n")
}

userDetails := map[string]interface{}{
    "user_id":     userId,
    "username":    username,
    "generated_at": generatedAt,
    "expires_at" : expiresAt,            
} 

return userDetails, nil

}


## Protocol
- https://docs.wso2.com/display/AM190/Generating+Access+Tokens+with+User+Credentials+-+Password+Grant+Type