portainer/api/auth.go

89 lines
2.1 KiB
Go

package main
import (
"encoding/json"
"github.com/asaskevich/govalidator"
"golang.org/x/crypto/bcrypt"
"io/ioutil"
"log"
"net/http"
)
type (
credentials struct {
Username string `valid:"alphanum,required"`
Password string `valid:"length(8)"`
}
authResponse struct {
JWT string `json:"jwt"`
}
)
func hashPassword(password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", nil
}
return string(hash), nil
}
func checkPasswordValidity(password string, hash string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}
// authHandler defines a handler function used to authenticate users
func (api *api) authHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.Header().Set("Allow", "POST")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Unable to parse request body", http.StatusBadRequest)
return
}
var credentials credentials
err = json.Unmarshal(body, &credentials)
if err != nil {
http.Error(w, "Unable to parse credentials", http.StatusBadRequest)
return
}
_, err = govalidator.ValidateStruct(credentials)
if err != nil {
http.Error(w, "Invalid credentials format", http.StatusBadRequest)
return
}
var username = credentials.Username
var password = credentials.Password
u, err := api.dataStore.getUserByUsername(username)
if err != nil {
log.Printf("User not found: %s", username)
http.Error(w, "User not found", http.StatusNotFound)
return
}
err = checkPasswordValidity(password, u.Password)
if err != nil {
log.Printf("Invalid credentials for user: %s", username)
http.Error(w, "Invalid credentials", http.StatusUnprocessableEntity)
return
}
token, err := api.generateJWTToken(username)
if err != nil {
log.Printf("Unable to generate JWT token: %s", err.Error())
http.Error(w, "Unable to generate JWT token", http.StatusInternalServerError)
return
}
response := authResponse{
JWT: token,
}
json.NewEncoder(w).Encode(response)
}