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

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

Issue 2993763002: tokenserver: Extract rules check into a separate function. (Closed)
Patch Set: more nits 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.go
diff --git a/tokenserver/appengine/impl/serviceaccounts/config.go b/tokenserver/appengine/impl/serviceaccounts/config.go
index 5b9e48d2f850dcd2213a55e5c6e504f5e8714ab0..59a95ecbcd89a0a040305e0d7c9321cbc6d6af4f 100644
--- a/tokenserver/appengine/impl/serviceaccounts/config.go
+++ b/tokenserver/appengine/impl/serviceaccounts/config.go
@@ -17,10 +17,15 @@ package serviceaccounts
import (
"fmt"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+
"golang.org/x/net/context"
"github.com/luci/luci-go/common/config/validation"
"github.com/luci/luci-go/common/data/stringset"
+ "github.com/luci/luci-go/common/logging"
+ "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/identityset"
@@ -60,6 +65,15 @@ type Rule struct {
Proxies *identityset.Set // parsed 'proxy'
}
+// RulesQuery describes circumstances of using some service account.
+//
+// Passed to 'Check'.
+type RulesQuery struct {
+ ServiceAccount string // email of an account being used
+ Proxy identity.Identity // who's calling the Token Server
+ EndUser identity.Identity // who initiates the usage of an account
+}
+
// RulesCache is a stateful object with parsed service_accounts.cfg rules.
//
// It uses policy.Policy internally to manage datastore-cached copy of imported
@@ -161,6 +175,50 @@ func (r *Rules) Rule(serviceAccount string) *Rule {
return r.rules[serviceAccount]
}
+// Check checks that rules allow the requested usage.
+//
+// Returns the corresponding rule on success, or gRPC error on failure.
+// The returned rule can be consulted further to check additional restrictions,
+// such as allowed OAuth scopes or validity duration.
+//
+// It is supposed to be called as part of some RPC handler. It logs errors
+// internally, so no need to log them outside.
+func (r *Rules) Check(c context.Context, query *RulesQuery) (*Rule, error) {
+ // Grab the rule for this account. Don't leak information about presence or
+ // absence of the account to the caller, they may not be authorized to see the
+ // account at all.
+ rule := r.rules[query.ServiceAccount]
+ if rule == nil {
+ logging.Errorf(c, "No rule for service account %q in the config rev %s", query.ServiceAccount, r.revision)
+ return nil, grpc.Errorf(codes.PermissionDenied, "unknown service account or not enough permissions to use it")
+ }
+ logging.Infof(c, "Found the matching rule %q in the config rev %s", rule.Rule.Name, r.revision)
+
+ // If the 'Proxy' is in 'Proxies' list, we assume it's known to us and we
+ // trust it enough to start returning more detailed error messages.
+ switch known, err := rule.Proxies.IsMember(c, query.Proxy); {
+ case err != nil:
+ logging.WithError(err).Errorf(c, "Failed to check membership of caller %q", query.Proxy)
+ return nil, grpc.Errorf(codes.Internal, "membership check failed")
+ case !known:
+ logging.Errorf(c, "Caller %q is not authorized to use account %q", query.Proxy, query.ServiceAccount)
+ return nil, grpc.Errorf(codes.PermissionDenied, "unknown service account or not enough permissions to use it")
+ }
+
+ switch known, err := rule.EndUsers.IsMember(c, query.EndUser); {
+ case err != nil:
+ logging.WithError(err).Errorf(c, "Failed to check membership of end user %q", query.EndUser)
+ return nil, grpc.Errorf(codes.Internal, "membership check failed")
+ case !known:
+ logging.Errorf(c, "End user %q is not authorized to use account %q", query.EndUser, query.ServiceAccount)
+ return nil, grpc.Errorf(
+ codes.PermissionDenied, "per rule %q the user %q is not authorized to use the service account %q",
+ rule.Rule.Name, query.EndUser, query.ServiceAccount)
+ }
+
+ return rule, nil
+}
+
// makeRule converts ServiceAccountRule into queriable Rule.
//
// Mutates 'ruleProto' in-place filling in defaults.

Powered by Google App Engine
This is Rietveld 408576698