Skip to content

Commit 7f0ed96

Browse files
committed
Merge remote-tracking branch 'upstream/master' into release/3.1.0
2 parents 2cd9314 + 24072a9 commit 7f0ed96

File tree

7 files changed

+147
-29
lines changed

7 files changed

+147
-29
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,10 @@ For more information please refer to [MongoDB Authentication Process](http://doc
649649
Plain-text user password (will be hashed)
650650

651651
##### `roles`
652-
Array with user roles. Default: ['dbAdmin']
652+
Array with user roles as string.
653+
Roles will be granted to user's database if no alternative database is explicitly defined.
654+
Example: ['dbAdmin', 'readWrite@other_database']
655+
Default: ['dbAdmin']
653656

654657
### Providers
655658

@@ -697,7 +700,10 @@ Plaintext password of the user.
697700
Name of database. It will be created, if not exists.
698701

699702
##### `roles`
700-
Array with user roles. Default: ['dbAdmin']
703+
Array with user roles as string.
704+
Roles will be granted to user's database if no alternative database is explicitly defined.
705+
Example: ['dbAdmin', 'readWrite@other_database']
706+
Default: ['dbAdmin']
701707

702708
##### `tries`
703709
The maximum amount of two second tries to wait MongoDB startup. Default: 10

lib/facter/is_master.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ def get_options_from_hash_config(config)
1010
result = []
1111

1212
result << "--port #{config['net.port']}" unless config['net.port'].nil?
13-
result << "--ssl --host #{Facter.value(:fqdn)}" if config['net.ssl.mode'] == 'requireSSL'
13+
# use --ssl and --host if:
14+
# - sslMode is "requireSSL"
15+
# - Parameter --sslPEMKeyFile is set
16+
# - Parameter --sslCAFile is set
17+
result << "--ssl --host #{Facter.value(:fqdn)}" if config['net.ssl.mode'] == 'requireSSL' || !config['net.ssl.PEMKeyFile'].nil? || !config['net.ssl.CAFile'].nil?
1418
result << "--sslPEMKeyFile #{config['net.ssl.PEMKeyFile']}" unless config['net.ssl.PEMKeyFile'].nil?
1519
result << "--sslCAFile #{config['net.ssl.CAFile']}" unless config['net.ssl.CAFile'].nil?
1620
result << '--ipv6' unless config['net.ipv6'].nil?
@@ -28,7 +32,11 @@ def get_options_from_keyvalue_config(file)
2832
result = []
2933

3034
result << "--port #{config['port']}" unless config['port'].nil?
31-
result << "--ssl --host #{Facter.value(:fqdn)}" if config['ssl'] == 'requireSSL'
35+
# use --ssl and --host if:
36+
# - sslMode is "requireSSL"
37+
# - Parameter --sslPEMKeyFile is set
38+
# - Parameter --sslCAFile is set
39+
result << "--ssl --host #{Facter.value(:fqdn)}" if config['ssl'] == 'requireSSL' || !config['sslcert'].nil? || !config['sslca'].nil?
3240
result << "--sslPEMKeyFile #{config['sslcert']}" unless config['sslcert'].nil?
3341
result << "--sslCAFile #{config['sslca']}" unless config['sslca'].nil?
3442
result << '--ipv6' unless config['ipv6'].nil?

lib/puppet/provider/mongodb.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ def self.conn_string
8383
first_ip_in_list = bindip.split(',').first
8484
ip_real = case first_ip_in_list
8585
when '0.0.0.0'
86-
'127.0.0.1'
86+
Facter.value(:fqdn)
8787
when %r{\[?::0\]?}
88-
'::1'
88+
Facter.value(:fqdn)
8989
else
9090
first_ip_in_list
9191
end

lib/puppet/provider/mongodb_user/mongodb.rb

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def create
4949
customData: {
5050
createdBy: "Puppet Mongodb_user['#{@resource[:name]}']"
5151
},
52-
roles: @resource[:roles],
52+
roles: role_hashes(@resource[:roles], @resource[:database]),
5353
digestPassword: false
5454
}
5555

@@ -110,14 +110,14 @@ def password=(value)
110110

111111
def roles=(roles)
112112
if db_ismaster
113-
grant = roles - @property_hash[:roles]
113+
grant = to_roles(roles, @resource[:database]) - to_roles(@property_hash[:roles], @resource[:database])
114114
unless grant.empty?
115-
mongo_eval("db.getSiblingDB(#{@resource[:database].to_json}).grantRolesToUser(#{@resource[:username].to_json}, #{grant.to_json})")
115+
mongo_eval("db.getSiblingDB(#{@resource[:database].to_json}).grantRolesToUser(#{@resource[:username].to_json}, #{role_hashes(grant, @resource[:database]).to_json})")
116116
end
117117

