Actually use the auth middleware for assets routes
This commit is contained in:
parent
8da42184eb
commit
3664286506
@ -11,4 +11,9 @@
|
|||||||
|
|
||||||
# If empty then a derived static directory is used
|
# If empty then a derived static directory is used
|
||||||
staticProxyURL = "http://127.0.0.1:4002";
|
staticProxyURL = "http://127.0.0.1:4002";
|
||||||
|
|
||||||
|
# password is "bar". This should definitely be changed for prod.
|
||||||
|
apiAuthUsers = {
|
||||||
|
"foo" = "$2a$13$0JdWlUfHc.3XimEMpEu1cuu6RodhUvzD9l7iiAqa4YkM3mcFV5Pxi";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@
|
|||||||
# listening
|
# listening
|
||||||
export MEDIOCRE_BLOG_LISTEN_PROTO="${config.listenProto}"
|
export MEDIOCRE_BLOG_LISTEN_PROTO="${config.listenProto}"
|
||||||
export MEDIOCRE_BLOG_LISTEN_ADDR="${config.listenAddr}"
|
export MEDIOCRE_BLOG_LISTEN_ADDR="${config.listenAddr}"
|
||||||
|
|
||||||
|
# api
|
||||||
|
export MEDIOCRE_BLOG_API_AUTH_USERS='${builtins.toJSON config.apiAuthUsers}'
|
||||||
'';
|
'';
|
||||||
|
|
||||||
build = buildGoModule {
|
build = buildGoModule {
|
||||||
|
@ -54,6 +54,11 @@ type Params struct {
|
|||||||
// reverse-proxied there.
|
// reverse-proxied there.
|
||||||
StaticDir string
|
StaticDir string
|
||||||
StaticProxy *url.URL
|
StaticProxy *url.URL
|
||||||
|
|
||||||
|
// AuthUsers keys are usernames which are allowed to edit server-side data,
|
||||||
|
// and the values are the password hash which accompanies those users. The
|
||||||
|
// password hash must have been produced by NewPasswordHash.
|
||||||
|
AuthUsers map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupCfg implement the cfg.Cfger interface.
|
// SetupCfg implement the cfg.Cfger interface.
|
||||||
@ -176,6 +181,8 @@ func (a *api) handler() http.Handler {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auther := NewAuther(a.params.AuthUsers)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.Handle("/", staticHandler)
|
mux.Handle("/", staticHandler)
|
||||||
@ -209,8 +216,12 @@ func (a *api) handler() http.Handler {
|
|||||||
v2Mux.Handle("/assets/", http.StripPrefix("/assets",
|
v2Mux.Handle("/assets/", http.StripPrefix("/assets",
|
||||||
apiutil.MethodMux(map[string]http.Handler{
|
apiutil.MethodMux(map[string]http.Handler{
|
||||||
"GET": a.getPostAssetHandler(),
|
"GET": a.getPostAssetHandler(),
|
||||||
"POST": formMiddleware(a.postPostAssetHandler()),
|
"POST": authMiddleware(auther,
|
||||||
"DELETE": formMiddleware(a.deletePostAssetHandler()),
|
formMiddleware(a.postPostAssetHandler()),
|
||||||
|
),
|
||||||
|
"DELETE": authMiddleware(auther,
|
||||||
|
formMiddleware(a.deletePostAssetHandler()),
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
v2Mux.Handle("/", a.renderIndexHandler())
|
v2Mux.Handle("/", a.renderIndexHandler())
|
||||||
|
@ -3,13 +3,14 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/mediocregopher/blog.mediocregopher.com/srv/api/apiutil"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPasswordHash returns the hash of the given plaintext password, for use
|
// NewPasswordHash returns the hash of the given plaintext password, for use
|
||||||
// with Auther.
|
// with Auther.
|
||||||
func NewPasswordHash(plaintext string) string {
|
func NewPasswordHash(plaintext string) string {
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plaintext), 12)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plaintext), 13)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -48,9 +49,10 @@ func (a *auther) Allowed(username, password string) bool {
|
|||||||
|
|
||||||
func authMiddleware(auther Auther, h http.Handler) http.Handler {
|
func authMiddleware(auther Auther, h http.Handler) http.Handler {
|
||||||
|
|
||||||
respondUnauthorized := func(rw http.ResponseWriter) {
|
respondUnauthorized := func(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.Header().Set("WWW-Authenticate", `Basic realm="NOPE"`)
|
rw.Header().Set("WWW-Authenticate", `Basic realm="NOPE"`)
|
||||||
rw.WriteHeader(http.StatusUnauthorized)
|
rw.WriteHeader(http.StatusUnauthorized)
|
||||||
|
apiutil.GetRequestLogger(r).WarnString(r.Context(), "unauthorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
@ -58,12 +60,12 @@ func authMiddleware(auther Auther, h http.Handler) http.Handler {
|
|||||||
username, password, ok := r.BasicAuth()
|
username, password, ok := r.BasicAuth()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
respondUnauthorized(rw)
|
respondUnauthorized(rw, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !auther.Allowed(username, password) {
|
if !auther.Allowed(username, password) {
|
||||||
respondUnauthorized(rw)
|
respondUnauthorized(rw, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
srv/src/cmd/hash-password/main.go
Normal file
23
srv/src/cmd/hash-password/main.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mediocregopher/blog.mediocregopher.com/srv/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
fmt.Fprint(os.Stderr, "Password: ")
|
||||||
|
|
||||||
|
line, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(api.NewPasswordHash(strings.TrimSpace(line)))
|
||||||
|
}
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -55,6 +56,8 @@ func main() {
|
|||||||
|
|
||||||
pathPrefix := cfg.String("path-prefix", "", "Prefix which is optionally applied to all URL paths rendered by the blog")
|
pathPrefix := cfg.String("path-prefix", "", "Prefix which is optionally applied to all URL paths rendered by the blog")
|
||||||
|
|
||||||
|
apiAuthUsersStr := cfg.String("api-auth-users", "{}", "JSON object with usernames as values and password hashes (produced by the hash-password binary) as values. Denotes users which are able to edit server-side data")
|
||||||
|
|
||||||
// initialization
|
// initialization
|
||||||
err := cfg.Init(ctx)
|
err := cfg.Init(ctx)
|
||||||
|
|
||||||
@ -128,6 +131,11 @@ func main() {
|
|||||||
postStore := post.NewStore(postSQLDB)
|
postStore := post.NewStore(postSQLDB)
|
||||||
postAssetStore := post.NewAssetStore(postSQLDB)
|
postAssetStore := post.NewAssetStore(postSQLDB)
|
||||||
|
|
||||||
|
var apiAuthUsers map[string]string
|
||||||
|
if err := json.Unmarshal([]byte(*apiAuthUsersStr), &apiAuthUsers); err != nil {
|
||||||
|
logger.Fatal(ctx, "unmarshaling -api-auth-users", err)
|
||||||
|
}
|
||||||
|
|
||||||
apiParams.Logger = logger.WithNamespace("api")
|
apiParams.Logger = logger.WithNamespace("api")
|
||||||
apiParams.PowManager = powMgr
|
apiParams.PowManager = powMgr
|
||||||
apiParams.PathPrefix = *pathPrefix
|
apiParams.PathPrefix = *pathPrefix
|
||||||
@ -136,6 +144,7 @@ func main() {
|
|||||||
apiParams.MailingList = ml
|
apiParams.MailingList = ml
|
||||||
apiParams.GlobalRoom = chatGlobalRoom
|
apiParams.GlobalRoom = chatGlobalRoom
|
||||||
apiParams.UserIDCalculator = chatUserIDCalc
|
apiParams.UserIDCalculator = chatUserIDCalc
|
||||||
|
apiParams.AuthUsers = apiAuthUsers
|
||||||
|
|
||||||
logger.Info(ctx, "listening")
|
logger.Info(ctx, "listening")
|
||||||
a, err := api.New(apiParams)
|
a, err := api.New(apiParams)
|
||||||
|
Loading…
Reference in New Issue
Block a user