Bind Feishu identity to OpenVPN sessions and refine management UI

This commit is contained in:
opsx committed 2026-10-22 23:24:41 +08:00
1 parent 347799cb1e
commit 8fd8c0cd73
27 files changed
+1556 -1011

No files matched your search

@@ -47,7 +47,7 @@ func TestFeishuExchangeUsesJSONAndRejectsUnexpectedIdentity(t *testing.T) {
t.Fatalf("exchange: %q %v", token, err)
}
user, tenant, err := fetchFeishuUser(context.Background(), token)
if err != nil || tenant != "tenant_1" || user.Subject != "tenant_1:ou_1" {
if err != nil || tenant != "tenant_1" || user.Subject != "tenant_1:ou_1" || user.Name != "Alice" {
t.Fatalf("identity: %+v %s %v", user, tenant, err)
}
}
@@ -86,7 +86,7 @@ func TestGrantSingleUseAndSignedToken(t *testing.T) {
if err != nil {
t.Fatal(err)
}
grant := codeData{requestState: requestState{ClientID: "opsx-vpn", Redirect: "https://vpn.example.com/oauth2/callback", Nonce: "nonce-1"}, Subject: "tenant:ou_1"}
grant := codeData{requestState: requestState{ClientID: "opsx-vpn", Redirect: "https://vpn.example.com/oauth2/callback", Nonce: "nonce-1"}, Subject: "tenant:ou_1", Name: "Alice"}
if err := saveGrant("code", code, grant, time.Minute); err != nil {
t.Fatal(err)
}
@@ -122,7 +122,7 @@ func TestGrantSingleUseAndSignedToken(t *testing.T) {
t.Fatal(err)
}
var claims map[string]any
if json.Unmarshal(claimsRaw, &claims) != nil || claims["sub"] != "tenant:ou_1" || claims["nonce"] != "nonce-1" || claims["aud"] != "opsx-vpn" {
if json.Unmarshal(claimsRaw, &claims) != nil || claims["sub"] != "tenant:ou_1" || claims["name"] != "Alice" || claims["nonce"] != "nonce-1" || claims["aud"] != "opsx-vpn" {
t.Fatalf("unexpected claims: %v", claims)
}
if info, err := filepath.Glob(filepath.Join(dir, "identity", "*.pem")); err != nil || len(info) != 1 {
@@ -130,6 +130,33 @@ func TestGrantSingleUseAndSignedToken(t *testing.T) {
}
}
func TestIDTokenOmitsMissingDisplayName(t *testing.T) {
t.Setenv("VPN_DATA_DIR", t.TempDir())
key, kid, err := signingKey()
if err != nil {
t.Fatal(err)
}
token, err := signIDToken(key, kid, "https://vpn.example.com/id", model.IdentityProvider{ClientID: "opsx-vpn"}, codeData{Subject: "tenant:ou_1"})
if err != nil {
t.Fatal(err)
}
parts := strings.Split(token, ".")
if len(parts) != 3 {
t.Fatal("invalid JWT")
}
body, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
t.Fatal(err)
}
var claims map[string]any
if json.Unmarshal(body, &claims) != nil || claims["sub"] != "tenant:ou_1" {
t.Fatalf("stable identity missing: %v", claims)
}
if _, present := claims["name"]; present {
t.Fatal("empty display name should not be added to ID token")
}
}
func TestRedirectIsExactAndNoOpenRedirect(t *testing.T) {
if !validateRedirect("https://vpn.example.com/oauth2/callback", "vpn.example.com") {
t.Fatal("valid callback rejected")