1

Please see my code below. As you can see it's a simple service with two endpoints:

  1. /test <-- basic auth protected using middleware
  2. /static <-- serves all the files in the ./static directory

Now I'm trying to add the basic authentication middleware pattern to the /static endpoint as well, but for some reason I can't figure out how. I'm having trouble converting the *route (the outcome of r.PathPrefix) to something the middleware() function understands. (I've also created a playground, but due to the external import, this won't work)

package main

import (
    "encoding/base64"
    "log"
    "net/http"
    "strings"

    "github.com/gorilla/mux"
)

const (
    username = "test"
    password = "test"
)

func main() {
    r := mux.NewRouter()

    // add normal endpoint
    r.HandleFunc("/test", middleWare(myHandler, basicAuth))

    // add static
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

    srv := &http.Server{
        Handler: r,
        Addr:    "0.0.0.0:8080",
    }

    log.Print("listening on 0.0.0.0:8080")
    log.Fatal(srv.ListenAndServe())
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("yes!"))
    return
}

func middleWare(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
    for _, m := range middleware {
        h = m(h)
    }

    return h
}

func basicAuth(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)

        s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
        if len(s) != 2 {
            http.Error(w, "Not authorized", 401)
            return
        }

        b, err := base64.StdEncoding.DecodeString(s[1])
        if err != nil {
            http.Error(w, err.Error(), 401)
            return
        }

        pair := strings.SplitN(string(b), ":", 2)
        if len(pair) != 2 {
            http.Error(w, "Not authorized", 401)
            return
        }

        if pair[0] != username || pair[1] != password {
            http.Error(w, "Not authorized", 401)
            return
        }

        h.ServeHTTP(w, r)
    }
}
Rogier Lommers
  • 2,263
  • 3
  • 24
  • 38
  • The quoted code doesn't appear to be attempting to apply the middleware to basic auth - can you show the code you're trying to use? – Adrian Jun 14 '18 at 18:45
  • Well, that's exactly my problem: I don't know how to refactor the static handler in a way that it's using the middleware pattern. – Rogier Lommers Jun 14 '18 at 18:46
  • Exactly the same way as the dynamic handler. `http.FileServer` returns a `http.Handler`, it works the same as any other handler. – Adrian Jun 14 '18 at 18:47
  • The reason I ask for the code that isn't working is because your question stated you attemped something that didn't work - seeing what didn't work, rather than code that doesn't attempt your goal at all, is more useful for helping to troubleshoot. – Adrian Jun 14 '18 at 18:49
  • I tried this: `r.HandleFunc("/static", middleWare(r.PathPrefix("/static/").Handler(staticHandler), basicAuth))` but then it complains about the fact that *mux.Route isn't a http.HandleFunc. So how do I convert/wrap it? I seriously have no idea. – Rogier Lommers Jun 14 '18 at 18:59

1 Answers1

1

Well, turns out I used an ancient version of mux, which was lacking the use() function :).

Rogier Lommers
  • 2,263
  • 3
  • 24
  • 38