package verify import ( "bytes" "encoding/json" "io" http "net/http" "net/url" "github.com/MicahParks/keyfunc" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" "edge-infra.dev/pkg/edge/iam/log" "edge-infra.dev/pkg/edge/iam/util" "edge-infra.dev/pkg/edge/iam/verify/templates" ) const ( oauth2TokenPath = "/oauth2/token" //nolint:gosec // Linter is not smart. wellKnownJWKSPath = "/.well-known/jwks.json" verifyCallbackPath = "/verify/callback" ) type TokenResponse struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` ExpiresIn int `json:"expires_in"` Scope string `json:"scope"` } func (v *Verifier) client(ctx *gin.Context) { log := log.Get(ctx.Request.Context()) result := &Result{ Name: "verify client result", Pass: true, } // accessing jwks (will be used for parsing the JWT token) jwksURL := IssuerURL() + wellKnownJWKSPath jwks, err := keyfunc.Get(jwksURL, keyfunc.Options{}) if err != nil { step := Step{Name: "load jwks", Pass: false} writeResult(ctx, templates.Callback, result, step) return } // setting the http body in x-www-form-urlencoded form data := url.Values{} data.Set("client_id", v.ClientID) data.Set("client_secret", v.ClientSecret) data.Set("grant_type", "client_credentials") // Make a POST request to the token endpoint res, err := http.Post(IssuerURL()+oauth2TokenPath, "application/x-www-form-urlencoded", bytes.NewBufferString(data.Encode())) if err != nil { step := Step{Name: "make request to token endpoint", Pass: false} writeResult(ctx, templates.Callback, result, step) return } defer res.Body.Close() // Read the response body of token endpoint body, err := io.ReadAll(res.Body) if err != nil { log.Error(err, "Error reading response") return } // Unmarshal the response JSON into a TokenResponse struct var tokenRes TokenResponse err = json.Unmarshal(body, &tokenRes) if err != nil { log.Error(err, "Error unmarshaling response") return } // parse and validate the access token accessToken, _ := jwt.Parse(tokenRes.AccessToken, jwks.Keyfunc) rolesOk := false if accessToken.Valid { // deserialse the claims claims, _ := accessToken.Claims.(jwt.MapClaims) serialisedRls, _ := claims["rls"].(string) roles, _ := util.Deserialize(serialisedRls) // check if the role contains SELLING_EXECUTE for _, role := range roles { if role == "SELLING_EXECUTE" { rolesOk = true break } } } steps := make([]Step, 0) steps = append(steps, Step{Name: "valid access token", Pass: accessToken.Valid}, Step{Name: "roles include SELLING_EXECUTE", Pass: rolesOk}, ) writeResult(ctx, templates.Client, result, steps...) }