118-
revoke = @property_hash[:roles] - roles
118+
revoke = to_roles(@property_hash[:roles], @resource[:database]) - to_roles(roles, @resource[:database])
119119
unless revoke.empty?
120-
mongo_eval("db.getSiblingDB(#{@resource[:database].to_json}).revokeRolesFromUser(#{@resource[:username].to_json}, #{revoke.to_json})")
120+
mongo_eval("db.getSiblingDB(#{@resource[:database].to_json}).revokeRolesFromUser(#{@resource[:username].to_json}, #{role_hashes(revoke, @resource[:database]).to_json})")
121121
end
122122
else
123123
Puppet.warning 'User roles operations are available only from master host'
@@ -128,11 +128,37 @@ def roles=(roles)
128128

129129
def self.from_roles(roles, db)
130130
roles.map do |entry|
131-
if entry['db'] == db
131+
if entry['db'].empty? || entry['db'] == db
132132
entry['role']
133133
else
134134
"#{entry['role']}@#{entry['db']}"
135135
end
136136
end.sort
137137
end
138+
139+
def to_roles(roles, db)
140+
roles.map do |entry|
141+
if entry.include? '@'
142+
entry
143+
else
144+
"#{entry}@#{db}"
145+
end
146+
end
147+
end
148+
149+
def role_hashes(roles, db)
150+
roles.sort.map do |entry|
151+
if entry.include? '@'
152+
{
153+
'role' => entry.gsub(%r{^(.*)@.*$}, '\1'),
154+
'db' => entry.gsub(%r{^.*@(.*)$}, '\1')
155+
}
156+
else
157+
{
158+
'role' => entry,
159+
'db' => db
160+
}
161+
end
162+
end
163+
end
138164
end

lib/puppet/type/mongodb_user.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def initialize(*args)
4040
newproperty(:roles, array_matching: :all) do
4141
desc "The user's roles."
4242
defaultto ['dbAdmin']
43-
newvalue(%r{^\w+$})
43+
newvalue(%r{^\w+(@\w+)?$})
4444

4545
# Pretty output for arrays.
4646
def should_to_s(value)

spec/acceptance/user_spec.rb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,82 @@ class { 'mongodb::server': port => 27018 }
5050
end
5151
end
5252
end
53+
54+
context 'with the basic roles syntax' do
55+
it 'compiles with no errors' do
56+
pp = <<-EOS
57+
class { 'mongodb::server': }
58+
-> class { 'mongodb::client': }
59+
-> mongodb_database { 'testdb': ensure => present }
60+
->
61+
mongodb_user {'testuser':
62+
ensure => present,
63+
password_hash => mongodb_password('testuser', 'passw0rd'),
64+
database => 'testdb',
65+
roles => ['readWrite', 'dbAdmin'],
66+
}
67+
EOS
68+
69+
apply_manifest(pp, catch_failures: true)
70+
apply_manifest(pp, catch_changes: true)
71+
end
72+
73+
it 'creates the user' do
74+
shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r|
75+
expect(r.stdout.chomp).to eq('1')
76+
end
77+
end
78+
end
79+
80+
context 'with the new multidb role syntax' do
81+
it 'compiles with no errors' do
82+
pp = <<-EOS
83+
class { 'mongodb::server': }
84+
-> class { 'mongodb::client': }
85+
-> mongodb_database { 'testdb': ensure => present }
86+
-> mongodb_database { 'testdb2': ensure => present }
87+
->
88+
mongodb_user {'testuser':
89+
ensure => present,
90+
password_hash => mongodb_password('testuser', 'passw0rd'),
91+
database => 'testdb',
92+
roles => ['readWrite', 'dbAdmin'],
93+
}
94+
->
95+
mongodb_user {'testuser2':
96+
ensure => present,
97+
password_hash => mongodb_password('testuser2', 'passw0rd'),
98+
database => 'testdb2',
99+
roles => ['readWrite', 'dbAdmin', 'readWrite@testdb', 'dbAdmin@testdb'],
100+
}
101+
EOS
102+
103+
apply_manifest(pp, catch_failures: true)
104+
apply_manifest(pp, catch_changes: true)
105+
end
106+
107+
it 'allows the testuser' do
108+
shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r|
109+
expect(r.stdout.chomp).to eq('1')
110+
end
111+
end
112+
113+
it 'assigns roles to testuser' do
114+
shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\"); db.getUser(\"testuser\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r|
115+
expect(r.stdout.split(%r{\n})).to contain_exactly('readWrite@testdb', 'dbAdmin@testdb')
116+
end
117+
end
118+
119+
it 'allows the second user to connect to its default database' do
120+
shell("mongo testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\")'") do |r|
121+
expect(r.stdout.chomp).to eq('1')
122+
end
123+
end
124+
125+
it 'assigns roles to testuser2' do
126+
shell("mongo testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\"); db.getUser(\"testuser2\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r|
127+
expect(r.stdout.split(%r{\n})).to contain_exactly('readWrite@testdb2', 'dbAdmin@testdb2', 'readWrite@testdb', 'dbAdmin@testdb')
128+
end
129+
end
130+
end
53131
end

spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
describe Puppet::Type.type(:mongodb_user).provider(:mongodb) do
66
let(:raw_users) do
77
[
8-
{ '_id' => 'admin.root', 'user' => 'root', 'db' => 'admin', 'credentials' => { 'MONGODB-CR' => 'pass', 'SCRAM-SHA-1' => { 'iterationCount' => 10_000, 'salt' => 'salt', 'storedKey' => 'storedKey', 'serverKey' => 'serverKey' } }, 'roles' => [{ 'role' => 'role2', 'db' => 'admin' }, { 'role' => 'role1', 'db' => 'admin' }] }
8+
{ '_id' => 'admin.root', 'user' => 'root', 'db' => 'admin', 'credentials' => { 'MONGODB-CR' => 'pass', 'SCRAM-SHA-1' => { 'iterationCount' => 10_000, 'salt' => 'salt', 'storedKey' => 'storedKey', 'serverKey' => 'serverKey' } }, 'roles' => [{ 'role' => 'role2', 'db' => 'admin' }, { 'role' => 'role3', 'db' => 'user_database' }, { 'role' => 'role1', 'db' => 'admin' }] }
99
].to_json
1010
end
1111

@@ -17,7 +17,7 @@
1717
name: 'new_user',
1818
database: 'new_database',
1919
password_hash: 'pass',
20-
roles: %w[role1 role2],
20+
roles: %w[role1 role2@other_database],
2121
provider: described_class.name
2222
)
2323
end
@@ -56,7 +56,7 @@
5656
"createUser":"new_user",
5757
"pwd":"pass",
5858
"customData":{"createdBy":"Puppet Mongodb_user['new_user']"},
59-
"roles":["role1","role2"],
59+
"roles":[{"role":"role1","db":"new_database"},{"role":"role2","db":"other_database"}],
6060
"digestPassword":false
6161
}
6262
EOS
@@ -114,40 +114,40 @@
114114

