go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/appengine/gaeauth/server/db.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package server 16 17 import ( 18 "context" 19 "errors" 20 21 "go.chromium.org/luci/appengine/gaeauth/server/internal/authdbimpl" 22 "go.chromium.org/luci/common/clock" 23 "go.chromium.org/luci/common/logging" 24 "go.chromium.org/luci/gae/service/info" 25 "go.chromium.org/luci/server/auth/authdb" 26 ) 27 28 // errNotConfigured is returned on real GAE if auth service URL is not set. 29 var errNotConfigured = errors.New( 30 "Auth Service URL is not configured, you MUST configure it for apps used " + 31 "in production, visit /admin/portal/auth_service to do so.") 32 33 // GetAuthDB fetches AuthDB snapshot from the datastore and returns authdb.DB 34 // interface wrapping it. 35 // 36 // It may reuse existing one (`prev`), if no changes were made. If `prev` is 37 // nil, always fetches a new copy from the datastore. 38 // 39 // If auth_service URL is not configured, returns special kind of authdb.DB that 40 // implements some default authorization rules (allow everything on dev server, 41 // forbid everything and emit errors on real GAE). 42 func GetAuthDB(ctx context.Context, prev authdb.DB) (authdb.DB, error) { 43 // Grab revision number of most recent snapshot. 44 latest, err := authdbimpl.GetLatestSnapshotInfo(ctx) 45 if err != nil { 46 return nil, err 47 } 48 49 // If auth_service URL is not configured, use default db implementation. 50 if latest == nil { 51 if info.IsDevAppServer(ctx) { 52 return authdb.DevServerDB{}, nil 53 } 54 return authdb.ErroringDB{Error: errNotConfigured}, nil 55 } 56 57 // No newer version in the datastore? Reuse what we have in memory. `prev` may 58 // be an instance of ErroringDB or DevServerDB, so use non-panicking type 59 // assertion. 60 if prevDB, _ := prev.(*authdb.SnapshotDB); prevDB != nil { 61 if prevDB.AuthServiceURL == latest.AuthServiceURL && prevDB.Rev == latest.Rev { 62 return prevDB, nil 63 } 64 } 65 66 // Fetch new snapshot from the datastore. It was validated already when it was 67 // stored, so skip expensive validation step. Log how long it takes to keep an 68 // eye on performance here, since it has potential to become slow. 69 start := clock.Now(ctx) 70 proto, err := authdbimpl.GetAuthDBSnapshot(ctx, latest.GetSnapshotID()) 71 if err != nil { 72 return nil, err 73 } 74 db, err := authdb.NewSnapshotDB(proto, latest.AuthServiceURL, latest.Rev, false) 75 logging.Infof(ctx, "auth: AuthDB at rev %d fetched in %s", latest.Rev, clock.Now(ctx).Sub(start)) 76 if err != nil { 77 logging.Errorf(ctx, "auth: AuthDB is invalid - %s", err) 78 return nil, err 79 } 80 81 return db, nil 82 }