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

Unified Diff: server/auth/authdb/snapshot.go

Issue 2386643003: auth: Make luci-go services trust signatures produced by the token server. (Closed)
Patch Set: add tests Created 4 years, 2 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
« no previous file with comments | « server/auth/authdb/erroring.go ('k') | server/auth/authdb/snapshot_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: server/auth/authdb/snapshot.go
diff --git a/server/auth/authdb/snapshot.go b/server/auth/authdb/snapshot.go
index 0ede9ac2fc201e786d9ca53f7b7d171b95bd2ec6..2906fa703f9837706dbe933c1d7beb0f3929971e 100644
--- a/server/auth/authdb/snapshot.go
+++ b/server/auth/authdb/snapshot.go
@@ -8,12 +8,17 @@ import (
"fmt"
"net"
"strings"
+ "sync"
+ "time"
"golang.org/x/net/context"
+ "github.com/luci/luci-go/common/clock"
+ "github.com/luci/luci-go/common/data/caching/lazyslot"
"github.com/luci/luci-go/common/logging"
"github.com/luci/luci-go/server/auth/identity"
"github.com/luci/luci-go/server/auth/service/protocol"
+ "github.com/luci/luci-go/server/auth/signing"
"github.com/luci/luci-go/server/secrets"
)
@@ -36,8 +41,14 @@ type SnapshotDB struct {
assignments map[identity.Identity]string // IP whitelist assignements
whitelists map[string][]net.IPNet // IP whitelists
+
+ // Certs are loaded lazily in GetCertificates since they are used only when
+ // checking delegation tokens, which is relatively rare.
+ certs lazyslot.Slot
}
+var _ DB = &SnapshotDB{}
+
// group is a node in a group graph. Nested groups are referenced directly via
// pointer.
type group struct {
@@ -46,7 +57,8 @@ type group struct {
nested []*group // pointers to nested groups
}
-var _ DB = &SnapshotDB{}
+// certMap is used in GetCertificate and fetchTrustedCerts.
+type certMap map[identity.Identity]*signing.PublicCertificates
// NewSnapshotDB creates new instance of SnapshotDB.
//
@@ -60,6 +72,18 @@ func NewSnapshotDB(authDB *protocol.AuthDB, authServiceURL string, rev int64) (*
tokenServiceURL: authDB.GetTokenServerUrl(),
}
+ // Load all trusted certificates lazily and refresh each hour.
+ db.certs.Fetcher = func(c context.Context, prev lazyslot.Value) (lazyslot.Value, error) {
+ mapping, err := db.fetchTrustedCerts(c)
+ if err != nil {
+ return lazyslot.Value{}, err
+ }
+ return lazyslot.Value{
+ Value: mapping,
+ Expiration: clock.Now(c).Add(time.Hour),
+ }, nil
+ }
+
// Set of all allowed clientIDs.
db.clientIDs = make(map[string]struct{}, 2+len(authDB.GetOauthAdditionalClientIds()))
db.clientIDs[googleAPIExplorerClientID] = struct{}{}
@@ -258,6 +282,16 @@ func (db *SnapshotDB) SharedSecrets(c context.Context) (secrets.Store, error) {
return db.secrets, nil
}
+// GetCertificates returns a bundle with certificates of a trusted signer.
+func (db *SnapshotDB) GetCertificates(c context.Context, signerID identity.Identity) (*signing.PublicCertificates, error) {
+ val, err := db.certs.Get(c)
+ if err != nil {
+ return nil, err
+ }
+ trustedCertsMap := val.Value.(certMap)
+ return trustedCertsMap[signerID], nil
+}
+
// GetWhitelistForIdentity returns name of the IP whitelist to use to check
// IP of requests from given `ident`.
//
@@ -295,3 +329,58 @@ func (db *SnapshotDB) GetAuthServiceURL(c context.Context) (string, error) {
func (db *SnapshotDB) GetTokenServiceURL(c context.Context) (string, error) {
return db.tokenServiceURL, nil
}
+
+//// Implementation details.
+
+// fetchTrustedCerts is called by db.certs to fetch certificates.
+func (db *SnapshotDB) fetchTrustedCerts(c context.Context) (certMap, error) {
+ // TODO(vadimsh): Stop loading certs from AuthServiceURL when all tokens
+ // are generated by the token server.
+ var urls []string
+ if db.tokenServiceURL != "" {
+ urls = []string{db.tokenServiceURL, db.AuthServiceURL}
+ } else {
+ urls = []string{db.AuthServiceURL}
+ }
+
+ certs := make([]*signing.PublicCertificates, len(urls))
+ errs := make([]error, len(urls))
+
+ // Fetch in parallel.
+ wg := sync.WaitGroup{}
+ for i := range urls {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ certs[i], errs[i] = signing.FetchCertificatesFromLUCIService(c, urls[i])
+ }(i)
+ }
+ wg.Wait()
+
+ // Each certificate bundle is available under two keys: "service:<app-id>" and
+ // "user:<service-account-name>". This is so because there's one to one
+ // association between GAE apps and corresponding @appspot.gserviceaccount.com
+ // service accounts.
+ mapping := make(certMap, 2*len(certs))
+ for i, cert := range certs {
+ if errs[i] != nil {
+ return nil, errs[i]
+ }
+ if cert.AppID != "" {
+ id, err := identity.MakeIdentity("service:" + cert.AppID)
+ if err != nil {
+ return nil, fmt.Errorf("invalid app_id %q in fetched certificates bundle - %s", cert.AppID, err)
+ }
+ mapping[id] = cert
+ }
+ if cert.ServiceAccountName != "" {
+ id, err := identity.MakeIdentity("user:" + cert.ServiceAccountName)
+ if err != nil {
+ return nil, fmt.Errorf("invalid service_account_name %q in fetched certificates bundle - %s", cert.ServiceAccountName, err)
+ }
+ mapping[id] = cert
+ }
+ }
+
+ return mapping, nil
+}
« no previous file with comments | « server/auth/authdb/erroring.go ('k') | server/auth/authdb/snapshot_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698