def _init_db(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format(error.__class__.__name__)) alice = db_models.User(id='alice', otp_secret='secret') calie = db_models.User(id='calie', otp_secret='secret') session = db_manager.Session() session.add(alice) session.add(calie) session.commit() session.close()
def rpc_login(self, session, username, password, otp=None): logger = logging.getLogger('KingPhisher.Server.Authentication') if not ipaddress.ip_address(self.client_address[0]).is_loopback: logger.warning("failed login request from {0} for user {1}, (invalid source address)".format(self.client_address[0], username)) raise ValueError('invalid source address for login') fail_default = (False, ConnectionErrorReason.ERROR_INVALID_CREDENTIALS, None) fail_otp = (False, ConnectionErrorReason.ERROR_INVALID_OTP, None) if not (username and password): logger.warning("failed login request from {0} for user {1}, (missing username or password)".format(self.client_address[0], username)) return fail_default if not self.server.forked_authenticator.authenticate(username, password): logger.warning("failed login request from {0} for user {1}, (authentication failed)".format(self.client_address[0], username)) return fail_default user = db_manager.get_row_by_id(session, db_models.User, username) if not user: logger.info('creating new user object with id: ' + username) user = db_models.User(id=username) session.add(user) session.commit() elif user.otp_secret: if otp is None: logger.debug("failed login request from {0} for user {1}, (missing otp)".format(self.client_address[0], username)) return fail_otp if not (isinstance(otp, str) and len(otp) == 6 and otp.isdigit()): logger.warning("failed login request from {0} for user {1}, (invalid otp)".format(self.client_address[0], username)) return fail_otp totp = pyotp.TOTP(user.otp_secret) now = datetime.datetime.now() if not otp in (totp.at(now + datetime.timedelta(seconds=offset)) for offset in (0, -30, 30)): logger.warning("failed login request from {0} for user {1}, (invalid otp)".format(self.client_address[0], username)) return fail_otp logger.info("successful login request from {0} for user {1}".format(self.client_address[0], username)) return True, ConnectionErrorReason.SUCCESS, self.server.session_manager.put(username)
def setUp(self): username = '******' self._session = db_manager.Session() self.user = self._session.query( db_models.User).filter_by(name=username).first() if self.user is None: self.user = db_models.User(name=username) self._session.add(self.user) self._session.commit()
def rpc_test_login(self, username, password, otp=None): session = db_manager.Session() user = session.query(db_models.User).filter_by(name=username).first() if not user: user = db_models.User(name=username) user.last_login = db_models.current_timestamp() session.add(user) session.commit() session_id = self.server.session_manager.put(user) session.close() return True, constants.ConnectionErrorReason.SUCCESS, session_id
def test_get_row_by_id(self): self._init_db() session = db_manager.Session() user = db_models.User(id='alice') session.add(user) campaign_name = random_string(10) campaign = db_models.Campaign(name=campaign_name, user_id=user.id) session.add(campaign) session.commit() self.assertIsNotNone(campaign.id) campaign_id = campaign.id del campaign row = db_manager.get_row_by_id(session, db_models.Campaign, campaign_id) self.assertEqual(row.id, campaign_id) self.assertEqual(row.name, campaign_name)
def rpc_client_initialize(self): """ Initialize any client information necessary. :return: This method always returns True. :rtype: bool """ username = self.basic_auth_user if not username: return True session = db_manager.Session() if not db_manager.get_row_by_id(session, db_models.User, username): user = db_models.User(id=username) session.add(user) session.commit() session.close() return True
def rpc_login(handler, session, username, password, otp=None): logger = logging.getLogger('KingPhisher.Server.Authentication') if not ipaddress.ip_address(handler.client_address[0]).is_loopback: logger.warning("failed login request from {0} for user {1}, (invalid source address)".format(handler.client_address[0], username)) raise ValueError('invalid source address for login') fail_default = (False, ConnectionErrorReason.ERROR_INVALID_CREDENTIALS, None) fail_otp = (False, ConnectionErrorReason.ERROR_INVALID_OTP, None) if not (username and password): logger.warning("failed login request from {0} for user {1}, (missing username or password)".format(handler.client_address[0], username)) return fail_default if not handler.server.forked_authenticator.authenticate(username, password): logger.warning("failed login request from {0} for user {1}, (authentication failed)".format(handler.client_address[0], username)) return fail_default user = session.query(db_models.User).filter_by(name=username).first() if not user: logger.info('creating new user object with name: ' + username) user = db_models.User(name=username) elif user.has_expired: logger.warning("failed login request from {0} for user {1}, (user has expired)".format(handler.client_address[0], username)) return fail_default elif user.otp_secret: if otp is None: logger.debug("failed login request from {0} for user {1}, (missing otp)".format(handler.client_address[0], username)) return fail_otp if not (isinstance(otp, str) and len(otp) == 6 and otp.isdigit()): logger.warning("failed login request from {0} for user {1}, (invalid otp)".format(handler.client_address[0], username)) return fail_otp totp = pyotp.TOTP(user.otp_secret) now = datetime.datetime.now() if otp not in (totp.at(now + datetime.timedelta(seconds=offset)) for offset in (0, -30, 30)): logger.warning("failed login request from {0} for user {1}, (invalid otp)".format(handler.client_address[0], username)) return fail_otp user.last_login = db_models.current_timestamp() session.add(user) session.commit() session_id = handler.server.session_manager.put(user) logger.info("successful login request from {0} for user {1}".format(handler.client_address[0], username)) signals.send_safe('rpc-user-logged-in', logger, handler, session=session_id, name=username) return True, ConnectionErrorReason.SUCCESS, session_id
def main(): parser = argparse.ArgumentParser( description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') parser.add_argument('--force', dest='force', action='store_true', default=False, help='create the user if necessary') parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret') if has_qrcode: parser.add_argument('--qrcode', dest='qrcode_filename', help='generate a qrcode image file') parser.add_argument('user', help='the user to mange') parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform') parser.epilog = PARSER_EPILOG arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = yaml.load(arguments.server_config) database_connection_url = server_config['server']['database'] else: raise RuntimeError('no database connection was specified') manager.init_database(database_connection_url) session = manager.Session() user = session.query(models.User).filter_by(id=arguments.user).first() if not user: if not arguments.force: color.print_error("invalid user id: {0}".format(arguments.user)) return user = models.User(id=arguments.user) session.add(user) color.print_status('the specified user was created') for case in utilities.switch(arguments.action): if case('remove'): user.otp_secret = None break if case('set'): if user.otp_secret: color.print_error( "the specified user already has an otp secret set") return if arguments.otp_secret: new_otp = arguments.otp_secret else: new_otp = pyotp.random_base32() if len(new_otp) != 16: color.print_error("invalid otp secret length, must be 16") return user.otp_secret = new_otp break if user.otp_secret: color.print_status("user: {0} otp: {1}".format(user.id, user.otp_secret)) totp = pyotp.TOTP(user.otp_secret) uri = totp.provisioning_uri(user.id + '@king-phisher') + '&issuer=King%20Phisher' color.print_status("provisioning uri: {0}".format(uri)) if has_qrcode and arguments.qrcode_filename: img = qrcode.make(uri) img.save(arguments.qrcode_filename) color.print_status("wrote qrcode image to: " + arguments.qrcode_filename) else: color.print_status("user: {0} otp: N/A".format(user.id)) session.commit()
def test_models_convert_to_dictionaries(self): model = db_models.User(name='alice') dictionary = model.to_dict() self.assertIsInstance(dictionary, dict) self.assertIn('name', dictionary)
def test_users_dont_default_to_admin(self): user = db_models.User(name='alice') self.assertFalse(user.is_admin)