Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

(#11046) improve freebsd user and group providers #338

Merged
merged 4 commits into from

3 participants

@pcarlisle
Owner

Add password support to FreeBSD and enhance the pw user and group providers.

tdb added some commits
@tdb tdb (#11318) Add password management on FreeBSD
This adds the manages_passwords feature to the pw user provider. It is based
on the patch by Andrew Hust that was integrated into FreeBSD puppet port. It
adds tests covering the create, delete and modify processes of the provider.

This integrates a fix for #7500 that was introduced by the original patch.
The existing code takes the first character of each property and uses it as a
flag. However, with pw, the -p flag is for setting the password expiration.
The result is that the password isn't set at create time and that the password
is set to expire. The next run of puppet correctly sets the password but the
expiry is still set. The new code avoids using -p for passwords, and also sets
the password correctly when an account is created.

Reviewed-by: Patrick Carlisle <patrick@puppetlabs.com>
884381f
@tdb tdb (#10962) Make sure managehome is respected on FreeBSD
When modifying the home directory of a user and managehome is set
the -m flag should be used with pw. This ensures that the new home
directory is created if it doesn't exist.

Also add test to verify this behaviour.
fb111ef
@tdb tdb (#11046) Improve pw group provider on FreeBSD
Make the pw group provider on FreeBSD support managing group members.
Also readd the allowdupe feature since in testing on FreeBSD 7, 8
and 9 the -o flag to pw works as documented.

Add tests for the provider.

Reviewed-by: Patrick Carlisle <patrick@puppetlabs.com>
9b8829d
@tdb tdb (#11046) Add support for user expiry in pw user provider
Add support for setting an expiry date for a user in the pw user
provider. FreeBSD uses the format DD-MM-YYYY rather than Puppet's
YYYY-MM-DD. Tests added to confirm the value is correctly swapped
around.

Also added custom accessor method to take the unix timestamp given
by the operating system to a Puppet-style YYYY-MM-DD. This stops
Puppet from repeatedly trying to set the expiry date if it's already
correct.
032043e
@daniel-pittman daniel-pittman merged commit 75d7cad into puppetlabs:2.7.x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 17, 2012
  1. @tdb @pcarlisle

    (#11318) Add password management on FreeBSD

    tdb authored pcarlisle committed
    This adds the manages_passwords feature to the pw user provider. It is based
    on the patch by Andrew Hust that was integrated into FreeBSD puppet port. It
    adds tests covering the create, delete and modify processes of the provider.
    
    This integrates a fix for #7500 that was introduced by the original patch.
    The existing code takes the first character of each property and uses it as a
    flag. However, with pw, the -p flag is for setting the password expiration.
    The result is that the password isn't set at create time and that the password
    is set to expire. The next run of puppet correctly sets the password but the
    expiry is still set. The new code avoids using -p for passwords, and also sets
    the password correctly when an account is created.
    
    Reviewed-by: Patrick Carlisle <patrick@puppetlabs.com>
  2. @tdb @pcarlisle

    (#10962) Make sure managehome is respected on FreeBSD

    tdb authored pcarlisle committed
    When modifying the home directory of a user and managehome is set
    the -m flag should be used with pw. This ensures that the new home
    directory is created if it doesn't exist.
    
    Also add test to verify this behaviour.
  3. @tdb @pcarlisle

    (#11046) Improve pw group provider on FreeBSD

    tdb authored pcarlisle committed
    Make the pw group provider on FreeBSD support managing group members.
    Also readd the allowdupe feature since in testing on FreeBSD 7, 8
    and 9 the -o flag to pw works as documented.
    
    Add tests for the provider.
    
    Reviewed-by: Patrick Carlisle <patrick@puppetlabs.com>
  4. @tdb @pcarlisle

    (#11046) Add support for user expiry in pw user provider

    tdb authored pcarlisle committed
    Add support for setting an expiry date for a user in the pw user
    provider. FreeBSD uses the format DD-MM-YYYY rather than Puppet's
    YYYY-MM-DD. Tests added to confirm the value is correctly swapped
    around.
    
    Also added custom accessor method to take the unix timestamp given
    by the operating system to a Puppet-style YYYY-MM-DD. This stops
    Puppet from repeatedly trying to set the expiry date if it's already
    correct.
This page is out of date. Refresh to see the latest.
View
34 lib/puppet/provider/group/pw.rb
@@ -1,34 +1,48 @@
require 'puppet/provider/nameservice/pw'
Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do
- desc "Group management via `pw`.
+ desc "Group management via `pw` on FreeBSD."
- Only works on FreeBSD.
+ commands :pw => "pw"
+ has_features :manages_members
- "
-
- commands :pw => "/usr/sbin/pw"
defaultfor :operatingsystem => :freebsd
+ options :members, :flag => "-M", :method => :mem
+
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end
def addcmd
cmd = [command(:pw), "groupadd", @resource[:name]]
+
if gid = @resource.should(:gid)
unless gid == :absent
cmd << flag(:gid) << gid
end
end
- # Apparently, contrary to the man page, groupadd does
- # not accept -o.
- #if @parent[:allowdupe] == :true
- # cmd << "-o"
- #end
+ if members = @resource.should(:members)
+ unless members == :absent
+ if members.is_a?(Array)
+ members = members.join(",")
+ end
+ cmd << "-M" << members
+ end
+ end
+
+ cmd << "-o" if @resource.allowdupe?
cmd
end
+
+ def modifycmd(param, value)
+ # members may be an array, need a comma separated list
+ if param == :members and value.is_a?(Array)
+ value = value.join(",")
+ end
+ super(param, value)
+ end
end
View
58 lib/puppet/provider/user/pw.rb
@@ -1,16 +1,18 @@
require 'puppet/provider/nameservice/pw'
+require 'open3'
Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do
desc "User management via `pw` on FreeBSD."
commands :pw => "pw"
- has_features :manages_homedir, :allows_duplicates
+ has_features :manages_homedir, :allows_duplicates, :manages_passwords, :manages_expiry
defaultfor :operatingsystem => :freebsd
options :home, :flag => "-d", :method => :dir
options :comment, :method => :gecos
options :groups, :flag => "-G"
+ options :expiry, :method => :expire
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
@@ -23,10 +25,14 @@
def addcmd
cmd = [command(:pw), "useradd", @resource[:name]]
@resource.class.validproperties.each do |property|
- next if property == :ensure
+ next if property == :ensure or property == :password
# the value needs to be quoted, mostly because -c might
# have spaces in it
if value = @resource.should(property) and value != ""
+ if property == :expiry
+ # FreeBSD uses DD-MM-YYYY rather than YYYY-MM-DD
+ value = value.split("-").reverse.join("-")
+ end
cmd << flag(property) << value
end
end
@@ -37,5 +43,53 @@ def addcmd
cmd
end
+
+ def modifycmd(param, value)
+ if param == :expiry
+ # FreeBSD uses DD-MM-YYYY rather than YYYY-MM-DD
+ value = value.split("-").reverse.join("-")
+ end
+ cmd = super(param, value)
+ cmd << "-m" if @resource.managehome?
+ cmd
+ end
+
+ def create
+ super
+
+ # Set the password after create if given
+ self.password = @resource[:password] if @resource[:password]
+ end
+
+ # use pw to update password hash
+ def password=(cryptopw)
+ Puppet.debug "change password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
+ stdin, stdout, stderr = Open3.popen3("pw user mod #{@resource[:name]} -H 0")
+ stdin.puts(cryptopw)
+ stdin.close
+ Puppet.debug "finished password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
+ end
+
+ # get password from /etc/master.passwd
+ def password
+ Puppet.debug "checking password for user '#{@resource[:name]}' method called"
+ current_passline = `getent passwd #{@resource[:name]}`
+ current_password = current_passline.chomp.split(':')[1] if current_passline
+ Puppet.debug "finished password for user '#{@resource[:name]}' method called : '#{current_password}'"
+ current_password
+ end
+
+ # Get expiry from system and convert to Puppet-style date
+ def expiry
+ expiry = self.get(:expiry)
+ expiry = :absent if expiry == 0
+
+ if expiry != :absent
+ t = Time.at(expiry)
+ expiry = "%4d-%02d-%02d" % [t.year, t.month, t.mday]
+ end
+
+ expiry
+ end
end
View
81 spec/unit/provider/group/pw_spec.rb
@@ -0,0 +1,81 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+provider_class = Puppet::Type.type(:group).provider(:pw)
+
+describe provider_class do
+ let :resource do
+ Puppet::Type.type(:group).new(:name => "testgroup", :provider => :pw)
+ end
+
+ let :provider do
+ resource.provider
+ end
+
+ describe "when creating groups" do
+ let :provider do
+ prov = resource.provider
+ prov.expects(:exists?).returns nil
+ prov
+ end
+
+ it "should run pw with no additional flags when no properties are given" do
+ provider.addcmd.must == [provider_class.command(:pw), "groupadd", "testgroup"]
+ provider.expects(:execute).with([provider_class.command(:pw), "groupadd", "testgroup"])
+ provider.create
+ end
+
+ it "should use -o when allowdupe is enabled" do
+ resource[:allowdupe] = true
+ provider.expects(:execute).with(includes("-o"))
+ provider.create
+ end
+
+ it "should use -g with the correct argument when the gid property is set" do
+ resource[:gid] = 12345
+ provider.expects(:execute).with(all_of(includes("-g"), includes(12345)))
+ provider.create
+ end
+
+ it "should use -M with the correct argument when the members property is set" do
+ resource[:members] = "user1"
+ provider.expects(:execute).with(all_of(includes("-M"), includes("user1")))
+ provider.create
+ end
+
+ it "should use -M with all the given users when the members property is set to an array" do
+ resource[:members] = ["user1", "user2"]
+ provider.expects(:execute).with(all_of(includes("-M"), includes("user1,user2")))
+ provider.create
+ end
+ end
+
+ describe "when deleting groups" do
+ it "should run pw with no additional flags" do
+ provider.expects(:exists?).returns true
+ provider.deletecmd.must == [provider_class.command(:pw), "groupdel", "testgroup"]
+ provider.expects(:execute).with([provider_class.command(:pw), "groupdel", "testgroup"])
+ provider.delete
+ end
+ end
+
+ describe "when modifying groups" do
+ it "should run pw with the correct arguments" do
+ provider.modifycmd("gid", 12345).must == [provider_class.command(:pw), "groupmod", "testgroup", "-g", 12345]
+ provider.expects(:execute).with([provider_class.command(:pw), "groupmod", "testgroup", "-g", 12345])
+ provider.gid = 12345
+ end
+
+ it "should use -M with the correct argument when the members property is changed" do
+ resource[:members] = "user1"
+ provider.expects(:execute).with(all_of(includes("-M"), includes("user2")))
+ provider.members = "user2"
+ end
+
+ it "should use -M with all the given users when the members property is changed with an array" do
+ resource[:members] = ["user1", "user2"]
+ provider.expects(:execute).with(all_of(includes("-M"), includes("user3,user4")))
+ provider.members = ["user3", "user4"]
+ end
+ end
+end
View
183 spec/unit/provider/user/pw_spec.rb
@@ -0,0 +1,183 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+provider_class = Puppet::Type.type(:user).provider(:pw)
+
+describe provider_class do
+ let :resource do
+ Puppet::Type.type(:user).new(:name => "testuser", :provider => :pw)
+ end
+
+ describe "when creating users" do
+ let :provider do
+ prov = resource.provider
+ prov.expects(:exists?).returns nil
+ prov
+ end
+
+ it "should run pw with no additional flags when no properties are given" do
+ provider.addcmd.must == [provider_class.command(:pw), "useradd", "testuser"]
+ provider.expects(:execute).with([provider_class.command(:pw), "useradd", "testuser"])
+ provider.create
+ end
+
+ it "should use -o when allowdupe is enabled" do
+ resource[:allowdupe] = true
+ provider.expects(:execute).with(includes("-o"))
+ provider.create
+ end
+
+ it "should use -c with the correct argument when the comment property is set" do
+ resource[:comment] = "Testuser Name"
+ provider.expects(:execute).with(all_of(includes("-c"), includes("Testuser Name")))
+ provider.create
+ end
+
+ it "should use -e with the correct argument when the expiry property is set" do
+ resource[:expiry] = "2010-02-19"
+ provider.expects(:execute).with(all_of(includes("-e"), includes("19-02-2010")))
+ provider.create
+ end
+
+ it "should use -g with the correct argument when the gid property is set" do
+ resource[:gid] = 12345
+ provider.expects(:execute).with(all_of(includes("-g"), includes(12345)))
+ provider.create
+ end
+
+ it "should use -G with the correct argument when the groups property is set" do
+ resource[:groups] = "group1"
+ provider.expects(:execute).with(all_of(includes("-G"), includes("group1")))
+ provider.create
+ end
+
+ it "should use -G with all the given groups when the groups property is set to an array" do
+ resource[:groups] = ["group1", "group2"]
+ provider.expects(:execute).with(all_of(includes("-G"), includes("group1,group2")))
+ provider.create
+ end
+
+ it "should use -d with the correct argument when the home property is set" do
+ resource[:home] = "/home/testuser"
+ provider.expects(:execute).with(all_of(includes("-d"), includes("/home/testuser")))
+ provider.create
+ end
+
+ it "should use -m when the managehome property is enabled" do
+ resource[:managehome] = true
+ provider.expects(:execute).with(includes("-m"))
+ provider.create
+ end
+
+ it "should call the password set function with the correct argument when the password property is set" do
+ resource[:password] = "*"
+ provider.expects(:execute)
+ provider.expects(:password=).with("*")
+ provider.create
+ end
+
+ it "should use -s with the correct argument when the shell property is set" do
+ resource[:shell] = "/bin/sh"
+ provider.expects(:execute).with(all_of(includes("-s"), includes("/bin/sh")))
+ provider.create
+ end
+
+ it "should use -u with the correct argument when the uid property is set" do
+ resource[:uid] = 12345
+ provider.expects(:execute).with(all_of(includes("-u"), includes(12345)))
+ provider.create
+ end
+
+ # (#7500) -p should not be used to set a password (it means something else)
+ it "should not use -p when a password is given" do
+ resource[:password] = "*"
+ provider.addcmd.should_not include("-p")
+ provider.expects(:password=)
+ provider.expects(:execute).with(Not(includes("-p")))
+ provider.create
+ end
+ end
+
+ describe "when deleting users" do
+ it "should run pw with no additional flags" do
+ provider = resource.provider
+ provider.expects(:exists?).returns true
+ provider.deletecmd.must == [provider_class.command(:pw), "userdel", "testuser"]
+ provider.expects(:execute).with([provider_class.command(:pw), "userdel", "testuser"])
+ provider.delete
+ end
+ end
+
+ describe "when modifying users" do
+ let :provider do
+ resource.provider
+ end
+
+ it "should run pw with the correct arguments" do
+ provider.modifycmd("uid", 12345).must == [provider_class.command(:pw), "usermod", "testuser", "-u", 12345]
+ provider.expects(:execute).with([provider_class.command(:pw), "usermod", "testuser", "-u", 12345])
+ provider.uid = 12345
+ end
+
+ it "should use -c with the correct argument when the comment property is changed" do
+ resource[:comment] = "Testuser Name"
+ provider.expects(:execute).with(all_of(includes("-c"), includes("Testuser New Name")))
+ provider.comment = "Testuser New Name"
+ end
+
+ it "should use -e with the correct argument when the expiry property is changed" do
+ resource[:expiry] = "2010-02-19"
+ provider.expects(:execute).with(all_of(includes("-e"), includes("19-02-2011")))
+ provider.expiry = "2011-02-19"
+ end
+
+ it "should use -g with the correct argument when the gid property is changed" do
+ resource[:gid] = 12345
+ provider.expects(:execute).with(all_of(includes("-g"), includes(54321)))
+ provider.gid = 54321
+ end
+
+ it "should use -G with the correct argument when the groups property is changed" do
+ resource[:groups] = "group1"
+ provider.expects(:execute).with(all_of(includes("-G"), includes("group2")))
+ provider.groups = "group2"
+ end
+
+ it "should use -G with all the given groups when the groups property is changed with an array" do
+ resource[:groups] = ["group1", "group2"]
+ provider.expects(:execute).with(all_of(includes("-G"), includes("group3,group4")))
+ provider.groups = "group3,group4"
+ end
+
+ it "should use -d with the correct argument when the home property is changed" do
+ resource[:home] = "/home/testuser"
+ provider.expects(:execute).with(all_of(includes("-d"), includes("/newhome/testuser")))
+ provider.home = "/newhome/testuser"
+ end
+
+ it "should use -m and -d with the correct argument when the home property is changed and managehome is enabled" do
+ resource[:home] = "/home/testuser"
+ resource[:managehome] = true
+ provider.expects(:execute).with(all_of(includes("-d"), includes("/newhome/testuser"), includes("-m")))
+ provider.home = "/newhome/testuser"
+ end
+
+ it "should call the password set function with the correct argument when the password property is changed" do
+ resource[:password] = "*"
+ provider.expects(:password=).with("!")
+ provider.password = "!"
+ end
+
+ it "should use -s with the correct argument when the shell property is changed" do
+ resource[:shell] = "/bin/sh"
+ provider.expects(:execute).with(all_of(includes("-s"), includes("/bin/tcsh")))
+ provider.shell = "/bin/tcsh"
+ end
+
+ it "should use -u with the correct argument when the uid property is changed" do
+ resource[:uid] = 12345
+ provider.expects(:execute).with(all_of(includes("-u"), includes(54321)))
+ provider.uid = 54321
+ end
+ end
+end
Something went wrong with that request. Please try again.