portainer/api/users.go

220 lines
5.3 KiB
Go

package main
import (
"encoding/json"
"github.com/gorilla/mux"
"io/ioutil"
"log"
"net/http"
)
type (
passwordCheckRequest struct {
Password string `json:"password"`
}
passwordCheckResponse struct {
Valid bool `json:"valid"`
}
initAdminRequest struct {
Password string `json:"password"`
}
)
// handle /users
// Allowed methods: POST
func (api *api) usersHandler(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 user userItem
err = json.Unmarshal(body, &user)
if err != nil {
http.Error(w, "Unable to parse user data", http.StatusBadRequest)
return
}
user.Password, err = hashPassword(user.Password)
if err != nil {
http.Error(w, "Unable to hash user password", http.StatusInternalServerError)
return
}
err = api.dataStore.updateUser(user)
if err != nil {
log.Printf("Unable to persist user: %s", err.Error())
http.Error(w, "Unable to persist user", http.StatusInternalServerError)
return
}
}
// handle /users/admin/check
// Allowed methods: POST
func (api *api) checkAdminHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
w.Header().Set("Allow", "GET")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
user, err := api.dataStore.getUserByUsername("admin")
if err == errUserNotFound {
log.Printf("User not found: %s", "admin")
http.Error(w, "User not found", http.StatusNotFound)
return
}
if err != nil {
log.Printf("Unable to retrieve user: %s", err.Error())
http.Error(w, "Unable to retrieve user", http.StatusInternalServerError)
return
}
user.Password = ""
json.NewEncoder(w).Encode(user)
}
// handle /users/admin/init
// Allowed methods: POST
func (api *api) initAdminHandler(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 requestData initAdminRequest
err = json.Unmarshal(body, &requestData)
if err != nil {
http.Error(w, "Unable to parse user data", http.StatusBadRequest)
return
}
user := userItem{
Username: "admin",
}
user.Password, err = hashPassword(requestData.Password)
if err != nil {
http.Error(w, "Unable to hash user password", http.StatusInternalServerError)
return
}
err = api.dataStore.updateUser(user)
if err != nil {
log.Printf("Unable to persist user: %s", err.Error())
http.Error(w, "Unable to persist user", http.StatusInternalServerError)
return
}
}
// handle /users/{username}
// Allowed methods: PUT, GET
func (api *api) userHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "PUT" {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Unable to parse request body", http.StatusBadRequest)
return
}
var user userItem
err = json.Unmarshal(body, &user)
if err != nil {
http.Error(w, "Unable to parse user data", http.StatusBadRequest)
return
}
user.Password, err = hashPassword(user.Password)
if err != nil {
http.Error(w, "Unable to hash user password", http.StatusInternalServerError)
return
}
err = api.dataStore.updateUser(user)
if err != nil {
log.Printf("Unable to persist user: %s", err.Error())
http.Error(w, "Unable to persist user", http.StatusInternalServerError)
return
}
} else if r.Method == "GET" {
vars := mux.Vars(r)
username := vars["username"]
user, err := api.dataStore.getUserByUsername(username)
if err == errUserNotFound {
log.Printf("User not found: %s", username)
http.Error(w, "User not found", http.StatusNotFound)
return
}
if err != nil {
log.Printf("Unable to retrieve user: %s", err.Error())
http.Error(w, "Unable to retrieve user", http.StatusInternalServerError)
return
}
user.Password = ""
json.NewEncoder(w).Encode(user)
} else {
w.Header().Set("Allow", "PUT, GET")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
}
// handle /users/{username}/passwd
// Allowed methods: POST
func (api *api) userPasswordHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.Header().Set("Allow", "POST")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
vars := mux.Vars(r)
username := vars["username"]
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Unable to parse request body", http.StatusBadRequest)
return
}
var data passwordCheckRequest
err = json.Unmarshal(body, &data)
if err != nil {
http.Error(w, "Unable to parse user data", http.StatusBadRequest)
return
}
user, err := api.dataStore.getUserByUsername(username)
if err != nil {
log.Printf("Unable to retrieve user: %s", err.Error())
http.Error(w, "Unable to retrieve user", http.StatusInternalServerError)
return
}
valid := true
err = checkPasswordValidity(data.Password, user.Password)
if err != nil {
valid = false
}
response := passwordCheckResponse{
Valid: valid,
}
json.NewEncoder(w).Encode(response)
}