2
0
Alexander Belanger 5 жил өмнө
parent
commit
d02285ca54

+ 2 - 0
go.mod

@@ -13,6 +13,7 @@ require (
 	github.com/containerd/containerd v1.4.1 // indirect
 	github.com/coreos/rkt v1.30.0
 	github.com/creack/pty v1.1.11 // indirect
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/digitalocean/godo v1.56.0
 	github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492
 	github.com/docker/distribution v2.7.1+incompatible
@@ -31,6 +32,7 @@ require (
 	github.com/go-test/deep v1.0.7
 	github.com/google/go-cmp v0.5.2
 	github.com/google/go-github v17.0.0+incompatible
+	github.com/google/go-github/v32 v32.1.0
 	github.com/google/go-github/v33 v33.0.0
 	github.com/google/go-querystring v1.0.0 // indirect
 	github.com/googleapis/gnostic v0.2.2 // indirect

+ 3 - 0
go.sum

@@ -471,6 +471,8 @@ github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
+github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
 github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
 github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
 github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@@ -1067,6 +1069,7 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=

+ 0 - 0
internal/auth/sessionstore.go → internal/auth/sessionstore/sessionstore.go


+ 0 - 0
internal/auth/sessionstore_test.go → internal/auth/sessionstore/sessionstore_test.go


+ 119 - 0
internal/auth/token/token.go

@@ -0,0 +1,119 @@
+package token
+
+import (
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/dgrijalva/jwt-go"
+)
+
+type Subject string
+
+const (
+	User Subject = "user"
+	API  Subject = "api"
+)
+
+type TokenGeneratorConf struct {
+	TokenSecret string
+}
+
+type Token struct {
+	SubKind   Subject
+	Sub       string
+	ProjectID uint
+	IBy       uint
+	IAt       *time.Time
+}
+
+func (t *Token) GetTokenForUser(userID, projID uint) (*Token, error) {
+	if userID == 0 || projID == 0 {
+		return nil, fmt.Errorf("id cannot be 0")
+	}
+
+	iat := time.Now()
+
+	return &Token{
+		SubKind:   User,
+		Sub:       fmt.Sprintf("%d", userID),
+		ProjectID: projID,
+		IBy:       userID,
+		IAt:       &iat,
+	}, nil
+}
+
+func (t *Token) GetTokenForAPI(userID, projID uint) (*Token, error) {
+	if userID == 0 || projID == 0 {
+		return nil, fmt.Errorf("id cannot be 0")
+	}
+
+	iat := time.Now()
+
+	return &Token{
+		SubKind:   API,
+		Sub:       string(API),
+		ProjectID: projID,
+		IBy:       userID,
+		IAt:       &iat,
+	}, nil
+}
+
+func (t *Token) EncodeToken(conf *TokenGeneratorConf) (string, error) {
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
+		"sub_kind":   t.SubKind,
+		"sub":        t.Sub,
+		"iby":        t.IBy,
+		"iat":        t.IAt.Unix(),
+		"project_id": t.ProjectID,
+	})
+
+	// Sign and get the complete encoded token as a string using the secret
+	return token.SignedString(conf.TokenSecret)
+}
+
+func GetTokenFromEncoded(tokenString string, conf *TokenGeneratorConf) (*Token, error) {
+	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
+		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
+		}
+
+		return conf.TokenSecret, nil
+	})
+
+	if err != nil {
+		return nil, fmt.Errorf("could not parse token")
+	}
+
+	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
+		iby, err := strconv.ParseUint(fmt.Sprintf("%v", claims["iby"]), 10, 64)
+
+		if err != nil {
+			return nil, fmt.Errorf("invalid iby claim")
+		}
+
+		projID, err := strconv.ParseUint(fmt.Sprintf("%v", claims["project_id"]), 10, 64)
+
+		if err != nil {
+			return nil, fmt.Errorf("invalid iby claim")
+		}
+
+		iatUnix, err := strconv.ParseInt(fmt.Sprintf("%v", claims["iat"]), 10, 64)
+
+		if err != nil {
+			return nil, fmt.Errorf("invalid iby claim")
+		}
+
+		iat := time.Unix(iatUnix, 0)
+
+		return &Token{
+			SubKind:   Subject(fmt.Sprintf("%v", claims["sub_kind"])),
+			Sub:       fmt.Sprintf("%v", claims["sub"]),
+			IBy:       uint(iby),
+			IAt:       &iat,
+			ProjectID: uint(projID),
+		}, nil
+	}
+
+	return nil, fmt.Errorf("invalid token")
+}

