Repository: honeydipper/honeydipper
Pull request #554 (2023-07-01 16:26:12)

fix: correct web driver token_sources missing headers
#### Description
* add headers to the access_token request
* longest allowed token expiration time is 10 min
* token_sources should be under data in driver.Options

#### This PR fixes the following issues
<!--
Replace this comment with fixed issues in the following format:
Fixes #123
Fixes #124
-->



Patch:
diff --git a/drivers/cmd/web/token.go b/drivers/cmd/web/token.go
index 9a9cd0c..c84dd96 100644
--- a/drivers/cmd/web/token.go
+++ b/drivers/cmd/web/token.go
@@ -22,7 +22,7 @@ import (
 const globalGitHubURL = "https://api.github.com"
 
 func getToken(source string) string {
-	s := dipper.MustGetMapData(driver.Options, "token_sources."+source).(map[string]interface{})
+	s := dipper.MustGetMapData(driver.Options, "data.token_sources."+source).(map[string]interface{})
 	switch s["type"].(string) {
 	case "github":
 
@@ -34,20 +34,12 @@ func getToken(source string) string {
 	return ""
 }
 
-func getGitHubToken(s map[string]interface{}) string {
-	saved, ok := s["_saved"]
-	if ok {
-		exp := dipper.MustGetMapData(s, "_expiresAt").(time.Time)
-		//nolint: gomnd
-		if time.Now().Add(2 * time.Second).Before(exp) {
-			return saved.(string)
-		}
-	}
-
+func getGitHubJWT(s map[string]interface{}) (string, time.Time) {
 	//nolint: gomnd
-	expiresAt := time.Now().Add(time.Minute * 15)
+	expiresAt := time.Now().Add(time.Minute * 10).Truncate(time.Second)
 	claims := &jwt.RegisteredClaims{
-		IssuedAt:  jwt.NewNumericDate(time.Now().Add(-time.Minute * 1)),
+		//nolint: gomnd
+		IssuedAt:  jwt.NewNumericDate(time.Now().Add(-time.Second * 30).Truncate(time.Second)),
 		ExpiresAt: jwt.NewNumericDate(expiresAt),
 		Issuer:    s["app_id"].(string),
 	}
@@ -63,9 +55,25 @@ func getGitHubToken(s map[string]interface{}) string {
 	}
 	jwtTokenStr := dipper.Must(jwtToken.SignedString(pk)).(string)
 
+	return jwtTokenStr, expiresAt
+}
+
+func getGitHubToken(s map[string]interface{}) string {
+	saved, ok := s["_saved"]
+	if ok {
+		exp := dipper.MustGetMapData(s, "_expiresAt").(time.Time)
+		//nolint: gomnd
+		if time.Now().Add(2 * time.Second).Before(exp) {
+			return saved.(string)
+		}
+	}
+
+	jwtTokenStr, expiresAt := getGitHubJWT(s)
+
 	header := http.Header{}
-	header.Set("accept", "application/vnd.github+json")
-	header.Set("authorization", "Bearer "+jwtTokenStr)
+	header.Set("Accept", "application/vnd.github+json")
+	header.Set("Authorization", "Bearer "+jwtTokenStr)
+	dipper.Logger.Debugf("the gh jwt is %s", jwtTokenStr)
 
 	permissions := dipper.MustGetMapData(s, "permissions").(map[string]interface{})
 	contentBytes := dipper.Must(json.Marshal(map[string]interface{}{
@@ -79,13 +87,18 @@ func getGitHubToken(s map[string]interface{}) string {
 	if !ok {
 		u = globalGitHubURL
 	}
-	req := dipper.Must(http.NewRequest("POST", u.(string)+"/app/installations/"+instID+"/access_token", buf)).(*http.Request)
+	req := dipper.Must(http.NewRequest("POST", u.(string)+"/app/installations/"+instID+"/access_tokens", buf)).(*http.Request)
+	req.Header = header
 	client := http.Client{}
 	//nolint: bodyClose
 	resp := dipper.Must(client.Do(req)).(*http.Response)
 	defer resp.Body.Close()
-	if resp.StatusCode != http.StatusOK {
-		log.Panicf("[%s] failed to fetch github access token with status code %+v", driver.Service, resp.StatusCode)
+	if resp.StatusCode != http.StatusCreated {
+		log.Panicf("[%s] failed to fetch github access token with status code %+v, %+v",
+			driver.Service,
+			resp.StatusCode,
+			string(dipper.Must(io.ReadAll(resp.Body)).([]byte)),
+		)
 	}
 
 	bodyObj := map[string]interface{}{}
diff --git a/go.mod b/go.mod
index 641678e..20fec00 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
 	cloud.google.com/go/spanner v1.45.0
 	cloud.google.com/go/storage v1.29.0
 	github.com/DataDog/datadog-go v4.8.3+incompatible
-	github.com/Masterminds/goutils v1.1.1 // indirect
+	github.com/Masterminds/goutils v1.1.1
 	github.com/casbin/casbin/v2 v2.41.0
 	github.com/ghodss/yaml v1.0.0
 	github.com/gin-gonic/gin v1.9.1


Test patch:
diff --git a/drivers/cmd/web/token_test.go b/drivers/cmd/web/token_test.go
index af1f73a..572e669 100644
--- a/drivers/cmd/web/token_test.go
+++ b/drivers/cmd/web/token_test.go
@@ -25,7 +25,7 @@ func TestGetToken(t *testing.T) {
 
 	gock.New("https://api.github.com").
 		Post("/app/installations/123/access_token").
-		Reply(200).
+		Reply(201).
 		JSON(map[string]string{"token": "foobar"})
 
 	keyb64 := dipper.Must(ioutil.ReadFile("test_fixtures/testkey")).([]byte)
@@ -42,8 +42,10 @@ func TestGetToken(t *testing.T) {
 	}
 
 	driver.Options = map[string]interface{}{
-		"token_sources": map[string]interface{}{
-			"test1": githubSource,
+		"data": map[string]interface{}{
+			"token_sources": map[string]interface{}{
+				"test1": githubSource,
+			},
 		},
 	}
 
@@ -60,7 +62,7 @@ func TestGetToken(t *testing.T) {
 
 	gock.New("https://api.github.com").
 		Post("/app/installations/123/access_token").
-		Reply(200).
+		Reply(201).
 		JSON(map[string]string{"token": "foobar2"})
 
 	githubSource["_expiresAt"] = time.Now().Add(-time.Minute * 15)
@@ -69,7 +71,7 @@ func TestGetToken(t *testing.T) {
 
 	gock.New("https://api.github.com").
 		Post("/app/installations/123/access_token").
-		Reply(200).
+		Reply(201).
 		JSON(map[string]string{"token": "foobar3"})
 
 	githubSource["_expiresAt"] = time.Now().Add(-time.Minute * 15)