Enable Feishu session username override with OpenVPN 2.7
This commit is contained in:
1 parent
8fd8c0cd73
commit
db3092344f
3 files changed
+115
-5
No files matched your search
@@ -60,13 +60,35 @@ func yamlString(s string) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func oidcConfig(t *model.Tunnel, cfg map[string]interface{}) string {
|
||||
func supportsOverrideUsername() bool {
|
||||
bin, ok := findOpenVPNBin()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
out, err := exec.Command(bin, "--version").Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
m := regexp.MustCompile(`OpenVPN\s+(\d+)\.(\d+)\.(\d+)`).FindSubmatch(out)
|
||||
if len(m) != 4 {
|
||||
return false
|
||||
}
|
||||
major, _ := strconv.Atoi(string(m[1]))
|
||||
minor, _ := strconv.Atoi(string(m[2]))
|
||||
return major > 2 || major == 2 && minor >= 7
|
||||
}
|
||||
|
||||
func oidcConfig(t *model.Tunnel, cfg map[string]interface{}, overrideUsername bool) string {
|
||||
dir := service.InstanceDir(t)
|
||||
usernameConfig := ""
|
||||
overrideConfig := ""
|
||||
if service.Str(cfg, "oidc_provider") == "builtin" {
|
||||
usernameConfig = " openvpn-username: \"string(token.claims.sub)\"\n"
|
||||
if overrideUsername {
|
||||
overrideConfig = " override-username: true\n"
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("http:\n baseurl: %s\n listen: %s\n secret: %s\n template: %s\noauth2:\n%s issuer: %s\n client:\n id: %s\n secret: %s\nopenvpn:\n addr: %s\n password: %s\n auth-token-user: true\n",
|
||||
return fmt.Sprintf("http:\n baseurl: %s\n listen: %s\n secret: %s\n template: %s\noauth2:\n%s issuer: %s\n client:\n id: %s\n secret: %s\nopenvpn:\n%s addr: %s\n password: %s\n auth-token-user: true\n",
|
||||
yamlString(service.Str(cfg, "oidc_base_url")),
|
||||
yamlString(fmt.Sprintf("127.0.0.1:%d", int(service.Num(cfg, "oidc_http_port", 19090)))),
|
||||
yamlString(service.Str(cfg, "oidc_http_secret")),
|
||||
@@ -75,6 +97,7 @@ func oidcConfig(t *model.Tunnel, cfg map[string]interface{}) string {
|
||||
yamlString(service.Str(cfg, "oidc_issuer")),
|
||||
yamlString(service.Str(cfg, "oidc_client_id")),
|
||||
yamlString(service.Str(cfg, "oidc_client_secret")),
|
||||
overrideConfig,
|
||||
yamlString("unix://"+filepath.Join(dir, "management.sock")),
|
||||
yamlString(service.Str(cfg, "oidc_management_password")))
|
||||
}
|
||||
@@ -153,7 +176,7 @@ func prepareOIDC(t *model.Tunnel, cfg map[string]interface{}) error {
|
||||
if err := os.Chmod(pagePath, 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
configPath, err := service.WriteConfig(t, "openvpn-auth-oauth2.yaml", oidcConfig(t, cfg))
|
||||
configPath, err := service.WriteConfig(t, "openvpn-auth-oauth2.yaml", oidcConfig(t, cfg, supportsOverrideUsername()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -98,16 +98,47 @@ func TestBuiltInOIDCUsesStableSubjectAsOpenVPNUsername(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"oidc_provider": "builtin", "oidc_issuer": "https://vpn.example.com/id",
|
||||
}
|
||||
generated := oidcConfig(tunnel, config)
|
||||
generated := oidcConfig(tunnel, config, true)
|
||||
if !strings.Contains(generated, `openvpn-username: "string(token.claims.sub)"`) {
|
||||
t.Fatalf("built-in issuer must use verified subject as username: %s", generated)
|
||||
}
|
||||
if !strings.Contains(generated, "override-username: true") {
|
||||
t.Fatal("OpenVPN 2.7 must receive the authenticated subject in its status output")
|
||||
}
|
||||
if generated := oidcConfig(tunnel, config, false); strings.Contains(generated, "override-username:") {
|
||||
t.Fatal("OpenVPN 2.6 must not receive an unsupported username override")
|
||||
}
|
||||
config["oidc_provider"] = "external"
|
||||
if generated := oidcConfig(tunnel, config); strings.Contains(generated, "openvpn-username:") {
|
||||
if generated := oidcConfig(tunnel, config, true); strings.Contains(generated, "openvpn-username:") || strings.Contains(generated, "override-username:") {
|
||||
t.Fatalf("external issuer username behavior must remain unchanged: %s", generated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrideUsernameRequiresOpenVPN27(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
t.Setenv("VPN_DATA_DIR", dir)
|
||||
binDir := filepath.Join(dir, "bin")
|
||||
if err := os.MkdirAll(binDir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bin := filepath.Join(binDir, "openvpn")
|
||||
for _, tc := range []struct {
|
||||
version string
|
||||
want bool
|
||||
}{
|
||||
{"OpenVPN 2.6.19 test\n", false},
|
||||
{"OpenVPN 2.7.8 test\n", true},
|
||||
{"unexpected output\n", false},
|
||||
} {
|
||||
if err := os.WriteFile(bin, []byte("#!/bin/sh\necho '"+strings.TrimSpace(tc.version)+"'\n"), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := supportsOverrideUsername(); got != tc.want {
|
||||
t.Fatalf("version %q: supportsOverrideUsername() = %v, want %v", tc.version, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOIDCRejectsUnsafeURLs(t *testing.T) {
|
||||
base := map[string]interface{}{
|
||||
"auth_mode": "oidc", "oidc_issuer": "https://idp.example.com/realms/a",
|
||||
|
||||
Reference in new issue
Block a user