Skip to content

Commit

Permalink
Merge pull request #7 from d-strobel/feat/kerberos-authentication
Browse files Browse the repository at this point in the history
Feat/kerberos authentication
  • Loading branch information
d-strobel authored Nov 11, 2023
2 parents 645caab + 1430bd8 commit 2804e9c
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 37 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ To run all tests run the following command:
make testacc
```

## Third-Party libraries
* [masterzen/winrm](https://github.com/masterzen/winrm)

## Inspirations
* [hashicorp - terraform-provider-ad](https://github.com/hashicorp/terraform-provider-ad)

Expand Down
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package gowindows

import (
"github.com/d-strobel/gowindows/connection"
"github.com/d-strobel/gowindows/package/local"
"github.com/d-strobel/gowindows/windows/local"
)

type Client struct {
Expand Down
2 changes: 1 addition & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"

"github.com/d-strobel/gowindows/connection"
"github.com/d-strobel/gowindows/package/local"
"github.com/d-strobel/gowindows/windows/local"
"github.com/stretchr/testify/mock"
)

Expand Down
12 changes: 0 additions & 12 deletions connection/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@ package connection
import (
"context"
"errors"
"time"

"github.com/masterzen/winrm"
"golang.org/x/crypto/ssh"
)

const (
// WinRM default values
defaultWinRMPort int = 5986
defaultWinRMUseTLS bool = false
defaultWinRMInsecure bool = true
defaultWinRMTimeout time.Duration = 0

// SSH default values
defaultSSHPort int = 22
)

type Connection struct {
WinRM *winrm.Client
SSH *ssh.Client
Expand Down
44 changes: 44 additions & 0 deletions connection/kerberos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package connection

import (
"github.com/masterzen/winrm"
)

type KerberosConfig struct {
Realm string
KrbConfigFile string
}

const (
// Default kerberos values
defaultKerberosProtocol = "http"
)

// winRMKerberosParams returns the neccessary parameters
// to pass into the kerberos winrm connection
func winRMKerberosParams(config *WinRMConfig) *winrm.Parameters {

// Init default parameters
params := winrm.DefaultParameters

// Set the protocol
kerberosProtocol := defaultKerberosProtocol
if config.WinRMUseTLS {
kerberosProtocol = "https"
}

// Configure kerberos transporter
params.TransportDecorator = func() winrm.Transporter {
return &winrm.ClientKerberos{
Username: config.WinRMUsername,
Password: config.WinRMPassword,
Hostname: config.WinRMHost,
Realm: config.WinRMKerberos.Realm,
Port: config.WinRMPort,
Proto: kerberosProtocol,
KrbConf: config.WinRMKerberos.KrbConfigFile,
}
}

return params
}
58 changes: 58 additions & 0 deletions connection/kerberos_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package connection

import (
"testing"

"github.com/masterzen/winrm"
"github.com/stretchr/testify/assert"
)

func TestWinRMKerberosParams(t *testing.T) {
// Create a sample WinRM configuration
winRMConfig := &WinRMConfig{
WinRMUsername: "testUser",
WinRMPassword: "testPassword",
WinRMHost: "testHost",
WinRMKerberos: &KerberosConfig{
Realm: "testRealm",
KrbConfigFile: "/path/to/krb5.conf",
},
WinRMUseTLS: false,
WinRMPort: 5985,
}

// Call the function to get the parameters
params := winRMKerberosParams(winRMConfig)

// Check that the parameters are set as expected
assert.NotNil(t, params)
assert.NotNil(t, params.TransportDecorator)
assert.Equal(t, winRMConfig.WinRMUsername, params.TransportDecorator().(*winrm.ClientKerberos).Username)
assert.Equal(t, winRMConfig.WinRMPassword, params.TransportDecorator().(*winrm.ClientKerberos).Password)
assert.Equal(t, winRMConfig.WinRMHost, params.TransportDecorator().(*winrm.ClientKerberos).Hostname)
assert.Equal(t, winRMConfig.WinRMKerberos.Realm, params.TransportDecorator().(*winrm.ClientKerberos).Realm)
assert.Equal(t, winRMConfig.WinRMPort, params.TransportDecorator().(*winrm.ClientKerberos).Port)
assert.Equal(t, "http", params.TransportDecorator().(*winrm.ClientKerberos).Proto)
assert.Equal(t, winRMConfig.WinRMKerberos.KrbConfigFile, params.TransportDecorator().(*winrm.ClientKerberos).KrbConf)
}

func TestWinRMKerberosParamsWithTLS(t *testing.T) {
// Create a sample WinRM configuration with WinRMUseTLS set to true
winRMConfig := &WinRMConfig{
WinRMUsername: "testUser",
WinRMPassword: "testPassword",
WinRMHost: "testHost",
WinRMKerberos: &KerberosConfig{
Realm: "testRealm",
KrbConfigFile: "/path/to/krb5.conf",
},
WinRMUseTLS: true, // Set WinRMUseTLS to true
WinRMPort: 5985,
}

// Call the function to get the parameters
params := winRMKerberosParams(winRMConfig)

// Check that the protocol is set to "https" when WinRMUseTLS is true
assert.Equal(t, "https", params.TransportDecorator().(*winrm.ClientKerberos).Proto)
}
7 changes: 6 additions & 1 deletion connection/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ type SSHConfig struct {
SSHPassword string
}

const (
// SSH default values
defaultSSHPort int = 22
)

func newSSHClient(config *SSHConfig) (*ssh.Client, error) {

// Assert
Expand All @@ -24,7 +29,7 @@ func newSSHClient(config *SSHConfig) (*ssh.Client, error) {
}

// Parse ssh host string
sshHost := fmt.Sprintf("%s:%s", config.SSHHost, fmt.Sprint(config.SSHPort))
sshHost := fmt.Sprintf("%s:%d", config.SSHHost, config.SSHPort)

// Configuration
sshConfig := &ssh.ClientConfig{
Expand Down
19 changes: 0 additions & 19 deletions connection/ssh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,6 @@ import (
)

func TestNewSSHClient(t *testing.T) {
// t.Run("ValidConfig", func(t *testing.T) {

// config := &SSHConfig{
// SSHHost: os.Getenv("GOWINDOWS_TEST_SSH_HOST"),
// SSHPort: 22,
// SSHUsername: os.Getenv("GOWINDOWS_TEST_SSH_USERNAME"),
// SSHPassword: os.Getenv("GOWINDOWS_TEST_SSH_PASSWORD"),
// }

// client, err := newSSHClient(config)
// if err != nil {
// t.Errorf("Expected no error, but got %v", err)
// }
// if client == nil {
// t.Error("Expected a non-nil SSH client, but got nil")
// }

// })

t.Run("InvalidConfig", func(t *testing.T) {
// Test case with missing required fields
config := &SSHConfig{}
Expand Down
27 changes: 24 additions & 3 deletions connection/winrm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ type WinRMConfig struct {
WinRMUseTLS bool
WinRMInsecure bool
WinRMTimeout time.Duration
WinRMKerberos *KerberosConfig
}

const (
// WinRM default values
defaultWinRMPort int = 5985
defaultWinRMPortTLS int = 5986
defaultWinRMUseTLS bool = false
defaultWinRMInsecure bool = true
defaultWinRMTimeout time.Duration = 0
)

func newWinRMClient(config *WinRMConfig) (*winrm.Client, error) {

// Assert
Expand All @@ -25,12 +35,17 @@ func newWinRMClient(config *WinRMConfig) (*winrm.Client, error) {
}

// Set default values
if config.WinRMPort == 0 {
config.WinRMPort = defaultWinRMPort
}
if !config.WinRMUseTLS {
config.WinRMUseTLS = defaultWinRMUseTLS
}
if config.WinRMPort == 0 {
config.WinRMPort = defaultWinRMPort

// Set a different default port if TLS enabled
if config.WinRMUseTLS {
config.WinRMPort = defaultWinRMPortTLS
}
}
if config.WinRMTimeout == 0 {
config.WinRMTimeout = defaultWinRMTimeout
}
Expand All @@ -52,5 +67,11 @@ func newWinRMClient(config *WinRMConfig) (*winrm.Client, error) {
config.WinRMTimeout,
)

// Kerberos transport
if config.WinRMKerberos != nil {
params := winRMKerberosParams(config)
return winrm.NewClientWithParameters(winRMEndpoint, config.WinRMUsername, config.WinRMPassword, params)
}

return winrm.NewClient(winRMEndpoint, config.WinRMUsername, config.WinRMPassword)
}
63 changes: 63 additions & 0 deletions connection/winrm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,66 @@ func TestNewWinRMClient(t *testing.T) {
}
})
}

func TestNewWinRMClientWithDefaultValues(t *testing.T) {
t.Run("Defaults Used", func(t *testing.T) {
// Test case with minimal configuration, should use default values
config := &WinRMConfig{
WinRMHost: "example.com",
WinRMUsername: "username",
WinRMPassword: "password",
}

client, err := newWinRMClient(config)

if err != nil {
t.Errorf("Expected no error, but got %v", err)
}

if client == nil {
t.Error("Expected a non-nil client, but got nil")
}

// Check that default values were applied
if config.WinRMPort != defaultWinRMPort {
t.Errorf("Expected WinRMPort to be %d, but got %d", defaultWinRMPort, config.WinRMPort)
}

if config.WinRMUseTLS != defaultWinRMUseTLS {
t.Errorf("Expected WinRMUseTLS to be %v, but got %v", defaultWinRMUseTLS, config.WinRMUseTLS)
}

if config.WinRMTimeout != defaultWinRMTimeout {
t.Errorf("Expected WinRMTimeout to be %v, but got %v", defaultWinRMTimeout, config.WinRMTimeout)
}
})

t.Run("TLS Used", func(t *testing.T) {
// Test case with minimal configuration, should use default values
config := &WinRMConfig{
WinRMHost: "example.com",
WinRMUsername: "username",
WinRMPassword: "password",
WinRMUseTLS: true,
}

client, err := newWinRMClient(config)

if err != nil {
t.Errorf("Expected no error, but got %v", err)
}

if client == nil {
t.Error("Expected a non-nil client, but got nil")
}

// Check that default values were applied
if config.WinRMPort != defaultWinRMPortTLS {
t.Errorf("Expected WinRMPort to be %d, but got %d", defaultWinRMPortTLS, config.WinRMPort)
}

if config.WinRMTimeout != defaultWinRMTimeout {
t.Errorf("Expected WinRMTimeout to be %v, but got %v", defaultWinRMTimeout, config.WinRMTimeout)
}
})
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 2804e9c

Please sign in to comment.