diff --git a/main.go b/main.go index 577bbfc..6576a93 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ package main import ( "bytes" "crypto/sha1" + "crypto/sha256" "encoding/json" "errors" "fmt" @@ -184,21 +185,42 @@ func handleOAuthCallback(res http.ResponseWriter, r *http.Request) { func handleCodesJSON(res http.ResponseWriter, r *http.Request) { sess, _ := cookieStore.Get(r, sessionName) iAccessToken, hasAccessToken := sess.Values["access_token"] + iToken := sess.Values["vault_token"] if !hasAccessToken { http.Error(res, `{"error":"Not logged in"}`, http.StatusUnauthorized) return } - accessToken := iAccessToken.(string) - tokens, err := getSecretsFromVault(accessToken) + var tok string + if iToken != nil { + tok = iToken.(string) + log.WithFields(log.Fields{"token": hashSecret(tok)}).Debugf("Restored token from Session") + } + + tok, err := useOrRenewToken(tok, accessToken) + if err != nil { + log.Errorf("Unable to authorize against vault: %s", err) + http.Error(res, `{"error":"Unexpected error while fetching tokens"}`, http.StatusInternalServerError) + return + } + log.WithFields(log.Fields{"token": hashSecret(tok)}).Debugf("Checked / renewed token") + + tokens, err := getSecretsFromVault(tok) if err != nil { log.Errorf("Unable to fetch codes: %s", err) http.Error(res, `{"error":"Unexpected error while fetching tokens"}`, http.StatusInternalServerError) return } + sess.Values["vault_token"] = tok + if err := sess.Save(r, res); err != nil { + log.Errorf("Was not able to set the cookie: %s", err) + http.Error(res, "Something went wrong while fetching token. Sorry.", http.StatusInternalServerError) + return + } + n := time.Now() result := struct { Tokens []*token `json:"tokens"` @@ -230,3 +252,7 @@ func handleStatics(res http.ResponseWriter, r *http.Request) { res.Header().Set("Content-Type", t) res.Write(b) } + +func hashSecret(in string) string { + return fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(in))) +} diff --git a/token.go b/token.go index e7bc539..76596a5 100644 --- a/token.go +++ b/token.go @@ -8,9 +8,9 @@ import ( "sync" "time" + log "github.com/Sirupsen/logrus" "github.com/hashicorp/vault/api" "github.com/pquerna/otp/totp" - "github.com/prometheus/common/log" ) type token struct { @@ -50,7 +50,36 @@ func (t tokenList) LongestName() (l int) { return } -func getSecretsFromVault(accessToken string) ([]*token, error) { +func useOrRenewToken(tok, accessToken string) (string, error) { + client, err := api.NewClient(&api.Config{ + Address: cfg.Vault.Address, + }) + + if err != nil { + return "", fmt.Errorf("Unable to create client: %s", err) + } + + if tok != "" { + client.SetToken(tok) + if s, err := client.Auth().Token().LookupSelf(); err == nil && s.Data != nil { + log.WithFields(log.Fields{"token": hashSecret(tok)}).Debugf("Token is valid for another %vs", s.Data["ttl"]) + return tok, nil + } else { + log.WithFields(log.Fields{"token": hashSecret(tok)}).Debugf("Token did not met requirements: err = %s", err) + if s != nil { + log.WithFields(log.Fields{"token": hashSecret(tok)}).Debugf("Token did not met requirements: data = %v", s.Data) + } + } + } + + if s, err := client.Logical().Write("auth/github/login", map[string]interface{}{"token": accessToken}); err != nil || s.Auth == nil { + return "", fmt.Errorf("Login did not work: Error = %s", err) + } else { + return s.Auth.ClientToken, nil + } +} + +func getSecretsFromVault(tok string) ([]*token, error) { client, err := api.NewClient(&api.Config{ Address: cfg.Vault.Address, }) @@ -59,11 +88,7 @@ func getSecretsFromVault(accessToken string) ([]*token, error) { return nil, fmt.Errorf("Unable to create client: %s", err) } - if s, err := client.Logical().Write("auth/github/login", map[string]interface{}{"token": accessToken}); err != nil || s.Auth == nil { - return nil, fmt.Errorf("Login did not work: Error = %s", err) - } else { - client.SetToken(s.Auth.ClientToken) - } + client.SetToken(tok) key := cfg.Vault.Prefix