Skip to content

Commit d62a078

Browse files
authored
Merge pull request #81 from bartowl/bugfix/issue_79
update password really only when needed with update_password=always + support for password_hash
2 parents f3a07f1 + a54814b commit d62a078

File tree

2 files changed

+45
-46
lines changed

2 files changed

+45
-46
lines changed

library/oracle_user

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ oracle_user: hostname=localhost service_name=orcl user=system password=manager s
110110
111111
'''
112112

113+
import hashlib
114+
from binascii import unhexlify
115+
113116
try:
114117
import cx_Oracle
115118
except ImportError:
@@ -160,7 +163,7 @@ def create_user(module, cursor, schema, schema_password, schema_password_hash, d
160163

161164
if authentication_type == 'password':
162165
if (schema_password_hash):
163-
sql = 'create user %s identified by values \"%s\" ' % (schema, schema_password_hash)
166+
sql = 'create user %s identified by values \'%s\' ' % (schema, schema_password_hash)
164167
else:
165168
sql = 'create user %s identified by \"%s\" '% (schema, schema_password)
166169
elif authentication_type == 'global':
@@ -205,7 +208,7 @@ def create_user(module, cursor, schema, schema_password, schema_password_hash, d
205208

206209
# Get the current password hash for the user
207210
def get_user_password_hash(module, cursor, schema):
208-
sql = 'select password from sys.user$ where name = upper(\'%s\')' % schema
211+
sql = 'select spare4 from sys.user$ where name = upper(\'%s\')' % schema
209212
try:
210213
cursor.execute(sql)
211214
pwhashresult = cursor.fetchone()[0]
@@ -216,18 +219,40 @@ def get_user_password_hash(module, cursor, schema):
216219

217220
return pwhashresult
218221

222+
# Check plaintext password against retrieved hash
223+
# currently works with S: hashes only, returns true otherwise
224+
def password_matches_hash(password,password_hash):
225+
# S: style hash
226+
if ('S:' in password_hash):
227+
for ch in password_hash.split('S:')[1][:60].upper():
228+
if((ch < '0' or ch > '9') and (ch < 'A' or ch > 'F')):
229+
return False # not a valid hex string character found, should not happen
230+
hash=password_hash.split('S:')[1][:40]
231+
salt=password_hash.split('S:')[1][40:60]
232+
sha1 = hashlib.sha1()
233+
sha1.update(password.encode('utf-8'))
234+
sha1.update(unhexlify(salt))
235+
return hash.upper() == sha1.hexdigest().upper()
236+
237+
# no supported hashes found
238+
return False
239+
219240
# Modify the user/schema
220241
def modify_user(module, cursor, schema, schema_password, schema_password_hash, default_tablespace, default_temp_tablespace, update_password, profile, authentication_type, state, container_data):
221242

222243
sql_get_curr_def = 'select lower(account_status)'
223244
sql = 'alter user %s' % schema
245+
pw_change_needed = False
224246

225247
if update_password == 'always':
226248
if authentication_type == 'password':
227-
if schema_password_hash:
249+
old_pw_hash = get_user_password_hash(module, cursor, schema)
250+
if (schema_password_hash and (old_pw_hash != schema_password_hash)):
251+
pw_change_needed = True
228252
sql += ' identified by values \'%s\'' % (schema_password_hash)
229-
elif schema_password:
230-
sql += ' identified by %s ' % (schema_password)
253+
elif schema_password and not password_matches_hash(schema_password,old_pw_hash):
254+
pw_change_needed = True
255+
sql += ' identified by \"%s\" ' % (schema_password)
231256
elif authentication_type == 'external':
232257
sql += ' identified externally '
233258
sql_get_curr_def += ' ,lower(authentication_type)'
@@ -283,47 +308,21 @@ def modify_user(module, cursor, schema, schema_password, schema_password_hash, d
283308

284309
sql_get_curr_def += ' from dba_users where username = upper(\'%s\')' % schema
285310

286-
if update_password == 'always':
287-
old_pw_hash = get_user_password_hash(module, cursor, schema)
288-
289311
wanted_list = [x.lower() for x in wanted_list]
290312
curr_defaults = execute_sql_get(module, cursor, sql_get_curr_def)
291313
curr_defaults = [list(t) for t in curr_defaults]
292314

293-
if (schema_password_hash):
294-
if update_password == 'always':
295-
# if (wanted_list in curr_defaults) and (old_pw_hash == schema_password_hash):
296-
# # Everything is kosher, exit changed=False
297-
# module.exit_json(msg='The schema (%s) is in the intented state' % (schema), changed=False)
298-
# else:
299-
# # Make the change and exit changed=True
300-
execute_sql(module, cursor, sql)
301-
module.exit_json(msg='Successfully altered the user (%s)' % (schema), changed=True)
315+
if (wanted_list in curr_defaults):
316+
if (update_password == 'always' and pw_change_needed):
317+
execute_sql(module, cursor, sql)
318+
module.exit_json(msg='Successfully altered the user password (%s)' % (schema), changed=True)
302319
else:
303-
if (wanted_list in curr_defaults):
304-
module.exit_json(msg='The schema (%s) is in the intented state' % (schema), changed=False)
305-
else:
306-
# Make the change and exit changed=Truecontainer = module.params["container"]
307-
execute_sql(module, cursor, sql)
308-
module.exit_json(msg='Successfully altered the user (%s)' % (schema), changed=True)
320+
module.exit_json(msg='The schema (%s) is in the intented state' % (schema), changed=False)
309321
else:
310-
if (wanted_list in curr_defaults):
311-
if update_password == 'always':
312-
## DISABLING THE PRE/POST-CHECK
313-
# change everything and compare hash pre/post. If same => exit change=False else exit change=True
314-
execute_sql(module, cursor, sql)
315-
# new_pw_hash = get_user_password_hash(module, cursor, schema)
316-
# if new_pw_hash == old_pw_hash:
317-
# module.exit_json(msg='The schema (%s) is in the intented state' % (schema), changed=False)
318-
# else:
319-
module.exit_json(msg='Successfully altered the user (%s)' % (schema), changed=True)
320-
else:
321-
module.exit_json(msg='The schema (%s) is in the intented state' % (schema), changed=False)
322-
else:
323-
# do the complete change -> exit with change=True
324-
# module.exit_json(msg=sql)
325-
execute_sql(module, cursor, sql)
326-
module.exit_json(msg='Successfully altered the user (%s, %s)' % (schema, sql), changed=True)
322+
# do the complete change -> exit with change=True
323+
# module.exit_json(msg=sql)
324+
execute_sql(module, cursor, sql)
325+
module.exit_json(msg='Successfully altered the user (%s, %s)' % (schema, sql), changed=True)
327326

328327
return True
329328

roles/oradb-manage-users/tasks/main.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
password={{ db_password_cdb }}
1111
mode="{{ db_mode }}"
1212
schema={{ item.1.schema }}
13-
schema_password={{ user_cdb_password }}
14-
schema_password_hash={{ user_cdb_password_hash | default(omit) }}
13+
schema_password={{ item.1.password_is_hash | default(false) | ternary(omit,user_cdb_password) }}
14+
schema_password_hash={{ item.1.password_is_hash | default(false) | ternary(user_cdb_password,omit) }}
1515
profile={{ item.1.profile | default (omit) }}
1616
state={{ item.1.state }}
1717
default_tablespace={{ item.1.default_tablespace | default (omit) }}
1818
default_temp_tablespace={{ item.1.default_temp_tablespace | default (omit) }}
1919
container={{ item.1.container | default(omit) }}
20-
update_password={{ item.1.update_password | default('on_create') }}
20+
update_password={{ item.1.update_password | default(omit) }}
2121
authentication_type={{ item.1.authentication_type | default(omit) }}
2222
grants={{ item.1.grants | default (omit) }}
2323
with_subelements:
@@ -45,13 +45,13 @@
4545
password={{ db_password_pdb }}
4646
mode="{{ db_mode }}"
4747
schema={{ item.1.schema }}
48-
schema_password={{ user_pdb_password }}
49-
schema_password_hash={{ user_pdb_password_hash | default(omit) }}
48+
schema_password={{ item.1.password_is_hash | default(false) | ternary(omit,user_pdb_password) }}
49+
schema_password_hash={{ item.1.password_is_hash | default(false) | ternary(user_pdb_password,omit) }}
5050
profile={{ item.1.profile | default (omit) }}
5151
state={{ item.1.state }}
5252
default_tablespace={{ item.1.default_tablespace | default (omit) }}
5353
default_temp_tablespace={{ item.1.default_temp_tablespace | default (omit) }}
54-
update_password={{ item.1.update_password | default('on_create') }}
54+
update_password={{ item.1.update_password | default(omit) }}
5555
authentication_type={{ item.1.authentication_type | default(omit) }}
5656
grants={{ item.1.grants | default (omit) }}
5757
with_subelements:

0 commit comments

Comments
 (0)