summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2018-11-05 07:27:05 -0800
committerGitHub <noreply@github.com>2018-11-05 07:27:05 -0800
commit27bf43db30c3db696dbaab87d19343666a819e72 (patch)
tree163a46d0a1ea9466651568598dc9e31842d5db7a
parent324a2a16d89be612e6f4681f3b01f0ab11daf5da (diff)
parent31089f89eba528a74678beb953d54896228205d1 (diff)
downloadchef-27bf43db30c3db696dbaab87d19343666a819e72.tar.gz
Merge pull request #7842 from Intility/windows_firewall_rule
Add windows_firewall_rule
-rw-r--r--lib/chef/resource/windows_firewall_rule.rb199
-rw-r--r--lib/chef/resources.rb1
-rw-r--r--spec/unit/resource/windows_firewall_rule_spec.rb361
3 files changed, 561 insertions, 0 deletions
diff --git a/lib/chef/resource/windows_firewall_rule.rb b/lib/chef/resource/windows_firewall_rule.rb
new file mode 100644
index 0000000000..a7e4609605
--- /dev/null
+++ b/lib/chef/resource/windows_firewall_rule.rb
@@ -0,0 +1,199 @@
+# Author:: Matt Clifton (spartacus003@hotmail.com)
+# Author:: Matt Stratton (matt.stratton@gmail.com)
+# Author:: Tor Magnus Rakvåg (tor.magnus@outlook.com)
+# Author:: Tim Smith (tsmith@chef.io)
+# Copyright:: 2013-2015 Matt Clifton
+# Copyright:: 2018, Chef Software, Inc.
+# Copyright:: 2018, Intility AS
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/json_compat"
+
+class Chef
+ class Resource
+ class WindowsFirewallRule < Chef::Resource
+ resource_name :windows_firewall_rule
+
+ description "Use the windows_firewall_rule resource to create, change or remove windows firewall rules."
+ introduced "14.7"
+
+ property :rule_name, String,
+ name_property: true,
+ description: "The name to assign to the firewall rule."
+
+ property :description, String,
+ default: "Firewall rule",
+ description: "The description to assign to the firewall rule."
+
+ property :local_address, String,
+ description: "The local address the firewall rule applies to."
+
+ property :local_port, String,
+ description: "The local port the firewall rule applies to."
+
+ property :remote_address, String,
+ description: "The remote address the firewall rule applies to."
+
+ property :remote_port, String,
+ description: "The remote port the firewall rule applies to."
+
+ property :direction, [Symbol, String],
+ default: :inbound,
+ equal_to: [:inbound, :outbound],
+ description: "The direction of the firewall rule. Direction means either inbound or outbound traffic.",
+ coerce: proc { |d| d.is_a?(String) ? d.downcase.to_sym : d }
+
+ property :protocol, String,
+ default: "TCP",
+ description: "The protocol the firewall rule applies to."
+
+ property :firewall_action, [Symbol, String],
+ default: :allow,
+ equal_to: [:allow, :block, :notconfigured],
+ description: "The action of the firewall rule.",
+ coerce: proc { |f| f.is_a?(String) ? f.downcase.to_sym : f }
+
+ property :profile, [Symbol, String],
+ default: :any,
+ equal_to: [:public, :private, :domain, :any, :notapplicable],
+ description: "The profile the firewall rule applies to.",
+ coerce: proc { |p| p.is_a?(String) ? p.downcase.to_sym : p }
+
+ property :program, String,
+ description: "The program the firewall rule applies to."
+
+ property :service, String,
+ description: "The service the firewall rule applies to."
+
+ property :interface_type, [Symbol, String],
+ default: :any,
+ equal_to: [:any, :wireless, :wired, :remoteaccess],
+ description: "The interface type the firewall rule applies to.",
+ coerce: proc { |i| i.is_a?(String) ? i.downcase.to_sym : i }
+
+ property :enabled, [TrueClass, FalseClass],
+ default: true,
+ description: "Whether or not to enable the firewall rule."
+
+ alias_method :localip, :local_address
+ alias_method :remoteip, :remote_address
+ alias_method :localport, :local_port
+ alias_method :remoteport, :remote_port
+ alias_method :interfacetype, :interface_type
+
+ load_current_value do
+ load_state_cmd = load_firewall_state(rule_name)
+ output = powershell_out(load_state_cmd)
+ if output.stdout.empty?
+ current_value_does_not_exist!
+ else
+ state = Chef::JSONCompat.from_json(output.stdout)
+ end
+ local_address state["local_address"]
+ local_port state["local_port"]
+ remote_address state["remote_address"]
+ remote_port state["remote_port"]
+ direction state["direction"]
+ protocol state["protocol"]
+ firewall_action state["firewall_action"]
+ profile state["profile"]
+ program state["program"]
+ service state["service"]
+ interface_type state["interface_type"]
+ enabled state["enabled"]
+ end
+
+ action :create do
+ if current_resource
+ converge_if_changed :rule_name, :local_address, :local_port, :remote_address, :remote_port, :direction,
+ :protocol, :firewall_action, :profile, :program, :service, :interface_type, :enabled do
+ cmd = firewall_command("Set")
+ powershell_out!(cmd)
+ end
+ else
+ converge_by("create firewall rule #{new_resource.rule_name}") do
+ cmd = firewall_command("New")
+ powershell_out!(cmd)
+ end
+ end
+ end
+
+ action :delete do
+ if current_resource
+ converge_by("delete firewall rule #{new_resource.rule_name}") do
+ powershell_out!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'")
+ end
+ else
+ Chef::Log.info("Firewall rule \"#{new_resource.rule_name}\" doesn't exist. Skipping.")
+ end
+ end
+
+ action_class do
+ # build the command to create a firewall rule based on new_resource values
+ # @return [String] firewall create command
+ def firewall_command(cmdlet_type)
+ cmd = "#{cmdlet_type}-NetFirewallRule -Name '#{new_resource.rule_name}'"
+ cmd << " -DisplayName '#{new_resource.rule_name}'" if cmdlet_type == "New"
+ cmd << " -Description '#{new_resource.description}'" if new_resource.description
+ cmd << " -LocalAddress '#{new_resource.local_address}'" if new_resource.local_address
+ cmd << " -LocalPort '#{new_resource.local_port}'" if new_resource.local_port
+ cmd << " -RemoteAddress '#{new_resource.remote_address}'" if new_resource.remote_address
+ cmd << " -RemotePort '#{new_resource.remote_port}'" if new_resource.remote_port
+ cmd << " -Direction '#{new_resource.direction}'" if new_resource.direction
+ cmd << " -Protocol '#{new_resource.protocol}'" if new_resource.protocol
+ cmd << " -Action '#{new_resource.firewall_action}'" if new_resource.firewall_action
+ cmd << " -Profile '#{new_resource.profile}'" if new_resource.profile
+ cmd << " -Program '#{new_resource.program}'" if new_resource.program
+ cmd << " -Service '#{new_resource.service}'" if new_resource.service
+ cmd << " -InterfaceType '#{new_resource.interface_type}'" if new_resource.interface_type
+ cmd << " -Enabled '#{new_resource.enabled}'"
+
+ cmd
+ end
+ end
+
+ private
+
+ # build the command to load the current resource
+ # # @return [String] current firewall state
+ def load_firewall_state(rule_name)
+ <<-EOH
+ $rule = Get-NetFirewallRule -Name '#{rule_name}'
+ $addressFilter = $rule | Get-NetFirewallAddressFilter
+ $portFilter = $rule | Get-NetFirewallPortFilter
+ $applicationFilter = $rule | Get-NetFirewallApplicationFilter
+ $serviceFilter = $rule | Get-NetFirewallServiceFilter
+ $interfaceTypeFilter = $rule | Get-NetFirewallInterfaceTypeFilter
+ ([PSCustomObject]@{
+ rule_name = $rule.Name
+ description = $rule.Description
+ local_address = $addressFilter.LocalAddress
+ local_port = $portFilter.LocalPort
+ remote_address = $addressFilter.RemoteAddress
+ remote_port = $portFilter.RemotePort
+ direction = $rule.Direction.ToString()
+ protocol = $portFilter.Protocol
+ firewall_action = $rule.Action.ToString()
+ profile = $rule.Profile.ToString()
+ program = $applicationFilter.Program
+ service = $serviceFilter.Service
+ interface_type = $interfaceTypeFilter.InterfaceType.ToString()
+ enabled = [bool]::Parse($rule.Enabled.ToString())
+ }) | ConvertTo-Json
+ EOH
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 805d278cc6..32739087d5 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -134,6 +134,7 @@ require "chef/resource/windows_certificate"
require "chef/resource/windows_feature"
require "chef/resource/windows_feature_dism"
require "chef/resource/windows_feature_powershell"
+require "chef/resource/windows_firewall_rule"
require "chef/resource/windows_font"
require "chef/resource/windows_pagefile"
require "chef/resource/windows_path"
diff --git a/spec/unit/resource/windows_firewall_rule_spec.rb b/spec/unit/resource/windows_firewall_rule_spec.rb
new file mode 100644
index 0000000000..b20425e21b
--- /dev/null
+++ b/spec/unit/resource/windows_firewall_rule_spec.rb
@@ -0,0 +1,361 @@
+# Author:: Tor Magnus Rakvåg (tor.magnus@outlook.com)
+# Copyright:: 2018, Intility AS
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::WindowsFirewallRule do
+ let(:resource) { Chef::Resource::WindowsFirewallRule.new("rule") }
+ let(:provider) { resource.provider_for_action(:enable) }
+
+ it "has a resource name of :windows_firewall_rule" do
+ expect(resource.resource_name).to eql(:windows_firewall_rule)
+ end
+
+ it "the name_property is 'rule_name'" do
+ expect(resource.rule_name).to eql("rule")
+ end
+
+ it "the default action is :create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "supports :create and :delete actions" do
+ expect { resource.action :create }.not_to raise_error
+ expect { resource.action :delete }.not_to raise_error
+ end
+
+ it "the rule_name property accepts strings" do
+ resource.rule_name("rule2")
+ expect(resource.rule_name).to eql("rule2")
+ end
+
+ it "the description property accepts strings" do
+ resource.description("firewall rule")
+ expect(resource.description).to eql("firewall rule")
+ end
+
+ it "the local_address property accepts strings" do
+ resource.local_address("192.168.1.1")
+ expect(resource.local_address).to eql("192.168.1.1")
+ end
+
+ it "the local_port property accepts strings" do
+ resource.local_port("8080")
+ expect(resource.local_port).to eql("8080")
+ end
+
+ it "the remote_address property accepts strings" do
+ resource.remote_address("8.8.4.4")
+ expect(resource.remote_address).to eql("8.8.4.4")
+ end
+
+ it "the remote_port property accepts strings" do
+ resource.remote_port("8081")
+ expect(resource.remote_port).to eql("8081")
+ end
+
+ it "the direction property accepts :inbound and :outbound" do
+ resource.direction(:inbound)
+ expect(resource.direction).to eql(:inbound)
+ resource.direction(:outbound)
+ expect(resource.direction).to eql(:outbound)
+ end
+
+ it "the direction property coerces strings to symbols" do
+ resource.direction("Inbound")
+ expect(resource.direction).to eql(:inbound)
+ end
+
+ it "the protocol property accepts strings" do
+ resource.protocol("TCP")
+ expect(resource.protocol).to eql("TCP")
+ end
+
+ it "the firewall_action property accepts :allow, :block and :notconfigured" do
+ resource.firewall_action(:allow)
+ expect(resource.firewall_action).to eql(:allow)
+ resource.firewall_action(:block)
+ expect(resource.firewall_action).to eql(:block)
+ resource.firewall_action(:notconfigured)
+ expect(resource.firewall_action).to eql(:notconfigured)
+ end
+
+ it "the firewall_action property coerces strings to symbols" do
+ resource.firewall_action("Allow")
+ expect(resource.firewall_action).to eql(:allow)
+ end
+
+ it "the profile property accepts :public, :private, :domain, :any and :notapplicable" do
+ resource.profile(:public)
+ expect(resource.profile).to eql(:public)
+ resource.profile(:private)
+ expect(resource.profile).to eql(:private)
+ resource.profile(:domain)
+ expect(resource.profile).to eql(:domain)
+ resource.profile(:any)
+ expect(resource.profile).to eql(:any)
+ resource.profile(:notapplicable)
+ expect(resource.profile).to eql(:notapplicable)
+ end
+
+ it "the profile property coerces strings to symbols" do
+ resource.profile("Public")
+ expect(resource.profile).to eql(:public)
+ end
+
+ it "the program property accepts strings" do
+ resource.program("C:/Test/test.exe")
+ expect(resource.program).to eql("C:/Test/test.exe")
+ end
+
+ it "the service property accepts strings" do
+ resource.service("Spooler")
+ expect(resource.service).to eql("Spooler")
+ end
+
+ it "the interface_type property accepts :any, :wireless, :wired and :remoteaccess" do
+ resource.interface_type(:any)
+ expect(resource.interface_type).to eql(:any)
+ resource.interface_type(:wireless)
+ expect(resource.interface_type).to eql(:wireless)
+ resource.interface_type(:wired)
+ expect(resource.interface_type).to eql(:wired)
+ resource.interface_type(:remoteaccess)
+ expect(resource.interface_type).to eql(:remoteaccess)
+ end
+
+ it "the interface_type property coerces strings to symbols" do
+ resource.interface_type("Any")
+ expect(resource.interface_type).to eql(:any)
+ end
+
+ it "the enabled property accepts true and false" do
+ resource.enabled(true)
+ expect(resource.enabled).to eql(true)
+ resource.enabled(false)
+ expect(resource.enabled).to eql(false)
+ end
+
+ it "aliases :localip to :local_address" do
+ resource.localip("192.168.30.30")
+ expect(resource.local_address).to eql("192.168.30.30")
+ end
+
+ it "aliases :remoteip to :remote_address" do
+ resource.remoteip("8.8.8.8")
+ expect(resource.remote_address).to eql("8.8.8.8")
+ end
+
+ it "aliases :localport to :local_port" do
+ resource.localport("80")
+ expect(resource.local_port).to eql("80")
+ end
+
+ it "aliases :remoteport to :remote_port" do
+ resource.remoteport("8080")
+ expect(resource.remote_port).to eql("8080")
+ end
+
+ it "aliases :interfacetype to :interface_type" do
+ resource.interfacetype(:any)
+ expect(resource.interface_type).to eql(:any)
+ end
+
+ describe "#firewall_command" do
+ before do
+ resource.rule_name("test_rule")
+ end
+
+ context "#new" do
+ it "build a minimal command" do
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets a description" do
+ resource.description("New description")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'New description' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets LocalAddress" do
+ resource.local_address("127.0.0.1")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -LocalAddress '127.0.0.1' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets LocalPort" do
+ resource.local_port("80")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -LocalPort '80' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets RemoteAddress" do
+ resource.remote_address("8.8.8.8")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -RemoteAddress '8.8.8.8' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets RemotePort" do
+ resource.remote_port("443")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -RemotePort '443' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Direction" do
+ resource.direction(:outbound)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'outbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Protocol" do
+ resource.protocol("UDP")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'UDP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Action" do
+ resource.firewall_action(:block)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'block' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Profile" do
+ resource.profile(:private)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'private' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Program" do
+ resource.program("C:/calc.exe")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Program 'C:/calc.exe' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Service" do
+ resource.service("Spooler")
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Service 'Spooler' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets InterfaceType" do
+ resource.interface_type(:wired)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'wired' -Enabled 'true'")
+ end
+
+ it "sets Enabled" do
+ resource.enabled(false)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'false'")
+ end
+
+ it "sets all properties" do
+ resource.rule_name("test_rule_the_second")
+ resource.description("some other rule")
+ resource.local_address("192.168.40.40")
+ resource.local_port("80")
+ resource.remote_address("8.8.4.4")
+ resource.remote_port("8081")
+ resource.direction(:outbound)
+ resource.protocol("UDP")
+ resource.firewall_action(:notconfigured)
+ resource.profile(:domain)
+ resource.program('%WINDIR%\System32\lsass.exe')
+ resource.service("SomeService")
+ resource.interface_type(:remoteaccess)
+ resource.enabled(false)
+ expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule_the_second' -DisplayName 'test_rule_the_second' -Description 'some other rule' -LocalAddress '192.168.40.40' -LocalPort '80' -RemoteAddress '8.8.4.4' -RemotePort '8081' -Direction 'outbound' -Protocol 'UDP' -Action 'notconfigured' -Profile 'domain' -Program '%WINDIR%\\System32\\lsass.exe' -Service 'SomeService' -InterfaceType 'remoteaccess' -Enabled 'false'")
+ end
+ end
+
+ context "#set" do
+ it "build a minimal command" do
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets a description" do
+ resource.description("New description")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'New description' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets LocalAddress" do
+ resource.local_address("127.0.0.1")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -LocalAddress '127.0.0.1' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets LocalPort" do
+ resource.local_port("80")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -LocalPort '80' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets RemoteAddress" do
+ resource.remote_address("8.8.8.8")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -RemoteAddress '8.8.8.8' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets RemotePort" do
+ resource.remote_port("443")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -RemotePort '443' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Direction" do
+ resource.direction(:outbound)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'outbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Protocol" do
+ resource.protocol("UDP")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'UDP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Action" do
+ resource.firewall_action(:block)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'block' -Profile 'any' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Profile" do
+ resource.profile(:private)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'private' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Program" do
+ resource.program("C:/calc.exe")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Program 'C:/calc.exe' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets Service" do
+ resource.service("Spooler")
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Service 'Spooler' -InterfaceType 'any' -Enabled 'true'")
+ end
+
+ it "sets InterfaceType" do
+ resource.interface_type(:wired)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'wired' -Enabled 'true'")
+ end
+
+ it "sets Enabled" do
+ resource.enabled(false)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'false'")
+ end
+
+ it "sets all properties" do
+ resource.rule_name("test_rule_the_second")
+ resource.description("some other rule")
+ resource.local_address("192.168.40.40")
+ resource.local_port("80")
+ resource.remote_address("8.8.4.4")
+ resource.remote_port("8081")
+ resource.direction(:outbound)
+ resource.protocol("UDP")
+ resource.firewall_action(:notconfigured)
+ resource.profile(:domain)
+ resource.program('%WINDIR%\System32\lsass.exe')
+ resource.service("SomeService")
+ resource.interface_type(:remoteaccess)
+ resource.enabled(false)
+ expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule_the_second' -Description 'some other rule' -LocalAddress '192.168.40.40' -LocalPort '80' -RemoteAddress '8.8.4.4' -RemotePort '8081' -Direction 'outbound' -Protocol 'UDP' -Action 'notconfigured' -Profile 'domain' -Program '%WINDIR%\\System32\\lsass.exe' -Service 'SomeService' -InterfaceType 'remoteaccess' -Enabled 'false'")
+ end
+ end
+ end
+end