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
+}