-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig_test.go
More file actions
131 lines (112 loc) · 5.35 KB
/
Copy pathconfig_test.go
File metadata and controls
131 lines (112 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package authbytecore
import (
"reflect"
"strings"
"testing"
"github.com/go-quicktest/qt"
"github.com/spf13/viper"
)
// TestACRForMethodDistinct proves step-up requests a method-specific acr_values,
// and the permitted methods (eParaksts Mobile vs eID Scan) resolve to DIFFERENT
// values, so Entrust can actually force the requested method (the login-method ↔
// signing-flow binding). It also proves the eID-card (sc_plugin) "eid" method has
// NO acr — eID-card login is Web eID only.
func TestACRForMethodDistinct(t *testing.T) {
c := &Configuration{
EparakstsACRMobile: "urn:test:acr:mobile",
EparakstsACREIDScan: "urn:test:acr:eidscan",
}
qt.Check(t, qt.Equals(c.ACRForMethod("eparakstsMobile"), "urn:test:acr:mobile"))
qt.Check(t, qt.Equals(c.ACRForMethod("eidScan"), "urn:test:acr:eidscan"))
qt.Check(t, qt.Not(qt.Equals(c.ACRForMethod("eparakstsMobile"), c.ACRForMethod("eidScan"))))
// eID (sc_plugin) is no longer a TrustedX login method → no acr.
qt.Check(t, qt.Equals(c.ACRForMethod("eid"), ""))
// Web eID card login is not an Entrust method → no acr (step-up to it goes
// through the Web eID challenge route, not /authorize).
qt.Check(t, qt.Equals(c.ACRForMethod("webEid"), ""))
qt.Check(t, qt.Equals(c.ACRForMethod("unknown"), ""))
}
// TestDefaultsGiveDistinctACRs proves the shipped defaults are also distinct (a
// regression guard against re-introducing identical placeholder ACRs) and that
// no eid (sc_plugin) acr default is shipped.
func TestDefaultsGiveDistinctACRs(t *testing.T) {
v := viper.New()
NewConfiguration().Bind("", v)
mobile := v.GetString("eparaksts_acr_mobile")
eidScan := v.GetString("eparaksts_acr_eidscan")
qt.Check(t, qt.IsTrue(mobile != ""))
qt.Check(t, qt.IsTrue(eidScan != ""))
qt.Check(t, qt.Not(qt.Equals(mobile, eidScan)))
// No eid-card acr default — eID card is Web eID only.
qt.Check(t, qt.Equals(v.GetString("eparaksts_acr_eid"), ""))
}
// TestUpstreamConfigKeysBindToEnvironment proves that every upstream-connector
// setting is actually REACHABLE from the environment — the property the type
// system does not check and a reader cannot see.
//
// It is derived, not listed: the keys come from the struct's own mapstructure
// tags, so a field added tomorrow is covered the day it is added rather than
// the day someone remembers to extend a list. That is the whole point. The
// defect it was written for was a field that existed at every layer — declared,
// validated, applied to the connector, documented in the README — and had no
// BindEnv call, so setting the documented variable did nothing and said
// nothing. Nothing in the build could see it, because nothing in the build
// reads an environment variable that is never bound.
//
// The convention this relies on, which holds for every key here: the
// environment variable is the mapstructure key, upper-cased.
// One upstream per deployment: the generic connector or the eParaksts profile,
// never both — a second configured family used to be picked over silently,
// which is how a misconfiguration goes unnoticed until somebody logs in through
// the wrong provider. And never none.
func TestValidateUpstreamRefusesTwoFamiliesAndNone(t *testing.T) {
both := Configuration{
OIDCUpstreamAuthorityURL: "https://login.example/tenant/v2.0", OIDCUpstreamClientID: "cid",
EparakstsAuthorityURL: "https://eparaksts.example", EparakstsClientID: "e",
}
err := both.validateUpstream()
qt.Assert(t, qt.IsNotNil(err))
qt.Assert(t, qt.StringContains(err.Error(), "two upstream identity providers"))
none := Configuration{}
qt.Assert(t, qt.IsNotNil(none.validateUpstream()))
generic := Configuration{OIDCUpstreamAuthorityURL: "https://login.example/tenant/v2.0", OIDCUpstreamClientID: "cid"}
qt.Assert(t, qt.IsNil(generic.validateUpstream()))
eparaksts := Configuration{EparakstsAuthorityURL: "https://eparaksts.example", EparakstsClientID: "e"}
qt.Assert(t, qt.IsNil(eparaksts.validateUpstream()))
// The explicit-endpoint form of the generic connector counts as configured too.
explicit := Configuration{
OIDCUpstreamAuthorizeURL: "https://idp.example/a", OIDCUpstreamTokenURL: "https://idp.example/t",
OIDCUpstreamUserInfoURL: "https://idp.example/u", OIDCUpstreamClientID: "cid",
EparakstsAuthorityURL: "https://eparaksts.example",
}
qt.Assert(t, qt.StringContains(explicit.validateUpstream().Error(), "two upstream identity providers"))
}
func TestUpstreamConfigKeysBindToEnvironment(t *testing.T) {
prefixes := []string{"oidc_upstream_", "eparaksts_"}
typ := reflect.TypeOf(Configuration{})
keys := make([]string, 0, typ.NumField())
for i := range typ.NumField() {
key := typ.Field(i).Tag.Get("mapstructure")
for _, prefix := range prefixes {
if strings.HasPrefix(key, prefix) {
keys = append(keys, key)
break
}
}
}
// A guard on the guard: a refactor that renamed the fields away from these
// prefixes would otherwise leave this test passing over nothing at all.
qt.Assert(t, qt.IsTrue(len(keys) >= 10))
for _, key := range keys {
t.Run(key, func(t *testing.T) {
want := "probe-" + key
t.Setenv(strings.ToUpper(key), want)
v := viper.New()
NewConfiguration().Bind("", v)
qt.Check(t, qt.Equals(v.GetString(key), want),
qt.Commentf("%s is not bound to %s — add it to the BindEnv block; "+
"a field with no binding is invisible until an operator sets it and nothing happens",
key, strings.ToUpper(key)))
})
}
}