jwt support, using seperate descriptor attributes(success) for jwt and apikey
diff --git a/adapter/apigeeKeyAttributes.go b/adapter/apigeeKeyAttributes.go index 5c5047c..8cc3c5b 100644 --- a/adapter/apigeeKeyAttributes.go +++ b/adapter/apigeeKeyAttributes.go
@@ -22,20 +22,23 @@ "strings" "github.com/apid/istioApigeeAdapter/adapter/config" "istio.io/mixer/pkg/adapter" + "github.com/apid/istioApigeeAdapter/common" ) const ( keyAttrsName = "apigeeKeyAttributes" keyAttrsDesc = "Set attributes based on an Apigee API key" - keyParam = "apiKey" - jwtParam = "jwtToken" - pathParam = "requestPath" - successParam = "success" - successStringParam = "successString" - clientIDParam = "clientID" - appNameParam = "applicationName" - productNameParam = "apiProduct" + keyParam = "apiKey" + jwtParam = "jwtToken" + pathParam = "requestPath" + apiKeySuccessParam = "apiKeySuccess" + apiKeySuccessStringParam = "apiKeySuccessString" + jwtSuccessParam = "jwtSuccess" + jwtSuccessStringParam = "jwtSuccessString" + clientIDParam = "clientID" + appNameParam = "applicationName" + productNameParam = "apiProduct" ) var keyAttrsConf = &config.VerifyKeyParams{} @@ -81,13 +84,15 @@ func (g *keyAttrsGenerator) Generate(in map[string]interface{}) (map[string]interface{}, error) { out := make(map[string]interface{}) - out[successParam] = false - out[successStringParam] = "false" + out[apiKeySuccessParam] = false + out[apiKeySuccessStringParam] = "false" + out[jwtSuccessParam] = false + out[jwtSuccessStringParam] = "false" - key := getString(in, keyParam) + apiKey := getString(in, keyParam) jwt_token := getString(in, jwtParam) - if key == "" && jwt_token == "" { + if apiKey == "" && jwt_token == "" { return out, nil } @@ -97,63 +102,70 @@ } if jwt_token != "" { + // TODO: throw appropriate error to user eg. token expired, token invalid + if strings.HasPrefix(jwt_token, "Bearer") { token := strings.Split(jwt_token, " ")[1] jwt_token = token } else { g.env.Logger().Errorf("Cannot verify jwt token, Bearer missing") - return out, nil } - claims, err := g.jwtVerifier.Verify(jwt_token) - - if err != nil { - g.env.Logger().Errorf("Cannot verify jwt token : %s", err) - return out, nil - } - + claims, verificationErr := g.jwtVerifier.Verify(jwt_token) // considers token as valid if exp, iat, iss is not present - err = claims.Valid() - // invalid token - if err != nil { - g.env.Logger().Errorf("jwt token invalid : %s", err) - return out, nil + if verificationErr != nil { + g.env.Logger().Errorf("Cannot verify jwt token : %s", verificationErr) + } else { + validationErr := claims.Valid() + + if validationErr != nil { + g.env.Logger().Errorf("Validation error, jwt token : %s", validationErr) + } else { + // TODO: check scopes + + key := claims.(*apigeeClaims).ClientId + success, app, products, err := g.checkKey(key) + + g.env.Logger().Errorf("Key check failed : %s", err) + + out[jwtSuccessParam] = success + out[jwtSuccessStringParam] = strconv.FormatBool(success) + + if app.valid { + out[clientIDParam] = app.clientID + out[appNameParam] = app.name + } + + if success { + out[productNameParam] = products[0].Name + } + } + } + } + + if apiKey != "" { + success, app, products, err := g.checkKey(apiKey) + + g.env.Logger().Errorf("key check failed : %s", err) + + if len(products) == 0 { + success = false } - // TODO: check scopes + // TODO match API products by path - // prioritizing jwt over apikey (if user passes both jwt and apikey) - key = claims.(*apigeeClaims).ClientId - } + out[apiKeySuccessParam] = success + out[apiKeySuccessStringParam] = strconv.FormatBool(success) - // Look up API key from cache, making HTTP request if necessary - app, err := g.applications.get(key) - if err != nil { - g.env.Logger().Errorf("Error verifying API key: %s", err) - return nil, err - } + if app.valid { + out[clientIDParam] = app.clientID + out[appNameParam] = app.name + } - success := app.valid - - // Look up API products from cache, making HTTP request if necessary - products, err := g.products.getProducts(app.apiProducts) - if err != nil { - return nil, fmt.Errorf("Cannot fetch API product list: %s", err) - } - if len(products) == 0 { - success = false - } - // TODO match API products by path - - out[successParam] = success - out[successStringParam] = strconv.FormatBool(success) - if app.valid { - out[clientIDParam] = app.clientID - out[appNameParam] = app.name - } - if success { - out[productNameParam] = products[0].Name + if success { + out[productNameParam] = products[0].Name + } } return out, nil @@ -163,6 +175,31 @@ return nil } +func (g *keyAttrsGenerator) checkKey(key string) (bool, *application, []common.APIProduct, error) { + // Look up API key from cache, making HTTP request if necessary + app, err := g.applications.get(key) + if err != nil { + g.env.Logger().Errorf("Error verifying API key: %s", err) + return false, nil, nil, err + } + + success := app.valid + + // Look up API products from cache, making HTTP request if necessary + products, err := g.products.getProducts(app.apiProducts) + if err != nil { + return false, nil, nil, fmt.Errorf("Cannot fetch API product list: %s", err) + } + + if len(products) == 0 { + success = false + } + + // TODO match API products by path + + return success, app, products, err +} + func getPulicKeyUrl(cfg *config.VerifyKeyParams) (string) { return fmt.Sprintf(defaultPublicKeyURL, cfg.Organization, cfg.Environment) -} \ No newline at end of file +}