@@ -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+
113116try :
114117 import cx_Oracle
115118except 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
207210def 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
220241def 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
0 commit comments