veyron/services/identity: Better error handling and displaying to user
for viewing blessings from audit logs.
Change-Id: I83116fa1a470ed5c62979243e728c6d8898b5fe6
diff --git a/services/identity/auditor/blessing_auditor.go b/services/identity/auditor/blessing_auditor.go
index a76bc89..28f7b62 100644
--- a/services/identity/auditor/blessing_auditor.go
+++ b/services/identity/auditor/blessing_auditor.go
@@ -10,7 +10,6 @@
vsecurity "veyron.io/veyron/veyron/security"
"veyron.io/veyron/veyron/security/audit"
"veyron.io/veyron/veyron2/security"
- "veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron2/vom"
)
@@ -27,6 +26,7 @@
Timestamp time.Time // Time when the blesings were created.
RevocationCaveatID string
Blessings security.Blessings
+ DecodeError error
}
// NewSQLBlessingAuditor returns an auditor for wrapping a principal with, and a BlessingLogReader
@@ -70,12 +70,7 @@
defer close(dst)
dbch := r.db.Query(email)
for dbentry := range dbch {
- var entry BlessingEntry
- if err := entry.fromDatabaseEntry(dbentry); err != nil {
- vlog.Errorf("Corrupt database data? %#v, %v", dbentry, err)
- continue
- }
- dst <- entry
+ dst <- newBlessingEntry(dbentry)
}
}
@@ -115,22 +110,29 @@
return d, nil
}
-func (b *BlessingEntry) fromDatabaseEntry(dbentry databaseEntry) error {
- b.Email = dbentry.email
- b.Timestamp = dbentry.timestamp
+func newBlessingEntry(dbentry databaseEntry) BlessingEntry {
+ if dbentry.decodeErr != nil {
+ return BlessingEntry{DecodeError: dbentry.decodeErr}
+ }
+ b := BlessingEntry{
+ Email: dbentry.email,
+ Timestamp: dbentry.timestamp,
+ }
var wireBlessings security.WireBlessings
var err error
- if err := vom.NewDecoder(bytes.NewBuffer(dbentry.blessings)).Decode(&wireBlessings); err != nil {
- return err
+ if err = vom.NewDecoder(bytes.NewBuffer(dbentry.blessings)).Decode(&wireBlessings); err != nil {
+ return BlessingEntry{DecodeError: fmt.Errorf("failed to decode blessings: %s", err)}
}
if b.Blessings, err = security.NewBlessings(wireBlessings); err != nil {
- return err
+ return BlessingEntry{DecodeError: fmt.Errorf("failed to construct blessings: %s", err)}
}
- if err := vom.NewDecoder(bytes.NewBuffer(dbentry.caveats)).Decode(&b.Caveats); err != nil {
- return err
+ if err = vom.NewDecoder(bytes.NewBuffer(dbentry.caveats)).Decode(&b.Caveats); err != nil {
+ return BlessingEntry{DecodeError: fmt.Errorf("failed to decode caveats: %s", err)}
}
- b.RevocationCaveatID, err = revocationCaveatID(b.Caveats)
- return err
+ if b.RevocationCaveatID, err = revocationCaveatID(b.Caveats); err != nil {
+ return BlessingEntry{DecodeError: fmt.Errorf("error getting revocationCaveatID: %s", err)}
+ }
+ return b
}
func revocationCaveatID(caveats []security.Caveat) (string, error) {
diff --git a/services/identity/auditor/sql_database.go b/services/identity/auditor/sql_database.go
index 7b601b6..405f97f 100644
--- a/services/identity/auditor/sql_database.go
+++ b/services/identity/auditor/sql_database.go
@@ -25,6 +25,7 @@
email, revocationCaveatID string
caveats, blessings []byte
timestamp time.Time
+ decodeErr error
}
// newSQLDatabase returns a SQL implementation of the database interface.
@@ -72,13 +73,14 @@
rows, err := s.queryStmt.Query(email)
if err != nil {
vlog.Errorf("query failed %v", err)
+ dst <- databaseEntry{decodeErr: fmt.Errorf("Failed to query for all audits: %v", err)}
return
}
for rows.Next() {
var dbentry databaseEntry
if err = rows.Scan(&dbentry.email, &dbentry.caveats, &dbentry.revocationCaveatID, &dbentry.timestamp, &dbentry.blessings); err != nil {
vlog.Errorf("scan of row failed %v", err)
- return
+ dbentry.decodeErr = fmt.Errorf("failed to read sql row, %s", err)
}
dst <- dbentry
}
diff --git a/services/identity/googleoauth/handler.go b/services/identity/googleoauth/handler.go
index 255c9b1..109f3fd 100644
--- a/services/identity/googleoauth/handler.go
+++ b/services/identity/googleoauth/handler.go
@@ -178,6 +178,7 @@
RevocationTime time.Time
Blessed security.Blessings
Token string
+ Error error
}
tmplargs := struct {
Log chan tmplentry
@@ -201,6 +202,7 @@
defer close(ch)
for entry := range entrych {
tmplEntry := tmplentry{
+ Error: entry.DecodeError,
Timestamp: entry.Timestamp,
Caveats: entry.Caveats,
Blessed: entry.Blessings,
@@ -212,6 +214,7 @@
caveatID := base64.URLEncoding.EncodeToString([]byte(entry.RevocationCaveatID))
if tmplEntry.Token, err = h.csrfCop.NewToken(w, r, clientIDCookie, caveatID); err != nil {
vlog.Errorf("Failed to create CSRF token[%v] for request %#v", err, r)
+ tmplEntry.Error = fmt.Errorf("server error: unable to create revocation token")
}
}
}
diff --git a/services/identity/googleoauth/template.go b/services/identity/googleoauth/template.go
index 6bac1f7..2bd72bd 100644
--- a/services/identity/googleoauth/template.go
+++ b/services/identity/googleoauth/template.go
@@ -72,7 +72,7 @@
<h3>Blessing log for {{.Email}}</h3>
<table class="table table-bordered table-hover table-responsive">
<thead>
-<tr>
+ <tr>
<th>Blessed as</th>
<th>Public Key</th>
<th>Issued</th>
@@ -82,27 +82,33 @@
</thead>
<tbody>
{{range .Log}}
-<tr>
-<td>{{.Blessed}}</td>
-<td>{{.Blessed.PublicKey}}</td>
-<td><div class="unixtime" data-unixtime={{.Timestamp.Unix}}>{{.Timestamp.String}}</div></td>
-<td>
-{{range .Caveats}}
- {{.}}</br>
-{{end}}
-</td>
-<td>
- {{ if .Token }}
- <button class="revoke" value="{{.Token}}">Revoke</button>
- {{ else if not .RevocationTime.IsZero }}
- <div class="unixtime" data-unixtime={{.RevocationTime.Unix}}>{{.RevocationTime.String}}</div>
- {{ end }}
-</td>
-</tr>
+ {{if .Error}}
+ <tr class="bg-danger">
+ <td colspan="5">Failed to read audit log: Error: {{.Error}}</td>
+ </tr>
+ {{else}}
+ <tr>
+ <td>{{.Blessed}}</td>
+ <td>{{.Blessed.PublicKey}}</td>
+ <td><div class="unixtime" data-unixtime={{.Timestamp.Unix}}>{{.Timestamp.String}}</div></td>
+ <td>
+ {{range .Caveats}}
+ {{.}}</br>
+ {{end}}
+ </td>
+ <td>
+ {{ if .Token }}
+ <button class="revoke" value="{{.Token}}">Revoke</button>
+ {{ else if not .RevocationTime.IsZero }}
+ <div class="unixtime" data-unixtime={{.RevocationTime.Unix}}>{{.RevocationTime.String}}</div>
+ {{ end }}
+ </td>
+ </tr>
+ {{end}}
{{else}}
-<tr>
-<td colspan=5>No blessings issued</td>
-</tr>
+ <tr>
+ <td colspan=5>No blessings issued</td>
+ </tr>
{{end}}
</tbody>
</table>