class Inspec::Resources::User

end
its(:encrypted_password) { should eq 1234 }
it { should have_authorized_key ‘ssh-rsa ADg54…3434 user@example.local’ }
its(‘maximum_days_between_password_change’) { should eq 99 }
its(‘minimum_days_between_password_change’) { should eq 0 }
it { should have_login_shell ‘/bin/bash’ }
it { should have_home_directory ‘/root’ }
it { should have_uid 0 }
it { should belong_to_primary_group ‘root’ }
it { should belong_to_group ‘root’ }
describe user(‘root’) do
but are made available as part of Serverspec compatibility in March, 2022.
The following Serverspec matchers were deprecated in favor for direct value access
end
its(‘badpasswordattempts’) { should eq 0 }
its(‘maxbadpasswords’) { should eq 0 }
its(‘passwordage’) { should eq 355 }
its(‘warndays’) { should eq nil }
its(‘maxdays’) { should eq 42 }
its(‘mindays’) { should eq 0 }
its(‘shell’) { should eq nil } // not supported on Windows
its(‘home’) { should eq ” }
its(‘groups’) { should eq [‘Administrators’, ‘Users’]}
its(‘group’) { should eq nil } // not supported on Windows
its(‘gid’) { should eq nil } // not supported on Windows
its(‘uid’) { should eq “S-1-5-21-1759981009-4135989804-1844563890-500” }
it { should exist }
describe user(‘Administrator’) do
end
its(‘badpasswordattempts’) { should eq 0 }
its(‘maxbadpasswords’) { should eq nil } // not yet supported on linux
its(‘passwordage’) { should be >= 0 }
its(‘warndays’) { should eq 5 }
its(‘maxdays’) { should eq 99 }
its(‘mindays’) { should eq 0 }
its(‘shell’) { should eq ‘/bin/bash’ }
its(‘home’) { should eq ‘/root’ }
its(‘groups’) { should eq [‘root’, ‘wheel’]}
its(‘group’) { should eq ‘root’ }
its(‘gid’) { should eq 0 }
its(‘uid’) { should eq 0 }
it { should exist }
describe user(‘root’) do
The ‘user` resource handles the special case where only one resource is required

def badpasswordattempts

def badpasswordattempts
  credentials[:badpasswordattempts] unless credentials.nil?
end

def belongs_to_group?(group_name)

belongs_to_group matcher: compatibility with serverspec
def belongs_to_group?(group_name)
  groups.include?(group_name)
end

def belongs_to_primary_group?(group_name)

belongs_to_primary_group matcher: compatibility with serverspec
def belongs_to_primary_group?(group_name)
  groupname == group_name
end

def credentials

def credentials
  return @cred_cache if defined?(@cred_cache)
  @cred_cache = @user_provider.credentials(@username) unless @user_provider.nil?
end

def disabled?

def disabled?
  identity[:disabled] == true unless identity.nil?
end

def domain

def domain
  meta_info[:domain] unless meta_info.nil?
end

def enabled?

def enabled?
  identity[:disabled] == false unless identity.nil?
end

def encrypted_password

applicable for unix/linux systems with getent utility.
it allows to run test against the hashed passwords of the given user
encrypted_password property: compatibility with serverspec
def encrypted_password
  raise Inspec::Exceptions::ResourceSkipped, "encrypted_password property is not applicable for your system" if inspec.os.windows? || inspec.os.darwin?
  # shadow_information returns array of the information from the shadow file
  # the value at 1st index is the encrypted_password information
  shadow_information[1]
end

def exists?

def exists?
  !identity.nil? && !identity[:username].nil?
end

def find_getent_utility

check if getent exist in the system
def find_getent_utility
  %w{/usr/bin/getent /bin/getent getent}.each do |cmd|
    return cmd if inspec.command(cmd).exist?
  end
  raise Inspec::Exceptions::ResourceFailed, "Could not find `getent` on your system."
end

def get_authorized_keys

get_authorized_keys return the key/keys stored in the authorized_keys path
helper method for has_authorized_key matcher
def get_authorized_keys
  # cat is used in unix system to display content of file; similarly type is used for windows
  bin = inspec.os.windows? ? "type" : "cat"
  # auth_path gets assigned with the valid path for authorized_keys
  auth_path = ""
  # possible paths where authorized_keys are stored
  # inspec.command is used over inspec.file because inspec.file requires absolute path
  %w{~/.ssh/authorized_keys ~/.ssh/authorized_keys2}.each do |path|
    if inspec.command("#{bin} #{path}").exit_status == 0
      auth_path = path
      break
    end
  end
  # if auth_path is empty, no valid path was found, hence raise exception
  raise Inspec::Exceptions::ResourceSkipped, "Can't find any valid path for authorized_keys" if auth_path.empty?
  # authorized_keys are obtained in the standard output;
  # split keys on newline if more than one keys are part of authorized_keys
  inspec.command("#{bin} #{auth_path}").stdout.split("\n").map(&:strip)
end

def gid

def gid
  identity[:gid] unless identity.nil?
end

def groupname

def groupname
  identity[:groupname] unless identity.nil?
end

def groups

def groups
  unless identity.nil?
    inspec.os.windows? ? UserGroups.new(identity[:groups]) : identity[:groups]
  end
end

def has_authorized_key?(compare_key)

has_authorized_key matcher: compatibility with serverspec
def has_authorized_key?(compare_key)
  # get_authorized_keys returns the list of key, check if given key is included.
  get_authorized_keys.include?(compare_key)
end

def has_home_directory?(compare_home)

has_home_directory matcher: compatibility with serverspec
def has_home_directory?(compare_home)
  home == compare_home
end

def has_login_shell?(compare_shell)

has_login_shell matcher: compatibility with serverspec
def has_login_shell?(compare_shell)
  shell == compare_shell
end

def has_uid?(compare_uid)

has_uid matcher: compatibility with serverspec
@see: https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/matchers/built_in/has.rb
implements rspec has matcher, to be compatible with serverspec
def has_uid?(compare_uid)
  uid == compare_uid
end

def home

def home
  meta_info[:home] unless meta_info.nil?
end

def identity

returns the iden
def identity
  return @id_cache if defined?(@id_cache)
  @id_cache = @user_provider.identity(@username) unless @user_provider.nil?
end

def initialize(username = nil)

def initialize(username = nil)
  @username = username
  # select user provider
  @user_provider = select_user_manager(inspec.os)
  return skip_resource "The `user` resource is not supported on your OS yet." if @user_provider.nil?
end

def lastlogin

def lastlogin
  meta_info[:lastlogin] unless meta_info.nil?
end

def maxbadpasswords

def maxbadpasswords
  credentials[:maxbadpasswords] unless credentials.nil?
end

def maxdays

returns the maximum days between password changes
def maxdays
  credentials[:maxdays] unless credentials.nil?
end

def maximum_days_between_password_change

implement 'maxdays' method to be compatible with serverspec
def maximum_days_between_password_change
  maxdays
end

def meta_info

def meta_info
  return @meta_cache if defined?(@meta_cache)
  @meta_cache = @user_provider.meta_info(@username) unless @user_provider.nil?
end

def mindays

returns the minimum days between password changes
def mindays
  credentials[:mindays] unless credentials.nil?
end

def minimum_days_between_password_change

implement 'mindays' method to be compatible with serverspec
def minimum_days_between_password_change
  mindays
end

def passwordage

def passwordage
  credentials[:passwordage] unless credentials.nil?
end

def resource_id

def resource_id
  @username || "User"
end

def shadow_information

Helper method for encrypted_password property
def shadow_information
  # check if getent is available on the system
  bin = find_getent_utility
  # fetch details of the passwd file for the current user using getent
  cmd = inspec.command("#{bin} shadow #{@username}")
  raise Inspec::Exceptions::ResourceFailed, "Executing #{bin} shadow #{@username} failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
  # shadow information are : separated values, split and return
  cmd.stdout.split(":").map(&:strip)
end

def shell

def shell
  meta_info[:shell] unless meta_info.nil?
end

def to_s

def to_s
  "User #{@username}"
end

def uid

def uid
  identity[:uid] unless identity.nil?
end

def userflags

def userflags
  meta_info[:userflags] unless meta_info.nil?
end

def username

def username
  identity[:username] unless identity.nil?
end

def warndays

returns the days for password change warning
def warndays
  credentials[:warndays] unless credentials.nil?
end