auth: auth flow complete on server-side
This commit is contained in:
parent
ce02dca041
commit
1b8e5b4d70
|
@ -56,8 +56,12 @@ func New(db *db.Database, name, password string) (*User, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
invalidate := time.Now().Add(time.Duration(config.GetInt("invalidate.hours", 7*24)) * time.Hour)
|
invalidate := time.Now().Add(time.Duration(config.GetInt("invalidate.hours", 7*24)) * time.Hour)
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), config.GetInt("hash.cost", 16))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
res, err := db.Exec(q, name, password, key, invalidate)
|
res, err := db.Exec(q, name, hash, key, invalidate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -96,6 +100,7 @@ func (u *User) Set(newPassword string) error {
|
||||||
func (u *User) Validate(password string) bool {
|
func (u *User) Validate(password string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword(u.Hash, []byte(password))
|
err := bcrypt.CompareHashAndPassword(u.Hash, []byte(password))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debug().Err(err).Msg("incorrect credentials")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
4
main.go
4
main.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"code.chrissexton.org/cws/cabinet/auth"
|
||||||
"code.chrissexton.org/cws/cabinet/entry"
|
"code.chrissexton.org/cws/cabinet/entry"
|
||||||
|
|
||||||
"code.chrissexton.org/cws/cabinet/db"
|
"code.chrissexton.org/cws/cabinet/db"
|
||||||
|
@ -45,6 +46,9 @@ func main() {
|
||||||
if err := entry.PrepareTable(tx); err != nil {
|
if err := entry.PrepareTable(tx); err != nil {
|
||||||
log.Fatal().Err(err).Msg("could not create database")
|
log.Fatal().Err(err).Msg("could not create database")
|
||||||
}
|
}
|
||||||
|
if err = auth.PrepareTable(tx); err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("could not create database")
|
||||||
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
|
|
||||||
s := web.New(*httpAddr, db, box)
|
s := web.New(*httpAddr, db, box)
|
||||||
|
|
47
web/auth.go
47
web/auth.go
|
@ -2,9 +2,12 @@ package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.chrissexton.org/cws/cabinet/auth"
|
"code.chrissexton.org/cws/cabinet/auth"
|
||||||
|
"code.chrissexton.org/cws/cabinet/config"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,7 +22,21 @@ func (web *Web) auth(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Validate(password) {
|
if user.Validate(password) {
|
||||||
|
resp := struct {
|
||||||
|
Status bool
|
||||||
|
User auth.User
|
||||||
|
}{
|
||||||
|
true,
|
||||||
|
*user,
|
||||||
|
}
|
||||||
|
j, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
log.Error().Err(err).Msg("Error encoding json response")
|
||||||
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
|
w.Write(j)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
|
@ -30,7 +47,35 @@ func (web *Web) auth(w http.ResponseWriter, r *http.Request) {
|
||||||
j, err := json.Marshal(resp)
|
j, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
log.Error().Err(err).Msg("Error")
|
log.Error().Err(err).Msg("Error encoding json response")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
w.Write(j)
|
w.Write(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (web *Web) newUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
secret := r.Header.Get("X-secret")
|
||||||
|
if secret != config.Get("secret", "abc123") {
|
||||||
|
w.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(r.Body)
|
||||||
|
req := struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}{}
|
||||||
|
err := dec.Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
fmt.Fprint(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = auth.New(web.db, req.Username, req.Password)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
fmt.Fprint(w, err)
|
||||||
|
log.Error().Err(err).Msg("Could not create user")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(200)
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"code.chrissexton.org/cws/cabinet/auth"
|
||||||
"code.chrissexton.org/cws/cabinet/db"
|
"code.chrissexton.org/cws/cabinet/db"
|
||||||
|
|
||||||
packr "github.com/gobuffalo/packr/v2"
|
packr "github.com/gobuffalo/packr/v2"
|
||||||
|
@ -38,15 +39,20 @@ func New(addr string, db *db.Database, box *packr.Box) *Web {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthMiddleware struct{}
|
type AuthMiddleware struct {
|
||||||
|
db *db.Database
|
||||||
|
}
|
||||||
|
|
||||||
func (aw *AuthMiddleware) Middleware(next http.Handler) http.Handler {
|
func (aw *AuthMiddleware) Middleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Header.Get("X-Auth-Key") == "" {
|
key := r.Header.Get("X-Auth-Key")
|
||||||
|
u, err := auth.GetByKey(aw.db, key)
|
||||||
|
if key == "" || err != nil {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
fmt.Fprint(w, "invalid login")
|
fmt.Fprint(w, "invalid login")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("This shit is authed!")
|
log.Debug().Msgf("This shit is authed to user %s!", u.Name)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -54,7 +60,7 @@ func (aw *AuthMiddleware) Middleware(next http.Handler) http.Handler {
|
||||||
func (web *Web) routeSetup() http.Handler {
|
func (web *Web) routeSetup() http.Handler {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
api := r.PathPrefix("/v1/").Subrouter()
|
api := r.PathPrefix("/v1/").Subrouter()
|
||||||
auth := AuthMiddleware{}
|
auth := AuthMiddleware{web.db}
|
||||||
|
|
||||||
authedApi := r.PathPrefix("/v1/").Subrouter()
|
authedApi := r.PathPrefix("/v1/").Subrouter()
|
||||||
authedApi.Use(auth.Middleware)
|
authedApi.Use(auth.Middleware)
|
||||||
|
@ -69,16 +75,18 @@ func (web *Web) routeSetup() http.Handler {
|
||||||
|
|
||||||
// curl 'http://127.0.0.1:8080/v1/test' -X POST -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/json;charset=utf-8' --data '{ "test": 1 }'
|
// curl 'http://127.0.0.1:8080/v1/test' -X POST -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/json;charset=utf-8' --data '{ "test": 1 }'
|
||||||
|
|
||||||
api.HandleFunc("/entries", web.allEntries).Methods(http.MethodGet)
|
authedApi.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost)
|
||||||
api.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost)
|
authedApi.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost).
|
||||||
api.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost).
|
|
||||||
HeadersRegexp("Content-Type", "application/(text|json).*")
|
HeadersRegexp("Content-Type", "application/(text|json).*")
|
||||||
api.HandleFunc("/entries", web.newMarkdownEntry).Methods(http.MethodPost).
|
authedApi.HandleFunc("/entries", web.newMarkdownEntry).Methods(http.MethodPost).
|
||||||
HeadersRegexp("Content-Type", "application/markdown.*")
|
HeadersRegexp("Content-Type", "application/markdown.*")
|
||||||
api.HandleFunc("/entries/{slug}", web.removeEntry).Methods(http.MethodDelete)
|
authedApi.HandleFunc("/entries/{slug}", web.removeEntry).Methods(http.MethodDelete)
|
||||||
api.HandleFunc("/entries/{slug}", web.editEntry).Methods(http.MethodPut)
|
authedApi.HandleFunc("/entries/{slug}", web.editEntry).Methods(http.MethodPut)
|
||||||
|
|
||||||
api.HandleFunc("/entries/{slug}", web.getEntry).Methods(http.MethodGet)
|
api.HandleFunc("/entries/{slug}", web.getEntry).Methods(http.MethodGet)
|
||||||
|
api.HandleFunc("/entries", web.allEntries).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
api.HandleFunc("/auth/new", web.newUser).Methods(http.MethodPost)
|
||||||
api.HandleFunc("/auth", web.auth).Methods(http.MethodPost)
|
api.HandleFunc("/auth", web.auth).Methods(http.MethodPost)
|
||||||
r.PathPrefix("/").HandlerFunc(web.indexHandler("/index.html"))
|
r.PathPrefix("/").HandlerFunc(web.indexHandler("/index.html"))
|
||||||
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
|
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
|
||||||
|
|
Loading…
Reference in New Issue