Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support NTLM for WinRM communicators. #17748

Merged
merged 5 commits into from
Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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