Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Unified Diff: tokenserver/appengine/impl/serviceaccounts/config_validation.go

Issue 2997433002: tokenserver: Validate and parse service_accounts.cfg rules. (Closed)
Patch Set: tokenserver: Validate and parse service_accounts.cfg rules. Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tokenserver/appengine/impl/serviceaccounts/config_validation.go
diff --git a/tokenserver/appengine/impl/serviceaccounts/config_validation.go b/tokenserver/appengine/impl/serviceaccounts/config_validation.go
index 907e33c085a2b8d79a0fbc7cc60e50446c48d826..8732375358a7cc7fcbaad6360cd9c01dbc7a2b15 100644
--- a/tokenserver/appengine/impl/serviceaccounts/config_validation.go
+++ b/tokenserver/appengine/impl/serviceaccounts/config_validation.go
@@ -15,7 +15,12 @@
package serviceaccounts
import (
+ "fmt"
+ "strings"
+
"github.com/luci/luci-go/common/config/validation"
+ "github.com/luci/luci-go/common/data/stringset"
+ "github.com/luci/luci-go/server/auth/identity"
"github.com/luci/luci-go/tokenserver/api/admin/v1"
"github.com/luci/luci-go/tokenserver/appengine/impl/utils/policy"
@@ -30,5 +35,89 @@ func validateConfigs(bundle policy.ConfigBundle, ctx *validation.Context) {
return
}
- // TODO(vadimsh): Validate cfg.Rules.
+ names := stringset.New(0)
+ accounts := map[string]string{} // service account -> rule name where its defined
+ for i, rule := range cfg.Rules {
+ // Rule name must be unique. Missing name will be handled by 'validateRule'.
+ if rule.Name != "" {
+ if names.Has(rule.Name) {
+ ctx.Error("two rules with identical name %q", rule.Name)
+ } else {
+ names.Add(rule.Name)
+ }
+ }
+
+ // There should be no overlap between service account sets covered by each
+ // rule.
+ for _, account := range rule.ServiceAccount {
+ if name, ok := accounts[account]; ok {
+ ctx.Error("service account %q is mentioned by more than one rule (%q and %q)", account, name, rule.Name)
+ } else {
+ accounts[account] = rule.Name
+ }
+ }
+
+ validateRule(fmt.Sprintf("rule #%d: %q", i+1, rule.Name), rule, ctx)
+ }
+}
+
+// validateRule checks single ServiceAccountRule proto.
+func validateRule(title string, r *admin.ServiceAccountRule, ctx *validation.Context) {
+ ctx.Enter(title)
+ defer ctx.Exit()
+
+ if r.Name == "" {
+ ctx.Error(`"name" is required`)
+ }
+
+ // Note: we allow any of the sets to be empty. The rule will just not match
+ // anything in this case, this is fine.
+ validateEmails("service_account", r.ServiceAccount, ctx)
+ validateScopes("allowed_scope", r.AllowedScope, ctx)
+ validateIdSet("end_user", r.EndUser, ctx)
+ validateIdSet("proxy", r.Proxy, ctx)
+
+ if r.MaxGrantValidityDuration != 0 {
+ switch {
+ case r.MaxGrantValidityDuration < 0:
+ ctx.Error(`"max_grant_validity_duration" must be positive`)
+ case r.MaxGrantValidityDuration > maxAllowedMaxGrantValidityDuration:
+ ctx.Error(`"max_grant_validity_duration" must not exceed %d`, maxAllowedMaxGrantValidityDuration)
+ }
+ }
+}
+
+func validateEmails(field string, emails []string, ctx *validation.Context) {
+ ctx.Enter("%q", field)
+ defer ctx.Exit()
+ for _, email := range emails {
+ // We reuse 'user:' identity validator, user identities are emails too.
+ if _, err := identity.MakeIdentity("user:" + email); err != nil {
+ ctx.Error("bad email %q - %s", email, err)
+ }
+ }
+}
+
+func validateScopes(field string, scopes []string, ctx *validation.Context) {
+ ctx.Enter("%q", field)
+ defer ctx.Exit()
+ for _, scope := range scopes {
+ if !strings.HasPrefix(scope, "https://www.googleapis.com/") {
+ ctx.Error("bad scope %q", scope)
+ }
+ }
+}
+
+func validateIdSet(field string, ids []string, ctx *validation.Context) {
+ ctx.Enter("%q", field)
+ defer ctx.Exit()
+ for _, entry := range ids {
+ if strings.HasPrefix(entry, "group:") {
+ if entry[len("group:"):] == "" {
+ ctx.Error("bad group entry - no group name")
+ }
+ } else if _, err := identity.MakeIdentity(entry); err != nil {
+ ctx.Error("bad identity %q - %s", entry, err)
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698