├── .devcontainer ├── Dockerfile ├── README.md └── devcontainer.json ├── .fixtures.yml ├── .gitattributes ├── .github ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── mend.yml │ ├── nightly.yml │ ├── release.yml │ └── release_prep.yml ├── .gitignore ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .pdkignore ├── .puppet-lint.rc ├── .rspec ├── .rubocop.yml ├── .rubocop_todo.yml ├── .sync.yml ├── .vscode └── extensions.json ├── .yardopts ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── DEVELOPERS.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── NOTICE ├── README.md ├── REFERENCE.md ├── Rakefile ├── data └── common.yaml ├── examples ├── hiera.pp ├── hiera.yaml ├── hieradata │ └── common.yaml └── init.pp ├── hiera.yaml ├── lib └── puppet │ ├── provider │ └── acl │ │ ├── windows.rb │ │ └── windows │ │ └── base.rb │ └── type │ ├── acl.rb │ └── acl │ ├── ace.rb │ └── rights.rb ├── metadata.json ├── pdk.yaml ├── provision.yaml ├── spec ├── acceptance │ ├── access_rights_directory │ │ ├── allow_rights_dir_spec.rb │ │ ├── deny_rights_dir_spec.rb │ │ └── mask_specific │ │ │ ├── allow_rights_dir_mask_spec.rb │ │ │ └── deny_rights_dir_mask_spec.rb │ ├── access_rights_file │ │ ├── allow_rights_file_spec.rb │ │ ├── deny_rights_file_spec.rb │ │ └── mask_specific │ │ │ ├── allow_rights_file_mask_spec.rb │ │ │ └── deny_rights_file_mask_spec.rb │ ├── basic_functionality │ │ └── negative │ │ │ └── negative_acl_on_linux_spec.rb │ ├── group │ │ ├── group_local_spec.rb │ │ ├── group_local_unicode_group_spec.rb │ │ ├── group_local_unicode_user_spec.rb │ │ ├── group_local_user_sid_spec.rb │ │ └── negative │ │ │ └── group_257_char_name_spec.rb │ ├── identity │ │ ├── negative │ │ │ └── specify_identity_spec.rb │ │ ├── specify_app_package_authority_idents_spec.rb │ │ ├── specify_group_identity_spec.rb │ │ ├── specify_sid_identity_spec.rb │ │ ├── specify_unicode_identity_spec.rb │ │ └── specify_user_identity_spec.rb │ ├── inheritance │ │ ├── inheritance_on_dir_spec.rb │ │ └── inheritance_on_file_spec.rb │ ├── owner │ │ ├── negative │ │ │ └── owner_257_char_name_spec.rb │ │ ├── owner_local_group_spec.rb │ │ ├── owner_local_user_sid_spec.rb │ │ └── owner_local_user_spec.rb │ ├── parameter_target │ │ ├── explicit_target_spec.rb │ │ ├── negative │ │ │ ├── negative_acl_spec.rb │ │ │ └── negative_acl_to_symlink_spec.rb │ │ ├── perms_on_dir_8dot3_spec.rb │ │ ├── perms_on_dir_spec.rb │ │ ├── perms_on_file_8dot3_spec.rb │ │ └── perms_on_file_spec.rb │ ├── propagation │ │ ├── prop_file_spec.rb │ │ ├── prop_self_all_child_spec.rb │ │ ├── prop_self_no_child_spec.rb │ │ └── prop_spec.rb │ ├── purge │ │ ├── negative │ │ │ ├── purge_all_perms_dir_spec.rb │ │ │ └── purge_all_perms_file_spec.rb │ │ ├── purge_all_other_perms_dir_spec.rb │ │ ├── purge_all_other_perms_file_spec.rb │ │ ├── purge_explicit_perms_dir_spec.rb │ │ └── purge_explicit_perms_file_spec.rb │ └── use_cases │ │ ├── complex_prop_inherit_spec.rb │ │ ├── grant_full_deny_full_spec.rb │ │ ├── multiple_aces_spec.rb │ │ ├── multiple_acls_shared_ident_spec.rb │ │ ├── multiple_acls_spec.rb │ │ └── negative │ │ ├── allow_deny_ident_spec.rb │ │ ├── locked_resource_spec.rb │ │ └── multi_acl_single_target_spec.rb ├── default_facts.yml ├── integration │ └── provider │ │ └── acl │ │ └── windows_spec.rb ├── spec_helper.rb ├── spec_helper_acceptance.rb ├── spec_helper_acceptance_local.rb ├── spec_helper_local.rb ├── support │ └── shared_examples.rb └── unit │ ├── provider │ └── acl │ │ └── windows_spec.rb │ └── type │ ├── acl │ └── ace_spec.rb │ └── acl_spec.rb └── tools └── ACL_Access_Rights_Mask_Addition.xlsx /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM puppet/pdk:latest 2 | 3 | # [Optional] Uncomment this section to install additional packages. 4 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 5 | # && apt-get -y install --no-install-recommends 6 | 7 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # devcontainer 2 | 3 | 4 | For format details, see https://aka.ms/devcontainer.json. 5 | 6 | For config options, see the README at: 7 | https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet 8 | 9 | ``` json 10 | { 11 | "name": "Puppet Development Kit (Community)", 12 | "dockerFile": "Dockerfile", 13 | 14 | // Set *default* container specific settings.json values on container create. 15 | "settings": { 16 | "terminal.integrated.profiles.linux": { 17 | "bash": { 18 | "path": "bash", 19 | } 20 | } 21 | }, 22 | 23 | // Add the IDs of extensions you want installed when the container is created. 24 | "extensions": [ 25 | "puppet.puppet-vscode", 26 | "rebornix.Ruby" 27 | ], 28 | 29 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 30 | "forwardPorts": [], 31 | 32 | // Use 'postCreateCommand' to run commands after the container is created. 33 | "postCreateCommand": "pdk --version", 34 | } 35 | ``` 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Puppet Development Kit (Community)", 3 | "dockerFile": "Dockerfile", 4 | 5 | "settings": { 6 | "terminal.integrated.profiles.linux": { 7 | "bash": { 8 | "path": "bash" 9 | } 10 | } 11 | }, 12 | 13 | "extensions": [ 14 | "puppet.puppet-vscode", 15 | "rebornix.Ruby" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | fixtures: 2 | repositories: 3 | facts: 'https://github.com/puppetlabs/puppetlabs-facts.git' 4 | puppet_agent: 5 | repo: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git' 6 | ref: v4.13.0 7 | provision: 'https://github.com/puppetlabs/provision.git' 8 | stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib.git' 9 | symlinks: 10 | acl: "#{source_dir}" 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rb eol=lf 2 | *.erb eol=lf 3 | *.pp eol=lf 4 | *.sh eol=lf 5 | *.epp eol=lf 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | Provide a detailed description of all the changes present in this pull request. 3 | 4 | ## Additional Context 5 | Add any additional context about the problem here. 6 | - [ ] Root cause and the steps to reproduce. (If applicable) 7 | - [ ] Thought process behind the implementation. 8 | 9 | ## Related Issues (if any) 10 | Mention any related issues or pull requests. 11 | 12 | ## Checklist 13 | - [ ] 🟢 Spec tests. 14 | - [ ] 🟢 Acceptance tests. 15 | - [ ] Manually verified. (For example `puppet apply`) -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "ci" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "main" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Spec: 11 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 12 | secrets: "inherit" 13 | 14 | Acceptance: 15 | needs: Spec 16 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 17 | secrets: "inherit" 18 | -------------------------------------------------------------------------------- /.github/workflows/mend.yml: -------------------------------------------------------------------------------- 1 | name: "mend" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "main" 7 | schedule: 8 | - cron: "0 0 * * *" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | 13 | mend: 14 | uses: "puppetlabs/cat-github-actions/.github/workflows/mend_ruby.yml@main" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: "nightly" 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | Spec: 10 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 11 | secrets: "inherit" 12 | 13 | Acceptance: 14 | needs: Spec 15 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 16 | secrets: "inherit" 17 | 18 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: "Publish module" 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release.yml@main" 9 | secrets: "inherit" 10 | -------------------------------------------------------------------------------- /.github/workflows/release_prep.yml: -------------------------------------------------------------------------------- 1 | name: "Release Prep" 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Module version to be released. Must be a valid semver string. (1.2.3)" 8 | required: true 9 | 10 | jobs: 11 | release_prep: 12 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release_prep.yml@main" 13 | with: 14 | version: "${{ github.event.inputs.version }}" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /.vendor/ 23 | /convert_report.txt 24 | /update_report.txt 25 | .DS_Store 26 | .project 27 | .envrc 28 | /inventory.yaml 29 | /spec/fixtures/litmus_inventory.yaml 30 | .resource_types 31 | .modules 32 | .task_cache.json 33 | .plan_cache.json 34 | .rerun.json 35 | bolt-debug.log 36 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | RUN sudo wget https://apt.puppet.com/puppet-tools-release-bionic.deb && \ 3 | wget https://apt.puppetlabs.com/puppet6-release-bionic.deb && \ 4 | sudo dpkg -i puppet6-release-bionic.deb && \ 5 | sudo dpkg -i puppet-tools-release-bionic.deb && \ 6 | sudo apt-get update && \ 7 | sudo apt-get install -y pdk zsh puppet-agent && \ 8 | sudo apt-get clean && \ 9 | sudo rm -rf /var/lib/apt/lists/* 10 | RUN sudo usermod -s $(which zsh) gitpod && \ 11 | sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" && \ 12 | echo "plugins=(git gitignore github gem pip bundler python ruby docker docker-compose)" >> /home/gitpod/.zshrc && \ 13 | echo 'PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/puppetlabs/bin:/opt/puppetlabs/puppet/bin"' >> /home/gitpod/.zshrc && \ 14 | sudo /opt/puppetlabs/puppet/bin/gem install puppet-debugger hub -N && \ 15 | mkdir -p /home/gitpod/.config/puppet && \ 16 | /opt/puppetlabs/puppet/bin/ruby -r yaml -e "puts ({'disabled' => true}).to_yaml" > /home/gitpod/.config/puppet/analytics.yml 17 | RUN rm -f puppet6-release-bionic.deb puppet-tools-release-bionic.deb 18 | ENTRYPOINT /usr/bin/zsh 19 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | - init: pdk bundle install 6 | 7 | vscode: 8 | extensions: 9 | - puppet.puppet-vscode@1.2.0:f5iEPbmOj6FoFTOV6q8LTg== 10 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /.vendor/ 23 | /convert_report.txt 24 | /update_report.txt 25 | .DS_Store 26 | .project 27 | .envrc 28 | /inventory.yaml 29 | /spec/fixtures/litmus_inventory.yaml 30 | .resource_types 31 | .modules 32 | .task_cache.json 33 | .plan_cache.json 34 | .rerun.json 35 | bolt-debug.log 36 | /.fixtures.yml 37 | /Gemfile 38 | /.gitattributes 39 | /.github/ 40 | /.gitignore 41 | /.pdkignore 42 | /.puppet-lint.rc 43 | /Rakefile 44 | /rakelib/ 45 | /.rspec 46 | /..yml 47 | /.yardopts 48 | /spec/ 49 | /.vscode/ 50 | /.sync.yml 51 | /.devcontainer/ 52 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | --relative 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2023-11-28 08:32:09 UTC using RuboCop version 1.48.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 3 10 | # This cop supports unsafe autocorrection (--autocorrect-all). 11 | # Configuration parameters: EnforcedStyle. 12 | # SupportedStyles: nested, compact 13 | Style/ClassAndModuleChildren: 14 | Exclude: 15 | - 'lib/puppet/provider/acl/windows/base.rb' 16 | - 'lib/puppet/type/acl/ace.rb' 17 | - 'lib/puppet/type/acl/rights.rb' 18 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ".gitlab-ci.yml": 3 | delete: true 4 | appveyor.yml: 5 | delete: true 6 | .rubocop.yml: 7 | include_todos: true 8 | Gemfile: 9 | optional: 10 | ":development": 11 | - gem: net-telnet 12 | spec/spec_helper.rb: 13 | mock_with: ":rspec" 14 | coverage_report: true 15 | .gitpod.Dockerfile: 16 | unmanaged: false 17 | .gitpod.yml: 18 | unmanaged: false 19 | .github/workflows/auto_release.yml: 20 | unmanaged: false 21 | .github/workflows/ci.yml: 22 | unmanaged: false 23 | .github/workflows/nightly.yml: 24 | unmanaged: false 25 | .github/workflows/release.yml: 26 | unmanaged: false 27 | .travis.yml: 28 | delete: true 29 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "puppet.puppet-vscode", 4 | "Shopify.ruby-lsp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | All notable changes to this project will be documented in this file. 5 | 6 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). 7 | 8 | ## [v5.0.3](https://github.com/puppetlabs/puppetlabs-acl/tree/v5.0.3) - 2025-01-28 9 | 10 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v5.0.2...v5.0.3) 11 | 12 | ### Fixed 13 | 14 | - (CAT-2206) Addressing undetected legacy facts [#307](https://github.com/puppetlabs/puppetlabs-acl/pull/307) ([amitkarsale](https://github.com/amitkarsale)) 15 | 16 | ## [v5.0.2](https://github.com/puppetlabs/puppetlabs-acl/tree/v5.0.2) - 2024-12-17 17 | 18 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v5.0.1...v5.0.2) 19 | 20 | ### Added 21 | 22 | - (CAT-2158) Upgrade rexml to address CVE-2024-49761 [#305](https://github.com/puppetlabs/puppetlabs-acl/pull/305) ([amitkarsale](https://github.com/amitkarsale)) 23 | 24 | ## [v5.0.1](https://github.com/puppetlabs/puppetlabs-acl/tree/v5.0.1) - 2024-06-27 25 | 26 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v5.0.0...v5.0.1) 27 | 28 | ## [v5.0.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v5.0.0) - 2023-04-19 29 | 30 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v4.1.2...v5.0.0) 31 | 32 | ### Changed 33 | 34 | - (CONT-686) - Add Puppet 8/Drop Puppet 6 [#279](https://github.com/puppetlabs/puppetlabs-acl/pull/279) ([jordanbreen28](https://github.com/jordanbreen28)) 35 | 36 | ## [v4.1.2](https://github.com/puppetlabs/puppetlabs-acl/tree/v4.1.2) - 2023-03-21 37 | 38 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v4.1.1...v4.1.2) 39 | 40 | ### Fixed 41 | 42 | - pdksync - (CONT-494) Pin github_changelog_generator and JSON gem versions [#270](https://github.com/puppetlabs/puppetlabs-acl/pull/270) ([david22swan](https://github.com/david22swan)) 43 | 44 | ## [v4.1.1](https://github.com/puppetlabs/puppetlabs-acl/tree/v4.1.1) - 2022-10-03 45 | 46 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v4.1.0...v4.1.1) 47 | 48 | ### Fixed 49 | 50 | - Removing unsupported windows versions [#265](https://github.com/puppetlabs/puppetlabs-acl/pull/265) ([jordanbreen28](https://github.com/jordanbreen28)) 51 | - (GH-260) Update mask docs [#263](https://github.com/puppetlabs/puppetlabs-acl/pull/263) ([pmcmaw](https://github.com/pmcmaw)) 52 | - (MODULES-10908) fix noop behavior [#261](https://github.com/puppetlabs/puppetlabs-acl/pull/261) ([garrettrowell](https://github.com/garrettrowell)) 53 | 54 | ## [v4.1.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v4.1.0) - 2022-05-23 55 | 56 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v4.0.0...v4.1.0) 57 | 58 | ### Added 59 | 60 | - pdksync - (FM-8922) - Add Support for Windows 2022 [#253](https://github.com/puppetlabs/puppetlabs-acl/pull/253) ([david22swan](https://github.com/david22swan)) 61 | 62 | ## [v4.0.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v4.0.0) - 2021-03-01 63 | 64 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v3.2.1...v4.0.0) 65 | 66 | ### Changed 67 | 68 | - pdksync - Remove Puppet 5 from testing and bump minimal version to 6.0.0 [#229](https://github.com/puppetlabs/puppetlabs-acl/pull/229) ([carabasdaniel](https://github.com/carabasdaniel)) 69 | 70 | ## [v3.2.1](https://github.com/puppetlabs/puppetlabs-acl/tree/v3.2.1) - 2020-11-30 71 | 72 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v3.2.0...v3.2.1) 73 | 74 | ### Fixed 75 | 76 | - (IAC-1089) Remove dependency on 'win32/security' gem for Puppet 7 compatibility [#208](https://github.com/puppetlabs/puppetlabs-acl/pull/208) ([sanfrancrisko](https://github.com/sanfrancrisko)) 77 | 78 | ## [v3.2.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v3.2.0) - 2020-08-19 79 | 80 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v3.1.1...v3.2.0) 81 | 82 | ### Added 83 | 84 | - pdksync - (IAC-973) - Update travis/appveyor to run on new default branch main [#199](https://github.com/puppetlabs/puppetlabs-acl/pull/199) ([david22swan](https://github.com/david22swan)) 85 | 86 | ### Fixed 87 | 88 | - (IAC-976) - Removal of inappropriate terminology [#203](https://github.com/puppetlabs/puppetlabs-acl/pull/203) ([pmcmaw](https://github.com/pmcmaw)) 89 | 90 | ## [v3.1.1](https://github.com/puppetlabs/puppetlabs-acl/tree/v3.1.1) - 2020-04-08 91 | 92 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v3.1.0...v3.1.1) 93 | 94 | ### Fixed 95 | 96 | - [MODULES-1336] Fix noop failure reports [#188](https://github.com/puppetlabs/puppetlabs-acl/pull/188) ([carabasdaniel](https://github.com/carabasdaniel)) 97 | 98 | ## [v3.1.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v3.1.0) - 2019-12-03 99 | 100 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/v3.0.0...v3.1.0) 101 | 102 | ## [v3.0.0](https://github.com/puppetlabs/puppetlabs-acl/tree/v3.0.0) - 2019-07-23 103 | 104 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/2.1.0...v3.0.0) 105 | 106 | ### Changed 107 | 108 | - (MODULES-9297) Raise lower Puppet bound to 5.5.10 [#152](https://github.com/puppetlabs/puppetlabs-acl/pull/152) ([eimlav](https://github.com/eimlav)) 109 | 110 | ### Added 111 | 112 | - (MODULES-9304) Add Puppet Strings docs [#153](https://github.com/puppetlabs/puppetlabs-acl/pull/153) ([eimlav](https://github.com/eimlav)) 113 | - (WIN280) add skip() unless pattern to tests [#145](https://github.com/puppetlabs/puppetlabs-acl/pull/145) ([ThoughtCrhyme](https://github.com/ThoughtCrhyme)) 114 | 115 | ## [2.1.0](https://github.com/puppetlabs/puppetlabs-acl/tree/2.1.0) - 2018-10-11 116 | 117 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/2.0.1...2.1.0) 118 | 119 | ### Added 120 | 121 | - (MODULES-6739) Add Testmode switcher [#124](https://github.com/puppetlabs/puppetlabs-acl/pull/124) ([jpogran](https://github.com/jpogran)) 122 | 123 | ### Fixed 124 | 125 | - (MODULES-5364) All version negative/prop_file fix [#110](https://github.com/puppetlabs/puppetlabs-acl/pull/110) ([Iristyle](https://github.com/Iristyle)) 126 | 127 | ## [2.0.1](https://github.com/puppetlabs/puppetlabs-acl/tree/2.0.1) - 2017-08-03 128 | 129 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/2.0.0...2.0.1) 130 | 131 | ### Fixed 132 | 133 | - (MODULES-5152) Fix ACE mutation on output [#105](https://github.com/puppetlabs/puppetlabs-acl/pull/105) ([Iristyle](https://github.com/Iristyle)) 134 | 135 | ## [2.0.0](https://github.com/puppetlabs/puppetlabs-acl/tree/2.0.0) - 2017-05-19 136 | 137 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.1.2...2.0.0) 138 | 139 | ### Changed 140 | 141 | - (MODULES-4275) Customize ACE YAML serialization [#97](https://github.com/puppetlabs/puppetlabs-acl/pull/97) ([Iristyle](https://github.com/Iristyle)) 142 | 143 | ### Fixed 144 | 145 | - Fix frozen string [#85](https://github.com/puppetlabs/puppetlabs-acl/pull/85) ([hunner](https://github.com/hunner)) 146 | - Workaround frozen strings on ruby 1.9 [#82](https://github.com/puppetlabs/puppetlabs-acl/pull/82) ([hunner](https://github.com/hunner)) 147 | - (MODULES-3632) Use json_pure always [#81](https://github.com/puppetlabs/puppetlabs-acl/pull/81) ([hunner](https://github.com/hunner)) 148 | 149 | ## [1.1.2](https://github.com/puppetlabs/puppetlabs-acl/tree/1.1.2) - 2015-12-07 150 | 151 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.1.1...1.1.2) 152 | 153 | ## [1.1.1](https://github.com/puppetlabs/puppetlabs-acl/tree/1.1.1) - 2015-07-29 154 | 155 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.1.0...1.1.1) 156 | 157 | ## [1.1.0](https://github.com/puppetlabs/puppetlabs-acl/tree/1.1.0) - 2015-02-17 158 | 159 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.0.4...1.1.0) 160 | 161 | ## [1.0.4](https://github.com/puppetlabs/puppetlabs-acl/tree/1.0.4) - 2014-12-30 162 | 163 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.0.3...1.0.4) 164 | 165 | ### Added 166 | 167 | - ACL Access Rights Mask Addition Worksheet [#44](https://github.com/puppetlabs/puppetlabs-acl/pull/44) ([ferventcoder](https://github.com/ferventcoder)) 168 | 169 | ### Fixed 170 | 171 | - (MODULES-1482) Fix Autorequires to only include resource title [#46](https://github.com/puppetlabs/puppetlabs-acl/pull/46) ([ferventcoder](https://github.com/ferventcoder)) 172 | 173 | ## [1.0.3](https://github.com/puppetlabs/puppetlabs-acl/tree/1.0.3) - 2014-08-27 174 | 175 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.0.2...1.0.3) 176 | 177 | ### Changed 178 | 179 | - (MODULES-1174) Puppet 3.7 compatibility [#38](https://github.com/puppetlabs/puppetlabs-acl/pull/38) ([Iristyle](https://github.com/Iristyle)) 180 | 181 | ### Fixed 182 | 183 | - install puppet when running against foss [#37](https://github.com/puppetlabs/puppetlabs-acl/pull/37) ([justinstoller](https://github.com/justinstoller)) 184 | 185 | ## [1.0.2](https://github.com/puppetlabs/puppetlabs-acl/tree/1.0.2) - 2014-07-16 186 | 187 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.0.1...1.0.2) 188 | 189 | ## [1.0.1](https://github.com/puppetlabs/puppetlabs-acl/tree/1.0.1) - 2014-05-27 190 | 191 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/1.0.0...1.0.1) 192 | 193 | ## [1.0.0](https://github.com/puppetlabs/puppetlabs-acl/tree/1.0.0) - 2014-05-21 194 | 195 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-acl/compare/14896caa52cfc479e4788442fe965492e94e6917...1.0.0) 196 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Setting ownership to the modules team 2 | * @puppetlabs/modules 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Puppet modules 2 | 3 | Check out our [Contributing to Supported Modules Blog Post](https://puppetlabs.github.io/iac/docs/contributing_to_a_module.html) to find all the information that you will need. 4 | -------------------------------------------------------------------------------- /DEVELOPERS.md: -------------------------------------------------------------------------------- 1 | ## Testing 2 | 3 | bundle install 4 | bundle exec rspec spec 5 | 6 | ## Example Manifests 7 | 8 | To run the example manifests you need to either specify this as part of the modules path (--modulepath on the command line, see [ModulePath](http://docs.puppet.com/references/3.stable/configuration.html#modulepath)), or you can create a symlink to the code directory and not have to specify. 9 | 10 | ### Creating Symlink 11 | 12 | First you must take the current code base and create a symlink in the modules directory. Your modules directory may be different, but your code directory will likely be different. Please validate. 13 | 14 | With symlinks on Windows, please run the following command an administrative command prompt (substituting the proper directories): 15 | 16 | mklink /D C:\ProgramData\PuppetLabs\puppet\etc\modules\acl C:\code\puppetlabs\puppetlabs-acl 17 | 18 | ### Running Resource Example 19 | 20 | We don't provide a default `puppet resource acl` without a file path. There could be many hundreds or more directories that would need to be searched, interrogated, and dumped out to to the command shell. That could take awhile and negatively affect performance and the information would likely be too much to be useful. However you can get information about a particular directory by using the resource call. 21 | 22 | Try the following: 23 | 24 | puppet resource acl c:/windows 25 | 26 | Note that inherited ACEs (access control entries) appear in the list as well. Note the results of this against: 27 | 28 | icacls.exe c:\windows 29 | 30 | ### Running Normal Manifest Example 31 | 32 | This works with a simple c:\temp folder. It should give you an idea of what the manifest will do when run. 33 | 34 | puppet apply tests\init.pp 35 | 36 | ### Running Hiera Manifest Example 37 | From a command line at the top level of the repository: 38 | 39 | puppet apply tests\hiera.pp --hiera_config %cd%\tests\hiera.yaml --path %cd% 40 | 41 | We override path (--path) so that we can use it in the hiera config to override the hiera data directory to something local. This isn't perfect but Rob hasn't found a better way to do it yet. 42 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | def location_for(place_or_version, fake_version = nil) 4 | git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} 5 | file_url_regex = %r{\Afile:\/\/(?.*)} 6 | 7 | if place_or_version && (git_url = place_or_version.match(git_url_regex)) 8 | [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact 9 | elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) 10 | ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] 11 | else 12 | [place_or_version, { require: false }] 13 | end 14 | end 15 | 16 | group :development do 17 | gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 18 | gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 19 | gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 20 | gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 21 | gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 22 | gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 23 | gem "deep_merge", '~> 1.2.2', require: false 24 | gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false 25 | gem "facterdb", '~> 2.1', require: false 26 | gem "metadata-json-lint", '~> 4.0', require: false 27 | gem "rspec-puppet-facts", '~> 4.0', require: false 28 | gem "dependency_checker", '~> 1.0.0', require: false 29 | gem "parallel_tests", '= 3.12.1', require: false 30 | gem "pry", '~> 0.10', require: false 31 | gem "simplecov-console", '~> 0.9', require: false 32 | gem "puppet-debugger", '~> 1.0', require: false 33 | gem "rubocop", '~> 1.50.0', require: false 34 | gem "rubocop-performance", '= 1.16.0', require: false 35 | gem "rubocop-rspec", '= 2.19.0', require: false 36 | gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] 37 | gem "rexml", '>= 3.3.9', require: false 38 | gem "net-telnet", require: false 39 | end 40 | group :development, :release_prep do 41 | gem "puppet-strings", '~> 4.0', require: false 42 | gem "puppetlabs_spec_helper", '~> 7.0', require: false 43 | end 44 | group :system_tests do 45 | gem "puppet_litmus", '~> 1.0', require: false, platforms: [:ruby, :x64_mingw] 46 | gem "CFPropertyList", '< 3.0.7', require: false, platforms: [:mswin, :mingw, :x64_mingw] 47 | gem "serverspec", '~> 2.41', require: false 48 | end 49 | 50 | puppet_version = ENV['PUPPET_GEM_VERSION'] 51 | facter_version = ENV['FACTER_GEM_VERSION'] 52 | hiera_version = ENV['HIERA_GEM_VERSION'] 53 | 54 | gems = {} 55 | 56 | gems['puppet'] = location_for(puppet_version) 57 | 58 | # If facter or hiera versions have been specified via the environment 59 | # variables 60 | 61 | gems['facter'] = location_for(facter_version) if facter_version 62 | gems['hiera'] = location_for(hiera_version) if hiera_version 63 | 64 | gems.each do |gem_name, gem_params| 65 | gem gem_name, *gem_params 66 | end 67 | 68 | # Evaluate Gemfile.local and ~/.gemfile if they exist 69 | extra_gemfiles = [ 70 | "#{__FILE__}.local", 71 | File.join(Dir.home, '.gemfile'), 72 | ] 73 | 74 | extra_gemfiles.each do |gemfile| 75 | if File.file?(gemfile) && File.readable?(gemfile) 76 | eval(File.read(gemfile), binding) 77 | end 78 | end 79 | # vim: syntax=ruby 80 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ## v3.0.0 2 | 3 | ### Summary 4 | 5 | Major release which removes support for older versions of Puppet-Agent. Also adds support for Windows Server 2019 6 | 7 | #### Features 8 | 9 | - Add support for Windows Server 2019 ([FM-7693](https://tickets.puppetlabs.com/browse/FM-7693)) 10 | - Add Puppet Strings docs ([MODULES-9304](https://tickets.puppetlabs.com/browse/MODULES-9304)) 11 | 12 | #### Bug Fixes 13 | 14 | - Update acceptance tests to improve the quality and efficiency ([MODULES-9294](https://tickets.puppetlabs.com/browse/MODULES-9294)) 15 | 16 | #### Changed 17 | 18 | - Raise lower Puppet bound to 5.5.10 ([MODULES-9297](https://tickets.puppetlabs.com/browse/MODULES-9297)) 19 | 20 | ## 2018-10-10 - Supported Release 2.1.0 21 | 22 | ### Summary 23 | 24 | Feature release including support for Windows Server 2016 and Puppet 6 25 | 26 | #### Features 27 | 28 | - Add support for Windows Server 2016 29 | - Convert module for PDK ([MODULES-6459](https://tickets.puppetlabs.com/browse/MODULES-6459)) 30 | - Add support for Puppet 6 ([MODULES-7832](https://tickets.puppetlabs.com/browse/MODULES-7832)) 31 | 32 | #### Bug Fixes 33 | 34 | - Update tests for Unicode on Windows 35 | - Convert acceptance tests to rspec format ([MODULES-5978](https://tickets.puppetlabs.com/browse/MODULES-5978)) 36 | - Update module to conform with rubocop ([MODULES-5899](https://tickets.puppetlabs.com/browse/MODULES-5899)) 37 | - Add support for Beaker Testmode Switcher ([MODULES-6739](https://tickets.puppetlabs.com/browse/MODULES-6739)) 38 | 39 | ## 2017-07-31 - Supported Release 2.0.1 40 | 41 | ### Summary 42 | 43 | Minor bugfix release 44 | 45 | #### Bug Fixes 46 | 47 | - Fixed issue with using ALL APPLICATION PACKAGES or ALL RESTRICTED APPLICATION PACKAGES accounts as the identity in a manifest ([MODULES-5152](https://tickets.puppetlabs.com/browse/MODULES-5227)). 48 | 49 | ## 2017-05-19 - Supported Release 2.0.0 50 | 51 | ### Summary 52 | 53 | Major release which removes support for older versions of Puppet-Agent. Also adds support of newer PE versions and fix for a future Puppet Agent release. 54 | 55 | #### Features 56 | 57 | - Added compatibility for Windows 10. 58 | - Updated module with Puppet standard module development tools. 59 | 60 | #### Bug Fixes 61 | 62 | - Removed Windows 2003 as a supported Operating System. 63 | - Fixed minor issues in testing due to changes in Gem file dependencies. 64 | - Added support for localization. 65 | - Updated puppet version compatibility for modern Puppet agents ([MODULES-4838](https://tickets.puppetlabs.com/browse/MODULES-4838)). 66 | - Fixed issue ACL YAML serialization in Ruby 2.3.x ([MODULES-4275](https://tickets.puppetlabs.com/browse/MODULES-4275)). 67 | 68 | ## 2015-12-08 - Supported Release 1.1.2 69 | 70 | ### Summary 71 | 72 | Small release for support of newer PE versions. 73 | 74 | ## 2015-07-28 - Supported Release 1.1.1 75 | 76 | ### Summary 77 | 78 | Add Puppet 4 and PE 2015.2.0 to metadata 79 | 80 | #### Features 81 | - README updates 82 | - Acceptance test fixes 83 | - Gemfile changes 84 | 85 | ## 2015-02-17 - Supported Release 1.1.0 86 | 87 | ### Summary 88 | 89 | Deprecates `type` in permissions array has been renamed to `perm_type` 90 | 91 | #### Features 92 | 93 | - Permissions parameter now takes array of hashes with `perm_type` instead of Puppet 4.0 protected word `type` 94 | 95 | ## 2014-12-30 - Supported Release 1.0.4 96 | 97 | ### Summary 98 | 99 | Bug fixes and typo in metadata summary 100 | 101 | ## 2014-08-25 - Supported Release 1.0.3 102 | 103 | ### Summary 104 | 105 | This release enables compatibility with x64-native ruby and puppet 3.7 106 | 107 | ## 2014-07-15 - Supported Release 1.0.2 108 | 109 | ### Summary 110 | 111 | This release merely updates metadata.json so the module can be uninstalled and 112 | upgraded via the puppet module command. 113 | 114 | ## 2014-03-04 - Supported Release 1.0.1 115 | 116 | ### Summary 117 | 118 | Add metadata compatibility for PE 3.2. 119 | 120 | ## 2014-03-04 - Supported Release 1.0.0 121 | 122 | ### Summary 123 | 124 | This is the initial supported release of the ACL module. 125 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Puppet Module - puppetlabs-acl 2 | 3 | Copyright 2013 - 2018 Puppet, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | 4 | 5 | ## Table of Contents 6 | 7 | ### Resource types 8 | 9 | * [`acl`](#acl): Manages access control lists (ACLs). The `acl` type is typically used when you need more complex management of permissions e.g. Windows. ACL 10 | 11 | ## Resource types 12 | 13 | ### `acl` 14 | 15 | Manages access control lists (ACLs). The `acl` type is 16 | typically used when you need more complex management of 17 | permissions e.g. Windows. ACLs typically contain access 18 | control entries (ACEs) that define a trustee (identity) 19 | with a set of rights, whether the type is allow or deny, 20 | and how inheritance and propagation of those ACEs are 21 | applied to the resource target and child types under it. 22 | The order that ACEs are listed in is important on Windows 23 | as it determines what is applied first. 24 | 25 | Order of ACE application on Windows is explicit deny, 26 | explicit allow, inherited deny, then inherited allow. You 27 | cannot specify inherited ACEs in a manifest, only whether 28 | to allow upstream inheritance to flow into the managed 29 | target location (known as security descriptor). Please 30 | ensure your modeled resources follow this order or Windows 31 | will complain. NOTE: `acl` type does not enforce or 32 | complain about ACE order. 33 | 34 | For very specific examples, see the readme[1] and learn 35 | about the different features of the `acl` type. 36 | 37 | [1] https://github.com/puppetlabs/puppetlabs-acl/blob/main/README.md 38 | 39 | **Autorequires:** If Puppet is managing the user, group or 40 | target of an acl resource, the acl type will autorequire 41 | them. 42 | 43 | **Examples:** 44 | 45 | Minimally expressed sample usage: 46 | 47 | At a minimum, you need to provide the target and at least 48 | one permission (access control entry or ACE). It will default 49 | the other settings to sensible defaults. 50 | 51 | 52 | ``` 53 | acl { 'c:/tempperms': 54 | permissions => [ 55 | { identity => 'Administrator', rights => ['full'] }, 56 | { identity => 'Users', rights => ['read','execute'] } 57 | ], 58 | } 59 | ``` 60 | 61 | Fully expressed sample usage: 62 | 63 | If you want you can provide a fully expressed ACL. The 64 | fully expressed acl in the sample below produces the same 65 | settings as the minimal sample above. 66 | 67 | ``` 68 | acl { 'c:/tempperms': 69 | target => 'c:/tempperms', 70 | target_type => 'file', 71 | purge => 'false', 72 | permissions => [ 73 | { identity => 'Administrator', rights => ['full'], perm_type=> 'allow', child_types => 'all', affects => 'all' }, 74 | { identity => 'Users', rights => ['read','execute'], perm_type=> 'allow', child_types => 'all', affects => 'all' } 75 | ], 76 | owner => 'Administrators', #Creator_Owner specific, doesn't manage unless specified 77 | group => 'Users', #Creator_Group specific, doesn't manage unless specified 78 | inherit_parent_permissions => 'true', 79 | } 80 | ``` 81 | 82 | Manage same ACL resource multiple acls sample usage: 83 | 84 | You can manage the same target across multiple acl 85 | resources with some caveats. The title of the resource 86 | needs to be unique. It is suggested that you only do 87 | this when you would need to (can get confusing). You should 88 | not set purge => 'true' on any of the resources that apply 89 | to the same target or you will see thrashing in reports as 90 | the permissions will be added and removed every catalog 91 | application. Use this feature with care. 92 | 93 | ``` 94 | acl { 'c:/tempperms': 95 | permissions => [ 96 | { identity => 'Administrator', rights => ['full'] } 97 | ], 98 | } 99 | 100 | acl { 'tempperms_Users': 101 | target => 'c:/tempperms', 102 | permissions => [ 103 | { identity => 'Users', rights => ['read','execute'] } 104 | ], 105 | } 106 | ``` 107 | 108 | Removing upstream inheritance with purge sample usage: 109 | 110 | ``` 111 | acl { 'c:/tempperms': 112 | purge => 'true', 113 | permissions => [ 114 | { identity => 'Administrators', rights => ['full'] }, 115 | { identity => 'Users', rights => ['full'] } 116 | ], 117 | inherit_parent_permissions => 'false', 118 | } 119 | ``` 120 | 121 | Warning: While managing ACLs you could lock the user running 122 | Puppet completely out of managing resources using 123 | `purge => 'true'` with `inherit_parent_permissions => 'false'`. 124 | If Puppet is locked out of managing the resource, manual 125 | intervention on affected nodes will be required. 126 | 127 | #### Properties 128 | 129 | The following properties are available in the `acl` type. 130 | 131 | ##### `group` 132 | 133 | The group identity is also known as a trustee or principal 134 | that is said to have access to the particular acl/security descriptor. 135 | This can be in the form of: 136 | 137 | 1. User - e.g. `'Bob'` or `'TheNet\\Bob'` 138 | 2. Group e.g. `'Administrators'` or `'BUILTIN\\Administrators'` 139 | 3. SID (Security ID) e.g. `'S-1-5-18'`. 140 | 141 | Defaults to not specified on Windows. This allows group to stay set 142 | to whatever it is currently set to (group can vary depending on the 143 | original CREATOR GROUP). The trustee must exist on the system and 144 | will auto-require on user and group resources. 145 | 146 | ##### `inherit_parent_permissions` 147 | 148 | Valid values: `true`, `false` 149 | 150 | Inherit Parent Permissions specifies whether to inherit 151 | permissions from parent ACLs or not. The default is `true`. 152 | 153 | Default value: `true` 154 | 155 | ##### `owner` 156 | 157 | The owner identity is also known as a trustee or principal 158 | that is said to own the particular acl/security descriptor. This 159 | can be in the form of: 160 | 161 | 1. User - e.g. `'Bob'` or `'TheNet\\Bob'` 162 | 2. Group e.g. `'Administrators'` or `'BUILTIN\\Administrators'` 163 | 3. SID (Security ID) e.g. `'S-1-5-18'`. 164 | 165 | Defaults to not specified on Windows. This allows owner to stay set 166 | to whatever it is currently set to (owner can vary depending on the 167 | original CREATOR OWNER). The trustee must exist on the system and 168 | will auto-require on user and group resources. 169 | 170 | ##### `permissions` 171 | 172 | Permissions is an array containing Access Control Entries 173 | (ACEs). Certain Operating Systems require these ACEs to be in 174 | explicit order (Windows). Every element in the array is a hash 175 | that will at the very least need `identity` and `rights` e.g 176 | `{ identity => 'Administrators', rights => ['full'] }` and at the 177 | very most can include `perm_type`, `child_types`, `affects`, and 178 | `mask` (mask should only be specified be with 179 | `rights => ['mask_specific']`) e.g. `{ identity => 'Administrators', 180 | rights => ['full'], type=> 'allow', child_types => 'all', 181 | affects => 'all' }`. 182 | 183 | `identity` is a group, user or ID (SID on Windows). The identity must 184 | exist on the system and will auto-require on user and group resources. 185 | This can be in the form of: 186 | 187 | 1. User - e.g. `'Bob'` or `'TheNet\\Bob'` 188 | 2. Group e.g. `'Administrators'` or `'BUILTIN\\Administrators'` 189 | 3. SID (Security ID) e.g. `'S-1-5-18'`. 190 | 191 | `rights` is an array that contains `'full'`, `'modify'`, 192 | `'mask_specific'` or some combination of `'write'`, `'read'`, and 193 | `'execute'`. If you specify `'mask_specific'` you must also specify 194 | `mask` with an integer (passed as a string) that represents the 195 | permissions mask. It is the numeric representation of the binary 196 | flags. 197 | 198 | `perm_type` is represented as `'allow'` (default) or `'deny'`. 199 | 200 | `child_types` determines how an ACE is inherited downstream from the 201 | target. Valid values are `'all'` (default), `'objects'`, `'containers'` 202 | or `'none'`. 203 | 204 | `affects` determines how the downstream inheritance is propagated. 205 | Valid values are `'all'` (default), `'self_only'`, `'children_only'`, 206 | `'self_and_direct_children_only'` or `'direct_children_only'`. 207 | 208 | Each permission (ACE) is determined to be unique based on 209 | identity, perm_type, child_types, and affects. While you can technically 210 | create more than one ACE that differs from other ACEs only in rights, 211 | acl module is not able to tell the difference between those so it 212 | will appear that the resource is out of sync every run when it is not. 213 | 214 | While you will see `is_inherited => 'true'` when running 215 | puppet resource acl path, puppet will not be able to manage the 216 | inherited permissions so those will need to be removed if using 217 | that to build a manifest. 218 | 219 | #### Parameters 220 | 221 | The following parameters are available in the `acl` type. 222 | 223 | * [`name`](#-acl--name) 224 | * [`provider`](#-acl--provider) 225 | * [`purge`](#-acl--purge) 226 | * [`target`](#-acl--target) 227 | * [`target_type`](#-acl--target_type) 228 | 229 | ##### `name` 230 | 231 | namevar 232 | 233 | The name of the acl resource. Used for uniqueness. Will set 234 | the target to this value if target is unset. 235 | 236 | ##### `provider` 237 | 238 | The specific backend to use for this `acl` resource. You will seldom need to specify this --- Puppet will usually 239 | discover the appropriate provider for your platform. 240 | 241 | ##### `purge` 242 | 243 | Valid values: `true`, `false`, `listed_permissions` 244 | 245 | Purge specifies whether to remove other explicit permissions 246 | if not specified in the permissions set. This doesn't do anything 247 | with permissions inherited from parents (to remove those you should 248 | combine `purge => 'false', inherit_parent_permissions => 'false'` - 249 | be VERY careful in doing so, you could lock out Puppet from 250 | managing the resource and manual intervention will be required). 251 | This also allows you to ensure the permissions listed are not on 252 | the ACL with `purge => listed_permissions`. 253 | The default is `false`. 254 | 255 | Default value: `false` 256 | 257 | ##### `target` 258 | 259 | The location the acl resource is pointing to. In the first 260 | release of ACL, this will be a file system location. 261 | The default is the name. 262 | 263 | ##### `target_type` 264 | 265 | Valid values: `file` 266 | 267 | The type of target for the Acl resource. In the first release 268 | of ACL, only `file` is allowed. Defaults to `file`. 269 | 270 | Default value: `file` 271 | 272 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'puppet_litmus/rake_tasks' if Gem.loaded_specs.key? 'puppet_litmus' 5 | require 'puppetlabs_spec_helper/rake_tasks' 6 | require 'puppet-syntax/tasks/puppet-syntax' 7 | require 'puppet-strings/tasks' if Gem.loaded_specs.key? 'puppet-strings' 8 | 9 | PuppetLint.configuration.send('disable_relative') 10 | -------------------------------------------------------------------------------- /data/common.yaml: -------------------------------------------------------------------------------- 1 | --- {} 2 | -------------------------------------------------------------------------------- /examples/hiera.pp: -------------------------------------------------------------------------------- 1 | # 2 | # == How to run this == 3 | # Please see ReadMe at the top of the repository for instructions on setup and running. 4 | # 5 | 6 | $acls = hiera_hash('acls', {}) 7 | 8 | notify { $acls: } 9 | create_resources(acl, $acls) 10 | 11 | $_temp_acl = Acl['tempdir'] 12 | 13 | file { 'c:/temp': 14 | ensure => 'directory', 15 | } 16 | # 17 | #file {'C:/temp': 18 | # ensure => 'directory', 19 | #} 20 | 21 | acl { 'c:\temp': 22 | permissions => [ 23 | { 24 | identity => 'Administrators', 25 | rights => [full] 26 | } 27 | ], 28 | owner => 'Administrators', 29 | inherit_parent_permissions => true, 30 | } 31 | 32 | acl { 'temp_dir_module_name': 33 | target => 'c:/temp', 34 | permissions => [ 35 | { 36 | identity => 'bob', 37 | rights => [read,execute] 38 | }, 39 | { 40 | identity => 'tim', 41 | rights => [read,execute] 42 | } 43 | ], 44 | } 45 | 46 | acl { 'temp_dir_module2_name': 47 | target => 'c:/temp', 48 | permissions => [ 49 | { 50 | identity => 'bill', 51 | rights => [full], 52 | affects => self_only 53 | } 54 | , 55 | { 56 | identity => 'tim', 57 | rights => [read,execute] 58 | } 59 | ], 60 | } 61 | 62 | $_temp_acl2 = Acl['c:/temp'] 63 | 64 | #pry() 65 | #$foo = inline_template("<% require 'pry';binding.pry %>") 66 | -------------------------------------------------------------------------------- /examples/hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :hierachy: 3 | - common 4 | :yaml: 5 | :datadir: "%{settings::path}/tests/hieradata" 6 | # :datadir: "%{settings::confdir}/modules/%{calling_module}/tests/hieradata" 7 | -------------------------------------------------------------------------------- /examples/hieradata/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | acls: 3 | tempdir: 4 | target: 'C:\temp' 5 | permissions: 6 | - identity: 'tim' 7 | rights: 8 | - read 9 | - list 10 | - execute 11 | - identity: 'bob' 12 | rights: 13 | - read 14 | - list 15 | - execute 16 | dir2: 17 | target: 'C:\temp' 18 | permissions: 19 | - identity: 'tim' 20 | rights: 21 | - full 22 | affects: self_only 23 | type: allow 24 | child_types: all 25 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | 4 | defaults: # Used for any hierarchy level that omits these keys. 5 | datadir: data # This path is relative to hiera.yaml's directory. 6 | data_hash: yaml_data # Use the built-in YAML backend. 7 | 8 | hierarchy: 9 | - name: "osfamily/major release" 10 | paths: 11 | # Used to distinguish between Debian and Ubuntu 12 | - "os/%{facts.os.name}/%{facts.os.release.major}.yaml" 13 | - "os/%{facts.os.family}/%{facts.os.release.major}.yaml" 14 | # Used for Solaris 15 | - "os/%{facts.os.family}/%{facts.kernelrelease}.yaml" 16 | - name: "osfamily" 17 | paths: 18 | - "os/%{facts.os.name}.yaml" 19 | - "os/%{facts.os.family}.yaml" 20 | - name: 'common' 21 | path: 'common.yaml' 22 | -------------------------------------------------------------------------------- /lib/puppet/provider/acl/windows.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet/type' 4 | require 'pathname' 5 | 6 | Puppet::Type.type(:acl).provide :windows do 7 | @doc = 'Windows specific provider for acl type.' 8 | 9 | # confine :feature => :microsoft_windows 10 | confine 'os.name': :windows 11 | defaultfor 'os.name': :windows 12 | 13 | require "#{Pathname.new(__FILE__).dirname}/../../../puppet/type/acl/ace" 14 | require "#{Pathname.new(__FILE__).dirname}/../../../puppet/provider/acl/windows/base" 15 | include Puppet::Provider::Acl::Windows::Base 16 | 17 | has_features :ace_order_required 18 | has_features :can_inherit_parent_permissions 19 | 20 | def initialize(value = {}) 21 | super(value) 22 | @property_flush = {} 23 | @security_descriptor = nil 24 | end 25 | 26 | def self.instances 27 | [] 28 | end 29 | 30 | def exists? 31 | case @resource[:target_type] 32 | when :file 33 | File.exist?(@resource[:target]) 34 | else 35 | raise Puppet::ResourceError, 'At present only :target_type => :file is supported on Windows.' 36 | end 37 | end 38 | 39 | def create 40 | case @resource[:target_type] 41 | when :file 42 | raise Puppet::Error, "ACL cannot create target resources. Target resource will already have a security descriptor on it when created. Ensure target '#{@resource[:target]}' exists." unless File.exist?(@resource[:target]) # rubocop:disable Layout/LineLength 43 | else 44 | raise Puppet::ResourceError, 'At present only :target_type => :file is supported on Windows.' 45 | end 46 | end 47 | 48 | def destroy 49 | case @resource[:target_type] 50 | when :file 51 | raise Puppet::Error, 'ACL cannot remove target resources, only permissions from those target resources. Ensure you pass non-inherited permissions to remove.' unless @resource[:permissions] 52 | else 53 | raise Puppet::ResourceError, 'At present only :target_type => :file is supported on Windows.' 54 | end 55 | end 56 | 57 | def validate 58 | case @resource[:target_type] 59 | when :file 60 | # Target may not be set, this is called prior to initialize 61 | if Puppet::Util::Windows::File.respond_to?(:symlink?) && Puppet::Util::Windows::File.symlink?(@resource[:target] || @resource[:name]) 62 | raise Puppet::ResourceError, "Puppet cannot manage ACLs of symbolic links (symlinks) on Windows. Resource target '#{@resource[:target] || @resource[:name]}' is a symlink." 63 | end 64 | end 65 | end 66 | 67 | def permissions 68 | get_current_permissions 69 | end 70 | 71 | def permissions=(value) 72 | value = update_permissions_if_file(value) 73 | unless @resource[:purge] == :listed_permissions 74 | non_existing_users = [] 75 | value.each do |permission| 76 | non_existing_users << permission.identity unless get_account_id(permission.identity) 77 | end 78 | raise Puppet::Error, "Failed to set permissions for '#{non_existing_users.join(', ')}': User or users do not exist." unless non_existing_users.empty? 79 | end 80 | 81 | @property_flush[:permissions] = value 82 | end 83 | 84 | def update_permissions_if_file(permissions) 85 | case @resource[:target_type] 86 | when :file 87 | if File.file?(@resource[:target]) && permissions 88 | permissions.each do |perm| 89 | perm.affects = :self_only if perm.affects == :all 90 | end 91 | end 92 | end 93 | 94 | permissions 95 | end 96 | 97 | def permissions_insync?(current, should) 98 | should = update_permissions_if_file(should) 99 | are_permissions_insync?(current, should, @resource[:purge]) 100 | end 101 | 102 | def permissions_should_to_s(should) 103 | return [] if should.nil? || !should.is_a?(Array) 104 | 105 | sd = get_security_descriptor 106 | return [] if sd.nil? 107 | 108 | should_aces = sync_aces(sd.dacl, should, @resource[:purge] == :true, @resource[:purge] == :listed_permissions) 109 | 110 | permissions_to_s(should_aces) 111 | end 112 | 113 | def permissions_to_s(permissions) 114 | return [] if permissions.nil? || !permissions.is_a?(Array) 115 | 116 | perms = permissions.reject(&:is_inherited) 117 | 118 | unless perms.nil? 119 | perms = perms.map do |perm| 120 | perm_hash = perm.to_hash 121 | perm_hash['identity'] = get_account_name(perm.identity) 122 | perm_hash 123 | end 124 | end 125 | 126 | perms 127 | end 128 | 129 | def owner 130 | get_current_owner 131 | end 132 | 133 | def owner=(value) 134 | raise Puppet::Error, "Failed to set owner to '#{value}': User does not exist." unless get_account_id(value) 135 | 136 | @property_flush[:owner] = value 137 | end 138 | 139 | def owner_insync?(current, should) 140 | account_insync?(current, should) 141 | end 142 | 143 | def owner_to_s(current_value) 144 | get_account_name(current_value) 145 | end 146 | 147 | def group 148 | get_current_group 149 | end 150 | 151 | def group=(value) 152 | raise Puppet::Error, "Failed to set group to '#{value}': Group does not exist." unless get_account_id(value) 153 | 154 | @property_flush[:group] = value 155 | end 156 | 157 | def group_insync?(current, should) 158 | account_insync?(current, should) 159 | end 160 | 161 | def group_to_s(current_value) 162 | get_account_name(current_value) 163 | end 164 | 165 | def inherit_parent_permissions 166 | inheriting_permissions? 167 | end 168 | 169 | def inherit_parent_permissions=(value) 170 | @property_flush[:inherit_parent_permissions] = value 171 | end 172 | 173 | def flush 174 | sd = get_security_descriptor 175 | 176 | sd.owner = get_account_id(@property_flush[:owner]) if @property_flush[:owner] 177 | sd.group = get_account_id(@property_flush[:group]) if @property_flush[:group] 178 | sd.protect = resource.munge_boolean(@property_flush[:inherit_parent_permissions]) == :false if @property_flush.key?(:inherit_parent_permissions) 179 | 180 | if @property_flush.key?(:inherit_parent_permissions) || @property_flush[:owner] || @property_flush[:group] 181 | # If owner/group/protect change, we should save the SD and reevaluate for sync of permissions 182 | set_security_descriptor(sd) 183 | sd = get_security_descriptor 184 | # Permissions may go out of whack due to a change here. Ensuring 185 | # we flush them below will help ensure we are in sync on first 186 | # convergence. 187 | @property_flush[:permissions] = @resource[:permissions] unless @property_flush[:permissions] 188 | end 189 | 190 | # There is a possibility someone will get a message of permissions 191 | # changing the first time they make changes to owner/group/protect 192 | # even if the outcome of making those changes would have resulted 193 | # in the DACL being in sync. Since there is a change on the 194 | # resource, I think we are fine with the extra message in the 195 | # report as Puppet figures things out. It will apply the sync based 196 | # on what the actual permissions are after setting owner, group, 197 | # and protect. 198 | if @property_flush[:permissions] 199 | dacl = convert_to_dacl(sync_aces(sd.dacl, @property_flush[:permissions], @resource[:purge] == :true, @resource[:purge] == :listed_permissions)) 200 | set_security_descriptor(Puppet::Util::Windows::SecurityDescriptor.new(sd.owner, sd.group, dacl, sd.protect)) 201 | end 202 | 203 | @property_flush.clear 204 | end 205 | end 206 | -------------------------------------------------------------------------------- /lib/puppet/type/acl/rights.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Helper class used to represent ACL Rights 4 | class Puppet::Type::Acl 5 | # Simple ACL Rights object 6 | class Rights 7 | attr_reader :value, :order 8 | 9 | def initialize(permission) 10 | return if permission.nil? || permission.empty? 11 | 12 | @value = permission.downcase.to_sym unless @value.is_a?(Symbol) 13 | right = { 14 | full: 0, 15 | modify: 1, 16 | write: 2, 17 | read: 3, 18 | execute: 4, 19 | mask_specific: 5 20 | } 21 | @order = right[@value] 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppetlabs-acl", 3 | "version": "5.0.3", 4 | "author": "puppetlabs", 5 | "summary": "This module provides the ability to manage ACLs on nodes", 6 | "license": "Apache-2.0", 7 | "source": "git://github.com/puppetlabs/puppetlabs-acl.git", 8 | "project_page": "https://github.com/puppetlabs/puppetlabs-acl", 9 | "issues_url": "https://github.com/puppetlabs/puppetlabs-acl/issues", 10 | "dependencies": [ 11 | 12 | ], 13 | "operatingsystem_support": [ 14 | { 15 | "operatingsystem": "Windows", 16 | "operatingsystemrelease": [ 17 | "10", 18 | "2012", 19 | "2012 R2", 20 | "2016", 21 | "2019", 22 | "2022" 23 | ] 24 | } 25 | ], 26 | "requirements": [ 27 | { 28 | "name": "puppet", 29 | "version_requirement": ">= 7.0.0 < 9.0.0" 30 | } 31 | ], 32 | "tags": [ 33 | "microsoft", 34 | "access control list", 35 | "access control entry", 36 | "acl", 37 | "ace", 38 | "file permissions" 39 | ], 40 | "description": "This module provides the ability to manage ACLs on nodes. Currently the only operating system supported is Windows", 41 | "pdk-version": "3.2.0", 42 | "template-url": "https://github.com/puppetlabs/pdk-templates.git#main", 43 | "template-ref": "tags/3.2.0.4-0-g5d17ec1" 44 | } 45 | -------------------------------------------------------------------------------- /pdk.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: [] 3 | -------------------------------------------------------------------------------- /provision.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | default: 3 | provisioner: abs 4 | images: 5 | - win-2016-x86_64 6 | vagrant: 7 | provisioner: vagrant 8 | images: 9 | - gusztavvargadr/windows-server 10 | release_checks: 11 | provisioner: abs 12 | images: 13 | - win-2012-x86_64 14 | - win-2012r2-x86_64 15 | - win-2016-core-x86_64 16 | - win-2019-core-x86_64 17 | - win-81-x86_64 18 | - win-10-pro-x86_64 19 | release_checks_7: 20 | provisioner: abs 21 | images: 22 | - win-2012r2-x86_64 23 | - win-2016-x86_64 24 | - win-2019-x86_64 25 | - win-10-pro-x86_64 26 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_directory/allow_rights_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Directory - Allow' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target}': 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { '#{user_id}': 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { '#{target}': 25 | permissions => [ 26 | { identity => '#{user_id}', perm_type => 'allow', rights => ['#{rights}'] }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:verify_acl_command) { "icacls #{target}" } 33 | 34 | context '"execute" Rights for Identity on Directory' do 35 | let(:rights) { 'execute' } 36 | let(:target) { "c:/temp/allow_#{rights}_rights_dir" } 37 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(Rc,S,X,RA\)} } 38 | 39 | include_examples 'execute manifest' 40 | end 41 | 42 | context '"modify" Rights for Identity on Directory' do 43 | let(:rights) { 'modify' } 44 | let(:target) { "c:/temp/allow_#{rights}_rights_dir" } 45 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(M\)} } 46 | 47 | include_examples 'execute manifest' 48 | end 49 | 50 | context '"read, execute" Rights for Identity on Directory' do 51 | let(:rights) { "read', 'execute" } 52 | let(:target) { 'c:/temp/allow_re_rights_dir' } 53 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(RX\)} } 54 | 55 | include_examples 'execute manifest' 56 | end 57 | 58 | context '"read" Rights for Identity on Directory' do 59 | let(:rights) { 'read' } 60 | let(:target) { "c:/temp/allow_#{rights}_rights_dir" } 61 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(R\)} } 62 | 63 | include_examples 'execute manifest' 64 | end 65 | 66 | context '"write, execute" Rights for Identity on Directory' do 67 | let(:rights) { "write','execute" } 68 | let(:target) { 'c:/temp/allow_we_rights_dir' } 69 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(W,Rc,X,RA\)} } 70 | 71 | include_examples 'execute manifest' 72 | end 73 | 74 | context '"write, read" Rights for Identity on Directory' do 75 | let(:rights) { "write','read" } 76 | let(:target) { 'c:/temp/allow_wr_rights_dir' } 77 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(R,W\)} } 78 | 79 | include_examples 'execute manifest' 80 | end 81 | 82 | context '"write, read, execute" Rights for Identity on Directory' do 83 | let(:rights) { "write','read','execute" } 84 | let(:target) { 'c:/temp/allow_wre_rights_dir' } 85 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(RX,W\)} } 86 | 87 | include_examples 'execute manifest' 88 | end 89 | 90 | context '"write" Rights for Identity on Directory' do 91 | let(:rights) { 'write' } 92 | let(:target) { "c:/temp/allow_#{rights}_rights_dir" } 93 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(W,Rc\)} } 94 | 95 | include_examples 'execute manifest' 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_directory/deny_rights_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Directory - Deny' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target}': 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { '#{user_id}': 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { '#{target}': 25 | permissions => [ 26 | { identity => '#{user_id}', rights => ['#{rights}'], perm_type => 'deny' }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:verify_acl_command) { "icacls #{target}" } 33 | 34 | context '"execute" Rights for Identity on Directory' do 35 | let(:rights) { 'execute' } 36 | let(:target) { "c:/temp/deny_#{rights}_rights_dir" } 37 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(Rc,S,X,RA\)} } 38 | 39 | include_examples 'execute manifest' 40 | end 41 | 42 | context '"full" Rights for Identity on Directory' do 43 | let(:rights) { 'full' } 44 | let(:target) { "c:/temp/deny_#{rights}_rights_dir" } 45 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(N\)} } 46 | 47 | include_examples 'execute manifest' 48 | end 49 | 50 | context '"modify" Rights for Identity on Directory' do 51 | let(:rights) { 'modify' } 52 | let(:target) { "c:/temp/deny_#{rights}_rights_dir" } 53 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(M\)} } 54 | 55 | include_examples 'execute manifest' 56 | end 57 | 58 | context '"read, execute" Rights for Identity on Directory' do 59 | let(:rights) { "read', 'execute" } 60 | let(:target) { 'c:/temp/deny_re_rights_dir' } 61 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(RX\)} } 62 | 63 | include_examples 'execute manifest' 64 | end 65 | 66 | context '"read" Rights for Identity on Directory' do 67 | let(:rights) { 'read' } 68 | let(:target) { "c:/temp/deny_#{rights}_rights_dir" } 69 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(R\)} } 70 | 71 | include_examples 'execute manifest' 72 | end 73 | 74 | context '"write, execute" Rights for Identity on Directory' do 75 | let(:rights) { "write','execute" } 76 | let(:target) { 'c:/temp/deny_we_rights_dir' } 77 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(W,Rc,X,RA\)} } 78 | 79 | include_examples 'execute manifest' 80 | end 81 | 82 | context '"write, read" Rights for Identity on Directory' do 83 | let(:rights) { "write','read" } 84 | let(:target) { 'c:/temp/deny_wr_rights_dir' } 85 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(R,W\)} } 86 | 87 | include_examples 'execute manifest' 88 | end 89 | 90 | context '"write, read, execute" Rights for Identity on Directory' do 91 | let(:rights) { "write','read','execute" } 92 | let(:target) { 'c:/temp/deny_wre_rights_dir' } 93 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(RX,W\)} } 94 | 95 | include_examples 'execute manifest' 96 | end 97 | 98 | context '"write" Rights for Identity on Directory' do 99 | let(:rights) { 'write' } 100 | let(:target) { "c:/temp/deny_#{rights}_rights_dir" } 101 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(W,Rc\)} } 102 | 103 | include_examples 'execute manifest' 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_directory/mask_specific/allow_rights_dir_mask_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Allow Mask Specific' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { 'c:/temp/allow_#{mask}_rights_dir': 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { '#{user_id}': 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { 'c:/temp/allow_#{mask}_rights_dir': 25 | permissions => [ 26 | { identity => '#{user_id}', rights => ['mask_specific'], mask => '#{mask}' }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:target) { "c:/temp/allow_#{mask}_rights_dir" } 33 | let(:verify_acl_command) { "icacls #{target}" } 34 | 35 | context '"AD, S, WA, X" Rights for Identity on Directory' do 36 | let(:mask) { '1048868' } 37 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(S,AD,X,WA\)} } 38 | 39 | include_examples 'execute manifest' 40 | end 41 | 42 | context '"RD, DC, WEA, RC" Rights for Identity on Directory' do 43 | let(:mask) { '131153' } 44 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(Rc,RD,WEA,DC\)} } 45 | 46 | include_examples 'execute manifest' 47 | end 48 | 49 | context '"S, DE, REA, WEA, RA, WA" Rights for Identity on Directory' do 50 | let(:mask) { '1114520' } 51 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(D,REA,WEA,RA,WA\)} } 52 | 53 | include_examples 'execute manifest' 54 | end 55 | 56 | context '"S, RA, WA, RC" Rights for Identity on Directory' do 57 | let(:mask) { '1180032' } 58 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(Rc,S,RA,WA\)} } 59 | 60 | include_examples 'execute manifest' 61 | end 62 | 63 | context '"WD, REA, RA, S" Rights for Identity on Directory' do 64 | let(:mask) { '1048714' } 65 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(S,WD,REA,RA\)} } 66 | 67 | include_examples 'execute manifest' 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_directory/mask_specific/deny_rights_dir_mask_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Directory - Deny Mask Specific' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { 'c:/temp/deny_#{mask}_rights_dir': 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { '#{user_id}': 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { 'c:/temp/deny_#{mask}_rights_dir': 25 | permissions => [ 26 | { identity => '#{user_id}', perm_type => 'deny', rights => ['mask_specific'], mask => '#{mask}' }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:target) { "c:/temp/deny_#{mask}_rights_dir" } 33 | let(:verify_acl_command) { "icacls #{target}" } 34 | 35 | context '"AD, S, WA, X" Rights for Identity on Directory' do 36 | let(:mask) { '1048868' } 37 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(S,AD,X,WA\)} } 38 | 39 | include_examples 'execute manifest' 40 | end 41 | 42 | context '"DE, REA, WEA, RA, WA" Rights for Identity on Directory' do 43 | let(:mask) { '65944' } 44 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(D,REA,WEA,RA,WA\)} } 45 | 46 | include_examples 'execute manifest' 47 | end 48 | 49 | context '"RD, S, DC, WEA, RC" Rights for Identity on Directory' do 50 | let(:mask) { '131153' } 51 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(Rc,S,RD,WEA,DC\)} } 52 | 53 | include_examples 'execute manifest' 54 | end 55 | 56 | context '"S, RA, WA, Rc" Rights for Identity on Directory' do 57 | let(:mask) { '1180032' } 58 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(Rc,S,RA,WA\)} } 59 | 60 | include_examples 'execute manifest' 61 | end 62 | 63 | context '"WD, REA, RA, S" Rights for Identity on File' do 64 | let(:mask) { '1048714' } 65 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(DENY\)\(S,WD,REA,RA\)} } 66 | 67 | include_examples 'execute manifest' 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_file/allow_rights_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'File - Allow' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_file}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { '#{target_parent}/#{target_file}': 26 | permissions => [ 27 | { identity => '#{user_id}', perm_type => 'allow', rights => ['#{rights}'] }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 34 | 35 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 36 | 37 | context '"execute" Rights for Identity on File' do 38 | let(:rights) { 'execute' } 39 | let(:target_file) { "allow_#{rights}_rights_file.txt" } 40 | let(:file_content) { 'The bed that eats people. DEATH BED!' } 41 | let(:acl_regex) { %r{.*\\bob:\(Rc,S,X,RA\)} } 42 | 43 | include_examples 'execute manifest and verify file' 44 | end 45 | 46 | context '"modify" Rights for Identity on File' do 47 | let(:rights) { 'modify' } 48 | let(:target_file) { "allow_#{rights}_rights_file.txt" } 49 | let(:file_content) { 'Snow on the bluff.' } 50 | let(:acl_regex) { %r{.*\\bob:\(M\)} } 51 | 52 | include_examples 'execute manifest and verify file' 53 | end 54 | 55 | context '"read, execute" Rights for Identity on File' do 56 | let(:rights) { "read','execute" } 57 | let(:target_file) { 'allow_re_rights_file.txt' } 58 | let(:file_content) { 'Get on the phone with baked beans!' } 59 | let(:acl_regex) { %r{.*\\bob:\(RX\)} } 60 | 61 | include_examples 'execute manifest and verify file' 62 | end 63 | 64 | context '"read" Rights for Identity on File' do 65 | let(:rights) { 'read' } 66 | let(:target_file) { "allow_#{rights}_rights_file.txt" } 67 | let(:file_content) { 'Deadly couch eating monster.' } 68 | let(:acl_regex) { %r{.*\\bob:\(R\)} } 69 | 70 | include_examples 'execute manifest and verify file' 71 | end 72 | 73 | context '"write, execute" Rights for Identity on File' do 74 | let(:rights) { "write','execute" } 75 | let(:target_file) { 'allow_we_rights_file.txt' } 76 | let(:file_content) { 'Get on the phone with baked beans!' } 77 | let(:acl_regex) { %r{.*\\bob:\(W,Rc,X,RA\)} } 78 | 79 | include_examples 'execute manifest and verify file' 80 | end 81 | 82 | context '"write, read" Rights for Identity on File' do 83 | let(:rights) { "write','read" } 84 | let(:target_file) { 'allow_wr_rights_file.txt' } 85 | let(:file_content) { 'Mushy bean paste in my eyes!' } 86 | let(:acl_regex) { %r{.*\\bob:\(R,W\)} } 87 | 88 | include_examples 'execute manifest and verify file' 89 | end 90 | 91 | context '"write, read, execute" Rights for Identity on File' do 92 | let(:rights) { "write','read','execute" } 93 | let(:target_file) { 'allow_wre_rights_file.txt' } 94 | let(:file_content) { 'Very small feet to eat.' } 95 | let(:acl_regex) { %r{.*\\bob:\(RX,W\)} } 96 | 97 | include_examples 'execute manifest and verify file' 98 | end 99 | 100 | context '"write" Rights for Identity on File' do 101 | let(:rights) { 'write' } 102 | let(:target_file) { "allow_#{rights}_rights_file.txt" } 103 | let(:file_content) { 'Smart bubbles in my bath.' } 104 | let(:acl_regex) { %r{.*\\bob:\(W,Rc\)} } 105 | 106 | include_examples 'execute manifest and verify file' 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_file/deny_rights_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'File - Deny' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_file}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { '#{target_parent}/#{target_file}': 26 | permissions => [ 27 | { identity => '#{user_id}', perm_type => 'deny', rights => ['#{rights}'] }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 34 | 35 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 36 | 37 | context '"execute" Rights for Identity on File' do 38 | let(:rights) { 'execute' } 39 | let(:file_content) { 'Smells like teen spirit or body odor.' } 40 | let(:target_file) { "deny_#{rights}_rights_file.txt" } 41 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(Rc,S,X,RA\)} } 42 | 43 | include_examples 'execute manifest and verify file' 44 | end 45 | 46 | context '"full" Rights for Identity on File' do 47 | let(:rights) { 'full' } 48 | let(:target_file) { "deny_#{rights}_rights_file.txt" } 49 | let(:file_content) { 'You have to fight for your right to party.' } 50 | let(:acl_regex) { %r{.*\\bob:\(N\)} } 51 | 52 | include_examples 'execute manifest and verify file' 53 | end 54 | 55 | context '"modify" Rights for Identity on File' do 56 | let(:rights) { 'modify' } 57 | let(:target_file) { "deny_#{rights}_rights_file.txt" } 58 | let(:file_content) { 'Giant flying space pigs with lasers.' } 59 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(M\)} } 60 | 61 | include_examples 'execute manifest and verify file' 62 | end 63 | 64 | context '"read, execute" Rights for Identity on File' do 65 | let(:rights) { "read','execute" } 66 | let(:target_file) { 'deny_re_rights_file.txt' } 67 | let(:file_content) { 'Your forcefield is good, but my teleporting is better.' } 68 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(RX\)} } 69 | 70 | include_examples 'execute manifest and verify file' 71 | end 72 | 73 | context '"read" Rights for Identity on File' do 74 | let(:rights) { 'read' } 75 | let(:target_file) { "deny_#{rights}_rights_file.txt" } 76 | let(:file_content) { 'Elvis is king of rock and roll.' } 77 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(R\)} } 78 | 79 | include_examples 'execute manifest and verify file' 80 | end 81 | 82 | context '"write, execute" Rights for Identity on File' do 83 | let(:rights) { "write','execute" } 84 | let(:target_file) { 'deny_we_rights_file.txt' } 85 | let(:file_content) { 'Now time for some rocket fuel.' } 86 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(W,Rc,X,RA\)} } 87 | 88 | include_examples 'execute manifest and verify file' 89 | end 90 | 91 | context '"write, read" Rights for Identity on File' do 92 | let(:rights) { "write','read" } 93 | let(:target_file) { 'deny_wr_rights_file.txt' } 94 | let(:file_content) { 'I live in a garbage can.' } 95 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(R,W\)} } 96 | 97 | include_examples 'execute manifest and verify file' 98 | end 99 | 100 | context '"write, read, execute" Rights for Identity on File' do 101 | let(:rights) { "write','read','execute" } 102 | let(:target_file) { 'deny_wre_rights_file.txt' } 103 | let(:file_content) { 'Flying rats.' } 104 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(RX,W\)} } 105 | 106 | include_examples 'execute manifest and verify file' 107 | end 108 | 109 | context '"write" Rights for Identity on File' do 110 | let(:rights) { 'write' } 111 | let(:target_file) { "deny_#{rights}_rights_file.txt" } 112 | let(:file_content) { 'Marxist cat wants some of your food.' } 113 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(W,Rc\)} } 114 | 115 | include_examples 'execute manifest and verify file' 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_file/mask_specific/allow_rights_file_mask_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'File - Allow Mask Specific' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { 'c:/temp/allow_#{mask}_rights_file.txt': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { 'c:/temp/allow_#{mask}_rights_file.txt': 26 | permissions => [ 27 | { identity => '#{user_id}', rights => ['mask_specific'], mask => '#{mask}' }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:verify_acl_command) { "icacls c:/temp/allow_#{mask}_rights_file.txt" } 34 | 35 | let(:verify_content_path) { "c:\\temp\\allow_#{mask}_rights_file.txt" } 36 | 37 | context '"AD, S, WA, X" Rights for Identity on File' do 38 | let(:mask) { '1048868' } 39 | let(:file_content) { 'The puppets are controlling my mind!' } 40 | let(:acl_regex) { %r{.*\\bob:\(S,AD,X,WA\)} } 41 | 42 | include_examples 'execute manifest and verify file' 43 | end 44 | 45 | context '"RD, DE, WEA, RC" Rights for Identity on File' do 46 | let(:mask) { '196625' } 47 | let(:file_content) { 'You are never going to feel it!' } 48 | let(:acl_regex) { %r{.*\\bob:\(DE,Rc,RD,WEA\)} } 49 | 50 | include_examples 'execute manifest and verify file' 51 | end 52 | 53 | context '"S, DE, REA, WEA, RA, WA" Rights for Identity on File' do 54 | let(:mask) { '1114520' } 55 | let(:file_content) { 'Karate time!' } 56 | let(:acl_regex) { %r{.*\\bob:\(D,REA,WEA,RA,WA\)} } 57 | 58 | include_examples 'execute manifest and verify file' 59 | end 60 | 61 | context '"S, RA, WA, RC" Rights for Identity on File' do 62 | let(:mask) { '1180032' } 63 | let(:file_content) { 'I like shoes made by Canadians.' } 64 | let(:acl_regex) { %r{.*\\bob:\(Rc,S,RA,WA\)} } 65 | 66 | include_examples 'execute manifest and verify file' 67 | end 68 | 69 | context '"WD, REA, RA, S" Rights for Identity on File' do 70 | let(:mask) { '1048714' } 71 | let(:file_content) { 'My mind is going... I can feel it.' } 72 | let(:acl_regex) { %r{.*\\bob:\(S,WD,REA,RA\)} } 73 | 74 | include_examples 'execute manifest and verify file' 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/acceptance/access_rights_file/mask_specific/deny_rights_file_mask_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'File - Deny Mask Specific' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { 'c:/temp/deny_#{mask}_rights_file.txt': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { 'c:/temp/deny_#{mask}_rights_file.txt': 26 | permissions => [ 27 | { identity => '#{user_id}', perm_type => 'deny', rights => ['mask_specific'], mask => '#{mask}' }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:verify_acl_command) { "icacls c:/temp/deny_#{mask}_rights_file.txt" } 34 | 35 | let(:verify_content_path) { "c:\\temp\\deny_#{mask}_rights_file.txt" } 36 | 37 | context '"AD, S, WA, X" Rights for Identity on File' do 38 | let(:mask) { '1048868' } 39 | let(:file_content) { 'Slippery when dry.' } 40 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(S,AD,X,WA\)} } 41 | 42 | include_examples 'execute manifest and verify file' 43 | end 44 | 45 | context '"RD, DE, WEA, RC" Rights for Identity on File' do 46 | let(:mask) { '196625' } 47 | let(:file_content) { 'Pressure, oh the pressure.' } 48 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(D,Rc,RD,WEA\)} } 49 | 50 | include_examples 'execute manifest and verify file' 51 | end 52 | 53 | context '"S, DE, REA, WEA, RA, WA" Rights for Identity on File' do 54 | let(:mask) { '1114520' } 55 | let(:file_content) { 'Gallons of hats on your head.' } 56 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(D,REA,WEA,RA,WA\)} } 57 | 58 | include_examples 'execute manifest and verify file' 59 | end 60 | 61 | context '"S, RA, WA, RC" Rights for Identity on File' do 62 | let(:mask) { '1180032' } 63 | let(:file_content) { 'We need experienced fighter pilots to train these pigs in the basics of aviation!' } 64 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(Rc,S,RA,WA\)} } 65 | 66 | include_examples 'execute manifest and verify file' 67 | end 68 | 69 | context '"WD, REA, RA, S" Rights for Identity on File' do 70 | let(:mask) { '1048714' } 71 | let(:file_content) { 'Tiny little people with small problems.' } 72 | let(:acl_regex) { %r{.*\\bob:\(DENY\)\(S,WD,REA,RA\)} } 73 | 74 | include_examples 'execute manifest and verify file' 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/acceptance/basic_functionality/negative/negative_acl_on_linux_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Basic Functionality - Negative' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '/tmp/acl_test': 9 | ensure => directory 10 | } 11 | 12 | acl { '/tmp/acl_test': 13 | permissions => [ 14 | { identity => 'root', rights => ['full'] }, 15 | ], 16 | } 17 | MANIFEST 18 | end 19 | 20 | context 'ACL Fails Gracefully on Linux', unless: os[:family] == 'windows' do 21 | it "verifes that the 'acl' type does not work on non-Windows agents" do 22 | apply_manifest(acl_manifest, expect_failures: true) do |result| 23 | expect(result.stderr).to match(%r{Error: Could not find a suitable provider for acl}) 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/acceptance/group/group_local_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Group' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/group_#{user_type}.txt": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{user_id}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | group { "#{group_id}": 26 | ensure => present 27 | } 28 | 29 | acl { "#{target_parent}/group_#{user_type}.txt": 30 | purge => 'true', 31 | permissions => [ 32 | { identity => 'CREATOR GROUP', 33 | rights => ['modify'] 34 | }, 35 | { identity => '#{user_id}', 36 | rights => ['read'] 37 | }, 38 | { identity => 'Administrators', 39 | rights => ['full'], 40 | affects => 'all', 41 | child_types => 'all' 42 | } 43 | ], 44 | group => '#{group_id}', 45 | inherit_parent_permissions => 'false' 46 | } 47 | MANIFEST 48 | end 49 | 50 | let(:verify_acl_command) { "icacls #{target_parent}/group_#{user_type}.txt" } 51 | 52 | let(:verify_content_path) { "#{target_parent}/group_#{user_type}.txt" } 53 | 54 | context 'Change Group to Local Group' do 55 | let(:user_type) { 'local_group' } 56 | let(:file_content) { 'Hot sand in your eyes!' } 57 | let(:group_id) { 'jerks' } 58 | let(:acl_regex) { %r{.*\\jerks:\(M\)} } 59 | 60 | include_examples 'execute manifest and verify file' 61 | end 62 | 63 | context 'Change Group to Local Group with Long Name' do 64 | let(:user_type) { 'local_long_group_name' } 65 | let(:file_content) { 'Uncontrolled napping.' } 66 | # rubocop:disable Layout/LineLength 67 | let(:group_id) { 'jasqddweruwqiouroaysfyuasudyfaisoyfqoiuwyefiaysdiyfzixycivzixyvciqywifyiasdiufyasdygfasirfwerqiuwyeriatsdtfastdfqwyitfastdfawerfytasdytfasydgtaisdytfiasydfiosayghiayhidfhygiasftawyegyfhgaysgfuyasgdyugfasuiyfguaqyfgausydgfaywgfuasgdfuaisydgfausasdfuygsadfyg' } 68 | let(:acl_regex) { %r{.*\\jasqddweruwqiouroaysfyuasudyfaisoyfqoiuwyefiaysdiyfzixycivzixyvciqywifyiasdiufyasdygfasirfwerqiuwyeriatsdtfastdfqwyitfastdfawerfytasdytfasydgtaisdytfiasydfiosayghiayhidfhygiasftawyegyfhgaysgfuyasgdyugfasuiyfguaqyfgausydgfaywgfuasgdfuaisydgfausasdfuygsadfyg:\(M\)} } 69 | 70 | # rubocop:enable Layout/LineLength 71 | 72 | include_examples 'execute manifest and verify file' 73 | end 74 | 75 | context 'Change Group to Local User with Long Name' do 76 | let(:user_type) { 'local_long_user_name' } 77 | let(:file_content) { 'Dog eat dog world.' } 78 | let(:group_id) { 'long_user_name_jerry' } 79 | let(:acl_regex) { %r{.*\\long_user_name_jerry:\(M\)} } 80 | 81 | include_examples 'execute manifest and verify file' 82 | end 83 | 84 | context 'Change Group to Local User' do 85 | random_username = generate_random_username 86 | let(:user_type) { 'local_user' } 87 | let(:file_content) { 'cat-man-doo!' } 88 | let(:group_id) { random_username } 89 | let(:acl_regex) { %r{.*\\#{group_id}:\(M\)} } 90 | 91 | include_examples 'execute manifest and verify file' 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /spec/acceptance/group/group_local_unicode_group_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | prefix = SecureRandom.uuid.to_s 6 | 7 | describe 'Group - Unicode' do 8 | let(:acl_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | 14 | file { "c:/temp/#{prefix}.txt": 15 | ensure => file, 16 | content => '#{file_content}', 17 | require => File['#{target_parent}'] 18 | } 19 | 20 | user { "#{user_id}": 21 | ensure => present, 22 | groups => 'Users', 23 | managehome => true, 24 | password => "L0v3Pupp3t!" 25 | } 26 | 27 | group { "#{group_id}": 28 | ensure => present 29 | } 30 | 31 | acl { "c:/temp/#{prefix}.txt": 32 | purge => 'true', 33 | permissions => [ 34 | { identity => 'CREATOR GROUP', 35 | rights => ['modify'] 36 | }, 37 | { identity => '#{user_id}', 38 | rights => ['read'] 39 | }, 40 | { identity => 'Administrators', 41 | rights => ['full'], 42 | affects => 'all', 43 | child_types => 'all' 44 | } 45 | ], 46 | group => '#{group_id}', 47 | inherit_parent_permissions => 'false' 48 | } 49 | MANIFEST 50 | end 51 | 52 | let(:verify_acl_command) { "(Get-ACL 'c:/temp/#{prefix}.txt' | Where-Object { $_.Group -match ('.*\\\\' + [regex]::Unescape(\"#{raw_group_id}\")) } | Measure-Object).Count" } 53 | let(:acl_regex) { %r{^1$} } 54 | 55 | context 'Change Group to Local Unicode Group' do 56 | let(:file_content) { 'Dangers driving drunk while insane.' } 57 | let(:raw_group_id) { 'group_\u4388\u542B\u3D3C\u7F4D\uF961\u4381\u53F4\u79C0\u3AB2\u8EDE' } 58 | let(:group_id) { "group_\u4388\u542B\u3D3C\u7F4D\uF961\u4381\u53F4\u79C0\u3AB2\u8EDE" } # 䎈含㴼罍率䎁叴秀㪲軞 59 | 60 | include_examples 'execute manifest and verify (with PowerShell)' 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/acceptance/group/group_local_unicode_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | prefix = SecureRandom.uuid.to_s 6 | 7 | describe 'Group - Unicode' do 8 | let(:acl_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | 14 | file { "c:/temp/#{prefix}.txt": 15 | ensure => file, 16 | content => '#{file_content}', 17 | require => File['#{target_parent}'] 18 | } 19 | 20 | user { "#{user_id}": 21 | ensure => present, 22 | groups => 'Users', 23 | managehome => true, 24 | password => "L0v3Pupp3t!" 25 | } 26 | 27 | user { "#{group_id}": 28 | ensure => present, 29 | groups => 'Users', 30 | managehome => true, 31 | password => "L0v3Pupp3t!" 32 | } 33 | 34 | acl { "c:/temp/#{prefix}.txt": 35 | purge => 'true', 36 | permissions => [ 37 | { identity => 'CREATOR GROUP', 38 | rights => ['modify'] 39 | }, 40 | { identity => '#{user_id}', 41 | rights => ['read'] 42 | }, 43 | { identity => 'Administrators', 44 | rights => ['full'], 45 | affects => 'all', 46 | child_types => 'all' 47 | } 48 | ], 49 | group => '#{group_id}', 50 | inherit_parent_permissions => 'false' 51 | } 52 | MANIFEST 53 | end 54 | 55 | let(:verify_acl_command) { "(Get-ACL 'c:/temp/#{prefix}.txt' | Where-Object { $_.Group -match ('.*\\\\' + [regex]::Unescape(\"#{raw_group_id}\")) } | Measure-Object).Count" } 56 | let(:acl_regex) { %r{^1$} } 57 | 58 | context 'Change Group to Local Unicode User' do 59 | let(:file_content) { 'Burning grass on a cold winter day.' } 60 | let(:raw_group_id) { 'group2_\u03A3\u03A4\u03A5\u03A6' } 61 | let(:group_id) { "group2_\u03A3\u03A4\u03A5\u03A6" } # ΣΤΥΦ 62 | 63 | include_examples 'execute manifest and verify (with PowerShell)' 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/acceptance/group/group_local_user_sid_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | sid = '' 6 | 7 | describe 'Group - SID' do 8 | context 'Change Group to Local User SID' do 9 | let(:setup_manifest) do 10 | <<-MANIFEST 11 | file { "#{target_parent}": 12 | ensure => directory 13 | } 14 | 15 | file { "#{target}": 16 | ensure => file, 17 | content => '#{file_content}', 18 | require => File['#{target_parent}'] 19 | } 20 | 21 | user { "#{user_id}": 22 | ensure => present, 23 | groups => 'Users', 24 | managehome => true, 25 | password => "L0v3Pupp3t!" 26 | } 27 | 28 | user { "#{group_id}": 29 | ensure => present, 30 | groups => 'Users', 31 | managehome => true, 32 | password => "L0v3Pupp3t!" 33 | } 34 | MANIFEST 35 | end 36 | 37 | let(:acl_manifest) do 38 | <<-MANIFEST 39 | acl { "#{target}": 40 | purge => 'true', 41 | permissions => [ 42 | { identity => 'CREATOR GROUP', 43 | rights => ['modify'] 44 | }, 45 | { identity => '#{user_id}', 46 | rights => ['read'] 47 | }, 48 | { identity => 'Administrators', 49 | rights => ['full'], 50 | affects => 'all', 51 | child_types => 'all' 52 | } 53 | ], 54 | group => '#{sid}', 55 | inherit_parent_permissions => 'false' 56 | } 57 | MANIFEST 58 | end 59 | 60 | let(:user_type) { 'local_user_sid' } 61 | let(:file_content) { 'Hot eyes in your sand!' } 62 | 63 | let(:target_name) { "group_#{user_type}.txt" } 64 | 65 | let(:target) { "#{target_parent}/#{target_name}" } 66 | let(:user_id) { 'bob' } 67 | let(:group_id) { 'tom' } 68 | 69 | let(:get_group_sid_command) do 70 | <<-CMD 71 | cmd /c "wmic useraccount where name='#{group_id}' get sid" 72 | CMD 73 | end 74 | 75 | let(:sid_regex) { %r{^(S-.+)$} } 76 | 77 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 78 | 79 | let(:verify_group_command) { "icacls #{target}" } 80 | let(:group_regex) { %r{.*\\tom:\(M\)} } 81 | 82 | it 'applies setup manifest' do 83 | acl_idempotent_apply(setup_manifest) 84 | end 85 | 86 | it 'retrieves SID of user account' do 87 | run_shell(get_group_sid_command) do |result| 88 | sid = sid_regex.match(result.stdout)[1] 89 | end 90 | end 91 | 92 | it 'applies ACL manifest' do 93 | # TODO: find out why this is not idempotent 94 | apply_manifest(acl_manifest, catch_failures: true) 95 | end 96 | 97 | it 'verifies ACL rights' do 98 | run_shell(verify_group_command) do |result| 99 | expect(result.stdout).to match(%r{#{group_regex}}) 100 | end 101 | end 102 | 103 | it 'verifies file data integrity' do 104 | expect(file(verify_content_path)).to be_file 105 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /spec/acceptance/group/negative/group_257_char_name_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Group - Negative' do 6 | let(:user_type) { '257_char_name' } 7 | let(:file_content) { 'Organized chaos party.' } 8 | 9 | let(:target_name) { "group_#{user_type}.txt" } 10 | 11 | let(:target) { "#{target_parent}/#{target_name}" } 12 | let(:group_id) { 'jadsqddweruwqiouroaysfyuasudyfaisoyfqoiuwyefiaysdiyfzixycivzixyvciqywifyiasdiufyasdygfasirfwerqiuwyeriatsdtfastdfqwyitfastdfawerfytasdytfasydgtaisdytfiasydfiosayghiayhidfhygiasftawyegyfhgaysgfuyasgdyugfasuiyfguaqyfgausydgfaywgfuasgdfuaisydgfausasdfuygsadfyg' } # rubocop:disable Layout/LineLength 13 | 14 | let(:expected_error) { %r{Error:.*Group does not exist.} } 15 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 16 | 17 | let(:acl_manifest) do 18 | <<-MANIFEST 19 | file { "#{target_parent}": 20 | ensure => directory 21 | } 22 | 23 | file { "#{target}": 24 | ensure => file, 25 | content => '#{file_content}', 26 | require => File['#{target_parent}'] 27 | } 28 | 29 | user { "#{user_id}": 30 | ensure => present, 31 | groups => 'Users', 32 | managehome => true, 33 | password => "L0v3Pupp3t!" 34 | } 35 | 36 | acl { "#{target}": 37 | purge => 'true', 38 | permissions => [ 39 | { identity => 'CREATOR GROUP', 40 | rights => ['modify'] 41 | }, 42 | { identity => '#{user_id}', 43 | rights => ['read'] 44 | }, 45 | { identity => 'Administrators', 46 | rights => ['full'], 47 | affects => 'all', 48 | child_types => 'all' 49 | } 50 | ], 51 | group => '#{group_id}', 52 | inherit_parent_permissions => 'false' 53 | } 54 | MANIFEST 55 | end 56 | 57 | context 'change group to local group with long name' do 58 | it 'attempts to apply manifest, raises error' do 59 | apply_manifest(acl_manifest, expect_failures: true) do |result| 60 | expect(result.stderr).to match(%r{#{expected_error}}) 61 | end 62 | end 63 | 64 | it 'verifies file data integrity' do 65 | expect(file(verify_content_path)).to be_file 66 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/acceptance/identity/negative/specify_identity_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Identity - Negative' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_file}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | acl { '#{target_parent}/#{target_file}': 19 | permissions => [ 20 | { identity => '#{id}', rights => ['full'] }, 21 | ], 22 | } 23 | MANIFEST 24 | end 25 | 26 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 27 | 28 | context 'Specify 257 Character String for Identity' do 29 | let(:target_file) { 'specify_257_char_ident.txt' } 30 | # Refers to group id 31 | let(:id) { 'nzxncvkjnzxjkcnvkjzxncvkjznxckjvnzxkjncvzxnvckjnzxkjcnvkjzxncvkjzxncvkjzxncvkjnzxkjcnvkzjxncvkjzxnvckjnzxkjcvnzxkncjvjkzxncvkjzxnvckjnzxjkcvnzxkjncvkjzxncvjkzxncvkjzxnkvcjnzxjkcvnkzxjncvkjzxncvkzckjvnzxkcvnjzxjkcnvzjxkncvkjzxnvkjsdnjkvnzxkjcnvkjznvkjxcbvzsp' } # rubocop:disable Layout/LineLength 32 | let(:file_content) { 'A bag of jerks.' } 33 | 34 | it 'applies manifest, raises error' do 35 | apply_manifest(acl_manifest, expect_failures: true) do |result| 36 | expect(result.stderr).to match(%r{Error: Failed to set permissions for }) 37 | end 38 | end 39 | 40 | it 'verifies file data integrity' do 41 | expect(file(verify_content_path)).to be_file 42 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 43 | end 44 | end 45 | 46 | context 'Specify Invalid Identity' do 47 | let(:target_file) { 'specify_invalid_ident.txt' } 48 | # Refers to user id 49 | let(:id) { 'user_not_here' } 50 | let(:file_content) { 'Car made of cats.' } 51 | 52 | it 'applies manifest, raises error' do 53 | apply_manifest(acl_manifest, expect_failures: true) do |result| 54 | expect(result.stderr).to match(%r{Error: Failed to set permissions for 'user_not_here'}) 55 | end 56 | end 57 | 58 | it 'verifies file data integrity' do 59 | expect(file(verify_content_path)).to be_file 60 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/acceptance/identity/specify_app_package_authority_idents_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Identity' do 6 | [ 7 | { id: 'S-1-15-2-1', 8 | acl_regx: %r{.*APPLICATION PACKAGE AUTHORITY\\ALL APPLICATION PACKAGES:\(OI\)\(CI\)\(F\)}, 9 | minimum_kernel: 6.3 }, 10 | # NOTE: 'APPLICATION PACKAGE AUTHORITY\\ALL APPLICATION PACKAGES' doesn't work due to Windows API 11 | { id: 'ALL APPLICATION PACKAGES', 12 | acl_regx: %r{.*APPLICATION PACKAGE AUTHORITY\\ALL APPLICATION PACKAGES:\(OI\)\(CI\)\(F\)}, 13 | minimum_kernel: 6.3 }, 14 | { id: 'S-1-15-2-2', 15 | acl_regx: %r{.*APPLICATION PACKAGE AUTHORITY\\ALL RESTRICTED APPLICATION PACKAGES:\(OI\)\(CI\)\(F\)}, 16 | minimum_kernel: 10.0 }, 17 | # NOTE: 'APPLICATION PACKAGE AUTHORITY\\ALL RESTRICTED APPLICATION PACKAGES' doesn't work due to Windows API 18 | { id: 'ALL RESTRICTED APPLICATION PACKAGES', 19 | acl_regx: %r{.*APPLICATION PACKAGE AUTHORITY\\ALL RESTRICTED APPLICATION PACKAGES:\(OI\)\(CI\)\(F\)}, 20 | minimum_kernel: 10.0 }, 21 | ].each do |account| 22 | target = "c:/#{SecureRandom.uuid}" 23 | verify_acl_command = "icacls #{target}" 24 | 25 | context 'specify APPLICATION PACKAGE AUTHORITY accounts' do 26 | it "Check Minimum Supported OS for #{account[:id]}" do 27 | # use of host_inventory returns nil with localhost 28 | kernelmajversion = run_shell('facter kernelmajversion').stdout.to_f 29 | 30 | # try next agent if user is unsupported on this Windows version 31 | if kernelmajversion < account[:minimum_kernel] 32 | warn("This test requires Windows kernel #{account[:minimum_kernel]} but this host only has #{kernelmajversion}") 33 | skip 34 | 35 | acl_manifest = <<-MANIFEST 36 | file { '#{target}': 37 | ensure => directory 38 | } 39 | 40 | acl { '#{target}': 41 | permissions => [ 42 | { identity => '#{account[:id]}', rights => ['full'] }, 43 | { identity => 'Administrators', rights => ['full'] }, 44 | ], 45 | } 46 | MANIFEST 47 | 48 | it 'applies manifest' do 49 | apply_manifest(acl_manifest, expect_failures) do |result| 50 | expect(result.exit_code).to eq(2) 51 | end 52 | apply_manifest(acl_manifest, catch_changes: true) 53 | end 54 | 55 | original_acl_rights = '' 56 | it 'verifies ACL rights' do 57 | run_shell(verify_acl_command) do |result| 58 | original_acl_rights = result.stdout 59 | expect(original_acl_rights).to match(%r{#{account[:acl_regx]}}) 60 | end 61 | end 62 | 63 | it 'applies manifest again, raises error' do 64 | apply_manifest(acl_manifest, expect_failures: true) do |result| 65 | expect(result.stderr).to match(%r{Error:}) 66 | end 67 | end 68 | 69 | it 'verifies ACL rights again' do 70 | run_shell(verify_acl_command) do |result| 71 | expect(result.stdout).to match(%r{account[:acl_regx]}) 72 | expect(result.stdout).to eq(original_acl_rights) 73 | end 74 | end 75 | end 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /spec/acceptance/identity/specify_group_identity_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Identity - Group' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_file}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | group { '#{group_id}': 19 | ensure => present, 20 | } 21 | 22 | acl { '#{target_parent}/#{target_file}': 23 | permissions => [ 24 | { identity => '#{group_id}', rights => ['full'] }, 25 | ], 26 | } 27 | MANIFEST 28 | end 29 | 30 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 31 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 32 | let(:acl_regex) { %r{.*\\#{group_id}:\(F\)} } 33 | 34 | context 'Specify Group Identity' do 35 | let(:target_file) { 'specify_group_ident.txt' } 36 | let(:group_id) { 'bobs' } 37 | let(:file_content) { 'Cat barf.' } 38 | 39 | include_examples 'execute manifest and verify file' 40 | end 41 | 42 | context 'Specify Group with Long Name for Identity' do 43 | let(:target_file) { 'specify_long_group_ident.txt' } 44 | # 256 Characters 45 | let(:group_id) { 'nzxncvkjnzxjkcnvkjzxncvkjznxckjvnzxkjncvzxnvckjnzxkjcnvkjzxncvkjzxncvkjzxncvkjnzxkjcnvkzjxncvkjzxnvckjnzxkjcvnzxkncjvjkzxncvkjzxnvckjnzxjkcvnzxkjncvkjzxncvjkzxncvkjzxnkvcjnzxjkcvnkzxjncvkjzxncvkzckjvnzxkcvnjzxjkcnvzjxkncvkjzxnvkjsdnjkvnzxkjcnvkjznvkjxcbvzs' } # rubocop:disable Layout/LineLength 46 | let(:file_content) { 'Pretty little poodle dressed in noodles.' } 47 | 48 | include_examples 'execute manifest and verify file' 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/acceptance/identity/specify_sid_identity_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | sid = '' 6 | 7 | describe 'Module - Identity' do 8 | let(:setup_manifest) do 9 | <<-MANIFEST 10 | file { '#{target_parent}': 11 | ensure => directory 12 | } 13 | 14 | file { '#{target_parent}/#{target_file}': 15 | ensure => file, 16 | content => '#{file_content}', 17 | require => File['#{target_parent}'] 18 | } 19 | 20 | user { '#{user_id}': 21 | ensure => present, 22 | groups => 'Users', 23 | managehome => true, 24 | password => "L0v3Pupp3t!" 25 | } 26 | MANIFEST 27 | end 28 | 29 | let(:acl_manifest) do 30 | <<-MANIFEST 31 | acl { '#{target_parent}/#{target_file}': 32 | permissions => [ 33 | { identity => '#{sid}', rights => ['full'] }, 34 | ], 35 | } 36 | MANIFEST 37 | end 38 | 39 | context 'Specify SID Identity' do 40 | let(:os_check_command) { 'cmd /c ver' } 41 | let(:os_check_regex) { %r{Version 5} } 42 | let(:target_file) { 'specify_sid_ident.txt' } 43 | 44 | let(:file_content) { 'Magic unicorn rainbow madness!' } 45 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 46 | 47 | let(:get_user_sid_command) do 48 | <<-CMD 49 | cmd /c "wmic useraccount where name='#{user_id}' get sid" 50 | CMD 51 | end 52 | 53 | let(:sid_regex) { %r{^(S-.+)$} } 54 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 55 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 56 | 57 | it 'applies setup manifest' do 58 | acl_idempotent_apply(setup_manifest) 59 | end 60 | 61 | it 'retrieves SID of user account' do 62 | run_shell(get_user_sid_command) do |result| 63 | sid = sid_regex.match(result.stdout)[1] 64 | end 65 | end 66 | 67 | it 'applies manifest' do 68 | acl_idempotent_apply(acl_manifest) 69 | end 70 | 71 | it 'verifies ACL rights' do 72 | run_shell(verify_acl_command) do |result| 73 | expect(result.stdout).to match(%r{#{acl_regex}}) 74 | end 75 | end 76 | 77 | it 'verifies file data integrity' do 78 | expect(file(verify_content_path)).to be_file 79 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/acceptance/identity/specify_unicode_identity_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Identity' do 6 | let(:acl_manifest_group) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | group { '#{group_id}': 19 | ensure => present, 20 | } 21 | 22 | acl { '#{target}': 23 | permissions => [ 24 | { identity => '#{group_id}', rights => ['full'] }, 25 | ], 26 | } 27 | MANIFEST 28 | end 29 | 30 | let(:acl_manifest_user) do 31 | <<-MANIFEST 32 | file { '#{target_parent}': 33 | ensure => directory 34 | } 35 | 36 | file { '#{target}': 37 | ensure => file, 38 | content => '#{file_content}', 39 | require => File['#{target_parent}'] 40 | } 41 | 42 | user { '#{user_id}': 43 | ensure => present, 44 | groups => 'Users', 45 | managehome => true, 46 | password => "L0v3Pupp3t!" 47 | } 48 | 49 | acl { '#{target}': 50 | permissions => [ 51 | { identity => '#{user_id}', rights => ['full'] }, 52 | ], 53 | } 54 | MANIFEST 55 | end 56 | 57 | let(:acl_regex) { %r{^1$} } 58 | 59 | context 'Specify Group Name Containing Unicode for Identity' do 60 | prefix = SecureRandom.uuid.to_s 61 | let(:acl_manifest) { acl_manifest_group } 62 | let(:target) { "#{target_parent}/#{prefix}.txt" } 63 | let(:raw_group_id) { 'group_\uB81D\uB534\uC2AB\uC788\uCC98' } 64 | let(:group_id) { "group_\uB81D\uB534\uC2AB\uC788\uCC98" } # 렝딴슫있처 65 | let(:file_content) { 'Garbage bag full of money.' } 66 | let(:verify_acl_command) { "(Get-ACL '#{target}' | ForEach-Object { $_.Access } | Where-Object { $_.IdentityReference -match ('\\\\' + [regex]::Unescape(\"#{raw_group_id}\")) -and $_.FileSystemRights -eq 'FullControl' } | Measure-Object).Count" } # rubocop:disable Layout/LineLength 67 | 68 | include_examples 'execute manifest and verify (with PowerShell)' 69 | end 70 | 71 | context 'Windows ACL Module - Specify User Name Containing Unicode for Identity' do 72 | prefix = SecureRandom.uuid.to_s 73 | let(:acl_manifest) { acl_manifest_user } 74 | let(:target) { "#{target_parent}/#{prefix}.txt" } 75 | let(:raw_user_id) { 'user_\uB81D\uB534\uC2AB\uC788\uCC98' } 76 | let(:user_id) { "user_\uB81D\uB534\uC2AB\uC788\uCC98" } # 렝딴슫있처 77 | let(:file_content) { 'Flying Spaghetti Monster wants to save your soul.' } 78 | let(:verify_acl_command) { "(Get-ACL '#{target}' | ForEach-Object { $_.Access } | Where-Object { $_.IdentityReference -match ('\\\\' + [regex]::Unescape(\"#{raw_user_id}\")) -and $_.FileSystemRights -eq 'FullControl' } | Measure-Object).Count" } # rubocop:disable Layout/LineLength 79 | 80 | include_examples 'execute manifest and verify (with PowerShell)' 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/acceptance/identity/specify_user_identity_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Identity - User' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_file}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { '#{target_parent}/#{target_file}': 26 | permissions => [ 27 | { identity => '#{user_id}', rights => ['full'] }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 34 | 35 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 36 | 37 | context 'Specify User with Long Name for Identity' do 38 | let(:target_file) { 'specify_long_user_ident.txt' } 39 | let(:user_id) { 'user_very_long_name1' } 40 | let(:file_content) { 'Brown cow goes moo.' } 41 | let(:acl_regex) { %r{.*\\#{user_id}:\(F\)} } 42 | 43 | include_examples 'execute manifest and verify file' 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/acceptance/inheritance/inheritance_on_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Inheritance - Directory' do 6 | let(:rights) { 'full' } 7 | let(:user_id_child) { 'roberto' } 8 | let(:target_name) { "inherit_#{perm_type}_on_#{asset_type}" } 9 | let(:target_child_name) { "child_#{asset_type}" } 10 | let(:target_child) { "#{target_parent}/#{target_name}/#{target_child_name}" } 11 | 12 | let(:acl_manifest) do 13 | <<-MANIFEST 14 | file { "#{target_parent}": 15 | ensure => directory 16 | } 17 | 18 | file { "#{target_parent}/#{target_name}": 19 | ensure => directory, 20 | require => File['#{target_parent}'] 21 | } 22 | 23 | file { "#{target_child}": 24 | ensure => directory, 25 | require => File['#{target_parent}/#{target_name}'] 26 | } 27 | 28 | user { "#{user_id}": 29 | ensure => present, 30 | groups => 'Users', 31 | managehome => true, 32 | password => "L0v3Pupp3t!" 33 | } 34 | 35 | user { "#{user_id_child}": 36 | ensure => present, 37 | groups => 'Users', 38 | managehome => true, 39 | password => "L0v3Pupp3t!" 40 | } 41 | 42 | acl { "#{target_parent}/#{target_name}": 43 | purge => 'true', 44 | permissions => [ 45 | { identity => '#{user_id}', 46 | rights => ['#{rights}'], 47 | perm_type => '#{perm_type}' 48 | }, 49 | { identity => 'Administrators', 50 | rights => ['full'] 51 | } 52 | ], 53 | inherit_parent_permissions => 'false' 54 | } 55 | -> 56 | acl { "#{target_child}": 57 | permissions => [ 58 | { identity => '#{user_id_child}', 59 | rights => ['#{rights}'], 60 | perm_type => '#{perm_type}' 61 | } 62 | ], 63 | inherit_parent_permissions => '#{child_inherit_type}' 64 | } 65 | MANIFEST 66 | end 67 | 68 | let(:verify_acl_command) { "icacls #{target_child}" } 69 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 70 | 71 | context 'Explicit Inheritance of "allow" Parent Permissions for Directory' do 72 | let(:perm_type) { 'allow' } 73 | let(:asset_type) { 'dir' } 74 | let(:child_inherit_type) { 'true' } 75 | let(:acl_regex) { %r{.*\\bob:\(I\)\(OI\)\(CI\)\(F\)} } 76 | 77 | include_examples 'execute manifest' 78 | end 79 | 80 | context 'Explicit Inheritance of "deny" Parent Permissions for Directory' do 81 | let(:perm_type) { 'deny' } 82 | let(:asset_type) { 'dir' } 83 | let(:child_inherit_type) { 'true' } 84 | let(:acl_regex) { %r{.*\\bob:\(I\)\(OI\)\(CI\)\(N\)} } 85 | 86 | include_examples 'execute manifest' 87 | end 88 | 89 | context 'Remove Inheritance of "allow" Parent Permissions for Directory' do 90 | let(:perm_type) { 'allow' } 91 | let(:asset_type) { 'dir' } 92 | let(:child_inherit_type) { 'false' } 93 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 94 | 95 | include_examples 'execute manifest' 96 | end 97 | 98 | context 'Remove Inheritance of "deny" Parent Permissions for Directory' do 99 | let(:perm_type) { 'deny' } 100 | let(:asset_type) { 'dir' } 101 | let(:child_inherit_type) { 'false' } 102 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(N\)} } 103 | 104 | include_examples 'execute manifest' 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /spec/acceptance/inheritance/inheritance_on_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Inheritance' do 6 | let(:rights) { 'full' } 7 | let(:user_id_child) { 'roberto' } 8 | let(:target_name) { "inherit_#{perm_type}_on_#{asset_type}" } 9 | let(:target_child_name) { "child_#{asset_type}" } 10 | let(:target_child) { "#{target_parent}/#{target_name}/#{target_child_name}" } 11 | 12 | let(:acl_manifest) do 13 | <<-MANIFEST 14 | file { "#{target_parent}": 15 | ensure => directory 16 | } 17 | 18 | file { "#{target_parent}/#{target_name}": 19 | ensure => directory, 20 | require => File['#{target_parent}'] 21 | } 22 | 23 | file { "#{target_child}": 24 | ensure => file, 25 | content => '#{file_content}', 26 | require => File['#{target_parent}/#{target_name}'] 27 | } 28 | 29 | user { "#{user_id}": 30 | ensure => present, 31 | groups => 'Users', 32 | managehome => true, 33 | password => "L0v3Pupp3t!" 34 | } 35 | 36 | user { "#{user_id_child}": 37 | ensure => present, 38 | groups => 'Users', 39 | managehome => true, 40 | password => "L0v3Pupp3t!" 41 | } 42 | 43 | acl { "#{target_parent}/#{target_name}": 44 | purge => 'true', 45 | permissions => [ 46 | { identity => '#{user_id}', 47 | rights => ['#{rights}'], 48 | perm_type => '#{perm_type}' 49 | }, 50 | { identity => 'Administrators', 51 | rights => ['full'] 52 | } 53 | ], 54 | inherit_parent_permissions => 'false' 55 | } 56 | -> 57 | acl { "#{target_child}": 58 | permissions => [ 59 | { identity => '#{user_id_child}', 60 | rights => ['#{rights}'], 61 | perm_type => '#{perm_type}' 62 | } 63 | ], 64 | inherit_parent_permissions => '#{child_inherit_type}' 65 | } 66 | MANIFEST 67 | end 68 | 69 | let(:verify_acl_command) { "icacls #{target_child}" } 70 | let(:verify_content_path) { "c:\\temp\\#{target_name}\\#{target_child_name}" } 71 | 72 | context 'Explicit Inheritance of "allow" Parent Permissions for File' do 73 | let(:perm_type) { 'allow' } 74 | let(:asset_type) { 'file' } 75 | let(:child_inherit_type) { 'true' } 76 | let(:file_content) { 'Car repair is expensive' } 77 | let(:acl_regex) { %r{.*\\bob:\(I\)\(F\)} } 78 | 79 | include_examples 'execute manifest and verify file' 80 | end 81 | 82 | context 'Explicit Inheritance of "deny" Parent Permissions for File' do 83 | let(:perm_type) { 'deny' } 84 | let(:asset_type) { 'file' } 85 | let(:child_inherit_type) { 'true' } 86 | let(:file_content) { 'Exploding pants on sale for half off.' } 87 | let(:acl_regex) { %r{.*\\bob:\(I\)\(N\)} } 88 | 89 | include_examples 'execute manifest and verify file' 90 | end 91 | 92 | context 'Remove Inheritance of "allow" Parent Permissions for File' do 93 | let(:perm_type) { 'allow' } 94 | let(:asset_type) { 'file' } 95 | let(:child_inherit_type) { 'false' } 96 | let(:file_content) { 'Smell-o-vision: brought to you by the makers of Taste-o-vision!' } 97 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 98 | 99 | include_examples 'execute manifest and verify file' 100 | end 101 | 102 | context 'Remove Inheritance of "deny" Parent Permissions for File' do 103 | let(:perm_type) { 'deny' } 104 | let(:asset_type) { 'file' } 105 | let(:child_inherit_type) { 'false' } 106 | let(:file_content) { 'She smirked as he disdainfully choked down her tasteless humor.' } 107 | let(:acl_regex) { %r{.*\\bob:\(N\)} } 108 | 109 | include_examples 'execute manifest and verify file' 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /spec/acceptance/owner/negative/owner_257_char_name_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Owner - Negative' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{user_id}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { "#{target_parent}/#{target_name}": 26 | permissions => [ 27 | { identity => '#{user_id}', 28 | rights => ['modify'] 29 | }, 30 | ], 31 | owner => '#{owner_id}' 32 | } 33 | MANIFEST 34 | end 35 | 36 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 37 | 38 | context 'Specify 257 Character String for Owner' do 39 | let(:file_content) { 'I AM TALKING VERY LOUD!' } 40 | let(:target_name) { 'owner_257_char_name.txt' } 41 | let(:owner_id) { 'jasqddsweruwqiouroaysfyuasudyfaisoyfqoiuwyefiaysdiyfzixycivzixyvciqywifyiasdiufyasdygfasirfwerqiuwyeriatsdtfastdfqwyitfastdfawerfytasdytfasydgtaisdytfiasydfiosayghiayhidfhygiasftawyegyfhgaysgfuyasgdyugfasuiyfguaqyfgausydgfaywgfuasgdfuaisydgfausasdfuygsadfyg' } # rubocop:disable Layout/LineLength 42 | 43 | it 'applies manifest, raises error' do 44 | apply_manifest(acl_manifest, expect_failures: true) do |result| 45 | expect(result.stderr).to match(%r{Error:.*User does not exist}) 46 | end 47 | end 48 | 49 | it 'verifies file data integrity' do 50 | expect(file(verify_content_path)).to be_file 51 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/acceptance/owner/owner_local_group_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Owner - Local Group' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | group { "#{owner_id}": 19 | ensure => present 20 | } 21 | 22 | user { "#{user_id}": 23 | ensure => present, 24 | groups => 'Users', 25 | managehome => true, 26 | password => "L0v3Pupp3t!" 27 | } 28 | 29 | acl { "#{target_parent}/#{target_name}": 30 | permissions => [ 31 | { identity => '#{user_id}', 32 | rights => ['modify'] 33 | }, 34 | ], 35 | owner => '#{owner_id}' 36 | } 37 | MANIFEST 38 | end 39 | 40 | let(:dosify_target) { "c:\\temp\\#{target_name}" } 41 | let(:verify_acl_command) { "cmd /c \"dir /q #{dosify_target}\"" } 42 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 43 | 44 | context 'Change Owner to Local Group' do 45 | let(:file_content) { 'Spearhead was a great MOHAA game.' } 46 | let(:target_name) { 'owner_local_group.txt' } 47 | let(:owner_id) { 'jerks' } 48 | let(:acl_regex) { %r{.*\\jerks} } 49 | 50 | include_examples 'execute manifest and verify file' 51 | end 52 | 53 | context 'Change Owner to Local Group with Long Name' do 54 | let(:file_content) { 'Cow are animals with mooing capabilities.' } 55 | let(:target_name) { 'owner_local_long_group_name.txt' } 56 | let(:owner_id) { 'jasqddweruwqiouroaysfyuasudyfaisoyfqoiuwyefiaysdiyfzixycivzixyvciqywifyiasdiufyasdygfasirfwerqiuwyeriatsdtfastdfqwyitfastdfawerfytasdytfasydgtaisdytfiasydfiosayghiayhidfhygiasftawyegyfhgaysgfuyasgdyugfasuiyfguaqyfgausydgfaywgfuasgdfuaisydgfausasdfuygsadfyg' } # rubocop:disable Layout/LineLength 57 | let(:acl_regex) { %r{.*\\jasq} } 58 | 59 | include_examples 'execute manifest and verify file' 60 | end 61 | 62 | context 'Change Owner to Local Unicode Group' do 63 | prefix = SecureRandom.uuid.to_s 64 | let(:file_content) { 'I thought things on a Saturday night.' } 65 | let(:target_name) { "#{prefix}.txt" } 66 | let(:raw_owner_id) { '\u4388\u542B\u3D3C\u7F4D\uF961\u4381\u53F4\u79C0\u3AB2\u8EDE' } 67 | let(:owner_id) { "\u4388\u542B\u3D3C\u7F4D\uF961\u4381\u53F4\u79C0\u3AB2\u8EDE" } # 䎈含㴼罍率䎁叴秀㪲軞 68 | let(:verify_acl_command) { "(Get-ACL '#{target_parent}/#{target_name}' | Where-Object { $_.Owner -match ('.*\\\\' + [regex]::Unescape(\"#{raw_owner_id}\")) } | Measure-Object).Count" } 69 | let(:acl_regex) { %r{^1$} } 70 | 71 | include_examples 'execute manifest and verify (with PowerShell)' 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/acceptance/owner/owner_local_user_sid_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | sid = '' 6 | 7 | describe 'Owner - SID' do 8 | let(:setup_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | 14 | file { "#{target_parent}/#{target_name}": 15 | ensure => file, 16 | content => '#{file_content}', 17 | require => File['#{target_parent}'] 18 | } 19 | 20 | user { "#{owner_id}": 21 | ensure => present, 22 | groups => 'Users', 23 | managehome => true, 24 | password => "L0v3Pupp3t!" 25 | } 26 | 27 | user { "#{user_id}": 28 | ensure => present, 29 | groups => 'Users', 30 | managehome => true, 31 | password => "L0v3Pupp3t!" 32 | } 33 | MANIFEST 34 | end 35 | 36 | let(:acl_manifest) do 37 | <<-MANIFEST 38 | acl { "#{target_parent}/#{target_name}": 39 | permissions => [ 40 | { identity => '#{user_id}', 41 | rights => ['modify'] 42 | }, 43 | ], 44 | owner => '#{sid}' 45 | } 46 | MANIFEST 47 | end 48 | 49 | context 'Change Owner to Local User SID' do 50 | let(:os_check_command) { 'cmd /c ver' } 51 | let(:os_check_regex) { %r{Version 5} } 52 | let(:file_content) { 'Rocket ship to the moon!' } 53 | let(:target_name) { 'owner_local_user_sid.txt' } 54 | let(:owner_id) { 'geraldo' } 55 | 56 | let(:get_owner_sid_command) do 57 | <<-CMD 58 | cmd /c "wmic useraccount where name='#{owner_id}' get sid" 59 | CMD 60 | end 61 | 62 | let(:sid_regex) { %r{^(S-.+)$} } 63 | 64 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 65 | let(:file_content_regex) { %r{\A#{file_content}\z} } 66 | 67 | let(:dosify_target) { "c:\\temp\\#{target_name}" } 68 | let(:verify_owner_command) { "cmd /c \"dir /q #{dosify_target}\"" } 69 | let(:owner_regex) { %r{.*\\#{owner_id}} } 70 | 71 | it 'applies setup manifest' do 72 | acl_idempotent_apply(setup_manifest) 73 | end 74 | 75 | it 'retrieves SID of user account' do 76 | run_shell(get_owner_sid_command) do |result| 77 | sid = sid_regex.match(result.stdout)[1] 78 | end 79 | end 80 | 81 | it 'applies manifest' do 82 | acl_idempotent_apply(acl_manifest) 83 | end 84 | 85 | it 'verifies ACL rights' do 86 | run_shell(verify_owner_command) do |result| 87 | expect(result.stdout).to match(%r{#{owner_regex}}) 88 | end 89 | end 90 | 91 | it 'verifies file data integrity' do 92 | expect(file(verify_content_path)).to be_file 93 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/acceptance/owner/owner_local_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Owner - Local User' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{owner_id}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | user { "#{user_id}": 26 | ensure => present, 27 | groups => 'Users', 28 | managehome => true, 29 | password => "L0v3Pupp3t!" 30 | } 31 | 32 | acl { "#{target_parent}/#{target_name}": 33 | permissions => [ 34 | { identity => '#{user_id}', 35 | rights => ['modify'] 36 | }, 37 | ], 38 | owner => '#{owner_id}' 39 | } 40 | MANIFEST 41 | end 42 | 43 | let(:dosify_target) { "c:\\temp\\#{target_name}" } 44 | let(:verify_acl_command) { "cmd /c \"dir /q #{dosify_target}\"" } 45 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 46 | 47 | context 'Change Owner to Local User' do 48 | let(:file_content) { 'MoewMeowMoewBlahBalh!' } 49 | let(:target_name) { 'owner_local_user.txt' } 50 | let(:owner_id) { 'racecar' } 51 | let(:acl_regex) { %r{.*\\#{owner_id}} } 52 | 53 | include_examples 'execute manifest and verify file' 54 | end 55 | 56 | context 'Change Owner to Local User with Long Name' do 57 | let(:file_content) { 'Dogs are barking animals. Cats are meowing animals.' } 58 | let(:target_name) { 'owner_local_long_user_name.txt' } 59 | let(:owner_id) { 'long_user_name_gerry' } 60 | # The dir command chops the username at 16 characters. 61 | let(:acl_regex) { %r{.*\\long} } 62 | 63 | include_examples 'execute manifest and verify file' 64 | end 65 | 66 | context 'Change Owner to Local Unicode User' do 67 | prefix = SecureRandom.uuid.to_s 68 | let(:file_content) { 'Blurpy Bing Dangle.' } 69 | let(:target_name) { "#{prefix}.txt" } 70 | let(:raw_owner_id) { '\u03A3\u03A4\u03A5\u03A6' } 71 | let(:owner_id) { "\u03A3\u03A4\u03A5\u03A6" } # ΣΤΥΦ 72 | let(:verify_acl_command) { "(Get-ACL '#{target_parent}/#{target_name}' | Where-Object { $_.Owner -match ('.*\\\\' + [regex]::Unescape(\"#{raw_owner_id}\")) } | Measure-Object).Count" } 73 | let(:acl_regex) { %r{^1$} } 74 | 75 | include_examples 'execute manifest and verify (with PowerShell)' 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/explicit_target_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Windows ACL Module - Explicit Use of "target" Parameter' do 6 | let(:target) { 'c:/temp/explicit_target' } 7 | let(:verify_acl_command) { "icacls #{target}" } 8 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 9 | 10 | let(:acl_manifest) do 11 | <<-MANIFEST 12 | file { '#{target_parent}': 13 | ensure => directory 14 | } 15 | 16 | file { '#{target}': 17 | ensure => directory, 18 | require => File['#{target_parent}'] 19 | } 20 | 21 | user { '#{user_id}': 22 | ensure => present, 23 | groups => 'Users', 24 | managehome => true, 25 | password => "L0v3Pupp3t!" 26 | } 27 | 28 | acl { 'explicit_target': 29 | target => '#{target}', 30 | permissions => [ 31 | { identity => '#{user_id}', rights => ['full'] }, 32 | ], 33 | } 34 | MANIFEST 35 | end 36 | 37 | include_examples 'execute manifest' 38 | end 39 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/negative/negative_acl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Parameter Target - Negative' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | -> 12 | user { "#{user_id}": 13 | ensure => present, 14 | groups => 'Users', 15 | managehome => true, 16 | password => "L0v3Pupp3t!" 17 | } 18 | -> 19 | acl { "#{target}": 20 | permissions => [ 21 | { identity => '#{user_id}', rights => ['full'] }, 22 | ], 23 | } 24 | MANIFEST 25 | end 26 | 27 | context 'Specify Blank Target' do 28 | let(:target) { '' } 29 | 30 | it 'applies manifest, raises error' do 31 | apply_manifest(acl_manifest, expect_failures: true) do |result| 32 | expect(result.stderr).to match(%r{Error:.*(A non-empty name must be specified|Empty string title at)}) 33 | end 34 | end 35 | end 36 | 37 | context 'Specify Target with Invalid Path Characters' do 38 | let(:target) { 'c:/temp/invalid_<:>|?*' } 39 | 40 | it 'applies manifest, raises error' do 41 | apply_manifest(acl_manifest, expect_failures: true) do |result| 42 | expect(result.stderr).to match(%r{Error:.*The filename, directory name, or volume label syntax is incorrect}) 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/negative/negative_acl_to_symlink_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Negative - Specify Symlink as Target' do 6 | let(:os_check_command) { 'cmd /c ver' } 7 | let(:os_check_regex) { %r{Version 5} } 8 | 9 | let(:target) { 'c:/temp/sym_target_file.txt' } 10 | let(:target_symlink) { 'c:/temp/symlink' } 11 | 12 | let(:file_content) { 'A link to the past.' } 13 | let(:verify_content_path) { "#{target_parent}/sym_target_file.txt" } 14 | 15 | let(:win_target) { 'c:\\temp\\sym_target_file.txt' } 16 | let(:win_target_symlink) { 'c:\\temp\\symlink' } 17 | let(:mklink_command) { "c:\\windows\\system32\\cmd.exe /c mklink #{win_target_symlink} #{win_target}" } 18 | 19 | let(:verify_acl_command) { "icacls #{target_symlink}" } 20 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 21 | 22 | let(:acl_manifest) do 23 | <<-MANIFEST 24 | file { "#{target_parent}": 25 | ensure => directory 26 | } 27 | 28 | file { '#{target}': 29 | ensure => file, 30 | content => '#{file_content}', 31 | require => File['#{target_parent}'] 32 | } 33 | 34 | user { "#{user_id}": 35 | ensure => present, 36 | groups => 'Users', 37 | managehome => true, 38 | password => "L0v3Pupp3t!", 39 | require => File['#{target}'] 40 | } 41 | 42 | file { '#{target_symlink}': 43 | ensure => link, 44 | target => '#{target}', 45 | require => User['#{user_id}'], 46 | } 47 | 48 | acl { "#{target_symlink}": 49 | permissions => [ 50 | { identity => '#{user_id}', rights => ['full'] }, 51 | ], 52 | require => File['#{target_symlink}'] 53 | } 54 | MANIFEST 55 | end 56 | 57 | it 'applies manifest' do 58 | # not idempotent. complains that "Puppet cannot manage ACLs of symbolic links". This is a known constraint of the module, see: https://github.com/puppetlabs/puppetlabs-acl#Limitations 59 | apply_manifest(acl_manifest, catch_failures: true) 60 | end 61 | 62 | it 'verifies ACL rights' do 63 | run_shell(verify_acl_command) do |result| 64 | expect(result.stdout).not_to match(acl_regex) 65 | end 66 | end 67 | 68 | it 'verifies file data integrity' do 69 | expect(file(verify_content_path)).to be_file 70 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/perms_on_dir_8dot3_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Permissions - Directory - 8.3' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { "#{target8dot3}": 25 | permissions => [ 26 | { identity => '#{user_id}', rights => ['full'] }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:acl_manifest_remove) do 33 | <<-MANIFEST 34 | acl { '#{target8dot3}': 35 | purge => 'listed_permissions', 36 | permissions => [ 37 | { identity => '#{user_id}', rights => ['full'] }, 38 | ], 39 | } 40 | MANIFEST 41 | end 42 | 43 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 44 | 45 | context 'Add Permissions to a 8.3 Directory' do 46 | let(:target) { 'c:/temp/dir_short_name' } 47 | let(:target8dot3) { 'c:/temp/DIR_SH~1' } 48 | let(:verify_acl_command) { "icacls #{target8dot3}" } 49 | 50 | include_examples 'execute manifest' 51 | end 52 | 53 | context 'Remove Permissions from a 8.3 Directory' do 54 | let(:target) { 'c:/temp/rem_dir_short_name' } 55 | let(:target8dot3) { 'c:/temp/REM_DI~1' } 56 | let(:verify_acl_command) { "icacls #{target8dot3}" } 57 | 58 | include_examples 'execute manifest', true 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/perms_on_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Permissions - Directory' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { "#{target}": 25 | permissions => [ 26 | { identity => '#{user_id}', rights => ['full'] }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:acl_manifest_remove) do 33 | <<-MANIFEST 34 | acl { '#{target}': 35 | purge => 'listed_permissions', 36 | permissions => [ 37 | { identity => '#{user_id}', rights => ['full'] }, 38 | ], 39 | } 40 | MANIFEST 41 | end 42 | 43 | let(:verify_acl_command) { "icacls #{target}" } 44 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 45 | 46 | context 'Add Permissions to a Directory with a Long Name (247 chars)' do 47 | let(:target) { 'c:/temp/ybqYlVTjWTRAaQPPyeaseAsuUhnclarfedIpqIdqwyimqPphcKpojhTHogTUWiaEkiOqbeEZKvNAqDcEjJarQzeNxihARGLytPNseasKZxhRxeCwZsopSUFTKTAgsxsBqRigMlZhFQiELGLZghRwhKXVHuUPxWqmeYCHejdQOoGRYqaxwdIqiYyhhSChEWlggsGToSLmrgPmotSACKrREyohRBPaKRUmlgCGVtrPhasdEfU' } # rubocop:disable Layout/LineLength 48 | 49 | include_examples 'execute manifest' 50 | end 51 | 52 | context 'Implicit Use of "target" Parameter Through Title' do 53 | let(:target) { 'c:/temp/implicit_target' } 54 | 55 | include_examples 'execute manifest' 56 | end 57 | 58 | context 'Remove Permissions from a Directory' do 59 | let(:target) { 'c:/temp/rem_perm_dir' } 60 | 61 | include_examples 'execute manifest', true 62 | end 63 | 64 | context 'Remove Permissions from a Directory with a Long Name (247 chars)' do 65 | let(:target) { 'c:/temp/rem_lVTjWTRAaQPPyeaseAsuUhnclarfedIpqIdqwyimqPphcKpojhTHogTUWiaEkiOqbeEZKvNAqDcEjJarQzeNxihARGLytPNseasKZxhRxeCwZsopSUFTKTAgsxsBqRigMlZhFQiELGLZghRwhKXVHuUPxWqmeYCHejdQOoGRYqaxwdIqiYyhhSChEWlggsGToSLmrgPmotSACKrREyohRBPaKRUmlgCGVtrPhasdEfU' } # rubocop:disable Layout/LineLength 66 | 67 | include_examples 'execute manifest', true 68 | end 69 | 70 | context 'Add Permissions to a Unicode Directory' do 71 | prefix = SecureRandom.uuid.to_s 72 | let(:raw_dirname) { "#{prefix}_\\u3140\\u3145\\u3176\\u3145\\u3172\\u3142\\u3144\\u3149\\u3151\\u3167\\u3169\\u3159\\u3158" } 73 | let(:dirname) { "#{prefix}_\u3140\u3145\u3176\u3145\u3172\u3142\u3144\u3149\u3151\u3167\u3169\u3159\u3158" } 74 | let(:target) { "#{target_parent}/#{dirname}" } 75 | let(:verify_acl_command) { "(Get-ACL ('#{target_parent}/' + [regex]::Unescape(\"#{raw_dirname}\")) | ForEach-Object { $_.Access } | Where-Object { $_.IdentityReference -match '\\\\bob' -and $_.FileSystemRights -eq 'FullControl' -and $_.InheritanceFlags -eq 'ContainerInherit, ObjectInherit' } | Measure-Object).Count" } # rubocop:disable Layout/LineLength 76 | let(:acl_regex) { %r{^1$} } 77 | 78 | include_examples 'execute manifest and verify (with PowerShell)' 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/perms_on_file_8dot3_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Permissions - File - 8.3' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{file_name}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { '#{target8dot3}': 26 | permissions => [ 27 | { identity => '#{user_id}', rights => ['full'] }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:acl_manifest_remove) do 34 | <<-MANIFEST 35 | acl { '#{target8dot3}': 36 | purge => 'listed_permissions', 37 | permissions => [ 38 | { identity => '#{user_id}', rights => ['full'] }, 39 | ], 40 | } 41 | MANIFEST 42 | end 43 | 44 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 45 | let(:verify_acl_command) { "icacls #{target_parent}/#{file_name}" } 46 | let(:verify_content_path) { "#{target_parent}/#{file_name}" } 47 | 48 | context 'Add Permissions to 8.3 File' do 49 | let(:file_name) { 'file_short_name.txt' } 50 | let(:target8dot3) { 'c:/temp/FILE_S~2.TXT' } 51 | let(:file_content) { 'short file names are very short' } 52 | 53 | include_examples 'execute manifest' 54 | end 55 | 56 | context 'Remove Permissions from 8.3 File' do 57 | let(:file_name) { 'rem_file_short_name.txt' } 58 | let(:target8dot3) { 'c:/temp/REM_FI~2.TXT' } 59 | let(:file_content) { 'wax candle butler space station zebra glasses' } 60 | 61 | include_examples 'execute manifest', true 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_target/perms_on_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Permissions - File' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { '#{target_parent}': 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{file_name}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { '#{user_id}': 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { '#{target_parent}/#{file_name}': 26 | permissions => [ 27 | { identity => '#{user_id}', rights => ['full'] }, 28 | ], 29 | } 30 | MANIFEST 31 | end 32 | 33 | let(:acl_manifest_remove) do 34 | <<-MANIFEST 35 | acl { '#{target_parent}/#{file_name}': 36 | purge => 'listed_permissions', 37 | permissions => [ 38 | { identity => '#{user_id}', rights => ['full'] }, 39 | ], 40 | } 41 | MANIFEST 42 | end 43 | 44 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 45 | let(:verify_acl_command) { "icacls #{target_parent}/#{file_name}" } 46 | let(:verify_content_path) { "#{target_parent}/#{file_name}" } 47 | 48 | context 'Add Permissions to a File' do 49 | let(:file_name) { 'add_perm_file.txt' } 50 | let(:file_content) { 'meowmeowmeow' } 51 | 52 | include_examples 'execute manifest', false, true 53 | end 54 | 55 | context 'Remove Permissions from a File' do 56 | let(:file_name) { 'rem_perm_file.txt' } 57 | let(:file_content) { 'I love puppet, puppet love puppet, puppet love!' } 58 | 59 | include_examples 'execute manifest', true, true 60 | end 61 | 62 | context 'Add Permissions to a Unicode File' do 63 | prefix = SecureRandom.uuid.to_s 64 | let(:raw_filename) { "#{prefix}_\\u3140\\u3145\\u3176\\u3145\\u3172\\u3142\\u3144\\u3149\\u3151\\u3167\\u3169\\u3159\\u3158.txt" } 65 | let(:file_name) { "#{prefix}_\u3140\u3145\u3176\u3145\u3172\u3142\u3144\u3149\u3151\u3167\u3169\u3159\u3158.txt" } 66 | let(:file_content) { 'Puppets and Muppets! Cats on the Interwebs!' } 67 | let(:verify_acl_command) { "(Get-Acl ('#{target_parent}/' + [regex]::Unescape(\"#{raw_filename}\")) | ForEach-Object { $_.Access } | Where-Object { $_.IdentityReference -match '\\\\#{user_id}' -and $_.FileSystemRights -eq 'FullControl' } | Measure-Object).Count" } # rubocop:disable Layout/LineLength 68 | let(:acl_regex) { %r{^1$} } 69 | 70 | include_examples 'execute manifest and verify (with PowerShell)' 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/acceptance/propagation/prop_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Propagate - Negative' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { '#{target_parent}/#{target_name}': 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{user_id}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | acl { "#{target_parent}/#{target_name}": 26 | purge => 'true', 27 | permissions => [ 28 | { identity => '#{user_id}', 29 | rights => ['#{rights}'], 30 | affects => '#{prop_type}', 31 | child_types => '#{affects_child_type}' 32 | }, 33 | { identity => 'Administrators', 34 | rights => ['full'], 35 | affects => 'all', 36 | child_types => 'all' 37 | } 38 | ], 39 | inherit_parent_permissions => 'false' 40 | } 41 | MANIFEST 42 | end 43 | 44 | context 'Set Propagation on a File' do 45 | let(:rights) { 'full' } 46 | let(:prop_type) { 'all' } 47 | let(:affects_child_type) { 'all' } 48 | let(:file_content) { 'Flying beavers attack Lake Oswego!' } 49 | let(:target_name) { 'prop_file' } 50 | 51 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 52 | 53 | # 4c734680aca3b3781ae9fb211759a5610c6679a8 changed how permissions are emitted 54 | # during a `puppet agent` / `puppet apply` (but not `puppet resource`), so that 55 | # instead of emitting a [Puppet::Type::Acl::Ace] for rendering to the console 56 | # a [Hash] is emitted in the permissions_to_s method 57 | # Puppet 4 and 5 have different behavior for rendering this data structure 58 | let(:verify_manifest_pup4) { %r{\{ affects => 'self_only', identity => '.*\\bob', rights => \['full'\s+\] \}} } 59 | let(:verify_manifest_pup5) { %r{\{"identity"=>".*\\bob", "rights"=>\["full"\], "affects"=>:self_only\}} } 60 | 61 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_name}" } 62 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 63 | 64 | let(:agent_version_response) { run_shell('puppet --version').stdout.chomp } 65 | let(:agent_version) { Gem::Version.new(agent_version_response) } 66 | 67 | include_examples 'execute manifest and verify file' 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/acceptance/propagation/prop_self_all_child_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Propagate' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!", 22 | } 23 | 24 | acl { "#{target_parent}/#{target_name}": 25 | purge => 'true', 26 | permissions => [ 27 | { identity => '#{user_id}', 28 | rights => ['#{rights}'], 29 | affects => '#{prop_type}', 30 | child_types => '#{affects_child_type}' 31 | }, 32 | { identity => 'Administrators', 33 | rights => ['full'], 34 | affects => 'all', 35 | child_types => 'all' 36 | } 37 | ], 38 | inherit_parent_permissions => 'false' 39 | } 40 | -> 41 | file { "#{target_child}": 42 | ensure => directory 43 | } 44 | MANIFEST 45 | end 46 | 47 | let(:rights) { 'full' } 48 | let(:target_name) { "prop_#{prop_type}_to_#{affects_child_type}" } 49 | let(:target_child_name) { "prop_#{prop_type}_child" } 50 | let(:target_child) { "#{target_parent}/#{target_name}/#{target_child_name}" } 51 | 52 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_name}" } 53 | let(:verify_child_acl_command) { "icacls #{target_child}" } 54 | 55 | context 'Negative - Propagate "self_only" to "all" Child Types' do 56 | let(:prop_type) { 'self_only' } 57 | let(:affects_child_type) { 'all' } 58 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 59 | 60 | include_examples 'execute manifest and verify child' 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/acceptance/propagation/prop_self_no_child_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Propagate' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { "#{target_parent}/#{target_name}": 25 | purge => 'true', 26 | permissions => [ 27 | { identity => '#{user_id}', 28 | rights => ['#{rights}'], 29 | affects => '#{prop_type}' 30 | }, 31 | { identity => 'Administrators', 32 | rights => ['full'], 33 | affects => 'all', 34 | child_types => 'all' 35 | } 36 | ], 37 | inherit_parent_permissions => 'false' 38 | } 39 | -> 40 | file { "#{target_child}": 41 | ensure => directory 42 | } 43 | MANIFEST 44 | end 45 | 46 | let(:rights) { 'full' } 47 | let(:target_name) { "prop_#{prop_type}" } 48 | let(:target_child_name) { "prop_#{prop_type}_child" } 49 | let(:target_child) { "#{target_parent}/#{target_name}/#{target_child_name}" } 50 | 51 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_name}" } 52 | let(:verify_child_acl_command) { "icacls #{target_child}" } 53 | 54 | context 'Propagate "self_only" to No Child Types' do 55 | let(:prop_type) { 'self_only' } 56 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 57 | 58 | include_examples 'execute manifest and verify child' 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/acceptance/propagation/prop_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Propagation' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { "#{target_parent}/#{target_name}": 25 | purge => 'true', 26 | permissions => [ 27 | { identity => '#{user_id}', 28 | rights => ['#{rights}'], 29 | affects => '#{prop_type}', 30 | child_types => '#{affects_child_type}' 31 | }, 32 | { identity => 'Administrators', 33 | rights => ['full'], 34 | affects => 'all', 35 | child_types => 'all' 36 | } 37 | ], 38 | inherit_parent_permissions => 'false' 39 | } 40 | MANIFEST 41 | end 42 | 43 | let(:rights) { 'full' } 44 | let(:target_name) { "prop_#{prop_type}_to_#{affects_child_type}" } 45 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_name}" } 46 | 47 | context 'Propagate "all" to "all" Child Types' do 48 | let(:prop_type) { 'all' } 49 | let(:affects_child_type) { 'all' } 50 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 51 | 52 | include_examples 'execute manifest' 53 | end 54 | 55 | context 'Propagate "all" to "containers" Child Types' do 56 | let(:prop_type) { 'all' } 57 | let(:affects_child_type) { 'containers' } 58 | let(:acl_regex) { %r{.*\\bob:\(CI\)\(F\)} } 59 | 60 | include_examples 'execute manifest' 61 | end 62 | 63 | context 'Propagate "all" to "none" Child Types' do 64 | let(:prop_type) { 'all' } 65 | let(:affects_child_type) { 'none' } 66 | let(:acl_regex) { %r{.*\\bob:\(F\)} } 67 | 68 | include_examples 'execute manifest' 69 | end 70 | 71 | context 'Propagate "all" to "objects" Child Types' do 72 | let(:prop_type) { 'all' } 73 | let(:affects_child_type) { 'objects' } 74 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(F\)} } 75 | 76 | include_examples 'execute manifest' 77 | end 78 | 79 | context 'Propagate "children_only" to "all" Child Types' do 80 | let(:prop_type) { 'children_only' } 81 | let(:affects_child_type) { 'all' } 82 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(IO\)\(F\)} } 83 | 84 | include_examples 'execute manifest' 85 | end 86 | 87 | context 'Propagate "children_only" to "containers" Child Types' do 88 | let(:prop_type) { 'children_only' } 89 | let(:affects_child_type) { 'containers' } 90 | let(:acl_regex) { %r{.*\\bob:\(CI\)\(IO\)\(F\)} } 91 | 92 | include_examples 'execute manifest' 93 | end 94 | 95 | context 'Propagate "children_only" to "objects" Child Types' do 96 | let(:prop_type) { 'children_only' } 97 | let(:affects_child_type) { 'objects' } 98 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(IO\)\(F\)} } 99 | 100 | include_examples 'execute manifest' 101 | end 102 | 103 | context 'Propagate "direct_children_only" to "all" Child Types' do 104 | let(:prop_type) { 'direct_children_only' } 105 | let(:affects_child_type) { 'all' } 106 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(NP\)\(IO\)\(F\)} } 107 | 108 | include_examples 'execute manifest' 109 | end 110 | 111 | context 'Propagate "direct_children_only" to "containers" Child Types' do 112 | let(:prop_type) { 'direct_children_only' } 113 | let(:affects_child_type) { 'containers' } 114 | let(:acl_regex) { %r{.*\\bob:\(CI\)\(NP\)\(IO\)\(F\)} } 115 | 116 | include_examples 'execute manifest' 117 | end 118 | 119 | context 'Propagate "direct_children_only" to "objects" Child Types' do 120 | let(:prop_type) { 'direct_children_only' } 121 | let(:affects_child_type) { 'objects' } 122 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(NP\)\(IO\)\(F\)} } 123 | 124 | include_examples 'execute manifest' 125 | end 126 | 127 | context 'Propagate "self_and_direct_children_only" to "all" Child Types' do 128 | let(:prop_type) { 'self_and_direct_children_only' } 129 | let(:affects_child_type) { 'all' } 130 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(CI\)\(NP\)\(F\)} } 131 | 132 | include_examples 'execute manifest' 133 | end 134 | 135 | context 'Propagate "self_and_direct_children_only" to "containers" Child Types' do 136 | let(:prop_type) { 'self_and_direct_children_only' } 137 | let(:affects_child_type) { 'containers' } 138 | let(:acl_regex) { %r{.*\\bob:\(CI\)\(NP\)\(F\)} } 139 | 140 | include_examples 'execute manifest' 141 | end 142 | 143 | context 'Propagate "self_and_direct_children_only" to "objects" Child Types' do 144 | let(:prop_type) { 'self_and_direct_children_only' } 145 | let(:affects_child_type) { 'objects' } 146 | let(:acl_regex) { %r{.*\\bob:\(OI\)\(NP\)\(F\)} } 147 | 148 | include_examples 'execute manifest' 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /spec/acceptance/purge/negative/purge_all_perms_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Purge' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_file}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | acl { "#{target_parent}/#{target_file}": 25 | permissions => [ 26 | { identity => '#{user_id}', rights => ['full'] }, 27 | ], 28 | } 29 | MANIFEST 30 | end 31 | 32 | let(:acl_manifest_purge) do 33 | <<-MANIFEST 34 | acl { "#{target_parent}/#{target_file}": 35 | purge => 'true', 36 | permissions => [], 37 | inherit_parent_permissions => 'false' 38 | } 39 | MANIFEST 40 | end 41 | 42 | context 'Negative - Purge Absolutely All Permissions from Directory without Inheritance' do 43 | let(:target_file) { 'purge_all_no_inherit' } 44 | 45 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 46 | let(:acl_regex_user_id) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 47 | 48 | let(:verify_purge_error) { %r{Error:.*Value for permissions should be an array with at least one element specified} } 49 | 50 | it 'applies manifest' do 51 | acl_idempotent_apply(acl_manifest) 52 | end 53 | 54 | it 'verifies ACL rights' do 55 | run_shell(verify_acl_command) do |result| 56 | expect(result.stdout).to match(%r{#{acl_regex_user_id}}) 57 | end 58 | end 59 | 60 | it 'attempts purge, raises error' do 61 | apply_manifest(acl_manifest_purge, expect_failures: true) do |result| 62 | expect(result.stderr).to match(%r{#{verify_purge_error}}) 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/acceptance/purge/negative/purge_all_perms_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Purge' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | file { "#{target}": 12 | ensure => file, 13 | content => '#{file_content}', 14 | require => File['#{target_parent}'] 15 | } 16 | user { "#{user_id}": 17 | ensure => present, 18 | groups => 'Users', 19 | managehome => true, 20 | password => "L0v3Pupp3t!" 21 | } 22 | acl { "#{target}": 23 | permissions => [ 24 | { identity => '#{user_id}', rights => ['full'] }, 25 | ], 26 | } 27 | MANIFEST 28 | end 29 | 30 | let(:acl_manifest_purge) do 31 | <<-MANIFEST 32 | acl { "#{target}": 33 | purge => 'true', 34 | permissions => [], 35 | inherit_parent_permissions => 'false' 36 | } 37 | MANIFEST 38 | end 39 | 40 | context 'Negative - Purge Absolutely All Permissions from File without Inheritance' do 41 | let(:target) { "#{target_parent}/purge_all_no_inherit.txt" } 42 | let(:file_content) { 'Breakfast is the most important meal of the day.' } 43 | let(:verify_content_path) { target } 44 | let(:verify_acl_command) { "icacls #{target}" } 45 | let(:acl_regex_user_id) { %r{.*\\bob:\(F\)} } 46 | 47 | let(:verify_purge_error) { %r{Error:.*Value for permissions should be an array with at least one element specified} } 48 | 49 | it 'applies manifest' do 50 | acl_idempotent_apply(acl_manifest) 51 | end 52 | 53 | it 'verifies ACL rights' do 54 | run_shell(verify_acl_command) do |result| 55 | expect(result.stdout).to match(%r{#{acl_regex_user_id}}) 56 | end 57 | end 58 | 59 | it 'attempts purge, raises error' do 60 | apply_manifest(acl_manifest_purge, expect_failures: true) do |result| 61 | expect(result.stderr).to match(%r{#{verify_purge_error}}) 62 | end 63 | end 64 | 65 | it 'verifies file data integrity' do 66 | expect(file(verify_content_path)).to be_file 67 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/acceptance/purge/purge_all_other_perms_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | random_username = generate_random_username 6 | 7 | describe 'Purge' do 8 | let(:acl_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | 14 | file { "#{target}": 15 | ensure => directory, 16 | require => File['#{target_parent}'] 17 | } 18 | 19 | user { "#{user_id1}": 20 | ensure => present, 21 | groups => 'Users', 22 | managehome => true, 23 | password => "L0v3Pupp3t!" 24 | } 25 | 26 | user { "#{user_id2}": 27 | ensure => present, 28 | groups => 'Users', 29 | managehome => true, 30 | password => "L0v3Pupp3t!" 31 | } 32 | 33 | acl { "#{target}": 34 | permissions => [ 35 | { identity => '#{user_id1}', rights => ['full'] }, 36 | ], 37 | } 38 | MANIFEST 39 | end 40 | 41 | let(:acl_manifest_purge) do 42 | <<-MANIFEST 43 | acl { "#{target}": 44 | purge => 'true', 45 | permissions => [ 46 | { identity => '#{user_id2}', rights => ['full'] }, 47 | ], 48 | inherit_parent_permissions => 'false' 49 | } 50 | MANIFEST 51 | end 52 | 53 | context 'Purge All Other Permissions from Directory without Inheritance' do 54 | let(:target) { "#{target_parent}/purge_all_other_no_inherit" } 55 | let(:user_id1) { 'bob' } 56 | let(:user_id2) { random_username } 57 | 58 | let(:verify_acl_command) { "icacls #{target}" } 59 | let(:acl_regex_user_id1) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 60 | let(:acl_regex_user_id2) { %r{\Ac:/temp/purge_all_other_no_inherit.*\\#{user_id2}:\(OI\)\(CI\)\(F\)(\\r|\\n|\r|\n)*Successfully} } 61 | 62 | it 'applies manifest' do 63 | acl_idempotent_apply(acl_manifest) 64 | end 65 | 66 | it 'verifies ACL rights' do 67 | run_shell(verify_acl_command) do |result| 68 | expect(result.stdout).to match(%r{#{acl_regex_user_id1}}) 69 | end 70 | end 71 | 72 | it 'executes purge' do 73 | acl_idempotent_apply(acl_manifest_purge) 74 | end 75 | 76 | it 'verifies ACL rights (post-purge)' do 77 | run_shell(verify_acl_command, acceptable_exit_codes: [0, 5]) do |result| 78 | expect(result.stdout).not_to match(acl_regex_user_id1) 79 | expect(result.stdout).to match(acl_regex_user_id2) 80 | end 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/acceptance/purge/purge_all_other_perms_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | random_username = generate_random_username 6 | 7 | describe 'Purge' do 8 | let(:acl_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | 14 | file { "#{target}": 15 | ensure => file, 16 | content => '#{file_content}', 17 | require => File['#{target_parent}'] 18 | } 19 | 20 | user { "#{user_id1}": 21 | ensure => present, 22 | groups => 'Users', 23 | managehome => true, 24 | password => "L0v3Pupp3t!" 25 | } 26 | 27 | user { "#{user_id2}": 28 | ensure => present, 29 | groups => 'Users', 30 | managehome => true, 31 | password => "L0v3Pupp3t!" 32 | } 33 | 34 | acl { "#{target}": 35 | permissions => [ 36 | { identity => '#{user_id1}', rights => ['full'] }, 37 | ], 38 | } 39 | MANIFEST 40 | end 41 | 42 | let(:acl_manifest_purge) do 43 | <<-MANIFEST 44 | acl { "#{target}": 45 | purge => 'true', 46 | permissions => [ 47 | { identity => '#{user_id2}', rights => ['full'] }, 48 | ], 49 | inherit_parent_permissions => 'false' 50 | } 51 | MANIFEST 52 | end 53 | 54 | context 'Purge All Other Permissions from File without Inheritance' do 55 | let(:target) { "#{target_parent}/purge_all_other_no_inherit.txt" } 56 | let(:user_id1) { 'bob' } 57 | let(:user_id2) { random_username } 58 | 59 | let(:file_content) { 'All your base are belong to us.' } 60 | 61 | let(:verify_acl_command) { "icacls #{target}" } 62 | let(:acl_regex_user_id1) { %r{.*\\bob:\(F\)} } 63 | 64 | it 'applies manifest' do 65 | acl_idempotent_apply(acl_manifest) 66 | end 67 | 68 | it 'verifies ACL rights' do 69 | run_shell(verify_acl_command) do |result| 70 | expect(result.stdout).to match(%r{#{acl_regex_user_id1}}) 71 | end 72 | end 73 | 74 | it 'executes purge' do 75 | apply_manifest(acl_manifest_purge, catch_failures: true) 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /spec/acceptance/purge/purge_explicit_perms_dir_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Purge' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | user { "#{user_id1}": 18 | ensure => present, 19 | groups => 'Users', 20 | managehome => true, 21 | password => "L0v3Pupp3t!" 22 | } 23 | 24 | user { "#{user_id2}": 25 | ensure => present, 26 | groups => 'Users', 27 | managehome => true, 28 | password => "L0v3Pupp3t!" 29 | } 30 | 31 | acl { "#{target}": 32 | permissions => [ 33 | { identity => '#{user_id1}', rights => ['full'] }, 34 | ], 35 | } 36 | MANIFEST 37 | end 38 | 39 | let(:acl_manifest_purge) do 40 | <<-MANIFEST 41 | acl { "#{target}": 42 | purge => 'true', 43 | permissions => [ 44 | { identity => '#{user_id2}', rights => ['full'] }, 45 | ], 46 | } 47 | MANIFEST 48 | end 49 | 50 | context 'Only Purge Explicit Permissions from Directory with Inheritance' do 51 | random_username = generate_random_username 52 | let(:target) { 'c:/temp/purge_exp_inherit' } 53 | let(:user_id1) { 'bob' } 54 | let(:user_id2) { random_username } 55 | 56 | let(:verify_acl_command) { "icacls #{target}" } 57 | let(:acl_regex_user_id1) { %r{.*\\bob:\(OI\)\(CI\)\(F\)} } 58 | let(:acl_regex_user_id2) { %r{.*\\#{user_id2}:\(OI\)\(CI\)\(F\)} } 59 | 60 | it 'applies manifest' do 61 | acl_idempotent_apply(acl_manifest) 62 | end 63 | 64 | it 'verifies ACL rights' do 65 | run_shell(verify_acl_command) do |result| 66 | expect(result.stdout).to match(%r{#{acl_regex_user_id1}}) 67 | end 68 | end 69 | 70 | it 'executes purge' do 71 | acl_idempotent_apply(acl_manifest_purge) 72 | end 73 | 74 | it 'verifies ACL rights (post-purge)' do 75 | run_shell(verify_acl_command) do |result| 76 | expect(result.stdout).not_to match(%r{#{acl_regex_user_id1}}) 77 | expect(result.stdout).to match(%r{#{acl_regex_user_id2}}) 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /spec/acceptance/purge/purge_explicit_perms_file_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Purge' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{user_id1}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | user { "#{user_id2}": 26 | ensure => present, 27 | groups => 'Users', 28 | managehome => true, 29 | password => "L0v3Pupp3t!" 30 | } 31 | 32 | acl { "#{target}": 33 | permissions => [ 34 | { identity => '#{user_id1}', rights => ['full'] }, 35 | ], 36 | } 37 | MANIFEST 38 | end 39 | 40 | let(:acl_manifest_purge) do 41 | <<-MANIFEST 42 | acl { "#{target}": 43 | purge => 'true', 44 | permissions => [ 45 | { identity => '#{user_id2}', rights => ['full'] }, 46 | ] 47 | } 48 | MANIFEST 49 | end 50 | 51 | context 'Negative- Only Purge Explicit Permissions from File with Inheritance' do 52 | random_username = generate_random_username 53 | 54 | let(:target) { "#{target_parent}/purge_exp_inherit.txt" } 55 | let(:user_id1) { 'bob' } 56 | let(:user_id2) { random_username } 57 | 58 | let(:file_content) { 'Surge Purge Merge' } 59 | let(:verify_content_path) { target } 60 | 61 | let(:verify_acl_command) { "icacls #{target}" } 62 | let(:acl_regex_user_id1) { %r{.*\\bob:\(F\)} } 63 | let(:acl_regex_user_id2) { %r{.*\\#{user_id2}:\(F\)} } 64 | 65 | it 'applies manifest' do 66 | acl_idempotent_apply(acl_manifest) 67 | end 68 | 69 | it 'verifies ACL rights' do 70 | run_shell(verify_acl_command) do |result| 71 | expect(result.stdout).to match(%r{#{acl_regex_user_id1}}) 72 | end 73 | end 74 | 75 | it 'executes purge' do 76 | acl_idempotent_apply(acl_manifest_purge) 77 | end 78 | 79 | it 'verifies ACL rights (post-purge)' do 80 | run_shell(verify_acl_command) do |result| 81 | expect(result.stdout).not_to match(%r{#{acl_regex_user_id1}}) 82 | expect(result.stdout).to match(%r{#{acl_regex_user_id2}}) 83 | end 84 | end 85 | 86 | it 'verifies file data integrity' do 87 | expect(file(verify_content_path)).to be_file 88 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/complex_prop_inherit_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | # TODO: FIX TESTS 6 | 7 | describe 'Use Cases' do 8 | let(:acl_manifest) do 9 | <<-MANIFEST 10 | file { "#{target_parent}": 11 | ensure => directory 12 | } 13 | group { "#{group1}": 14 | ensure => present 15 | } 16 | group { "#{group2}": 17 | ensure => present 18 | } 19 | user { "#{user_id1}": 20 | ensure => present, 21 | groups => ['Users', '#{group1}'], 22 | managehome => true, 23 | password => "L0v3Pupp3t!", 24 | require => Group['#{group1}'] 25 | } 26 | user { "#{user_id2}": 27 | ensure => present, 28 | groups => ['Users', '#{group2}'], 29 | managehome => true, 30 | password => "L0v3Pupp3t!", 31 | require => Group['#{group2}'] 32 | } 33 | file { "#{target}": 34 | ensure => directory, 35 | require => File['#{target_parent}'] 36 | } 37 | -> 38 | acl { "#{target}": 39 | purge => 'true', 40 | permissions => [ 41 | { 42 | identity => 'Administrators', 43 | perm_type => 'allow', 44 | rights => ['full'] 45 | }, 46 | { identity => '#{user_id1}', 47 | perm_type => 'allow', 48 | rights => ['read'], 49 | affects => 'children_only', 50 | child_types => 'all' 51 | }, 52 | { identity => '#{user_id2}', 53 | perm_type => 'deny', 54 | rights => ['read','execute'], 55 | affects => 'children_only', 56 | child_types => 'objects' 57 | }, 58 | { identity => '#{group1}', 59 | perm_type => 'allow', 60 | rights => ['read'], 61 | affects => 'children_only', 62 | child_types => 'containers' 63 | }, 64 | { identity => '#{group2}', 65 | perm_type => 'allow', 66 | rights => ['read'], 67 | affects => 'children_only', 68 | child_types => 'all' 69 | } 70 | ], 71 | inherit_parent_permissions => 'false' 72 | } 73 | -> 74 | file { "#{target_child}": 75 | ensure => directory 76 | } 77 | -> 78 | acl { "#{target_child}": 79 | purge => 'true', 80 | permissions => [ 81 | { identity => '#{user_id1}', 82 | perm_type => 'deny', 83 | rights => ['modify'], 84 | affects => 'children_only', 85 | child_types => 'objects' 86 | }, 87 | { identity => '#{user_id2}', 88 | perm_type => 'allow', 89 | rights => ['full'], 90 | affects => 'children_only', 91 | child_types => 'containers' 92 | } 93 | ], 94 | } 95 | -> 96 | file { "#{target_grand_child}": 97 | ensure => file, 98 | content => '#{file_content}' 99 | } 100 | -> 101 | acl { "#{target_grand_child}": 102 | permissions => [ 103 | { identity => '#{group2}', 104 | perm_type => 'deny', 105 | rights => ['full'], 106 | affects => 'self_only' 107 | } 108 | ], 109 | } 110 | MANIFEST 111 | end 112 | 113 | context 'Complex Propagation and Inheritance with Nested Paths' do 114 | random_username = generate_random_username 115 | let(:test_short_name) { 'complex_prop_inherit' } 116 | let(:file_content) { 'Sight seeing blind people.' } 117 | 118 | let(:target_name) { "use_case_#{test_short_name}" } 119 | let(:target_child_name) { "use_case_child_#{test_short_name}" } 120 | let(:target_grand_child_name) { "use_case_grand_child_#{test_short_name}.txt" } 121 | 122 | let(:target) { "#{target_parent}/#{target_name}" } 123 | let(:target_child) { "#{target}/#{target_child_name}" } 124 | let(:target_grand_child) { "#{target_child}/#{target_grand_child_name}" } 125 | 126 | let(:verify_content_path) { "#{target_parent}/#{target_name}/#{target_child_name}/#{target_grand_child_name}" } 127 | 128 | let(:group1) { 'jerks' } 129 | let(:group2) { 'cool_peeps' } 130 | 131 | let(:user_id1) { 'bob' } 132 | let(:user_id2) { random_username } 133 | 134 | let(:verify_acl_grand_child_command) { "icacls #{target_grand_child}" } 135 | 136 | let(:target_grand_child_first_ace_regex) { %r{.*\\cool_peeps:\(N\)} } 137 | let(:target_grand_child_second_ace_regex) { %r{.*\\bob:\(I\)\(DENY\)\(M\)} } 138 | let(:target_grand_child_third_ace_regex) { %r{.*\\Administrators:\(I\)\(F\)} } 139 | let(:target_grand_child_fourth_ace_regex) { %r{.*\\bob:\(I\)\(R\)} } 140 | let(:target_grand_child_fifth_ace_regex) { %r{.*\\#{user_id2}:\(I\)\(DENY\)\(RX\)} } 141 | let(:target_grand_child_sixth_ace_regex) { %r{.*\\cool_peeps:\(I\)\(R\)} } 142 | 143 | it 'applies manifest' do 144 | acl_idempotent_apply(acl_manifest) 145 | end 146 | 147 | it 'verifies ACL grand child rights' do 148 | run_shell(verify_acl_grand_child_command) do |result| 149 | # We only need to check the grand child because we are only concerned with rights 150 | # propagating and inheriting. 151 | expect(result.stdout).to match(%r{#{target_grand_child_first_ace_regex}}) 152 | expect(result.stdout).to match(%r{#{target_grand_child_second_ace_regex}}) 153 | expect(result.stdout).to match(%r{#{target_grand_child_third_ace_regex}}) 154 | expect(result.stdout).to match(%r{#{target_grand_child_fourth_ace_regex}}) 155 | expect(result.stdout).to match(%r{#{target_grand_child_fifth_ace_regex}}) 156 | expect(result.stdout).to match(%r{#{target_grand_child_sixth_ace_regex}}) 157 | end 158 | end 159 | 160 | it 'verfies file data integrity' do 161 | expect(file(verify_content_path)).to be_file 162 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 163 | end 164 | end 165 | end 166 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/grant_full_deny_full_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | file { "#{target_child}": 18 | ensure => file, 19 | content => '#{file_content}', 20 | require => File['#{target}'] 21 | } 22 | 23 | acl { "#{target}": 24 | permissions => [ 25 | { identity => '#{group}', perm_type => 'allow', rights => ['full'] }, 26 | ], 27 | } 28 | -> 29 | acl { "#{target_child}": 30 | permissions => [ 31 | { identity => '#{user_id}', perm_type => 'deny', rights => ['full'] }, 32 | ], 33 | } 34 | MANIFEST 35 | end 36 | 37 | let(:update_manifest) do 38 | <<-MANIFEST 39 | file { "#{target_child}": 40 | ensure => file, 41 | content => 'Better Content' 42 | } 43 | MANIFEST 44 | end 45 | 46 | let(:acl_clear_manifest) do 47 | <<-MANIFEST 48 | acl { "#{target_child}": 49 | purge => true, 50 | permissions => [ 51 | { identity => '#{user_id}', perm_type => 'allow', rights => ['full'] }, 52 | ], 53 | } 54 | MANIFEST 55 | end 56 | 57 | context "Inherit 'full' Rights for User's Group on Container and Deny User 'full' Rights on Object in Container" do 58 | let(:test_short_name) { 'grant_full_deny_full' } 59 | let(:file_content) { 'Sad people' } 60 | let(:target_name) { "use_case_#{test_short_name}" } 61 | let(:target_child_name) { "use_case_child_#{test_short_name}.txt" } 62 | let(:target) { "#{target_parent}/#{target_name}" } 63 | let(:target_child) { "#{target}/#{target_child_name}" } 64 | let(:verify_content_command) { "cat /cygdrive/c/temp/#{target_name}/#{target_child_name}" } 65 | let(:group) { 'Administrators' } 66 | let(:user_id) do 67 | # on AppVeyor the runtime user is not Administrator, requiring the username to be fetched 68 | run_shell(powershell('echo $env:UserName')).stdout.strip 69 | end 70 | let(:verify_acl_child_command) { "icacls #{target_child}" } 71 | let(:target_child_first_ace_regex) { %r{.*\\Administrators:\(I\)\(F\)} } 72 | let(:target_child_second_ace_regex) { %r{.*\\#{user_id}:\(N\)} } 73 | 74 | it 'applies manifest' do 75 | # not idempotent 76 | apply_manifest(acl_manifest, catch_failures: true) 77 | end 78 | 79 | it 'verifies ACL child rights' do 80 | run_shell(verify_acl_child_command) do |result| 81 | expect(result.stdout).to match(%r{#{target_child_first_ace_regex}}) 82 | expect(result.stdout).to match(%r{#{target_child_second_ace_regex}}) 83 | end 84 | end 85 | 86 | it 'attempts to update file, raises error' do 87 | apply_manifest(update_manifest, expect_failures: true) do |result| 88 | expect(result.stderr).to match(%r{Error:}) 89 | end 90 | end 91 | 92 | it 'verifies file data integrity' do 93 | # acl needs to be cleared so Administrator has access to read contents 94 | apply_manifest(acl_clear_manifest, catch_failures: true) 95 | expect(file(target_child)).to be_file 96 | expect(file(target_child).content).to match(%r{#{file_content}}) 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/multiple_aces_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | user { "#{user_id1}": 19 | ensure => present, 20 | groups => 'Users', 21 | managehome => true, 22 | password => "L0v3Pupp3t!" 23 | } 24 | 25 | user { "#{user_id2}": 26 | ensure => present, 27 | groups => 'Users', 28 | managehome => true, 29 | password => "L0v3Pupp3t!" 30 | } 31 | 32 | user { "#{user_id3}": 33 | ensure => present, 34 | groups => 'Users', 35 | managehome => true, 36 | password => "L0v3Pupp3t!" 37 | } 38 | 39 | user { "#{user_id4}": 40 | ensure => present, 41 | groups => 'Users', 42 | managehome => true, 43 | password => "L0v3Pupp3t!" 44 | } 45 | 46 | user { "#{user_id5}": 47 | ensure => present, 48 | groups => 'Users', 49 | managehome => true, 50 | password => "L0v3Pupp3t!" 51 | } 52 | 53 | user { "#{user_id6}": 54 | ensure => present, 55 | groups => 'Users', 56 | managehome => true, 57 | password => "L0v3Pupp3t!" 58 | } 59 | 60 | acl { "#{target}": 61 | permissions => [ 62 | { identity => '#{user_id1}', perm_type => 'allow', rights => ['full'] }, 63 | { identity => '#{user_id2}', perm_type => 'deny', rights => ['modify'] }, 64 | { identity => '#{user_id3}', perm_type => 'allow', rights => ['read'] }, 65 | { identity => '#{user_id4}', perm_type => 'deny', rights => ['read','execute'] }, 66 | { identity => '#{user_id5}', perm_type => 'allow', rights => ['write','execute'] }, 67 | { identity => '#{user_id6}', perm_type => 'deny', rights => ['write','read'] } 68 | ], 69 | } 70 | MANIFEST 71 | end 72 | 73 | context 'Multiple ACEs for Target Path' do 74 | random_username = generate_random_username 75 | 76 | let(:test_short_name) { 'multi_aces' } 77 | let(:file_content) { 'Ninjas all up in my face!' } 78 | let(:target_name) { "use_case_#{test_short_name}.txt" } 79 | let(:target) { "#{target_parent}/#{target_name}" } 80 | 81 | let(:user_id1) { 'bob' } 82 | let(:user_id2) { random_username } 83 | let(:user_id3) { 'billy' } 84 | let(:user_id4) { 'sarah' } 85 | let(:user_id5) { 'sally' } 86 | let(:user_id6) { 'betty' } 87 | 88 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 89 | 90 | let(:verify_acl_command) { "icacls #{target}" } 91 | let(:user_id1_ace_regex) { %r{.*\\bob:\(F\)} } 92 | let(:user_id2_ace_regex) { %r{.*\\#{user_id2}:\(DENY\)\(M\)} } 93 | let(:user_id3_ace_regex) { %r{.*\\billy:\(R\)} } 94 | let(:user_id4_ace_regex) { %r{.*\\sarah:\(DENY\)\(RX\)} } 95 | let(:user_id5_ace_regex) { %r{.*\\sally:\(W,Rc,X,RA\)} } 96 | let(:user_id6_ace_regex) { %r{.*\\betty:\(DENY\)\(R,W\)} } 97 | 98 | it 'applies manifest' do 99 | acl_idempotent_apply(acl_manifest) 100 | end 101 | 102 | it 'verifies ACL rights' do 103 | run_shell(verify_acl_command) do |result| 104 | expect(result.stdout).to match(%r{#{user_id1_ace_regex}}) 105 | expect(result.stdout).to match(%r{#{user_id2_ace_regex}}) 106 | expect(result.stdout).to match(%r{#{user_id3_ace_regex}}) 107 | expect(result.stdout).to match(%r{#{user_id4_ace_regex}}) 108 | expect(result.stdout).to match(%r{#{user_id5_ace_regex}}) 109 | expect(result.stdout).to match(%r{#{user_id6_ace_regex}}) 110 | end 111 | end 112 | 113 | it 'verifies file data integrity' do 114 | expect(file(verify_content_path)).to be_file 115 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 116 | end 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/multiple_acls_shared_ident_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | file { "#{target_child}": 18 | ensure => directory, 19 | require => File['#{target}'] 20 | } 21 | 22 | file { "#{target_grand_child}": 23 | ensure => directory, 24 | require => File['#{target_child}'] 25 | } 26 | 27 | group { "#{group1}": 28 | ensure => present 29 | } 30 | 31 | group { "#{group2}": 32 | ensure => present 33 | } 34 | 35 | user { "#{user_id1}": 36 | ensure => present, 37 | groups => ['Users', '#{group1}'], 38 | managehome => true, 39 | password => "L0v3Pupp3t!", 40 | require => Group['#{group1}'] 41 | } 42 | 43 | user { "#{user_id2}": 44 | ensure => present, 45 | groups => ['Users', '#{group2}'], 46 | managehome => true, 47 | password => "L0v3Pupp3t!", 48 | require => Group['#{group2}'] 49 | } 50 | 51 | acl { "#{target}": 52 | permissions => [ 53 | { identity => '#{user_id1}', perm_type => 'allow', rights => ['read'] }, 54 | { identity => '#{user_id2}', perm_type => 'deny', rights => ['read','execute'] }, 55 | { identity => '#{group1}', perm_type => 'allow', rights => ['read'] }, 56 | { identity => '#{group2}', perm_type => 'allow', rights => ['read'] } 57 | ], 58 | } 59 | -> 60 | acl { "#{target_child}": 61 | permissions => [ 62 | { identity => '#{user_id1}', perm_type => 'allow', rights => ['write'] }, 63 | { identity => '#{user_id2}', perm_type => 'deny', rights => ['write'] }, 64 | { identity => '#{group1}', perm_type => 'allow', rights => ['execute'] }, 65 | { identity => '#{group2}', perm_type => 'allow', rights => ['execute'] } 66 | ], 67 | } 68 | -> 69 | acl { "#{target_grand_child}": 70 | permissions => [ 71 | { identity => '#{user_id1}', perm_type => 'deny', rights => ['full'] }, 72 | { identity => '#{user_id2}', perm_type => 'deny', rights => ['full'] }, 73 | { identity => '#{group1}', perm_type => 'allow', rights => ['full'] }, 74 | { identity => '#{group2}', perm_type => 'allow', rights => ['full'] }, 75 | ], 76 | } 77 | MANIFEST 78 | end 79 | 80 | context 'Multiple ACL for Nested Paths with Varying Rights for Same Identity' do 81 | random_username = generate_random_username 82 | let(:test_short_name) { 'multi_acl_shared_ident' } 83 | let(:target_name) { "use_case_#{test_short_name}" } 84 | let(:target_child_name) { "use_case_child_#{test_short_name}" } 85 | let(:target_grand_child_name) { "use_case_grand_child_#{test_short_name}" } 86 | let(:target) { "#{target_parent}/#{target_name}" } 87 | let(:target_child) { "#{target}/#{target_child_name}" } 88 | let(:target_grand_child) { "#{target_child}/#{target_grand_child_name}" } 89 | 90 | let(:group1) { 'jerks' } 91 | let(:group2) { 'cool_peeps' } 92 | 93 | let(:user_id1) { 'bob' } 94 | let(:user_id2) { random_username } 95 | 96 | let(:verify_acl_command) { "icacls #{target}" } 97 | let(:verify_acl_child_command) { "icacls #{target_child}" } 98 | let(:verify_acl_grand_child_command) { "icacls #{target_grand_child}" } 99 | 100 | let(:target_group1_ace_regex) { %r{.*\\jerks:(\(I\))?\(OI\)\(CI\)\(R\)} } 101 | let(:target_group2_ace_regex) { %r{.*\\cool_peeps:(\(I\))?\(OI\)\(CI\)\(R\)} } 102 | let(:target_user_id1_ace_regex) { %r{.*\\bob:(\(I\))?\(OI\)\(CI\)\(R\)} } 103 | let(:target_user_id2_ace_regex) { %r{.*\\#{user_id2}:(\(I\))?\(OI\)\(CI\)\(DENY\)\(RX\)} } 104 | 105 | let(:target_child_group1_ace_regex) { %r{.*\\jerks:(\(I\))?\(OI\)\(CI\)\(Rc,S,X,RA\)} } 106 | let(:target_child_group2_ace_regex) { %r{.*\\cool_peeps:(\(I\))?\(OI\)\(CI\)\(Rc,S,X,RA\)} } 107 | let(:target_child_user_id1_ace_regex) { %r{.*\\bob:(\(I\))?\(OI\)\(CI\)\(W,Rc\)} } 108 | let(:target_child_user_id2_ace_regex) { %r{.*\\#{user_id2}:(\(I\))?\(OI\)\(CI\)\(DENY\)\(W,Rc\)} } 109 | 110 | let(:target_grand_child_group1_ace_regex) { %r{.*\\jerks:\(OI\)\(CI\)\(F\)} } 111 | let(:target_grand_child_group2_ace_regex) { %r{.*\\cool_peeps:\(OI\)\(CI\)\(F\)} } 112 | let(:target_grand_child_user_id1_ace_regex) { %r{.*\\bob:\(OI\)\(CI\)\(N\)} } 113 | let(:target_grand_child_user_id2_ace_regex) { %r{.*\\#{user_id2}:\(OI\)\(CI\)\(N\)} } 114 | 115 | it 'applies manifest' do 116 | acl_idempotent_apply(acl_manifest) 117 | end 118 | 119 | it 'verifies ACL rights' do 120 | run_shell(verify_acl_command) do |result| 121 | expect(result.stdout).to match(%r{#{target_group1_ace_regex}}) 122 | expect(result.stdout).to match(%r{#{target_group2_ace_regex}}) 123 | expect(result.stdout).to match(%r{#{target_user_id1_ace_regex}}) 124 | expect(result.stdout).to match(%r{#{target_user_id2_ace_regex}}) 125 | end 126 | end 127 | 128 | it 'verifies child ACL rights' do 129 | run_shell(verify_acl_child_command) do |result| 130 | # ACL from parent(s) will still apply. 131 | expect(result.stdout).to match(%r{#{target_group1_ace_regex}}) 132 | expect(result.stdout).to match(%r{#{target_group2_ace_regex}}) 133 | expect(result.stdout).to match(%r{#{target_user_id1_ace_regex}}) 134 | expect(result.stdout).to match(%r{#{target_user_id2_ace_regex}}) 135 | 136 | expect(result.stdout).to match(%r{#{target_child_group1_ace_regex}}) 137 | expect(result.stdout).to match(%r{#{target_child_group2_ace_regex}}) 138 | expect(result.stdout).to match(%r{#{target_child_user_id1_ace_regex}}) 139 | expect(result.stdout).to match(%r{#{target_child_user_id2_ace_regex}}) 140 | end 141 | end 142 | 143 | it 'verifies grand child ACL rights' do 144 | run_shell(verify_acl_grand_child_command) do |result| 145 | # ACL from parent(s) will still apply. 146 | expect(result.stdout).to match(%r{#{target_group1_ace_regex}}) 147 | expect(result.stdout).to match(%r{#{target_group2_ace_regex}}) 148 | expect(result.stdout).to match(%r{#{target_user_id1_ace_regex}}) 149 | expect(result.stdout).to match(%r{#{target_user_id2_ace_regex}}) 150 | 151 | # ACL from parent(s) will still apply. 152 | expect(result.stdout).to match(%r{#{target_child_group1_ace_regex}}) 153 | expect(result.stdout).to match(%r{#{target_child_group2_ace_regex}}) 154 | expect(result.stdout).to match(%r{#{target_child_user_id1_ace_regex}}) 155 | expect(result.stdout).to match(%r{#{target_child_user_id2_ace_regex}}) 156 | 157 | expect(result.stdout).to match(%r{#{target_grand_child_group1_ace_regex}}) 158 | expect(result.stdout).to match(%r{#{target_grand_child_group2_ace_regex}}) 159 | expect(result.stdout).to match(%r{#{target_grand_child_user_id1_ace_regex}}) 160 | expect(result.stdout).to match(%r{#{target_grand_child_user_id2_ace_regex}}) 161 | end 162 | end 163 | end 164 | end 165 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/multiple_acls_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target}": 13 | ensure => directory, 14 | require => File['#{target_parent}'] 15 | } 16 | 17 | file { "#{target_child}": 18 | ensure => directory, 19 | require => File['#{target}'] 20 | } 21 | 22 | user { "#{user_id1}": 23 | ensure => present, 24 | groups => 'Users', 25 | managehome => true, 26 | password => "L0v3Pupp3t!" 27 | } 28 | 29 | user { "#{user_id2}": 30 | ensure => present, 31 | groups => 'Users', 32 | managehome => true, 33 | password => "L0v3Pupp3t!" 34 | } 35 | 36 | user { "#{user_id3}": 37 | ensure => present, 38 | groups => 'Users', 39 | managehome => true, 40 | password => "L0v3Pupp3t!" 41 | } 42 | 43 | user { "#{user_id4}": 44 | ensure => present, 45 | groups => 'Users', 46 | managehome => true, 47 | password => "L0v3Pupp3t!" 48 | } 49 | 50 | user { "#{user_id5}": 51 | ensure => present, 52 | groups => 'Users', 53 | managehome => true, 54 | password => "L0v3Pupp3t!" 55 | } 56 | 57 | user { "#{user_id6}": 58 | ensure => present, 59 | groups => 'Users', 60 | managehome => true, 61 | password => "L0v3Pupp3t!" 62 | } 63 | 64 | acl { "#{target}": 65 | permissions => [ 66 | { identity => '#{user_id1}', perm_type => 'allow', rights => ['modify'] }, 67 | { identity => '#{user_id2}', perm_type => 'deny', rights => ['full'] }, 68 | { identity => '#{user_id3}', perm_type => 'allow', rights => ['write'] } 69 | ], 70 | } 71 | -> 72 | acl { "#{target_child}": 73 | permissions => [ 74 | { identity => '#{user_id4}', perm_type => 'deny', rights => ['full'] }, 75 | { identity => '#{user_id5}', perm_type => 'allow', rights => ['modify'] }, 76 | { identity => '#{user_id6}', perm_type => 'deny', rights => ['read'] } 77 | ], 78 | } 79 | MANIFEST 80 | end 81 | 82 | context 'ACL for Parent Path with Separate ACL for Child Path' do 83 | random_username = generate_random_username 84 | let(:test_short_name) { 'multi_acl' } 85 | let(:target_name) { "use_case_#{test_short_name}" } 86 | let(:target_child_name) { "use_case_child_#{test_short_name}" } 87 | 88 | let(:target) { "#{target_parent}/#{target_name}" } 89 | let(:target_child) { "#{target}/#{target_child_name}" } 90 | 91 | let(:user_id1) { 'bob' } 92 | let(:user_id2) { random_username } 93 | let(:user_id3) { 'billy' } 94 | let(:user_id4) { 'sarah' } 95 | let(:user_id5) { 'sally' } 96 | let(:user_id6) { 'betty' } 97 | 98 | let(:verify_acl_command) { "icacls #{target}" } 99 | let(:verify_acl_child_command) { "icacls #{target_child}" } 100 | let(:user_id1_ace_regex) { %r{.*\\bob:(\(I\))?\(OI\)\(CI\)\(M\)} } 101 | let(:user_id2_ace_regex) { %r{.*\\#{user_id2}:(\(I\))?\(OI\)\(CI\)\(N\)} } 102 | let(:user_id3_ace_regex) { %r{.*\\billy:(\(I\))?\(OI\)\(CI\)\(W,Rc\)} } 103 | let(:user_id4_ace_regex) { %r{.*\\sarah:\(OI\)\(CI\)\(N\)} } 104 | let(:user_id5_ace_regex) { %r{.*\\sally:\(OI\)\(CI\)\(M\)} } 105 | let(:user_id6_ace_regex) { %r{.*\\betty:\(OI\)\(CI\)\(DENY\)\(R\)} } 106 | 107 | it 'applies manifest' do 108 | acl_idempotent_apply(acl_manifest) 109 | end 110 | 111 | it 'verifies ACL rights' do 112 | run_shell(verify_acl_command) do |result| 113 | expect(result.stdout).to match(%r{#{user_id1_ace_regex}}) 114 | expect(result.stdout).to match(%r{#{user_id2_ace_regex}}) 115 | expect(result.stdout).to match(%r{#{user_id3_ace_regex}}) 116 | expect(result.stdout).not_to match(%r{#{user_id4_ace_regex}}) 117 | expect(result.stdout).not_to match(%r{#{user_id5_ace_regex}}) 118 | expect(result.stdout).not_to match(%r{#{user_id6_ace_regex}}) 119 | end 120 | end 121 | 122 | it 'verifies child ACL rights' do 123 | run_shell(verify_acl_child_command) do |result| 124 | expect(result.stdout).to match(%r{#{user_id1_ace_regex}}) 125 | expect(result.stdout).to match(%r{#{user_id2_ace_regex}}) 126 | expect(result.stdout).to match(%r{#{user_id3_ace_regex}}) 127 | expect(result.stdout).to match(%r{#{user_id4_ace_regex}}) 128 | expect(result.stdout).to match(%r{#{user_id5_ace_regex}}) 129 | expect(result.stdout).to match(%r{#{user_id6_ace_regex}}) 130 | end 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/negative/allow_deny_ident_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_file}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | acl { "#{target_parent}/#{target_file}": 19 | permissions => [ 20 | { identity => '#{user_id}',perm_type => 'allow', rights => ['full'] }, 21 | { identity => '#{user_id}',perm_type => 'deny', rights => ['full'] } 22 | ], 23 | } 24 | MANIFEST 25 | end 26 | 27 | context 'Negative - Allow and Deny ACE for Single Identity in ACL' do 28 | let(:test_short_name) { 'allow_deny_ident' } 29 | let(:file_content) { 'Epic fail' } 30 | let(:target_file) { "use_case_#{test_short_name}.txt" } 31 | let(:verify_content_path) { "#{target_parent}/#{target_file}" } 32 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_file}" } 33 | let(:target_first_ace_regex) { %r{.*\\bob:\(F\)} } 34 | let(:target_second_ace_regex) { %r{.*\\bob:\(N\)} } 35 | 36 | it 'applies manifest' do 37 | acl_idempotent_apply(acl_manifest) 38 | end 39 | 40 | it 'verifies ACL rights' do 41 | run_shell(verify_acl_command) do |result| 42 | expect(result.stdout).to match(target_first_ace_regex) 43 | expect(result.stdout).to match(target_second_ace_regex) 44 | end 45 | end 46 | 47 | it 'verifies file data integrity' do 48 | expect(file(verify_content_path)).to be_file 49 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/negative/locked_resource_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_file}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | acl { "#{target_parent}/#{target_file}": 19 | purge => 'true', 20 | permissions => [ 21 | { identity => '#{user_id}', rights => ['full'] } 22 | ], 23 | inherit_parent_permissions => 'false' 24 | } 25 | MANIFEST 26 | end 27 | 28 | let(:update_manifest) do 29 | <<-MANIFEST 30 | file { "#{target_parent}/#{target_file}": 31 | ensure => file, 32 | content => 'New Content' 33 | } 34 | MANIFEST 35 | end 36 | 37 | context 'Negative - Manage Locked Resource with ACL' do 38 | let(:test_short_name) { 'locked_resource' } 39 | let(:file_content) { 'Why this hurt bad!' } 40 | let(:target_file) { "use_case_#{test_short_name}.txt" } 41 | 42 | it 'applies manifest' do 43 | apply_manifest(acl_manifest, catch_failures: true) 44 | end 45 | 46 | it 'attempts to update file, raises error' do 47 | apply_manifest(update_manifest, expect_failures: true) do |result| 48 | expect(result.stderr).to match(%r{Error:.*Permission denied}) 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/acceptance/use_cases/negative/multi_acl_single_target_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Use Cases' do 6 | let(:acl_manifest) do 7 | <<-MANIFEST 8 | file { "#{target_parent}": 9 | ensure => directory 10 | } 11 | 12 | file { "#{target_parent}/#{target_name}": 13 | ensure => file, 14 | content => '#{file_content}', 15 | require => File['#{target_parent}'] 16 | } 17 | 18 | acl { "first_acl": 19 | target => '#{target_parent}/#{target_name}', 20 | permissions => [ 21 | { identity => '#{user_id}',perm_type => 'deny', rights => ['full'] } 22 | ], 23 | } 24 | 25 | acl { "second_acl": 26 | target => '#{target_parent}/#{target_name}', 27 | permissions => [ 28 | { identity => '#{user_id}',perm_type => 'deny', rights => ['full'] } 29 | ], 30 | } 31 | MANIFEST 32 | end 33 | 34 | context 'Negative - Multiple ACL for Single Path' do 35 | let(:test_short_name) { 'multi_acl_single_target' } 36 | let(:file_content) { 'MEGA ULTRA FAIL!' } 37 | let(:target_name) { "use_case_#{test_short_name}.txt" } 38 | let(:verify_content_path) { "#{target_parent}/#{target_name}" } 39 | let(:verify_acl_command) { "icacls #{target_parent}/#{target_name}" } 40 | let(:target_first_ace_regex) { %r{.*\\bob:\(F\)} } 41 | let(:target_second_ace_regex) { %r{.*\\bob:\(N\)} } 42 | 43 | it 'applies manifest' do 44 | acl_idempotent_apply(acl_manifest) 45 | end 46 | 47 | it 'verifies ACL rights' do 48 | run_shell(verify_acl_command) do |result| 49 | expect(result.stdout).not_to match(target_first_ace_regex) 50 | expect(result.stdout).to match(target_second_ace_regex) 51 | end 52 | end 53 | 54 | it 'verifies file data integrity' do 55 | expect(file(verify_content_path)).to be_file 56 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/default_facts.yml: -------------------------------------------------------------------------------- 1 | # Use default_module_facts.yml for module specific facts. 2 | # 3 | # Facts specified here will override the values provided by rspec-puppet-facts. 4 | --- 5 | networking: 6 | ip: "172.16.254.254" 7 | ip6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" 8 | mac: "AA:AA:AA:AA:AA:AA" 9 | is_pe: false 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |c| 4 | c.mock_with :rspec 5 | end 6 | 7 | require 'puppetlabs_spec_helper/module_spec_helper' 8 | require 'rspec-puppet-facts' 9 | 10 | require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) 11 | 12 | include RspecPuppetFacts 13 | 14 | default_facts = { 15 | puppetversion: Puppet.version, 16 | facterversion: Facter.version, 17 | } 18 | 19 | default_fact_files = [ 20 | File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), 21 | File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), 22 | ] 23 | 24 | default_fact_files.each do |f| 25 | next unless File.exist?(f) && File.readable?(f) && File.size?(f) 26 | 27 | begin 28 | require 'deep_merge' 29 | default_facts.deep_merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) 30 | rescue StandardError => e 31 | RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" 32 | end 33 | end 34 | 35 | # read default_facts and merge them over what is provided by facterdb 36 | default_facts.each do |fact, value| 37 | add_custom_fact fact, value, merge_facts: true 38 | end 39 | 40 | RSpec.configure do |c| 41 | c.default_facts = default_facts 42 | c.before :each do 43 | # set to strictest setting for testing 44 | # by default Puppet runs at warning level 45 | Puppet.settings[:strict] = :warning 46 | Puppet.settings[:strict_variables] = true 47 | end 48 | c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] 49 | c.after(:suite) do 50 | RSpec::Puppet::Coverage.report!(0) 51 | end 52 | 53 | # Filter backtrace noise 54 | backtrace_exclusion_patterns = [ 55 | %r{spec_helper}, 56 | %r{gems}, 57 | ] 58 | 59 | if c.respond_to?(:backtrace_exclusion_patterns) 60 | c.backtrace_exclusion_patterns = backtrace_exclusion_patterns 61 | elsif c.respond_to?(:backtrace_clean_patterns) 62 | c.backtrace_clean_patterns = backtrace_exclusion_patterns 63 | end 64 | end 65 | 66 | # Ensures that a module is defined 67 | # @param module_name Name of the module 68 | def ensure_module_defined(module_name) 69 | module_name.split('::').reduce(Object) do |last_module, next_module| 70 | last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) 71 | last_module.const_get(next_module, false) 72 | end 73 | end 74 | 75 | # 'spec_overrides' from sync.yml will appear below this line 76 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet_litmus' 4 | require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb')) 5 | 6 | PuppetLitmus.configure! 7 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Dir['./spec/support/**/*.rb'].sort.each { |f| require f } 4 | 5 | def target_parent 6 | 'c:/temp' 7 | end 8 | 9 | def user_id 10 | 'bob' 11 | end 12 | 13 | def generate_random_username 14 | charset = Array('A'..'Z') + Array('a'..'z') 15 | Array.new(5) { charset.sample }.join 16 | end 17 | 18 | def file_content_regex(file_content) 19 | %r{\A#{file_content}\z} 20 | end 21 | 22 | def windows_agents 23 | agents.select { |agent| agent['platform'].include?('windows') } 24 | end 25 | 26 | def linux_agents 27 | agents.select { |agent| fact_on(agent, 'kernel') == 'Linux' } 28 | end 29 | 30 | def acl_idempotent_apply(manifest) 31 | apply_manifest(manifest, catch_failures: true) 32 | apply_manifest(manifest, catch_changes: true) 33 | end 34 | 35 | # The following are modified helpers from beaker-4.7.0/lib/beaker/dsl/wrappers.rb 36 | 37 | # Returns a {Beaker::Command} object for executing powershell commands on a host 38 | # 39 | # @param [String] command The powershell command to execute 40 | # @param [Hash] args The commandline parameters to be passed to powershell 41 | # 42 | # @example Setting the contents of a file 43 | # powershell("Set-Content -path 'fu.txt' -value 'fu'") 44 | # 45 | # @example Using an alternative execution policy 46 | # powershell("Set-Content -path 'fu.txt' -value 'fu'", {'ExecutionPolicy' => 'Unrestricted'}) 47 | # 48 | # @example Using an EncodedCommand (defaults to non-encoded) 49 | # powershell("Set Content -path 'fu.txt', -value 'fu'", {'EncodedCommand => true}) 50 | # 51 | # @example executing from a file 52 | # powershell("", {'-File' => '/path/to/file'}) 53 | # 54 | # @return [Command] 55 | def powershell(command, args = {}) 56 | ps_opts = { 57 | 'ExecutionPolicy' => 'Bypass', 58 | 'InputFormat' => 'None', 59 | 'NoLogo' => '', 60 | 'NoProfile' => '', 61 | 'NonInteractive' => '' 62 | } 63 | encoded = false 64 | ps_opts.merge!(args) 65 | ps_args = [] 66 | 67 | # determine if the command should be encoded 68 | if ps_opts.key?('EncodedCommand') 69 | v = ps_opts.delete('EncodedCommand') 70 | # encode the commend if v is true, nil or empty 71 | encoded = v || v.eql?('') || v.nil? 72 | end 73 | 74 | ps_opts.each do |key, value| 75 | ps_args << if value.eql?('') || value.nil? 76 | "-#{key}" 77 | else 78 | "-#{key} #{value}" 79 | end 80 | end 81 | 82 | # may not have a command if executing a file 83 | if command && !command.empty? 84 | ps_args << if encoded 85 | "-EncodedCommand #{encode_command(command)}" 86 | else 87 | "-Command #{command}" 88 | end 89 | end 90 | 91 | "powershell.exe #{ps_args.join(' ')}" 92 | end 93 | 94 | # Convert the provided command string to Base64 95 | # @param [String] cmd The command to convert to Base64 96 | # @return [String] The converted string 97 | # @api private 98 | def encode_command(cmd) 99 | cmd = cmd.chars.to_a.join("\x00").chomp 100 | cmd << "\x00" unless cmd[-1].eql? "\x00" 101 | # use strict_encode because linefeeds are not correctly handled in our model 102 | Base64.strict_encode64(cmd).chomp 103 | end 104 | -------------------------------------------------------------------------------- /spec/spec_helper_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'pathname' 4 | require 'tmpdir' 5 | require 'fileutils' 6 | 7 | if Puppet.features.microsoft_windows? 8 | require 'puppet/util/windows/security' 9 | 10 | def take_ownership(path) 11 | path = path.tr('/', '\\') 12 | output = `takeown.exe /F #{path} /R /A /D Y 2>&1` 13 | puts "#{path} got error #{output}" if $CHILD_STATUS != 0 # check if the child process exited cleanly. 14 | end 15 | end 16 | 17 | RSpec.configure do |config| 18 | tmpdir = Dir.mktmpdir('rspecrun_acl') 19 | oldtmpdir = Dir.tmpdir 20 | ENV['TMPDIR'] = tmpdir 21 | 22 | config.expect_with :rspec do |c| 23 | c.syntax = [:should, :expect] 24 | end 25 | 26 | config.after :suite do 27 | # return to original tmpdir 28 | ENV['TMPDIR'] = oldtmpdir 29 | take_ownership(tmpdir) if Puppet::Util::Platform.windows? 30 | FileUtils.rm_rf(tmpdir) 31 | end 32 | end 33 | 34 | # We need this because the RAL uses 'should' as a method. This 35 | # allows us the same behaviour but with a different method name. 36 | class Object 37 | alias must should 38 | alias must_not should_not 39 | end 40 | -------------------------------------------------------------------------------- /spec/support/shared_examples.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | shared_examples 'execute manifest' do |remove = false, file_verify = false| 4 | it 'applies manifest' do 5 | # acl_idempotent_apply(acl_manifest) 6 | apply_manifest(acl_manifest, catch_failures: true) 7 | end 8 | 9 | it 'verifies ACL rights' do 10 | run_shell(verify_acl_command) do |result| 11 | expect(result.stdout).to match(%r{#{acl_regex}}) 12 | end 13 | end 14 | 15 | if remove 16 | it 'applies remove manifest' do 17 | apply_manifest(acl_manifest_remove, catch_failures: true) 18 | end 19 | 20 | it 'verifies ACL rights' do 21 | run_shell(verify_acl_command) do |result| 22 | expect(result.stdout).not_to match(%r{#{acl_regex}}) 23 | end 24 | end 25 | end 26 | 27 | if file_verify 28 | it 'verifies file data integrity' do 29 | expect(file(verify_content_path)).to be_file 30 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 31 | end 32 | end 33 | end 34 | 35 | shared_examples 'execute manifest and verify file' do 36 | it 'applies manifest' do 37 | # acl_idempotent_apply(acl_manifest) 38 | apply_manifest(acl_manifest, catch_failures: true) 39 | end 40 | 41 | it 'verifies ACL rights' do 42 | run_shell(verify_acl_command) do |result| 43 | expect(result.stdout).to match(%r{#{acl_regex}}) 44 | end 45 | end 46 | 47 | it 'verifies file data integrity' do 48 | expect(file(verify_content_path)).to be_file 49 | expect(file(verify_content_path).content).to match(%r{#{file_content}}) 50 | end 51 | end 52 | 53 | shared_examples 'execute manifest and verify (with PowerShell)' do 54 | it 'applies manifest' do 55 | # acl_idempotent_apply(acl_manifest) 56 | apply_manifest(acl_manifest, catch_failures: true) 57 | end 58 | 59 | it 'verifies ACL rights' do 60 | run_shell(powershell(verify_acl_command, 'EncodedCommand' => true)) do |result| 61 | expect(result.stdout.strip).to match(acl_regex) 62 | end 63 | end 64 | end 65 | 66 | shared_examples 'execute manifest and verify child' do 67 | it 'applies manifest' do 68 | # acl_idempotent_apply(acl_manifest) 69 | apply_manifest(acl_manifest, catch_failures: true) 70 | end 71 | 72 | it 'verifies ACL rights' do 73 | run_shell(verify_acl_command) do |result| 74 | expect(result.stdout).to match(%r{#{acl_regex}}) 75 | end 76 | end 77 | 78 | it 'verifies child ACL rights' do 79 | run_shell(verify_child_acl_command) do |result| 80 | expect(result.stdout).not_to match(%r{#{acl_regex}}) 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /tools/ACL_Access_Rights_Mask_Addition.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puppetlabs/puppetlabs-acl/e700c24eb471ce0806dfde3cd60db0741dc7f1c2/tools/ACL_Access_Rights_Mask_Addition.xlsx --------------------------------------------------------------------------------