# module Chef::Mixin::Securable::WindowsMacros

## WindowsMacros¶ ↑

    Defines methods for adding attributes to a chef resource to describe
    Windows file security metadata.

    This module is meant to be used to extend a class (instead of
    %xinclude`-ing). A class is automatically extended with this module when
    it includes WindowsSecurableAttributes.
    --
    TODO should this be separated into different files?

### Public Instance Methods

rights_attribute(name) click to toggle source

### #rights_attribute¶ ↑

“meta-method” for dynamically creating rights attributes on resources.

Multiple rights attributes can be declared. This enables resources to have multiple rights attributes with separate runtime states.

For example, +Chef::Resource::RemoteDirectory+ supports different rights on the directories and files by declaring separate rights attributes for each (rights and files_rights).

#### User Level API¶ ↑

Given a resource that calls

    rights_attribute(:rights)

Then the resource DSL could be used like this:

    rights :read, ["Administrators","Everyone"]
    rights :deny, "Pinky"
    rights :full_control, "Users", :applies_to_children => true
    rights :write, "John Keiser", :applies_to_children => :containers_only, :applies_to_self => false, :one_level_deep => true

#### Internal Data Structure¶ ↑

rights attributes support multiple right declarations in a single resource block–the data will be merged into a single internal hash.

The internal representation is a hash with the following keys:

- `:permissions`: Integer of Windows permissions flags, 1..2^32

or one of `[:full_control, :modify, :read_execute, :read, :write]`

- `:principals`: String or Array of Strings represnting usernames on

the system.

- `:applies_to_children` (optional): Boolean

- `:applies_to_self` (optional): Boolean

- `:one_level_deep` (optional): Boolean

    # File lib/chef/mixin/securable.rb, line 110
    def rights_attribute(name)

      # equivalent to something like:
      # def rights(permissions=nil, principals=nil, args_hash=nil)
      define_method(name) do |*args|
        # Ruby 1.8 compat: default the arguments
        permissions = args.length >= 1 ? args[0] : nil
        principals = args.length >= 2 ? args[1] : nil
        args_hash = args.length >= 3 ? args[2] : nil
        raise ArgumentError.new("wrong number of arguments (#{args.length} for 3)") if args.length >= 4

        rights = self.instance_variable_get("@#{name.to_s}".to_sym)
        unless permissions.nil?
          input = {
            :permissions => permissions,
            :principals => principals
          }
          input.merge!(args_hash) unless args_hash.nil?

          validations = {:permissions => { :required => true },
                         :principals => { :required => true, :kind_of => [String, Array] },
                         :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ]},
                         :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
                         :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] }
                        }
          validate(input, validations)

          [ permissions ].flatten.each do |permission|
            if permission.is_a?(Integer)
              if permission < 0 || permission > 1<<32
                raise ArgumentError, "permissions flags must be positive and <= 32 bits (#{permission})"
              end
            elsif !([:full_control, :modify, :read_execute, :read, :write].include?(permission.to_sym))
              raise ArgumentError, "permissions parameter must be :full_control, :modify, :read_execute, :read, :write or an integer representing Windows permission flags"
            end
          end

          [ principals ].flatten.each do |principal|
            if !principal.is_a?(String)
              raise ArgumentError, "principals parameter must be a string or array of strings representing usernames"
            end
          end

          if input[:applies_to_children] == false
            if input[:applies_to_self] == false
              raise ArgumentError, "'rights' attribute must specify either :applies_to_children or :applies_to_self."
            end
            if input[:one_level_deep] == true
              raise ArgumentError, "'rights' attribute specified :one_level_deep without specifying :applies_to_children."
            end
          end
          rights ||= []
          rights << input
        end
        set_or_return(
          name,
          rights,
          {}
        )
      end
    end