From 46f876feffe227dded17c28673b30bddc3015f2d Mon Sep 17 00:00:00 2001 From: Quentin BERTRAND Date: Tue, 19 Sep 2023 12:55:45 +0200 Subject: [PATCH] feat: add device auth parameter (#53) * feat: add device auth parameter * fix: value in module * fix: lint * fix: creates a server with device_auth attribute --- docs/resources/server.md | 1 + internal/pritunl/client.go | 4 ++ internal/pritunl/server.go | 1 + internal/pritunl/user.go | 1 + internal/provider/resource_server.go | 12 ++++ internal/provider/resource_server_test.go | 73 ++++++++++++++++++++--- 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/docs/resources/server.md b/docs/resources/server.md index b8d1ca1..a4d8dda 100644 --- a/docs/resources/server.md +++ b/docs/resources/server.md @@ -46,6 +46,7 @@ description: |- - **organization_ids** (List of String) The list of attached organizations to the server. - **sso_auth** (Boolean) Require client to authenticate with single sign-on provider on each connection using web browser. Requires client to have access to Pritunl web server port and running updated Pritunl Client. Single sign-on provider must already be configured for this feature to work properly. - **otp_auth** (Boolean) Enables two-step authentication using Google Authenticator. Verification code is entered as the user password when connecting +- **device_auth** (Boolean) Require administrator to approve every client device using TPM or Apple Secure Enclave - **ping_interval** (Number) Interval to ping client - **ping_timeout** (Number) Timeout for client ping. Must be greater then ping interval - **port** (Number) The port for the server diff --git a/internal/pritunl/client.go b/internal/pritunl/client.go index 3e0d70b..c09290e 100644 --- a/internal/pritunl/client.go +++ b/internal/pritunl/client.go @@ -299,6 +299,10 @@ func (c client) CreateServer(serverData map[string]interface{}) (*Server, error) serverStruct.OtpAuth = v.(bool) } + if v, ok := serverData["device_auth"]; ok { + serverStruct.DeviceAuth = v.(bool) + } + if v, ok := serverData["ipv6"]; ok { serverStruct.IPv6 = v.(bool) } diff --git a/internal/pritunl/server.go b/internal/pritunl/server.go index 6dba450..80c4f79 100644 --- a/internal/pritunl/server.go +++ b/internal/pritunl/server.go @@ -52,6 +52,7 @@ type Server struct { PreConnectMsg string `json:"pre_connect_msg,omitempty"` SsoAuth bool `json:"sso_auth,omitempty"` OtpAuth bool `json:"otp_auth,omitempty"` + DeviceAuth bool `json:"device_auth,omitempty"` MssFix int `json:"mss_fix,omitempty"` LzoCompression bool `json:"lzo_compression,omitempty"` BlockOutsideDns bool `json:"block_outside_dns,omitempty"` diff --git a/internal/pritunl/user.go b/internal/pritunl/user.go index bbfa713..61f4c89 100644 --- a/internal/pritunl/user.go +++ b/internal/pritunl/user.go @@ -24,6 +24,7 @@ type User struct { Audit bool `json:"audit,omitempty"` Gravatar bool `json:"gravatar,omitempty"` OtpAuth bool `json:"otp_auth,omitempty"` + DeviceAuth bool `json:"device_auth,omitempty"` Organization string `json:"organization,omitempty"` } diff --git a/internal/provider/resource_server.go b/internal/provider/resource_server.go index 1201964..4fdd848 100644 --- a/internal/provider/resource_server.go +++ b/internal/provider/resource_server.go @@ -203,6 +203,12 @@ func resourceServer() *schema.Resource { Optional: true, Description: "Enables two-step authentication using Google Authenticator. Verification code is entered as the user password when connecting", }, + "device_auth": { + Type: schema.TypeBool, + Required: false, + Optional: true, + Description: "Require administrator to approve every client device using TPM or Apple Secure Enclave", + }, "ipv6": { Type: schema.TypeBool, Required: false, @@ -526,6 +532,7 @@ func resourceReadServer(ctx context.Context, d *schema.ResourceData, meta interf d.Set("port_wg", server.PortWG) d.Set("sso_auth", server.SsoAuth) d.Set("otp_auth", server.OtpAuth) + d.Set("device_auth", server.DeviceAuth) d.Set("ipv6", server.IPv6) d.Set("dh_param_bits", server.DhParamBits) d.Set("ping_interval", server.PingInterval) @@ -647,6 +654,7 @@ func resourceCreateServer(ctx context.Context, d *schema.ResourceData, meta inte "port_wg": d.Get("port_wg"), "sso_auth": d.Get("sso_auth"), "otp_auth": d.Get("otp_auth"), + "device_auth": d.Get("device_auth"), "ipv6": d.Get("ipv6"), "dh_param_bits": d.Get("dh_param_bits"), "ping_interval": d.Get("ping_interval"), @@ -805,6 +813,10 @@ func resourceUpdateServer(ctx context.Context, d *schema.ResourceData, meta inte server.OtpAuth = d.Get("otp_auth").(bool) } + if d.HasChange("device_auth") { + server.DeviceAuth = d.Get("device_auth").(bool) + } + if d.HasChange("ipv6") { server.IPv6 = d.Get("ipv6").(bool) } diff --git a/internal/provider/resource_server_test.go b/internal/provider/resource_server_test.go index d96c468..d80d595 100644 --- a/internal/provider/resource_server_test.go +++ b/internal/provider/resource_server_test.go @@ -82,6 +82,56 @@ func TestAccPritunlServer(t *testing.T) { }) }) + t.Run("creates a server with device_auth attribute", func(t *testing.T) { + serverName := "tfacc-server1" + + testCase := func(t *testing.T, deviceAuth bool) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testPritunlServerDestroy, + Steps: []resource.TestStep{ + { + Config: testPritunlServerConfigWithDeviceAuth(serverName, deviceAuth), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("pritunl_server.test", "name", serverName), + resource.TestCheckResourceAttr("pritunl_server.test", "device_auth", strconv.FormatBool(deviceAuth)), + ), + }, + // import test + importStep("pritunl_server.test"), + }, + }) + } + + t.Run("with enabled option", func(t *testing.T) { + testCase(t, true) + }) + + t.Run("with disabled option", func(t *testing.T) { + testCase(t, false) + }) + + t.Run("without an option", func(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testPritunlServerDestroy, + Steps: []resource.TestStep{ + { + Config: testPritunlServerSimpleConfig(serverName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("pritunl_server.test", "name", serverName), + resource.TestCheckResourceAttr("pritunl_server.test", "device_auth", "false"), + ), + }, + // import test + importStep("pritunl_server.test"), + }, + }) + }) + }) + t.Run("creates a server with an attached organization", func(t *testing.T) { serverName := "tfacc-server1" orgName := "tfacc-org1" @@ -430,12 +480,21 @@ func testPritunlServerConfigWithSsoAuth(name string, ssoAuth bool) string { `, name, ssoAuth) } +func testPritunlServerConfigWithDeviceAuth(name string, deviceAuth bool) string { + return fmt.Sprintf(` + resource "pritunl_server" "test" { + name = "%[1]s" + device_auth = %[2]v + } + `, name, deviceAuth) +} + func testPritunlServerConfigWithAttachedOrganization(name, organizationName string) string { return fmt.Sprintf(` resource "pritunl_organization" "test" { name = "%[2]s" } - + resource "pritunl_server" "test" { name = "%[1]s" organization_ids = [ @@ -450,11 +509,11 @@ func testPritunlServerConfigWithAFewAttachedOrganizations(name, organization1Nam resource "pritunl_organization" "test" { name = "%[2]s" } - + resource "pritunl_organization" "test2" { name = "%[3]s" } - + resource "pritunl_server" "test" { name = "%[1]s" organization_ids = [ @@ -469,7 +528,7 @@ func testPritunlServerConfigWithAttachedRoute(name, route string) string { return fmt.Sprintf(` resource "pritunl_server" "test" { name = "%[1]s" - + route { network = "%[2]s" comment = "tfacc-route" @@ -482,17 +541,17 @@ func testPritunlServerConfigWithAFewAttachedRoutes(name, route1, route2, route3 return fmt.Sprintf(` resource "pritunl_server" "test" { name = "%[1]s" - + route { network = "%[2]s" comment = "tfacc-route" } - + route { network = "%[3]s" comment = "tfacc-route" } - + route { network = "%[4]s" comment = "tfacc-route"