Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 49 additions & 34 deletions handlers/sower.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type InputRequest struct {
Format string `json:"access_format"`
}

type Principal struct {
Raw string // original, e.g., "auth0|67ec..."
LabelSafe string // sanitized for k8s label value
}

func dispatch(w http.ResponseWriter, r *http.Request) {
log.Debug("Dispatch")
if r.Method != "POST" {
Expand Down Expand Up @@ -68,12 +73,13 @@ func dispatch(w http.ResponseWriter, r *http.Request) {
accessTokenVal = *accessToken
}

email, err := getEmailFromToken(accessTokenVal)
principal, err := getPrincipalFromToken(accessTokenVal)
if err != nil {
panic(err)
}

result, err := createK8sJob(currentAction, string(out), accessFormat, accessTokenVal, userName, email)
// pass both raw and safe; createK8sJob will still defensively sanitize at label write
result, err := createK8sJob(currentAction, string(out), accessFormat, accessTokenVal, userName, principal.LabelSafe)
if err != nil {
http.Error(w, err.Error(), 500)
return
Expand All @@ -88,28 +94,35 @@ func dispatch(w http.ResponseWriter, r *http.Request) {
}

func status(w http.ResponseWriter, r *http.Request) {
email := ""
UID := r.URL.Query().Get("UID")
if UID != "" {
username := ""
if bt := getBearerToken(r); bt != nil && *bt != "" {
if p, err := getPrincipalFromToken(*bt); err == nil {
username = p.LabelSafe
}
}

result, errUID := getJobStatusByID(UID, sanitizeLabelValue(username))
if errUID != nil {
http.Error(w, errUID.Error(), 500)
return
}

out, err := json.Marshal(result)
if err != nil {
http.Error(w, err.Error(), 500)
return
}

fmt.Fprint(w, string(out))
} else {
http.Error(w, "Missing UID argument", 400)
return
}
}

UID := r.URL.Query().Get("UID")
if UID != "" {
result, errUID := getJobStatusByID(UID, email)
if errUID != nil {
http.Error(w, errUID.Error(), 500)
return
}

out, err := json.Marshal(result)
if err != nil {
http.Error(w, err.Error(), 500)
return
}

fmt.Fprint(w, string(out))
} else {
http.Error(w, "Missing UID argument", 300)
return
}
}

func output(w http.ResponseWriter, r *http.Request) {
accessToken := getBearerToken(r)
Expand All @@ -119,14 +132,14 @@ func output(w http.ResponseWriter, r *http.Request) {
accessTokenVal = *accessToken
}

email, err := getEmailFromToken(accessTokenVal)
principal, err := getPrincipalFromToken(accessTokenVal)
if err != nil {
panic(err.Error())
}

UID := r.URL.Query().Get("UID")
if UID != "" {
result, errUID := getJobLogs(UID, email)
result, errUID := getJobLogs(UID, principal.LabelSafe)
if errUID != nil {
http.Error(w, errUID.Error(), 500)
return
Expand Down Expand Up @@ -173,12 +186,12 @@ func list(w http.ResponseWriter, r *http.Request) {
accessTokenVal = *accessToken
}

email, err := getEmailFromToken(accessTokenVal)
principal, err := getPrincipalFromToken(accessTokenVal)
if err != nil {
panic(err.Error())
}

result := listJobs(getJobClient(), email)
result := listJobs(getJobClient(), principal.LabelSafe)

out, err := json.Marshal(result)
if err != nil {
Expand All @@ -201,20 +214,20 @@ func getBearerToken(r *http.Request) *string {
return nil
}

func getEmailFromToken(accessTokenVal string) (string, error) {
func getPrincipalFromToken(accessTokenVal string) (Principal, error) {
jwksURL := "http://fence-service/.well-known/jwks"

// create the JWKS from the resource at the given URL
jwks, err := keyfunc.Get(jwksURL, keyfunc.Options{})
if err != nil {
log.Debugf("Failed to create JWKS from resource at the given URL.\nError: %s", err.Error())
return "", err
return Principal{}, err
}

token, err := jwt.Parse(accessTokenVal, jwks.Keyfunc)
if err != nil {
log.Debugf("Failed to parse the JWT.\nError: %s", err.Error())
return "", err
return Principal{}, err
}

// Verify if sub field exists, to identify if it is a user token or a client token
Expand All @@ -227,13 +240,15 @@ func getEmailFromToken(accessTokenVal string) (string, error) {
// User token
context := claims["context"].(map[string]interface{})
user := context["user"].(map[string]interface{})
username := user["name"].(string)
username = strings.ReplaceAll(username, "@", "_")
return username, nil
// This field was previously called "email" or "username"; it’s really a principal ID.
raw := user["name"].(string) // often email-ish or provider-prefixed ID
raw = strings.ReplaceAll(raw, "@", "_")
return Principal{Raw: raw, LabelSafe: sanitizeLabelValue(raw)}, nil
} else if claims["azp"] != nil {
// Client token
return claims["azp"].(string), nil
raw := claims["azp"].(string)
return Principal{Raw: raw, LabelSafe: sanitizeLabelValue(raw)}, nil
}
}
return "", nil
return Principal{}, nil
}
34 changes: 34 additions & 0 deletions handlers/util.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package handlers

import (
"crypto/sha256"
"encoding/hex"
"regexp"
)

func filter(scs []SowerConfig, test func(SowerConfig) bool) (ret []SowerConfig) {
for _, s := range scs {
if test(s) {
Expand All @@ -8,3 +14,31 @@ func filter(scs []SowerConfig, test func(SowerConfig) bool) (ret []SowerConfig)
}
return
}

var (
// valid: alphanum, '-', '_', '.', must start/end alnum, <= 63 chars
labelAllowed = regexp.MustCompile(`[^A-Za-z0-9_.-]+`)
trimEnds = regexp.MustCompile(`^[^A-Za-z0-9]+|[^A-Za-z0-9]+$`)
collapseDash = regexp.MustCompile(`[-._]{2,}`)
)

func sanitizeLabelValue(raw string) string {
if raw == "" {
return "id-" + shortHash("empty")
}
s := labelAllowed.ReplaceAllString(raw, "-")
s = collapseDash.ReplaceAllString(s, "-")
s = trimEnds.ReplaceAllString(s, "")
if len(s) > 63 {
s = s[:63]
}
if s == "" {
return "id-" + shortHash(raw)
}
return s
}

func shortHash(s string) string {
h := sha256.Sum256([]byte(s))
return hex.EncodeToString(h[:])[:16]
}