def change_password_with_keytab(username, password, keytab, principal, comment=None): """Change a user's Kerberos password using a keytab, subject to username and password validation. :param comment: comment to include in notification email """ validators.validate_username(username, check_exists=True) validators.validate_password(username, password) # try changing using kadmin pexpect cmd = '{kadmin_path} -K {keytab} -p {principal} cpw {username}'.format( kadmin_path=shlex.quote(KADMIN_PATH), keytab=shlex.quote(keytab), principal=shlex.quote(principal), username=shlex.quote(username)) child = pexpect.spawn(cmd, timeout=10) child.expect("{}@OCF.BERKELEY.EDU's Password:"******"Verify password - {}@OCF.BERKELEY.EDU's Password:".format(username)) child.sendline(password) child.expect(pexpect.EOF) output = child.before.decode('utf8') if 'kadmin' in output: raise ValueError('kadmin Error: {}'.format(output)) _notify_password_change(username, comment=comment)
def change_password_with_staffer(username, password, principal, admin_password): """Change a user's Kerberos password using kadmin and a password, subject to username and password validation.""" validators.validate_username(username) validators.validate_password(username, password) # try changing using kadmin pexpect cmd = '{kadmin_path} -p {principal} cpw {username}'.format( kadmin_path=shell.escape_arg(constants.KADMIN_PATH), principal=shell.escape_arg(principal), username=shell.escape_arg(username)) child = pexpect.spawn(cmd, timeout=10) child.expect("{}@OCF.BERKELEY.EDU's Password:"******"Verify password - {}@OCF.BERKELEY.EDU's Password:"******"{}@OCF.BERKELEY.EDU's Password:".format(principal)) child.sendline(admin_password) child.expect(pexpect.EOF) output = child.before.decode('utf8') if 'Looping detected' in output: raise ValueError('Invalid admin password given.') elif 'kadmin' in output: raise ValueError('kadmin Error: {}'.format(output)) _notify_password_change(username)
def change_password_with_keytab(username, password, keytab, principal, comment=None): """Change a user's Kerberos password using a keytab, subject to username and password validation. :param comment: comment to include in notification email """ validators.validate_username(username, check_exists=True) validators.validate_password(username, password) # try changing using kadmin pexpect cmd = '{kadmin_path} -K {keytab} -p {principal} cpw {username}'.format( kadmin_path=shell.escape_arg(constants.KADMIN_PATH), keytab=shell.escape_arg(keytab), principal=shell.escape_arg(principal), username=shell.escape_arg(username)) child = pexpect.spawn(cmd, timeout=10) child.expect("{}@OCF.BERKELEY.EDU's Password:"******"Verify password - {}@OCF.BERKELEY.EDU's Password:" .format(username)) child.sendline(password) child.expect(pexpect.EOF) output = child.before.decode('utf8') if 'kadmin' in output: raise ValueError('kadmin Error: {}'.format(output)) _notify_password_change(username, comment=comment)
def _get_password(request, addr_name): # If addr_name is None, then this is a wildcard address, and those can't # have passwords. if addr_name is None: return REMOVE_PASSWORD password = request.POST.get('password') if password is not None: password = password.strip() if not password: return REMOVE_PASSWORD try: validate_password(addr_name, password, strength_check=True) except ValueError as ex: _error(request, ex.args[0]) else: return crypt_password(password)
def password_matches(username, password): """Returns True if the password matches the user account given""" validators.validate_username(username) validators.validate_password(username, password, strength_check=False) if not validators.user_exists(username): raise ValueError("User doesn't exist") cmd = 'kinit --no-forwardable -l0 {}@OCF.BERKELEY.EDU'.format(username) child = pexpect.spawn(cmd, timeout=10) child.expect("{}@OCF.BERKELEY.EDU's Password:".format(username)) child.sendline(password) child.expect(pexpect.EOF) child.close() return child.exitstatus == 0
def change_password_with_staffer(username, password, principal, admin_password, comment=None): """Change a user's Kerberos password using kadmin and a password, subject to username and password validation. :param comment: comment to include in notification email """ validators.validate_username(username) validators.validate_password(username, password) # try changing using kadmin pexpect cmd = '{kadmin_path} -p {principal} cpw {username}'.format( kadmin_path=shlex.quote(KADMIN_PATH), principal=shlex.quote(principal), username=shlex.quote(username)) child = pexpect.spawn(cmd, timeout=10) child.expect("{}@OCF.BERKELEY.EDU's Password:"******"Verify password - {}@OCF.BERKELEY.EDU's Password:"******"{}@OCF.BERKELEY.EDU's Password:".format(principal)) child.sendline(admin_password) child.expect(pexpect.EOF) output = child.before.decode('utf8') if 'Looping detected' in output: raise ValueError('Invalid admin password given.') elif 'kadmin' in output: raise ValueError('kadmin Error: {}'.format(output)) _notify_password_change(username, comment=comment)
def test_success(self, password): validate_password('ckuehl', password)
def test_failure(self, password): with pytest.raises(ValueError): validate_password('ckuehl', password)
def main(): def pause_error_msg(): input('Press enter to edit group information (or Ctrl-C to exit)...') parser = ArgumentParser(description='Create new OCF group accounts.') parser.add_argument('oid', type=int, nargs='?', help='CalLink OID for the group.') args = parser.parse_args() group_name, callink_oid, email = get_group_information(args.oid) content = TEMPLATE.format(group_name=group_name, callink_oid=callink_oid, email=email) while True: content = edit_file(content) try: account = yaml.safe_load(content) except yaml.YAMLError as ex: print('Error parsing your YAML:') print(ex) pause_error_msg() continue missing_key = False for key in ['user_name', 'group_name', 'callink_oid', 'email']: if account.get(key) is None: print('Missing value for key: ' + key) missing_key = True if missing_key: pause_error_msg() continue try: password = prompt_for_new_password( validator=lambda pwd: validate_password( account['user_name'], pwd), ) except KeyboardInterrupt: # we want to allow cancelling during the "enter password" stage # without completely exiting approve print() pause_error_msg() continue request = make_account_request(account, password) if input('Submit request? [yN] ') not in ('y', 'Y'): pause_error_msg() continue tasks, celery, response = create_account(request) new_request = None if response.status == NewAccountResponse.REJECTED: print( bold( red('Account requested was rejected for the following reasons:' ))) for error in response.errors: print(red(' - {}'.format(error))) pause_error_msg() continue elif response.status == NewAccountResponse.FLAGGED: print( bold( yellow( 'Account requested was flagged for the following reasons:' ))) for error in response.errors: print(yellow(' - {}'.format(error))) print( bold( 'You can either create the account anyway, or go back and ' 'modify the request.')) choice = input('Create the account anyway? [yN] ') if choice in ('y', 'Y'): new_request = request._replace( handle_warnings=NewAccountRequest.WARNINGS_CREATE, ) task = tasks.validate_then_create_account.delay(new_request) response = wait_for_task(celery, task) else: pause_error_msg() continue if response.status == NewAccountResponse.CREATED: print(bold(green('Account created!'))) print('Your account was created successfully.') print('You\'ve been sent an email with more information.') return else: # this shouldn't be possible; we must have entered some weird state error_report(request, new_request, response) pause_error_msg()
def validate_password(username, password): try: validators.validate_password(username, password) except ValueError as ex: raise ValidationError(str(ex))
def main(): def pause_error_msg(): input('Press enter to edit group information (or Ctrl-C to exit)...') parser = ArgumentParser(description='Create new OCF group accounts.') parser.add_argument('oid', type=int, nargs='?', help='CalLink OID for the group.') args = parser.parse_args() group_name, callink_oid, email = get_group_information(args.oid) content = TEMPLATE.format( group_name=group_name, callink_oid=callink_oid, email=email ) while True: content = edit_file(content) try: account = yaml.safe_load(content) except yaml.YAMLError as ex: print('Error parsing your YAML:') print(ex) pause_error_msg() continue missing_key = False for key in ['user_name', 'group_name', 'callink_oid', 'email']: if account.get(key) is None: print('Missing value for key: ' + key) missing_key = True if missing_key: pause_error_msg() continue try: password = prompt_for_new_password( validator=lambda pwd: validate_password( account['user_name'], pwd), ) except KeyboardInterrupt: # we want to allow cancelling during the "enter password" stage # without completely exiting approve print() pause_error_msg() continue request = make_account_request(account, password) if input('Submit request? [yN] ') not in ('y', 'Y'): pause_error_msg() continue tasks, celery, response = create_account(request) new_request = None if response.status == NewAccountResponse.REJECTED: print(bold(red( 'Account requested was rejected for the following reasons:' ))) for error in response.errors: print(red(' - {}'.format(error))) pause_error_msg() continue elif response.status == NewAccountResponse.FLAGGED: print(bold(yellow( 'Account requested was flagged for the following reasons:' ))) for error in response.errors: print(yellow(' - {}'.format(error))) print(bold( 'You can either create the account anyway, or go back and ' 'modify the request.' )) choice = input('Create the account anyway? [yN] ') if choice in ('y', 'Y'): new_request = request._replace( handle_warnings=NewAccountRequest.WARNINGS_CREATE, ) task = tasks.validate_then_create_account.delay(new_request) response = wait_for_task(celery, task) else: pause_error_msg() continue if response.status == NewAccountResponse.CREATED: print(bold(green('Account created!'))) print('Your account was created successfully.') print('You\'ve been sent an email with more information.') return else: # this shouldn't be possible; we must have entered some weird state error_report(request, new_request, response) pause_error_msg()
def test_success(self, password): validate_password("ckuehl", password)
def test_failure(self, password): with pytest.raises(ValueError): validate_password("ckuehl", password)
def main(): def_group_name = '' def_callink_oid = '' def_email = '' parser = ArgumentParser(description='Create new OCF group accounts.') parser.add_argument('oid', type=int, nargs='?', help='CalLink OID for the group.') args = parser.parse_args() if args.oid: group = group_by_oid(args.oid) if not group: print(red('No group with OID {}').format(args.oid)) return if group['accounts']: print(yellow( 'Warning: there is an existing group account with OID {}: {}'.format( args.oid, ', '.join(group['accounts']), ), )) input('Press any key to continue...') def_group_name = group['name'] def_callink_oid = args.oid def_email = group['email'] content = TEMPLATE.format( group_name=def_group_name, callink_oid=def_callink_oid, email=def_email ) while True: content = edit_file(content) try: account = yaml.safe_load(content) except yaml.YAMLError as ex: print('Error parsing your YAML:') print(ex) input('Press enter to continue...') continue missing_key = False for key in ['user_name', 'group_name', 'callink_oid', 'email']: if account.get(key) is None: print('Missing value for key: ' + key) missing_key = True if missing_key: input('Press enter to continue...') continue try: password = prompt_for_new_password( validator=lambda pwd: validate_password( account['user_name'], pwd), ) except KeyboardInterrupt: # we want to allow cancelling during the "enter password" stage # without completely exiting approve print() input('Press enter to start over (or ^C again to cancel)...') continue request = NewAccountRequest( user_name=account['user_name'], real_name=account['group_name'], is_group=True, calnet_uid=None, callink_oid=account['callink_oid'], email=account['email'], encrypted_password=encrypt_password( password, RSA.importKey(CREATE_PUBLIC_KEY), ), handle_warnings=NewAccountRequest.WARNINGS_WARN, ) print() print(bold('Pending account request:')) print(dedent( """\ User Name: {request.user_name} Group Name: {request.real_name} CalLink OID: {request.callink_oid} Email: {request.email} """ ).format(request=request)) if input('Submit request? [yN] ') != 'y': input('Press enter to continue.') continue conf = ConfigParser() conf.read('/etc/ocf-create/ocf-create.conf') celery = Celery( broker=conf.get('celery', 'broker'), backend=conf.get('celery', 'backend'), ) tasks = get_tasks(celery) task = tasks.validate_then_create_account.delay(request) response = wait_for_task(celery, task) new_request = None if response.status == NewAccountResponse.REJECTED: print(bold(red( 'Account requested was rejected for the following reasons:' ))) for error in response.errors: print(red(' - {}'.format(error))) input('Press enter to start over (or ^C to cancel)...') continue elif response.status == NewAccountResponse.FLAGGED: print(bold(yellow( 'Account requested was flagged for the following reasons:' ))) for error in response.errors: print(yellow(' - {}'.format(error))) print(bold( 'You can either create the account anyway, or go back and ' 'modify the request.' )) choice = input('Create the account anyway? [yN] ') if choice in ('y', 'Y'): new_request = request._replace( handle_warnings=NewAccountRequest.WARNINGS_CREATE, ) task = tasks.validate_then_create_account.delay(new_request) response = wait_for_task(celery, task) else: input('Starting over, press enter to continue...') continue if response.status == NewAccountResponse.CREATED: print(bold(green('Account created!'))) print('Your account was created successfully.') print('You\'ve been sent an email with more information.') return else: # this shouldn't be possible; we must have entered some weird state # TODO: report via ocflib print(bold(red('Error: Entered unexpected state.'))) print(red('The request we submitted was:')) print(red(request)) print(red('The new request we submitted (if any) was:')) print(red(new_request)) print(red('The response we received was:')) print(red(response)) print(bold(red('Not really sure what to do here, sorry.'))) input('Press enter to start over...')