Skip to content

Commit

Permalink
Merge pull request #17748 from reancloud/winrm-ntlm
Browse files Browse the repository at this point in the history
Support NTLM for WinRM communicators.
  • Loading branch information
jbardin authored Apr 5, 2018
2 parents 61eae05 + 138e64d commit 060a3bc
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 0 deletions.
9 changes: 9 additions & 0 deletions communicator/winrm/communicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ func (c *Communicator) Connect(o terraform.UIOutput) error {

params := winrm.DefaultParameters
params.Timeout = formatDuration(c.Timeout())
if c.connInfo.NTLM == true {
params.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
}

client, err := winrm.NewClientWithParameters(
c.endpoint, c.connInfo.User, c.connInfo.Password, params)
Expand All @@ -78,13 +81,15 @@ func (c *Communicator) Connect(o terraform.UIOutput) error {
" Password: %t\n"+
" HTTPS: %t\n"+
" Insecure: %t\n"+
" NTLM: %t\n"+
" CACert: %t",
c.connInfo.Host,
c.connInfo.Port,
c.connInfo.User,
c.connInfo.Password != "",
c.connInfo.HTTPS,
c.connInfo.Insecure,
c.connInfo.NTLM,
c.connInfo.CACert != "",
))
}
Expand Down Expand Up @@ -213,6 +218,10 @@ func (c *Communicator) newCopyClient() (*winrmcp.Winrmcp, error) {
MaxOperationsPerShell: 15, // lowest common denominator
}

if c.connInfo.NTLM == true {
config.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
}

if c.connInfo.CACert != "" {
config.CACertBytes = []byte(c.connInfo.CACert)
}
Expand Down
67 changes: 67 additions & 0 deletions communicator/winrm/communicator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,73 @@ func TestScriptPath(t *testing.T) {
}
}

func TestNoTransportDecorator(t *testing.T) {
wrm := newMockWinRMServer(t)
defer wrm.Close()

r := &terraform.InstanceState{
Ephemeral: terraform.EphemeralState{
ConnInfo: map[string]string{
"type": "winrm",
"user": "user",
"password": "pass",
"host": wrm.Host,
"port": strconv.Itoa(wrm.Port),
"timeout": "30s",
},
},
}

c, err := New(r)
if err != nil {
t.Fatalf("error creating communicator: %s", err)
}

err = c.Connect(nil)
if err != nil {
t.Fatalf("error connecting communicator: %s", err)
}
defer c.Disconnect()

if c.client.TransportDecorator != nil {
t.Fatal("bad TransportDecorator: expected nil, got non-nil")
}
}

func TestTransportDecorator(t *testing.T) {
wrm := newMockWinRMServer(t)
defer wrm.Close()

r := &terraform.InstanceState{
Ephemeral: terraform.EphemeralState{
ConnInfo: map[string]string{
"type": "winrm",
"user": "user",
"password": "pass",
"host": wrm.Host,
"port": strconv.Itoa(wrm.Port),
"use_ntlm": "true",
"timeout": "30s",
},
},
}

c, err := New(r)
if err != nil {
t.Fatalf("error creating communicator: %s", err)
}

err = c.Connect(nil)
if err != nil {
t.Fatalf("error connecting communicator: %s", err)
}
defer c.Disconnect()

if c.client.TransportDecorator == nil {
t.Fatal("bad TransportDecorator: expected non-nil, got nil")
}
}

func TestScriptPath_randSeed(t *testing.T) {
// Pre GH-4186 fix, this value was the deterministic start the pseudorandom
// chain of unseeded math/rand values for Int31().
Expand Down
1 change: 1 addition & 0 deletions communicator/winrm/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type connectionInfo struct {
Port int
HTTPS bool
Insecure bool
NTLM bool `mapstructure:"use_ntlm"`
CACert string `mapstructure:"cacert"`
Timeout string
ScriptPath string `mapstructure:"script_path"`
Expand Down
4 changes: 4 additions & 0 deletions communicator/winrm/provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func TestProvisioner_connInfo(t *testing.T) {
"host": "127.0.0.1",
"port": "5985",
"https": "true",
"use_ntlm": "true",
"timeout": "30s",
},
},
Expand All @@ -41,6 +42,9 @@ func TestProvisioner_connInfo(t *testing.T) {
if conf.HTTPS != true {
t.Fatalf("expected: %v: got: %v", true, conf)
}
if conf.NTLM != true {
t.Fatalf("expected: %v: got: %v", true, conf)
}
if conf.Timeout != "30s" {
t.Fatalf("expected: %v: got: %v", "30s", conf)
}
Expand Down
1 change: 1 addition & 0 deletions terraform/eval_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func (n *EvalValidateProvisioner) validateConnConfig(connConfig *ResourceConfig)
// For type=winrm only (enforced in winrm communicator)
HTTPS interface{} `mapstructure:"https"`
Insecure interface{} `mapstructure:"insecure"`
NTLM interface{} `mapstructure:"use_ntlm"`
CACert interface{} `mapstructure:"cacert"`
}

Expand Down
2 changes: 2 additions & 0 deletions website/docs/provisioners/connection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ provisioner "file" {

* `insecure` - Set to `true` to not validate the HTTPS certificate chain.

* `use_ntlm` - Set to `true` to use NTLM authentication, rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Further reading for remote connection authentication can be found [here](https://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx).

* `cacert` - The CA certificate to validate against.

<a id="bastion"></a>
Expand Down

0 comments on commit 060a3bc

Please sign in to comment.