Update scope validation implementation

This commit is contained in:
NipuniBhagya 2025-05-21 10:00:01 +05:30
parent 5c22f36ddc
commit 64caaa0f7c
7 changed files with 202 additions and 138 deletions

View file

@ -4,54 +4,68 @@ import (
"fmt"
"net/http"
"strings"
)
type TokenClaims struct {
Scopes []string
}
"github.com/golang-jwt/jwt/v4"
"github.com/wso2/open-mcp-auth-proxy/internal/config"
"github.com/wso2/open-mcp-auth-proxy/internal/util"
)
type ScopeValidator struct{}
// Evaluate and checks the token claims against one or more required scopes.
func (d *ScopeValidator) ValidateAccess(
_ *http.Request,
claims *TokenClaims,
requiredScopes any,
r *http.Request,
claims *jwt.MapClaims,
config *config.Config,
) AccessControlResult {
var scopeStr string
switch v := requiredScopes.(type) {
case string:
scopeStr = v
case []string:
scopeStr = strings.Join(v, " ")
env, err := util.ParseRPCRequest(r)
if err != nil {
return AccessControlResult{DecisionDeny, "bad JSON-RPC request"}
}
requiredScopes := util.GetRequiredScopes(config, env.Method)
if len(requiredScopes) == 0 {
return AccessControlResult{DecisionAllow, ""}
}
required := make(map[string]struct{}, len(requiredScopes))
for _, s := range requiredScopes {
s = strings.TrimSpace(s)
if s != "" {
required[s] = struct{}{}
}
}
var tokenScopes []string
if claims, ok := (*claims)["scope"]; ok {
switch v := claims.(type) {
case string:
tokenScopes = strings.Fields(v)
case []interface{}:
for _, x := range v {
if s, ok := x.(string); ok && s != "" {
tokenScopes = append(tokenScopes, s)
}
}
}
}
tokenScopeSet := make(map[string]struct{}, len(tokenScopes))
for _, s := range tokenScopes {
tokenScopeSet[s] = struct{}{}
}
if strings.TrimSpace(scopeStr) == "" {
return AccessControlResult{DecisionAllow, ""}
}
scopes := strings.FieldsFunc(scopeStr, func(r rune) bool {
return r == ' ' || r == ','
})
required := make(map[string]struct{}, len(scopes))
for _, s := range scopes {
if s = strings.TrimSpace(s); s != "" {
required[s] = struct{}{}
}
}
for _, tokenScope := range claims.Scopes {
if _, ok := required[tokenScope]; ok {
return AccessControlResult{DecisionAllow, ""}
}
}
var list []string
var missing []string
for s := range required {
list = append(list, s)
if _, ok := tokenScopeSet[s]; !ok {
missing = append(missing, s)
}
}
if len(missing) == 0 {
return AccessControlResult{DecisionAllow, ""}
}
return AccessControlResult{
DecisionDeny,
fmt.Sprintf("missing required scope(s): %s", strings.Join(list, ", ")),
fmt.Sprintf("missing required scope(s): %s", strings.Join(missing, ", ")),
}
}