115115
describe 'roles' do
116116
it 'returns a sorted roles' do
117-
expect(instance.roles).to eq(%w[role1 role2])
117+
expect(instance.roles).to eq(%w[role1 role2 role3@user_database])
118118
end
119119
end
120120

121121
describe 'roles=' do
122122
it 'changes nothing' do
123-
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2])
123+
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2@other_database])
124124
expect(provider).not_to receive(:mongo_eval)
125-
provider.roles = %w[role1 role2]
125+
provider.roles = %w[role1 role2@other_database]
126126
end
127127

128128
it 'grant a role' do
129-
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2])
129+
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2@other_database])
130130
expect(provider).to receive(:mongo_eval).
131-
with('db.getSiblingDB("new_database").grantRolesToUser("new_user", ["role3"])')
132-
provider.roles = %w[role1 role2 role3]
131+
with('db.getSiblingDB("new_database").grantRolesToUser("new_user", [{"role":"role3","db":"new_database"}])')
132+
provider.roles = %w[role1 role2@other_database role3]
133133
end
134134

135135
it 'revokes a role' do
136-
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2])
136+
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2@other_database])
137137
expect(provider).to receive(:mongo_eval).
138-
with('db.getSiblingDB("new_database").revokeRolesFromUser("new_user", ["role1"])')
139-
provider.roles = ['role2']
138+
with('db.getSiblingDB("new_database").revokeRolesFromUser("new_user", [{"role":"role1","db":"new_database"}])')
139+
provider.roles = ['role2@other_database']
140140
end
141141

142142
# rubocop:disable RSpec/MultipleExpectations
143143
it 'exchanges a role' do
144-
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2])
144+
resource.provider.set(name: 'new_user', ensure: :present, roles: %w[role1 role2@other_database])
145145
expect(provider).to receive(:mongo_eval).
146-
with('db.getSiblingDB("new_database").revokeRolesFromUser("new_user", ["role1"])')
146+
with('db.getSiblingDB("new_database").revokeRolesFromUser("new_user", [{"role":"role1","db":"new_database"}])')
147147
expect(provider).to receive(:mongo_eval).
148-
with('db.getSiblingDB("new_database").grantRolesToUser("new_user", ["role3"])')
148+
with('db.getSiblingDB("new_database").grantRolesToUser("new_user", [{"role":"role3","db":"new_database"}])')
149149

150-
provider.roles = %w[role2 role3]
150+
provider.roles = %w[role2@other_database role3]
151151
end
152152
# rubocop:enable RSpec/MultipleExpectations
153153
end

0 commit comments

Comments
 (0)