aboutsummaryrefslogtreecommitdiff
path: root/server/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/handlers.go')
-rw-r--r--server/handlers.go167
1 files changed, 167 insertions, 0 deletions
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)
+ }
+}