From 3a3acc4673ec21a3c8c88798e786948374e3e793 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Tue, 30 Mar 2021 21:59:18 +0100 Subject: [PATCH] twitterchiver/viewer: swap openshiftauth for pomerium --- go/default.nix | 1 - go/go.mod | 1 + go/go.sum | 11 + go/openshiftauth/default.nix | 28 -- go/openshiftauth/example/example.go | 34 --- go/openshiftauth/openshiftauth.go | 285 ------------------ go/twitterchiver/default.nix | 2 +- go/twitterchiver/viewer/viewer.go | 58 +++- .../github.com/pomerium/sdk-go/default.nix | 18 ++ .../gopkg.in/square/go-jose.v2/default.nix | 18 ++ 10 files changed, 95 insertions(+), 361 deletions(-) delete mode 100644 go/openshiftauth/default.nix delete mode 100644 go/openshiftauth/example/example.go delete mode 100644 go/openshiftauth/openshiftauth.go create mode 100644 third_party/gopkgs/github.com/pomerium/sdk-go/default.nix create mode 100644 third_party/gopkgs/gopkg.in/square/go-jose.v2/default.nix diff --git a/go/default.nix b/go/default.nix index d55805b5f7..33a3520db8 100644 --- a/go/default.nix +++ b/go/default.nix @@ -5,6 +5,5 @@ args: { twitterchiver = import ./twitterchiver args; twitternuke = import ./twitternuke args; - openshiftauth = import ./openshiftauth args; minotarproxy = import ./minotarproxy args; } diff --git a/go/go.mod b/go/go.mod index d515bfa4db..fa79e3c283 100644 --- a/go/go.mod +++ b/go/go.mod @@ -16,5 +16,6 @@ require ( github.com/gorilla/sessions v1.2.1 github.com/jackc/pgtype v1.4.2 github.com/jackc/pgx/v4 v4.8.1 + github.com/pomerium/sdk-go v0.0.5 // indirect golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 ) diff --git a/go/go.sum b/go/go.sum index 28d5638003..24e418c352 100644 --- a/go/go.sum +++ b/go/go.sum @@ -32,6 +32,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -127,6 +128,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pomerium/sdk-go v0.0.5 h1:8iJg/uZ7AmhGfHvmHmpZOswzg9MDMcmpTMX0zpmDxxs= +github.com/pomerium/sdk-go v0.0.5/go.mod h1:z4HXhKxVTIQqmffpjQP6Oi+oP9r37a0Kx/jq69jcNRo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -145,6 +148,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -163,6 +167,8 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -201,8 +207,10 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -242,8 +250,11 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go/openshiftauth/default.nix b/go/openshiftauth/default.nix deleted file mode 100644 index 276f5c6a63..0000000000 --- a/go/openshiftauth/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Luke Granger-Brown -# -# SPDX-License-Identifier: Apache-2.0 - -{ depot, ... }: { - openshiftauth = depot.third_party.buildGo.package { - name = "hg.lukegb.com/lukegb/depot/go/openshiftauth"; - srcs = [ ./openshiftauth.go ]; - deps = with depot.third_party; [ - gopkgs."github.com".dghubble.gologin.v2 - gopkgs."github.com".dghubble.gologin.v2.oauth2 - gopkgs."github.com".dgrijalva.jwt-go - gopkgs."github.com".gorilla.mux - gopkgs."github.com".gorilla.securecookie - gopkgs."github.com".gorilla.sessions - gopkgs."golang.org".x.oauth2 - ]; - }; - - example = depot.third_party.buildGo.program { - name = "example"; - srcs = [ ./example/example.go ]; - deps = with depot.third_party; [ - depot.go.openshiftauth.openshiftauth - gopkgs."github.com".gorilla.mux - ]; - }; -} diff --git a/go/openshiftauth/example/example.go b/go/openshiftauth/example/example.go deleted file mode 100644 index c65ca85bdd..0000000000 --- a/go/openshiftauth/example/example.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - - "github.com/gorilla/mux" - "hg.lukegb.com/lukegb/depot/go/openshiftauth" -) - -func main() { - r := mux.NewRouter() - authR, err := openshiftauth.NewRouter(r) - if err != nil { - log.Fatalf("openshiftauth.NewRouter: %v", err) - } - - authR.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { - u := openshiftauth.UserFromContext(r.Context()) - rw.Header().Set("Content-Type", "application/json") - enc := json.NewEncoder(rw) - enc.SetIndent("", " ") - enc.Encode(u) - }) - r.HandleFunc("/healthz", func(rw http.ResponseWriter, r *http.Request) { - rw.Header().Set("Content-Type", "text/plain") - fmt.Fprintf(rw, "ok") - }) - - http.Handle("/", r) - http.ListenAndServe(":8080", nil) -} diff --git a/go/openshiftauth/openshiftauth.go b/go/openshiftauth/openshiftauth.go deleted file mode 100644 index 19f0afca1c..0000000000 --- a/go/openshiftauth/openshiftauth.go +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-FileCopyrightText: 2020 Luke Granger-Brown -// -// SPDX-License-Identifier: Apache-2.0 -package openshiftauth - -import ( - "context" - "encoding/gob" - "encoding/hex" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net/http" - "net/url" - "os" - - "github.com/dghubble/gologin/v2" - "github.com/dghubble/gologin/v2/oauth2" - "github.com/dgrijalva/jwt-go" - "github.com/gorilla/mux" - "github.com/gorilla/securecookie" - "github.com/gorilla/sessions" - xoauth2 "golang.org/x/oauth2" -) - -type SecretGetter func(ctx context.Context) (string, error) - -func TokenDirSecretGetter(ctx context.Context) (string, error) { - v, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") - if err != nil { - return "", fmt.Errorf("couldn't read serviceaccount secret: %w", err) - } - return string(v), nil -} - -type BaseHandler struct { - Config xoauth2.Config - SecretGetter SecretGetter -} - -func (h *BaseHandler) config(ctx context.Context) (*xoauth2.Config, error) { - s, err := h.SecretGetter(ctx) - if err != nil { - return nil, err - } - cfg := h.Config - cfg.ClientSecret = s - return &cfg, nil -} - -func (h *BaseHandler) wrapWithConfig(f func(cfg *xoauth2.Config) http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - cfg, err := h.config(r.Context()) - if err != nil { - http.Error(rw, err.Error(), http.StatusInternalServerError) - return - } - f(cfg).ServeHTTP(rw, r) - }) -} - -func (h *BaseHandler) CallbackHandler(success, failure http.Handler) http.Handler { - return h.wrapWithConfig(func(cfg *xoauth2.Config) http.Handler { - return oauth2.CallbackHandler(cfg, success, failure) - }) -} - -func (h *BaseHandler) LoginHandler(failure http.Handler) http.Handler { - return h.wrapWithConfig(func(cfg *xoauth2.Config) http.Handler { - return oauth2.LoginHandler(cfg, failure) - }) -} - -type contextKey string - -const ( - sessionContextKey contextKey = "session" -) - -func AttachSessionMiddleware(sess sessions.Store) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - s, err := sess.Get(r, "openshiftauth") - if err != nil { - log.Printf("decoding session: %v", err) - } - ctx := context.WithValue(r.Context(), sessionContextKey, s) - next.ServeHTTP(w, r.WithContext(ctx)) - }) - } -} - -func Session(ctx context.Context) *sessions.Session { - return ctx.Value(sessionContextKey).(*sessions.Session) -} - -func UserFromContext(ctx context.Context) *User { - s := Session(ctx) - if s.Values["user"] != nil { - return s.Values["user"].(*User) - } - return nil -} - -func secretFromEnv(name string, length int) []byte { - var bs []byte - if bsHex, ok := os.LookupEnv(name); ok { - newBS, err := hex.DecodeString(bsHex) - if err != nil { - log.Printf("failed to decode %v as hex: %v", name, err) - } else { - bs = newBS - } - } - if bs == nil { - log.Printf("generating a random %v: this is bad", name) - bs = securecookie.GenerateRandomKey(length) - } - return bs -} - -type User struct { - Metadata struct { - Name string `json:"name"` - } `json:"metadata"` - FullName string `json:"fullName"` - Identities []string `json:"identities"` - Groups []string `json:"groups"` -} - -func init() { - gob.Register(&User{}) -} - -func fetchUserForToken(ctx context.Context, token *xoauth2.Token) (*User, error) { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.k8s.lukegb.tech:6443/apis/user.openshift.io/v1/users/~", nil) - if err != nil { - return nil, fmt.Errorf("http.NewRequestWithContext for users/~ failed") - } - token.SetAuthHeader(req) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, fmt.Errorf("executing request for users/~ failed: %v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("openshift returned non-OK status %d %v", resp.StatusCode, resp.Status) - } - - var u User - if err := json.NewDecoder(resp.Body).Decode(&u); err != nil { - return nil, fmt.Errorf("decoding response from openshift: %v", err) - } - - return &u, nil -} - -func RequireAuth(next http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - u := UserFromContext(r.Context()) - if u == nil { - redirURL := r.URL.ResolveReference(r.URL) - redirURL.Path = "/.login/start" - redirURL.RawQuery = url.Values{ - "next": []string{r.URL.String()}, - }.Encode() - http.Redirect(rw, r, redirURL.String(), http.StatusSeeOther) - return - } - next.ServeHTTP(rw, r) - }) -} - -type serviceAccountDetails struct { - Namespace string `json:"kubernetes.io/serviceaccount/namespace"` - Name string `json:"kubernetes.io/serviceaccount/service-account.name"` - FullName string `json:"sub"` -} - -func parseServiceAccount() (*serviceAccountDetails, error) { - token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") - if err != nil { - return nil, fmt.Errorf("reading service account JWT: %w", err) - } - - // ParseUnverified is safe here because we're just using it to extract information about ourselves. - p := &jwt.Parser{} - claims := make(jwt.MapClaims) - if _, _, err := p.ParseUnverified(string(token), claims); err != nil { - return nil, fmt.Errorf("parsing JWT: %w", err) - } - val := func(s string) string { - v, ok := claims[s] - if !ok { - return "" - } - return v.(string) - } - sad := &serviceAccountDetails{ - Namespace: val("kubernetes.io/serviceaccount/namespace"), - Name: val("kubernetes.io/serviceaccount/service-account.name"), - FullName: val("sub"), - } - return sad, nil -} - -func NewRouter(r *mux.Router) (*mux.Router, error) { - sess := sessions.NewCookieStore( - secretFromEnv("OPENSHIFT_AUTH_SESSION_SIGN_SECRET", 32), - secretFromEnv("OPENSHIFT_AUTH_SESSION_ENC_SECRET", 32)) - r.Use(AttachSessionMiddleware(sess)) - - sad, err := parseServiceAccount() - if err != nil { - return nil, fmt.Errorf("loading service account information: %w", err) - } - log.Printf("using service account token for %v", sad.FullName) - - bh := &BaseHandler{ - Config: xoauth2.Config{ - ClientID: sad.FullName, - Endpoint: xoauth2.Endpoint{ - AuthURL: "https://oauth-openshift.apps.k8s.lukegb.tech/oauth/authorize", - TokenURL: "https://oauth-openshift.apps.k8s.lukegb.tech/oauth/token", - }, - RedirectURL: fmt.Sprintf("%s/.login/callback", os.Getenv("OPENSHIFT_AUTH_BASE")), - Scopes: []string{"user:info"}, - }, - SecretGetter: TokenDirSecretGetter, - } - baseURL, err := url.Parse(os.Getenv("OPENSHIFT_AUTH_BASE")) - if err != nil { - return nil, fmt.Errorf("failed to parse OPENSHIFT_AUTH_BASE as URL: %v", err) - } - stateConfig := gologin.DefaultCookieConfig - r.HandleFunc("/.login/start", func(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - if nextURL, err := url.Parse(r.URL.Query().Get("next")); err == nil { - nextURL = baseURL.ResolveReference(nextURL) - if nextURL.Scheme != baseURL.Scheme || nextURL.User != nil || nextURL.Host != baseURL.Host { - nextURL = nil - } - if nextURL != nil { - s := Session(ctx) - s.AddFlash(nextURL.RequestURI(), "_openshiftauth_next") - sessions.Save(r, rw) - } - } - oauth2.StateHandler(stateConfig, bh.LoginHandler(nil)).ServeHTTP(rw, r) - }) - r.Handle("/.login/callback", oauth2.StateHandler(stateConfig, bh.CallbackHandler( - http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - token, err := oauth2.TokenFromContext(ctx) - if err != nil { - http.Error(rw, "oauth2 TokenFromContext failed", http.StatusBadRequest) - return - } - - u, err := fetchUserForToken(ctx, token) - if err != nil { - http.Error(rw, fmt.Sprintf("fetchUserForToken: %v", err), http.StatusInternalServerError) - return - } - - s := Session(ctx) - s.Values["user"] = *u - sessions.Save(r, rw) - - next := "/" - nexts := s.Flashes("_openshiftauth_next") - if len(nexts) >= 1 { - next = nexts[0].(string) - } - http.Redirect(rw, r, next, http.StatusFound) - }), - nil))) - - authR := r.PathPrefix("/").Subrouter() - authR.Use(RequireAuth) - - return authR, nil -} diff --git a/go/twitterchiver/default.nix b/go/twitterchiver/default.nix index fc0c82bc6c..6872f2c142 100644 --- a/go/twitterchiver/default.nix +++ b/go/twitterchiver/default.nix @@ -22,7 +22,7 @@ depot.third_party.gopkgs."github.com".gorilla.mux depot.third_party.gopkgs."github.com".jackc.pgtype depot.third_party.gopkgs."github.com".jackc.pgx.v4.pgxpool - depot.go.openshiftauth.openshiftauth + depot.third_party.gopkgs."github.com".pomerium.sdk-go ]; dockerData = [ ( depot.pkgs.runCommand "source" {} '' diff --git a/go/twitterchiver/viewer/viewer.go b/go/twitterchiver/viewer/viewer.go index 096dd85ace..a531fc56e9 100644 --- a/go/twitterchiver/viewer/viewer.go +++ b/go/twitterchiver/viewer/viewer.go @@ -23,7 +23,7 @@ import ( "github.com/gorilla/mux" "github.com/jackc/pgtype" "github.com/jackc/pgx/v4/pgxpool" - "hg.lukegb.com/lukegb/depot/go/openshiftauth" + pomerium "github.com/pomerium/sdk-go" ) var ( @@ -100,6 +100,17 @@ func bestVariant(vs []interface{}) interface{} { return bestVariant } +type mapDatastore map[interface{}]interface{} + +func (ds mapDatastore) Get(key interface{}) (value interface{}, ok bool) { + value, ok = ds[key] + return value, ok +} + +func (ds mapDatastore) Add(key, value interface{}) { + ds[key] = value +} + func main() { flag.Parse() ctx := context.Background() @@ -117,20 +128,30 @@ func main() { }) var authR *mux.Router - if *localDisableAuth != "" { - authR = r - } else { - authR, err = openshiftauth.NewRouter(r) + var v *pomerium.Verifier + if *localDisableAuth == "" { + authR = r.PathPrefix("/").Subrouter() + var err error + v, err = pomerium.New(&pomerium.Options{ + JWKSEndpoint: "https://auth.int.lukegb.com/.well-known/pomerium/jwks.json", + Datastore: mapDatastore{}, + }) if err != nil { - log.Fatalf("openshiftauth.NewRouter: %v", err) + log.Fatalf("pomerium.New: %v", err) } + authR.Use(pomerium.AddIdentityToRequest(v)) } + authR = r - userFromContext := func(ctx context.Context) string { + userFromContext := func(ctx context.Context) (string, error) { if *localDisableAuth != "" { - return *localDisableAuth + return *localDisableAuth, nil } - return openshiftauth.UserFromContext(ctx).Metadata.Name + identity, err := pomerium.FromContext(ctx) + if err != nil { + return "", err + } + return identity.User, nil } writeError := func(rw http.ResponseWriter, status int, wrap string, err error) { @@ -143,7 +164,11 @@ func main() { authR.PathPrefix("/media/").Handler(http.StripPrefix("/media/", http.FileServer(http.Dir(*mediaDirectory)))) authR.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() - user := userFromContext(ctx) + user, err := userFromContext(ctx) + if err != nil { + http.Error(rw, fmt.Errorf("userFromContext: %w", err).Error(), http.StatusInternalServerError) + return + } twitterAccounts := userMapping[user] var allTweets, timelineTweets, unfetchedMedia, unfetchedRelated int @@ -214,7 +239,11 @@ ORDER BY 1 }) }) isAllowedToSee := func(ctx context.Context, twitterUser string) bool { - twitterAccounts := userMapping[userFromContext(ctx)] + user, err := userFromContext(ctx) + if err != nil { + return false + } + twitterAccounts := userMapping[user] for _, a := range twitterAccounts { if a == twitterUser { return true @@ -241,8 +270,13 @@ ORDER BY 1 ctx := r.Context() vars := mux.Vars(r) twitterUser := vars["twitterUser"] + user, err := userFromContext(ctx) + if err != nil { + http.Error(rw, fmt.Errorf("userFromContext: %w", err).Error(), http.StatusInternalServerError) + return + } if !isAllowedToSee(ctx, twitterUser) { - writeError(rw, http.StatusNotFound, "no such twitter user being archived", fmt.Errorf("user %q attempted to access %q", userFromContext(ctx), twitterUser)) + writeError(rw, http.StatusNotFound, "no such twitter user being archived", fmt.Errorf("user %q attempted to access %q", user, twitterUser)) return } diff --git a/third_party/gopkgs/github.com/pomerium/sdk-go/default.nix b/third_party/gopkgs/github.com/pomerium/sdk-go/default.nix new file mode 100644 index 0000000000..5ec21f3a9d --- /dev/null +++ b/third_party/gopkgs/github.com/pomerium/sdk-go/default.nix @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2020 Luke Granger-Brown +# +# SPDX-License-Identifier: Apache-2.0 + +{ depot, ... }: +depot.third_party.buildGo.external { + path = "github.com/pomerium/sdk-go"; + src = depot.third_party.nixpkgs.fetchFromGitHub { + owner = "pomerium"; + repo = "sdk-go"; + rev = "v0.0.5"; + hash = "sha256:08sa6jzixw09w519lr69wb69z7hx1158jbji9kh6f9wvxp0ny9lw"; + }; + deps = with depot.third_party; [ + gopkgs."gopkg.in".square."go-jose.v2" + gopkgs."gopkg.in".square."go-jose.v2".jwt + ]; +} diff --git a/third_party/gopkgs/gopkg.in/square/go-jose.v2/default.nix b/third_party/gopkgs/gopkg.in/square/go-jose.v2/default.nix new file mode 100644 index 0000000000..d75de694c8 --- /dev/null +++ b/third_party/gopkgs/gopkg.in/square/go-jose.v2/default.nix @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2020 Luke Granger-Brown +# +# SPDX-License-Identifier: Apache-2.0 + +{ depot, ... }: +depot.third_party.buildGo.external { + path = "gopkg.in/square/go-jose.v2"; + src = depot.third_party.nixpkgs.fetchFromGitHub { + owner = "square"; + repo = "go-jose"; + rev = "v2.5.1"; + hash = "sha256:0z0hbmb5yyvnjkyiyn259wkbqbjxs2pzx87jz472shn2bgggxa4n"; + }; + deps = with depot.third_party; [ + gopkgs."golang.org".x.crypto.ed25519 + gopkgs."golang.org".x.crypto.pbkdf2 + ]; +}