demo-secure/main.go

103 lines
2.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"runtime/debug"
jwt "github.com/dgrijalva/jwt-go"
)
func signingKey() []byte {
if k := os.Getenv("JWT_KEY"); k != "" {
return []byte(k)
}
return []byte("demo-only-not-for-real-use")
}
type versionInfo struct {
Service string `json:"service"`
Commit string `json:"commit"`
GoVersion string `json:"go_version"`
Deps map[string]string `json:"deps"`
JWTLibrary string `json:"jwt_library"`
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", index)
mux.HandleFunc("/version", version)
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "ok")
})
mux.HandleFunc("/verify", verifyToken)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("demo-secure listening on :%s", port)
if err := http.ListenAndServe(":"+port, mux); err != nil {
log.Fatal(err)
}
}
func index(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, `<!doctype html>
<html><head><title>demo-secure</title></head>
<body style="font-family:sans-serif;max-width:40em;margin:3em auto">
<h1>demo-secure</h1>
<p>A minimal Go service used to demonstrate the RHADS supply chain:
RHDH onboarding &rarr; RHTAS signing &rarr; RHTPA scanning &rarr; patch.</p>
<ul>
<li><a href="/version">/version</a> &mdash; dependency info</li>
<li><a href="/healthz">/healthz</a> &mdash; liveness</li>
<li><code>POST /verify</code> with a Bearer token &mdash; exercises the JWT library</li>
</ul>
</body></html>`)
}
func version(w http.ResponseWriter, _ *http.Request) {
info := versionInfo{
Service: "demo-secure",
Commit: os.Getenv("GIT_COMMIT"),
Deps: map[string]string{},
}
if bi, ok := debug.ReadBuildInfo(); ok {
info.GoVersion = bi.GoVersion
for _, d := range bi.Deps {
info.Deps[d.Path] = d.Version
if d.Path == "github.com/dgrijalva/jwt-go" || d.Path == "github.com/golang-jwt/jwt/v5" {
info.JWTLibrary = fmt.Sprintf("%s@%s", d.Path, d.Version)
}
}
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(info)
}
func verifyToken(w http.ResponseWriter, r *http.Request) {
tok := r.Header.Get("Authorization")
if len(tok) > 7 && tok[:7] == "Bearer " {
tok = tok[7:]
}
if tok == "" {
http.Error(w, "missing bearer token", http.StatusUnauthorized)
return
}
parsed, err := jwt.Parse(tok, func(t *jwt.Token) (interface{}, error) {
return signingKey(), nil
})
if err != nil || !parsed.Valid {
http.Error(w, "invalid token", http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(parsed.Claims)
}