grim/containers/oauth-kludge
Clone
Summary
Browse
Changes
Graph
Initial proof of concept
2020-11-22, Gary Kramlich
dcbfc4fd58e8
Parents
Children
cfb3a5d491b7
Initial proof of concept
4 files changed, 154 insertions(+), 0 deletions(-)
+2
-0
.hgignore
+9
-0
go.mod
+15
-0
go.sum
+128
-0
main.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Sun Nov 22 03:42:38 2020 -0600
@@ -0,0 +1,2 @@
+syntax: glob
+oauth-kludge
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/go.mod Sun Nov 22 03:42:38 2020 -0600
@@ -0,0 +1,9 @@
+module keep.imfreedom.org/grim/oauth-kludge
+
+go 1.15
+
+require (
+ github.com/go-http-utils/logger v0.0.0-20161128092850-f3a42dcdeae6
+ github.com/kelseyhightower/envconfig v1.4.0
+ github.com/stretchr/testify v1.6.1 // indirect
+)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/go.sum Sun Nov 22 03:42:38 2020 -0600
@@ -0,0 +1,15 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-http-utils/logger v0.0.0-20161128092850-f3a42dcdeae6 h1:R/ypabUA7vskKTRSlgP6rMUHTU6PBRgIcHVSU9qQ6qM=
+github.com/go-http-utils/logger v0.0.0-20161128092850-f3a42dcdeae6/go.mod h1:CpBLxS3WrxouNECP/Y1A3i6qDnUYs8BvcXjgOW4Vqcw=
+github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
+github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.go Sun Nov 22 03:42:38 2020 -0600
@@ -0,0 +1,128 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "os/signal"
+ "strings"
+ "syscall"
+ "time"
+
+ "github.com/go-http-utils/logger"
+ "github.com/kelseyhightower/envconfig"
+)
+
+type config struct {
+ ListenAddr string `envconfig:"LISTEN_ADDR" default:":8080"`
+ Scope string `envconfig:"SCOPE" required:"true"`
+ TokenEndpoint *url.URL `envconfig:"TOKEN_ENDPOINT" required:"true"`
+}
+
+var cfg config
+var client *http.Client = &http.Client{Timeout: 5 * time.Second}
+
+func sendError(w http.ResponseWriter, err error, status int) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ w.Write([]byte(fmt.Sprintf("{\"error\":\"%v\"}", err)))
+}
+
+func copyHeader(src, dest http.Header, name string) {
+ if value, found := src[name]; found {
+ dest[name] = value
+ }
+}
+
+func kludge(target *url.URL, scope string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // parse the form
+ if err := r.ParseForm(); err != nil {
+ sendError(w, err, http.StatusBadRequest)
+ return
+ }
+
+ if _, found := r.Form["scope"]; !found {
+ r.Form.Set("scope", scope)
+ }
+
+ newBody := strings.NewReader(r.Form.Encode())
+ newRequest, err := http.NewRequest(r.Method, target.String(), newBody)
+ if err != nil {
+ sendError(w, err, http.StatusInternalServerError)
+ return
+ }
+
+ // Remove the User-Agent header
+ newRequest.Header.Set("User-Agent", "")
+
+ // Copy the Content-Type header
+ newRequest.Header.Set("Content-Type", r.Header.Get("Content-Type"))
+
+ resp, err := client.Do(newRequest)
+ if err != nil {
+ sendError(w, err, http.StatusInternalServerError)
+ return
+ }
+
+ src := resp.Header
+ dest := w.Header()
+ copyHeader(src, dest, "Content-Type")
+ copyHeader(src, dest, "Cache-Control")
+ copyHeader(src, dest, "Pragma")
+ w.WriteHeader(resp.StatusCode)
+
+ io.Copy(w, resp.Body)
+ resp.Body.Close()
+ })
+}
+
+func newServer() *http.Server {
+ handler := logger.Handler(
+ kludge(cfg.TokenEndpoint, cfg.Scope),
+ os.Stdout,
+ logger.CommonLoggerType,
+ )
+
+ return &http.Server{
+ Addr: cfg.ListenAddr,
+ Handler: handler,
+ ReadTimeout: 5 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ }
+}
+
+func main() {
+ err := envconfig.Process("OAUTH_KLUDGE", &cfg)
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ return
+ }
+
+ // create a signal channel for catching os signals
+ signalChan := make(chan os.Signal, 1)
+ signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
+
+ // create our error channel
+ errChan := make(chan error, 1)
+
+ server := newServer()
+ go func() {
+ defer server.Close()
+ fmt.Printf("Listening on %s\n", cfg.ListenAddr)
+ errChan <- server.ListenAndServe()
+ }()
+
+ for {
+ select {
+ case err := <-errChan:
+ fmt.Printf("error: %v\n", err)
+ return
+ case s := <-signalChan:
+ fmt.Printf("caught %v\n", s)
+ return
+ }
+ }
+}