From 99225736d41e86c7f47eac4db3455b18178bba24 Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Mon, 20 Aug 2018 16:41:17 +0100 Subject: Make all handlers methods of app Merge server setup and helpers from web.go into server.go Handlers moved to handlers.go --- server/handlers.go | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 server/handlers.go (limited to 'server/handlers.go') diff --git a/server/handlers.go b/server/handlers.go new file mode 100644 index 0000000..b85550d --- /dev/null +++ b/server/handlers.go @@ -0,0 +1,167 @@ +package server + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "html/template" + "io" + "log" + "net/http" + "strconv" + "strings" + + "github.com/gorilla/csrf" + "github.com/nsheridan/cashier/lib" + "github.com/nsheridan/cashier/server/templates" + "github.com/pkg/errors" + "golang.org/x/oauth2" +) + +func (a *app) sign(w http.ResponseWriter, r *http.Request) { + var t string + if ah := r.Header.Get("Authorization"); ah != "" { + if len(ah) > 6 && strings.ToUpper(ah[0:7]) == "BEARER " { + t = ah[7:] + } + } + + token := &oauth2.Token{ + AccessToken: t, + } + if !a.authprovider.Valid(token) { + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprint(w, http.StatusText(http.StatusUnauthorized)) + return + } + + // Sign the pubkey and issue the cert. + req := &lib.SignRequest{} + if err := json.NewDecoder(r.Body).Decode(req); err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusBadRequest) + fmt.Fprint(w, http.StatusText(http.StatusBadRequest)) + return + } + + if a.requireReason && req.Message == "" { + w.Header().Add("X-Need-Reason", "required") + w.WriteHeader(http.StatusForbidden) + fmt.Fprint(w, http.StatusText(http.StatusForbidden)) + return + } + + username := a.authprovider.Username(token) + a.authprovider.Revoke(token) // We don't need this anymore. + cert, err := a.keysigner.SignUserKey(req, username) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error signing key") + return + } + if err := a.certstore.SetCert(cert); err != nil { + log.Printf("Error recording cert: %v", err) + } + if err := json.NewEncoder(w).Encode(&lib.SignResponse{ + Status: "ok", + Response: string(lib.GetPublicKey(cert)), + }); err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error signing key") + return + } +} + +func (a *app) auth(w http.ResponseWriter, r *http.Request) { + switch r.URL.EscapedPath() { + case "/auth/login": + buf := make([]byte, 32) + io.ReadFull(rand.Reader, buf) + state := hex.EncodeToString(buf) + a.setSessionVariable(w, r, "state", state) + http.Redirect(w, r, a.authprovider.StartSession(state), http.StatusFound) + case "/auth/callback": + state := a.getSessionVariable(r, "state") + if r.FormValue("state") != state { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(http.StatusText(http.StatusUnauthorized))) + break + } + originURL := a.getSessionVariable(r, "origin_url") + if originURL == "" { + originURL = "/" + } + code := r.FormValue("code") + token, err := a.authprovider.Exchange(code) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(http.StatusText(http.StatusInternalServerError))) + w.Write([]byte(err.Error())) + break + } + a.setAuthToken(w, r, token) + http.Redirect(w, r, originURL, http.StatusFound) + default: + w.WriteHeader(http.StatusInternalServerError) + } +} + +func (a *app) index(w http.ResponseWriter, r *http.Request) { + tok := a.getAuthToken(r) + page := struct { + Token string + }{tok.AccessToken} + page.Token = encodeString(page.Token) + tmpl := template.Must(template.New("token.html").Parse(templates.Token)) + tmpl.Execute(w, page) +} + +func (a *app) revoked(w http.ResponseWriter, r *http.Request) { + revoked, err := a.certstore.GetRevoked() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, errors.Wrap(err, "error retrieving revoked certs").Error()) + return + } + rl, err := a.keysigner.GenerateRevocationList(revoked) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, errors.Wrap(err, "unable to generate KRL").Error()) + return + } + w.Header().Set("Content-Type", "application/octet-stream") + w.Write(rl) +} + +func (a *app) getAllCerts(w http.ResponseWriter, r *http.Request) { + tmpl := template.Must(template.New("certs.html").Parse(templates.Certs)) + tmpl.Execute(w, map[string]interface{}{ + csrf.TemplateTag: csrf.TemplateField(r), + }) +} + +func (a *app) getCertsJSON(w http.ResponseWriter, r *http.Request) { + includeExpired, _ := strconv.ParseBool(r.URL.Query().Get("all")) + certs, err := a.certstore.List(includeExpired) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, http.StatusText(http.StatusInternalServerError)) + return + } + if err := json.NewEncoder(w).Encode(certs); err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, http.StatusText(http.StatusInternalServerError)) + return + } +} + +func (a *app) revoke(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if err := a.certstore.Revoke(r.Form["cert_id"]); err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Unable to revoke certs")) + } else { + http.Redirect(w, r, "/admin/certs", http.StatusSeeOther) + } +} -- cgit v1.2.3