+ 31 - 18
internal/integrations/ci/actions/actions.go

@@ -2,6 +2,8 @@ package actions
 
 import (
 	"context"
+	"encoding/base64"
+	"fmt"
 
 	"github.com/google/go-github/v33/github"
 	"github.com/porter-dev/porter/internal/models"
@@ -13,9 +15,10 @@ import (
 )
 
 type GithubActions struct {
-	GitRepo     *models.GitRepo
-	GitRepoName string
-	Repo        repository.Repository
+	GitRepo      *models.GitRepo
+	GitRepoName  string
+	GitRepoOwner string
+	Repo         repository.Repository
 
 	GithubConf *oauth2.Config
 
@@ -31,7 +34,7 @@ func (g *GithubActions) Setup() error {
 	}
 
 	// create a new secret with a webhook token
-	err = g.createGithubWebhookSecret(client)
+	err = g.createGithubSecret(client, g.getWebhookSecretName(), g.WebhookToken)
 
 	if err != nil {
 		return err
@@ -82,41 +85,51 @@ func (g *GithubActions) getClient() (*github.Client, error) {
 	return client, nil
 }
 
-func (g *GithubActions) createGithubWebhookSecret(client *github.Client) error {
+func (g *GithubActions) createGithubSecret(
+	client *github.Client,
+	secretName,
+	secretValue string,
+) error {
 	// get the public key for the repo
-	key, _, err := client.Actions.GetRepoPublicKey(context.TODO(), "", g.GitRepoName)
+	key, _, err := client.Actions.GetRepoPublicKey(context.TODO(), g.GitRepoOwner, g.GitRepoName)
 
 	if err != nil {
 		return err
 	}
 
-	// encrypt the webhook token with the public key
-	secretName := g.getSecretName()
-	secretValue := []byte(g.WebhookToken)
-	out := make([]byte, 0)
-
+	// encrypt the secret with the public key
 	keyBytes := [32]byte{}
 
-	copy(keyBytes[:], *key.Key)
+	keyDecoded, err := base64.StdEncoding.DecodeString(*key.Key)
+
+	if err != nil {
+		return err
+	}
+
+	copy(keyBytes[:], keyDecoded[:])
 
-	_, err = box.SealAnonymous(out, secretValue, &keyBytes, nil)
+	secretEncoded, err := box.SealAnonymous(nil, []byte(secretValue), &keyBytes, nil)
 
 	if err != nil {
 		return err
 	}
 
+	encrypted := base64.StdEncoding.EncodeToString(secretEncoded)
+
 	encryptedSecret := &github.EncryptedSecret{
 		Name:           secretName,
 		KeyID:          *key.KeyID,
-		EncryptedValue: string(out),
+		EncryptedValue: encrypted,
 	}
 
 	// write the secret to the repo
-	_, err = client.Actions.CreateOrUpdateRepoSecret(context.TODO(), "", g.GitRepoName, encryptedSecret)
+	_, err = client.Actions.CreateOrUpdateRepoSecret(context.TODO(), g.GitRepoOwner, g.GitRepoName, encryptedSecret)
 
-	return err
+	return nil
 }
 
-func (g *GithubActions) getSecretName() string {
-	return strings.Replace(strings.ToUpper(g.ReleaseName), "-", "_", -1)
+func (g *GithubActions) getWebhookSecretName() string {
+	return fmt.Sprintf("WEBHOOK_%s", strings.Replace(
+		strings.ToUpper(g.ReleaseName), "-", "_", -1),
+	)
 }