-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finalize pwfilesupport #25
Changes from 33 commits
8e055a2
db72942
58b7d61
2ca135c
8795a17
a94728b
1e4676f
85bdc3e
be63926
c2b010d
c872cac
4b3b680
c8c4450
c350714
8ca7da1
2c2795a
01babb1
f4674bc
f116ec3
914efcf
3fc2d10
fcdbb10
74e1e86
a4e8fb7
9e8e9ba
8370366
01d9e1b
5f8f4bd
e5bc35d
3581e56
b15165b
c53fc05
469a453
39d13f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ AllCops: | |
- vendor/**/* | ||
Metrics/ModuleLength: | ||
Max: 121 | ||
Metrics/LineLength: | ||
Max: 121 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,11 +21,10 @@ | |
|
||
# conf.d/10-ssl.conf | ||
|
||
if node['platform_family'] == 'suse' && node['platform_version'].to_i < 13 | ||
default['dovecot']['conf']['ssl'] = false | ||
else | ||
default['dovecot']['conf']['ssl'] = nil | ||
end | ||
default['dovecot']['conf']['ssl'] = \ | ||
if node['platform_family'] == 'suse' && node['platform_version'].to_i < 13 | ||
false | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
case node['platform_family'] | ||
when 'rhel', 'fedora' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,8 @@ | |
default['dovecot']['conf_files_user'] = 'root' | ||
default['dovecot']['conf_files_group'] = node['dovecot']['group'] | ||
default['dovecot']['conf_files_mode'] = '00644' | ||
default['dovecot']['conf']['password_file'] = \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
"#{node['dovecot']['conf_path']}/password" | ||
|
||
default['dovecot']['sensitive_files'] = %w( | ||
*.conf.ext | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# encoding: UTF-8 | ||
# | ||
# Cookbook Name:: dovecot | ||
# Library:: Pwfile | ||
# Author:: Xabier de Zuazo (<xabier@zuazo.org>) | ||
# Copyright:: Copyright (c) 2013-2014 Onddo Labs, SL. | ||
# License:: Apache License, Version 2.0 | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
module DovecotCookbook | ||
# Helper module to check password file and import it | ||
module Pwfile | ||
extend Chef::Mixin::ShellOut | ||
|
||
def self.exists?(localdata) | ||
true if ::File.exist?(localdata) | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK you don't need an def self.exists?(localdata)
::File.exist?(localdata)
end |
||
|
||
def self.file_to_hash(inputfile) | ||
output_entries = {} | ||
passwordfile = File.open(inputfile, File::RDONLY | File::CREAT, 640) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To use octal numbers, you must add a |
||
passwordfile.readlines.each do |line| | ||
user, data = fileline_to_userdb_hash(line) | ||
output_entries[user] = data | ||
end | ||
passwordfile.close | ||
output_entries | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this method can be simplified as follows: def self.file_to_hash(inputfile)
File.open(inputfile, File::RDONLY | File::CREAT, 0640) do |passwordfile|
passwordfile.readlines.each_with_object({}) do |line, output_entries|
user, data = fileline_to_userdb_hash(line)
output_entries[user] = data
end
end
end |
||
|
||
def self.passfile_read(input) | ||
# Returns Password file in userdb style hash and if exists | ||
[file_to_hash(input), exists?(input)] | ||
end | ||
|
||
def self.fileline_to_userdb_hash(input) | ||
# Returns a hash of details daken from the userdb file line | ||
data = [nil] * 7 | ||
if input.strip.split(':').length == 2 | ||
user, data[0] = input.strip.split(':') | ||
else | ||
user = input.strip.split(':')[0] | ||
data = input.strip.split(':')[1..7] | ||
end | ||
[user, data] | ||
end | ||
|
||
def self.dbentry_to_array(key, value) | ||
# Returns an array with 8 values to use with user copy. | ||
if value.is_a?(Array) | ||
[key] + (value + ([nil] * (7 - value.size))) | ||
else | ||
[key, value] + ([nil] * 6) | ||
end | ||
end | ||
|
||
def self.password_valid?(hashed_pw, plaintext_pw) | ||
true unless shell_out( | ||
"/usr/bin/doveadm pw -t '#{hashed_pw}' -p '#{plaintext_pw}'" | ||
).exitstatus != 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same here, no need for the def self.password_valid?(hashed_pw, plaintext_pw)
shell_out("/usr/bin/doveadm pw -t '#{hashed_pw}' -p '#{plaintext_pw}'")
.exitstatus == 0
end |
||
end | ||
|
||
def self.arrays_same?(array1, array2) | ||
true if (array1 - array2).empty? && (array2 - array1).empty? | ||
end | ||
|
||
def self.encrypt_password(plaintextpass) | ||
# Return the password generated by dovecot and remove newline | ||
shell_out("/usr/bin/doveadm pw -s MD5 -p \ | ||
#{plaintextpass}").stdout.tr("\n", '') | ||
end | ||
|
||
def self.generate_userpass(input_creds, plaintextpass, updated, file_exists) | ||
if !input_creds.nil? && file_exists == true | ||
if password_valid?( | ||
input_creds[0], plaintextpass | ||
) | ||
return [input_creds[0], updated] | ||
end | ||
end | ||
[encrypt_password(plaintextpass), true] | ||
end | ||
|
||
def self.compile_users(databag_users, current_users, pwfile_exists, updated, credentials) | ||
databag_users.each do |username, user_details| | ||
current_user = dbentry_to_array(username, user_details) | ||
current_user[1], updated = generate_userpass(current_users[username], current_user[1], updated, pwfile_exists) | ||
credentials.push(current_user) | ||
end | ||
updated | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# | ||
# Cookbook Name:: dovecot | ||
# Recipe:: create_pwfile | ||
# Author:: Xabier de Zuazo (<xabier@zuazo.org>) | ||
# Copyright:: Copyright (c) 2013-2014 Onddo Labs, SL. | ||
# License:: Apache License, Version 2.0 | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
# The file credentials should be like: | ||
# user:password:uid:gid:(gecos):home:(shell):extra_fields | ||
# We ignore gecos and shell, all the others are included in the script but | ||
# uid,gid,home,extra_Fields can be nil | ||
# user:pass:<num>:<num>::<string>::<Extras string> | ||
|
||
# Predefined Variables | ||
credentials = [] | ||
update_credentials = false | ||
|
||
ruby_block 'databag_to_dovecot_userdb' do | ||
block do | ||
passwd_file = node['dovecot']['conf']['password_file'] | ||
databag_users = data_bag_item(node['dovecot']['databag_name'], node['dovecot']['databag_users_item'])['users'] | ||
|
||
# Check if passwd file exists | ||
local_creds, pwfile_exists = DovecotCookbook::Pwfile.passfile_read(passwd_file) | ||
# Check if users on both passwd file and databag are the same | ||
# if not, force credentials update | ||
update_credentials = true unless DovecotCookbook::Pwfile.arrays_same?(databag_users.keys, local_creds.keys) | ||
# Check if users has a changed password, if not change it and force update | ||
update_credentials = DovecotCookbook::Pwfile.compile_users(databag_users, | ||
local_creds, | ||
pwfile_exists, | ||
update_credentials, | ||
credentials) | ||
end | ||
action :run | ||
end | ||
|
||
template node['dovecot']['conf']['password_file'] do | ||
source 'password.erb' | ||
owner node['dovecot']['user'] | ||
group node['dovecot']['group'] | ||
mode '0640' | ||
variables( | ||
credentials: credentials | ||
) | ||
only_if { update_credentials } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is added on my next commit ;) |
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<% @credentials.each do |user, password, uid, gid, gecos, homedir, shell, extra_fields| -%> | ||
<%= user %>:<%= password %>:<%= uid %>:<%= gid %>::<%= homedir %>::<%= extra_fields %> | ||
<% end -%> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add
databag_name
attribute here?Also, adding a example content of the data bag would make its usage easier. The same you used for the tests will be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it better to have it:
node['dovecot']['databag_name']['users_item']
?