lib/jss/api_object/policy.rb in ruby-jss-1.2.10 vs lib/jss/api_object/policy.rb in ruby-jss-1.3.2

- old
+ new

@@ -172,11 +172,13 @@ MGMT_ACCOUNT_ACTIONS = { no_change: 'doNotChange', change_pw: 'specified', generate_pw: 'random', enable_fv2: 'fileVaultEnable', - disable_fv2: 'fileVaultDisable' + disable_fv2: 'fileVaultDisable', + reset_random: 'resetRandom', + reset_pw: 'reset' }.freeze PACKAGE_ACTIONS = { install: 'Install', remove: 'Uninstall', @@ -189,10 +191,16 @@ before: 'Before', post: 'After', after: 'After' }.freeze + DISK_ENCRYPTION_ACTIONS = { + apply: "apply", + remediate: "remediate", + none: "none" + } + PRINTER_ACTIONS = { map: 'install', unmap: 'uninstall' }.freeze @@ -539,10 +547,11 @@ # @return [String] the message shown the user at policy start attr_reader :user_message_start # @return [String] the message shown the user at policy end attr_reader :user_message_finish + alias user_message_end user_message_finish # @return [Hash] # # Reboot options for the policy # @@ -668,10 +677,11 @@ @dock_items = @init_data[:dock_items] @disk_encryption = @init_data[:disk_encryption] @printers = @init_data[:printers] + @printers.shift # Not in jss yet end # set non-nil defaults @@ -912,10 +922,34 @@ @reboot_options[:message] = message @need_to_update = true end alias message= reboot_message= + # Set User Start Message + # + # @param user_message[String] Text of User Message + # + # @return [void] description of returned object + def user_message_start=(message) + raise JSS::InvalidDataError, 'User message must be a String' unless message.is_a? String + @user_message_start = message + @need_to_update = true + end + + # Set User Finish Message + # + # @param user_message[String] Text of User Message + # + # @return [void] description of returned object + def user_message_end=(message) + raise JSS::InvalidDataError, 'User message must be a String' unless message.is_a? String + @user_message_finish = message + @need_to_update = true + end + + alias user_message_finish= user_message_end= + # Set Startup Disk # Only Supports 'Specify Local Startup Disk' at the moment # # @param startup_disk_option[String] # @@ -1178,11 +1212,11 @@ @packages end # Remove a package from this policy by name or id # - # @param identfier [String,Integer] the name or id of the package to remove + # @param identifier [String,Integer] the name or id of the package to remove # # @return [Array, nil] the new packages array or nil if no change # def remove_package(identifier) removed = @packages.delete_if { |p| p[:id] == identifier || p[:name] == identifier } @@ -1268,11 +1302,11 @@ @scripts end # Remove a script from this policy by name or id # - # @param identfier [String,Integer] the name or id of the script to remove + # @param identifier [String,Integer] the name or id of the script to remove # # @return [Array, nil] the new scripts array or nil if no change # def remove_script(identifier) removed = @scripts.delete_if { |s| s[:id] == identifier || s[:name] == identifier } @@ -1290,10 +1324,53 @@ # @return [Array] the names of the directory_bindings handled by the policy def directory_binding_names @directory_bindings.map { |p| p[:name] } end + # Add a Directory Bidning to the list of directory_bindings handled by this policy. + # If the directory binding already exists in the policy, nil is returned and + # no changes are made. + # + # @param [String,Integer] identifier the name or id of the directory binding to add to this policy + # + # @param position [Symbol, Integer] where to add this directory binding among the list of + # directory_bindings. Zero-based, :start and 0 are the same, as are :end and -1. + # Defaults to :end + # + # @return [Array, nil] the new @directory_bindings array, nil if directory_binding was already in the policy + # + def add_directory_binding(identifier, **opts) + id = validate_directory_binding_opts identifier, opts + + return nil if @directory_bindings.map { |s| s[:id] }.include? id + + name = JSS::DirectoryBinding.map_all_ids_to(:name, api: @api)[id] + + directory_binding_data = { + id: id, + name: name + } + + @directory_bindings.insert opts[:position], directory_binding_data + + @need_to_update = true + @directory_bindings + end + + + # Remove a directory binding from this policy by name or id + # + # @param identifier [String,Integer] the name or id of the directory binding to remove + # + # @return [Array, nil] the new directory bindings array or nil if no change + # + def remove_directory_binding(identifier) + removed = @directory_bindings.delete_if { |s| s[:id] == identifier || s[:name] == identifier } + @need_to_update = true if removed + removed + end + ###### Dock items # @return [Array] the id's of the dock_items handled by the policy def dock_item_ids @dock_items.map { |p| p[:id] } @@ -1302,28 +1379,232 @@ # @return [Array] the names of the dock_items handled by the policy def dock_item_names @dock_items.map { |p| p[:name] } end + + ###### Printers + + # Add a specific printer object to the policy. + # + # @author Tyler Morgan + # + # @param newvalue [String,Integer] The name or the id of the printer to be added to this policy. + # + # @param position [Symbol, Integer] where to add this printer object among the list of printer + # objects. Zero-based, :start and 0 are the same, as are :end and -1. + # Defaults to :end + # + # @param action [Symbol] One of the PRINTER_ACTIONS symbols. What you want done with the printer object upon policy execution. + # + # @param make_default [TrueClass,FalseClass] Should this printer object be set to default. + # Defaults to false + # + # @return [String] The new printers array or nil if the printer was already in the policy + def add_printer(identifier, **opts) + id = validate_printer_opts identifier, opts + + return nil if @printers.map { |p| p[:id] }.include? id + + name = JSS::Printer.map_all_ids_to(:name, api: @api)[id] + + printer_data = { + id: id, + name: name, + action: PRINTER_ACTIONS[opts[:action]], + make_default: opts[:make_default] + } + + @printers.insert opts[:position], printer_data + + @need_to_update = true + @printers + end + + + # Remove a specific printer object from the policy. + # + # @author Tyler Morgan + # + # @param identifier [String,Integer] The name or id of the printer to be removed. + # + # @return [Array, nil] The new printers array or nil if no change. + def remove_printer(identifier) + removed = @printers.delete_if { |p| p[:id] == identifier || p[:name] == identifier } + + @need_to_update = true + removed + end + + # Add a dock item to the policy + def add_dock_item(identifier, action) + id = JSS::DockItem.valid_id identifier, api: @api + + raise JSS::NoSuchItemError, "No Dock Item matches '#{identifier}'" unless id + + raise JSS::InvalidDataError, "Action must be one of: :#{DOCK_ITEM_ACTIONS.keys.join ', :'}" unless DOCK_ITEM_ACTIONS.include? action + + return nil if @dock_items.map { |d| d[:id] }.include? id + + name = JSS::DockItem.map_all_ids_to(:name, api: @api)[id] + + @dock_items << {id: id, name: name, action: DOCK_ITEM_ACTIONS[action]} + + @need_to_update = true + @dock_items + end + + # Remove a dock item from the policy + def remove_dock_item(identifier) + # TODO: Add validation against JSS::DockItem + removed = @dock_items.delete_if { |d| d[:id] == identifier || d[:name] == identifier } + @need_to_update = true if removed + removed + end + # @return [Array] the id's of the printers handled by the policy def printer_ids begin @printers.map { |p| p[:id] } rescue TypeError return [] end end - + # @return [Array] the names of the printers handled by the policy def printer_names begin @printers.map { |p| p[:name] } rescue TypeError return [] end end + + + ###### Disk Encryption + + # Sets the Disk Encryption application to "Remediate" and sets the remediation key type to individual. + # + # @author Tyler Morgan + # + # @return [Void] + # + def reissue_key() + if @disk_encryption[:action] != DISK_ENCRYPTION_ACTIONS[:remediate] + # Setting New Action + hash = { + action: DISK_ENCRYPTION_ACTIONS[:remediate], + remediate_key_type: "Individual" + } + + @disk_encryption = hash + @need_to_update = true + + else + # Update + return + end + + end + + + # Sets the Disk Encryption application to "Apply" and sets the correct disk encryption configuration ID using either the name or id. + # + # @author Tyler Morgan + # + # @return [Void] + # + def apply_encryption_configuration(identifier) + + id = JSS::DiskEncryptionConfiguration.valid_id identifier + + return if id.nil? + + hash = { + action: DISK_ENCRYPTION_ACTIONS[:apply], + disk_encryption_configuration_id: id, + auth_restart: false + } + + @disk_encryption = hash + @need_to_update = true + end + + + # Removes the Disk Encryption settings associated with this specific policy. + # + # @author Tyler Morgan + # + # @return [Void] + # + def remove_encryption_configuration() + hash = { + action: DISK_ENCRYPTION_ACTIONS[:none] + } + + @disk_encryption = hash + @need_to_update = true + end + + # Interact with management account settings + # + # @param action [Key] one of the MGMT_ACCOUNT_ACTIONS keys + # + # @return The current specified management settings. + # + # Reference: https://developer.jamf.com/documentation#resources-with-passwords + # + def set_management_account(action, **opts) + # TODO: Add proper error handling + raise JSS::InvalidDataError, "Action must be one of: :#{MGMT_ACCOUNT_ACTIONS.keys.join ', :'}" unless MGMT_ACCOUNT_ACTIONS.include? action + + management_data = {} + + if action == :change_pw || action == :reset_pw + raise JSS::MissingDataError, ":password must be provided when changing management account password" if opts[:password].nil? + + management_data = { + action: MGMT_ACCOUNT_ACTIONS[action], + managed_password: opts[:password] + } + elsif action == :reset_random || action == :generate_pw + raise JSS::MissingDataError, ":password_length must be provided when setting a random password" if opts[:password_length].nil? + raise JSS::InvalidDataError, ":password_length must be an Integer" unless opts[:password_length].is_a? Integer + + management_data = { + action: MGMT_ACCOUNT_ACTIONS[action], + managed_password_length: opts[:password_length] + } + else + management_data = { + action: MGMT_ACCOUNT_ACTIONS[action] + } + end + + @management_account = management_data + + @need_to_update = true + + @management_account + + end + + # Check if management password matches provided password + # + # @param password[String] the password that is SHA256'ed to compare to the one from the API. + # + # @return [Boolean] The result of the comparison of the management password and provided text. + # + def verify_management_password(password) + raise JSS::InvalidDataError, "Management password must be a string." unless password.is_a? String + + raise JSS::UnsupportedError, "'#{@management_account[:action].to_s}' does not support management passwords." unless @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:change_pw] || @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:reset_pw] + + return Digest::SHA256.hexdigest(password).to_s == @management_account[:managed_password_sha256].to_s + end + ###### Actions # Try to execute this policy on this machine. # # @param show_output[Boolean] should the stdout and stderr of the @@ -1437,10 +1718,68 @@ id = JSS::Script.valid_id identifier, api: @api raise JSS::NoSuchItemError, "No script matches '#{identifier}'" unless id id end + # raise an error if the directory binding being added isn't valid + # + # @see #add_directory_binding + # + # @return [Integer, nil] the valid id for the package + # + def validate_directory_binding_opts(identifier, opts) + opts[:position] ||= -1 + + opts[:position] = + case opts[:position] + when :start then 0 + when :end then -1 + else JSS::Validate.integer(opts[:position]) + end + + # if the given position is past the end, set it to -1 (the end) + opts[:position] = -1 if opts[:position] > @directory_bindings.size + + id = JSS::DirectoryBinding.valid_id identifier, api: @api + raise JSS::NoSuchItemError, "No directory binding matches '#{identifier}'" unless id + id + end + + # Raises an error if the printer being added isn't valid, additionally checks the options and sets defaults where possible. + # + # @see #add_printer + # + # @return [Integer, nil] the valid id for the package + # + def validate_printer_opts(identifier, opts) + opts[:position] ||= -1 + + opts[:position] = + case opts[:position] + when :start then 0 + when :end then -1 + else JSS::Validate.integer(opts[:position]) + end + + # If the given position is past the end, set it to -1 (the end) + opts[:position] = -1 if opts[:position] > @printers.size + + # Checks if action to be done with the printer object is provided and valid. + raise JSS::MissingDataError, "action must be provided, must be one of :#{PRINTER_ACTIONS.keys.join(':,')}." if opts[:action].nil? + raise JSS::InvalidDataError, "action must be one of :#{PRINTER_ACTIONS.keys.join(',:')}." unless PRINTER_ACTIONS.keys.include? opts[:action] + + + # Checks if the make_default option is valid, and sets the default if needed. + raise JSS::InvalidDataError, "make_default must be either true or false." unless opts[:make_default].is_a?(TrueClass) || opts[:make_default].is_a?(FalseClass) || opts[:make_default].nil? + + opts[:make_default] = false if opts[:make_default].nil? + + id = JSS::Printer.valid_id identifier, api: @api + raise JSS::NoSuchItemError, "No printer matches '#{identifier}'" unless id + id + end + def rest_xml doc = REXML::Document.new APIConnection::XML_HEADER obj = doc.add_element RSRC_OBJECT_KEY.to_s general = obj.add_element 'general' @@ -1473,10 +1812,26 @@ maint.add_element('byhost').text = @fix_byhost.to_s maint.add_element('system_cache').text = @flush_system_cache.to_s maint.add_element('user_cache').text = @user_cache.to_s maint.add_element('verify').text = @verify_startup_disk.to_s + acct_maint = obj.add_element 'account_maintenance' + + mgmt_acct = acct_maint.add_element 'management_account' + JSS.hash_to_rexml_array(@management_account).each { |x| mgmt_acct << x } + + directory_bindings = acct_maint.add_element 'directory_bindings' + @directory_bindings.each do |b| + directory_binding = directory_bindings.add_element 'binding' + dbdeets = JSS.hash_to_rexml_array b + dbdeets.each { |d| directory_binding << d } + end + + user_interaction = obj.add_element 'user_interaction' + user_interaction.add_element('message_start').text = @user_message_start.to_s + user_interaction.add_element('message_finish').text = @user_message_finish.to_s + files_processes = obj.add_element 'files_processes' JSS.hash_to_rexml_array(@files_processes).each { |f| files_processes << f } pkg_conf = obj.add_element 'package_configuration' pkgs = pkg_conf.add_element 'packages' @@ -1489,9 +1844,29 @@ scripts = obj.add_element 'scripts' @scripts.each do |s| script = scripts.add_element 'script' sdeets = JSS.hash_to_rexml_array s sdeets.each { |d| script << d } + end + + disk_encryption = obj.add_element 'disk_encryption' + + @disk_encryption.each do |k,v| + disk_encryption.add_element(k.to_s).text = v.to_s + end + + printers = obj.add_element 'printers' + @printers.each do |pr| + printer = printers.add_element 'printer' + pdeets = JSS.hash_to_rexml_array pr + pdeets.each { |d| printer << d } + end + + dock_items = obj.add_element 'dock_items' + @dock_items.each do |d| + dock_item = dock_items.add_element 'dock_item' + ddeets = JSS.hash_to_rexml_array d + ddeets.each { |de| dock_item << de } end add_self_service_xml doc add_site_to_xml doc