55 lines
2.1 KiB
Go
55 lines
2.1 KiB
Go
|
|
package oidc
|
||
|
|
|
||
|
|
import (
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// approval-engine persists the assurance object verbatim and it is the only
|
||
|
|
// downstream evidence that MFA happened (KEY-WP-0013-T05). A reused browser
|
||
|
|
// session can be hours old, so reporting mint time would overstate how
|
||
|
|
// recently the person actually proved anything.
|
||
|
|
func TestAssuranceReportsAuthenticationTimeNotMintTime(t *testing.T) {
|
||
|
|
authenticated := time.Now().Add(-4 * time.Hour)
|
||
|
|
minted := time.Now()
|
||
|
|
|
||
|
|
claim := assuranceClaim(true, authenticated, minted)
|
||
|
|
if got := claim["at"].(int64); got != authenticated.Unix() {
|
||
|
|
t.Errorf("assurance.at = %d, want the authentication time %d", got, authenticated.Unix())
|
||
|
|
}
|
||
|
|
if claim["level"] != "aal2" || claim["mfa"] != true {
|
||
|
|
t.Errorf("MFA-verified authorization did not report aal2: %v", claim)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// A session stored before AuthTime existed has a zero value; falling back to
|
||
|
|
// mint time keeps the claim present rather than emitting a 1970 timestamp.
|
||
|
|
func TestAssuranceFallsBackToMintTimeWhenAuthTimeIsUnset(t *testing.T) {
|
||
|
|
minted := time.Now()
|
||
|
|
claim := assuranceClaim(false, time.Time{}, minted)
|
||
|
|
if got := claim["at"].(int64); got != minted.Unix() {
|
||
|
|
t.Errorf("assurance.at = %d, want the mint-time fallback %d", got, minted.Unix())
|
||
|
|
}
|
||
|
|
if claim["level"] != "aal1" || claim["mfa"] != false {
|
||
|
|
t.Errorf("unverified authorization did not report aal1: %v", claim)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The shape approval-engine and informed-decision consume. A missing key here
|
||
|
|
// breaks a downstream record that cannot be reconstructed later.
|
||
|
|
func TestAssuranceCarriesTheDocumentedShape(t *testing.T) {
|
||
|
|
claim := assuranceClaim(true, time.Now(), time.Now())
|
||
|
|
for _, key := range []string{"level", "methods", "mfa", "source", "at"} {
|
||
|
|
if _, ok := claim[key]; !ok {
|
||
|
|
t.Errorf("assurance object is missing %q: %v", key, claim)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
methods, ok := claim["methods"].([]string)
|
||
|
|
if !ok || len(methods) != 2 || methods[0] != "pwd" || methods[1] != "otp" {
|
||
|
|
t.Errorf("aal2 methods = %v, want [pwd otp]", claim["methods"])
|
||
|
|
}
|
||
|
|
if claim["source"] != "key-cape" {
|
||
|
|
t.Errorf("source = %v, want key-cape", claim["source"])
|
||
|
|
}
|
||
|
|
}
|