Implement creating users and tokens from REST API

This commit is contained in:
Anders Pitman
2020-10-29 17:56:38 -06:00
parent eb9409566d
commit 6b9f9aa413
3 changed files with 75 additions and 27 deletions

72
api.go
View File

@@ -28,6 +28,7 @@ func NewApi(config *BoringProxyConfig, db *Database, auth *Auth, tunMan *TunnelM
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
mux.Handle("/users/", http.StripPrefix("/users", http.HandlerFunc(api.handleUsers)))
mux.Handle("/tokens/", http.StripPrefix("/tokens", http.HandlerFunc(api.handleTokens)))
return api
}
@@ -184,6 +185,37 @@ func (a *Api) DeleteTunnel(tokenData TokenData, params url.Values) error {
return nil
}
func (a *Api) handleTokens(w http.ResponseWriter, r *http.Request) {
token, err := extractToken("access_token", r)
if err != nil {
w.WriteHeader(401)
w.Write([]byte("No token provided"))
return
}
tokenData, exists := a.db.GetTokenData(token)
if !exists {
w.WriteHeader(403)
w.Write([]byte("Not authorized"))
return
}
switch r.Method {
case "POST":
r.ParseForm()
token, err := a.CreateToken(tokenData, r.Form)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
}
io.WriteString(w, token)
default:
w.WriteHeader(405)
w.Write([]byte(err.Error()))
}
}
func (a *Api) CreateToken(tokenData TokenData, params url.Values) (string, error) {
owner := params.Get("owner")
@@ -346,7 +378,21 @@ func (a *Api) handleUsers(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
if len(parts) == 3 && parts[1] == "clients" {
if path == "/" {
switch r.Method {
case "POST":
err := a.CreateUser(tokenData, r.Form)
if err != nil {
w.WriteHeader(500)
io.WriteString(w, err.Error())
return
}
default:
w.WriteHeader(406)
io.WriteString(w, "Invalid method for /users")
return
}
} else if len(parts) == 3 && parts[1] == "clients" {
ownerId := parts[0]
clientId := parts[2]
if r.Method == "PUT" {
@@ -371,6 +417,30 @@ func (a *Api) handleUsers(w http.ResponseWriter, r *http.Request) {
}
}
func (a *Api) CreateUser(tokenData TokenData, params url.Values) error {
user, _ := a.db.GetUser(tokenData.Owner)
if !user.IsAdmin {
return errors.New("Unauthorized")
}
username := params.Get("username")
minUsernameLen := 6
if len(username) < minUsernameLen {
errStr := fmt.Sprintf("Username must be at least %d characters", minUsernameLen)
return errors.New(errStr)
}
isAdmin := params.Get("is-admin") == "on"
err := a.db.AddUser(username, isAdmin)
if err != nil {
return err
}
return nil
}
func (a *Api) SetClient(tokenData TokenData, params url.Values, ownerId, clientId string) error {
if tokenData.Owner != ownerId {

View File

@@ -8,6 +8,7 @@
- [ ] Improve SSH key download UI.
- [ ] Improve token list UI.
- [ ] Invalid database is wiping out tunnels
- [ ] Delete tokens when user is deleted
- [x] Head can be rendered before h.headHtml is ever set, ie if login page is visited before any other page
- [x] Responses to unauthorized requests are leaking information about the current tunnels through the generated CSS.
- [x] I think it's possible to create tokens for arbitrary user, even if you're not that user.

View File

@@ -162,13 +162,7 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request
case "/login":
h.handleLogin(w, r)
case "/users":
if user.IsAdmin {
h.handleUsers(w, r)
} else {
w.WriteHeader(403)
h.alertDialog(w, r, "Not authorized", "/#/tunnels")
return
}
h.handleUsers(w, r, tokenData)
case "/confirm-delete-user":
h.confirmDeleteUser(w, r)
@@ -565,7 +559,7 @@ func (h *WebUiHandler) sendLoginPage(w http.ResponseWriter, r *http.Request, cod
loginTemplate.Execute(w, loginData)
}
func (h *WebUiHandler) handleUsers(w http.ResponseWriter, r *http.Request) {
func (h *WebUiHandler) handleUsers(w http.ResponseWriter, r *http.Request, tokenData TokenData) {
if r.Method != "POST" {
w.WriteHeader(405)
@@ -575,24 +569,7 @@ func (h *WebUiHandler) handleUsers(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
if len(r.Form["username"]) != 1 {
w.WriteHeader(400)
w.Write([]byte("Invalid username parameter"))
return
}
username := r.Form["username"][0]
minUsernameLen := 6
if len(username) < minUsernameLen {
w.WriteHeader(400)
errStr := fmt.Sprintf("Username must be at least %d characters", minUsernameLen)
h.alertDialog(w, r, errStr, "/#/users")
return
}
isAdmin := len(r.Form["is-admin"]) == 1 && r.Form["is-admin"][0] == "on"
err := h.db.AddUser(username, isAdmin)
err := h.api.CreateUser(tokenData, r.Form)
if err != nil {
w.WriteHeader(500)
h.alertDialog(w, r, err.Error(), "/#/users")