def test_min_password_length(self): """Creating a Journalist with a password that is smaller than the minimum password length should raise an exception""" with self.assertRaises(InvalidPasswordLength): temp_journalist = Journalist( username="******", password='******')
def test_max_password_length(self): """Creating a Journalist with a password that is greater than the maximum password length should raise an exception""" overly_long_password = '******' * (Journalist.MAX_PASSWORD_LEN + 1) with self.assertRaises(InvalidPasswordLength): temp_journalist = Journalist(username="******", password=overly_long_password)
def test_min_password_length(self): """Creating a Journalist with a password that is smaller than the minimum password length should raise an exception. This uses the magic number 7 below to get around the "diceware-like" requirement that may cause a failure before the length check. """ password = ('a ' * 7)[0:(Journalist.MIN_PASSWORD_LEN - 1)] with self.assertRaises(InvalidPasswordLength): Journalist(username="******", password=password)
def setUp(self): common.shared_setup() # Patch the two-factor verification to avoid intermittent errors patcher = mock.patch('db.Journalist.verify_token') self.addCleanup(patcher.stop) self.mock_journalist_verify_token = patcher.start() self.mock_journalist_verify_token.return_value = True # Set up test users self.user_pw = "bar" self.user = Journalist(username="******", password=self.user_pw) self.admin_user_pw = "admin" self.admin_user = Journalist(username="******", password=self.admin_user_pw, is_admin=True) db_session.add(self.user) db_session.add(self.admin_user) db_session.commit()
def _add_user(is_admin=False): username = _get_username() print("Note: Journalist passwords are now autogenerated.") password = _make_password() print("This journalist's password is: {}".format(password)) is_hotp = _get_yubikey_usage() otp_secret = None if is_hotp: while True: otp_secret = raw_input( 'Please configure your YubiKey and enter the secret: ') if otp_secret: break try: user = Journalist(username=username, password=password, is_admin=is_admin, otp_secret=otp_secret) db_session.add(user) db_session.commit() except Exception as exc: db_session.rollback() if "UNIQUE constraint failed: journalists.username" in str(exc): print('ERROR: That username is already taken!') else: exc_type, exc_value, exc_traceback = sys.exc_info() print( repr( traceback.format_exception(exc_type, exc_value, exc_traceback))) return 1 else: print('User "{}" successfully added'.format(username)) if not otp_secret: # Print the QR code for FreeOTP/ Google Authenticator print( '\nScan the QR code below with FreeOTP or Google ' 'Authenticator:\n') uri = user.totp.provisioning_uri(username, issuer_name='SecureDrop') qr = qrcode.QRCode() qr.add_data(uri) qr.print_ascii(tty=sys.stdout.isatty()) print( '\nIf the barcode does not render correctly, try changing ' "your terminal's font (Monospace for Linux, Menlo for OS " 'X). If you are using iTerm on Mac OS X, you will need to ' 'change the "Non-ASCII Font", which is your profile\'s Text ' "settings.\n\nCan't scan the barcode? Enter following " 'shared secret ' 'manually:\n{}\n'.format(user.formatted_otp_secret)) return 0
def _journalist_logs_in(self): # Create a test user for logging in test_user_info = dict(username='******', password='******') test_user = Journalist(**test_user_info) db_session.add(test_user) db_session.commit() self._login_user(test_user_info['username'], test_user_info['password'], test_user.totp.now()) headline = self.driver.find_element_by_css_selector('span.headline') self.assertIn('Sources', headline.text)
def admin_add_user(): if request.method == 'POST': form_valid = True username = request.form['username'] if len(username) == 0: form_valid = False flash("Missing username", "error") password = request.form['password'] password_again = request.form['password_again'] if password != password_again: form_valid = False flash("Passwords didn't match", "error") is_admin = bool(request.form.get('is_admin')) if form_valid: try: otp_secret = None if request.form.get('is_hotp', False): otp_secret = request.form.get('otp_secret', '') new_user = Journalist(username=username, password=password, is_admin=is_admin, otp_secret=otp_secret) db_session.add(new_user) db_session.commit() except InvalidPasswordLength: form_valid = False flash( "Your password must be between {} and {} characters.". format(Journalist.MIN_PASSWORD_LEN, Journalist.MAX_PASSWORD_LEN), "error") except IntegrityError as e: db_session.rollback() form_valid = False if "UNIQUE constraint failed: journalists.username" in str(e): flash("That username is already in use", "error") else: flash( "An error occurred saving this user to the database." " Please check the application logs.", "error") app.logger.error("Adding user '{}' failed: {}".format( username, e)) if form_valid: return redirect( url_for('admin_new_user_two_factor', uid=new_user.id)) return render_template("admin_add_user.html")
def add_user(): form = NewUserForm() if form.validate_on_submit(): form_valid = True username = request.form['username'] password = request.form['password'] is_admin = bool(request.form.get('is_admin')) try: otp_secret = None if request.form.get('is_hotp', False): otp_secret = request.form.get('otp_secret', '') new_user = Journalist(username=username, password=password, is_admin=is_admin, otp_secret=otp_secret) db_session.add(new_user) db_session.commit() except PasswordError: flash(gettext( 'There was an error with the autogenerated password. ' 'User not created. Please try again.'), 'error') form_valid = False except InvalidUsernameException as e: form_valid = False flash('Invalid username: '******'{}' failed: {}".format( username, e)) if form_valid: return redirect(url_for('admin.new_user_two_factor', uid=new_user.id)) return render_template("admin_add_user.html", password=make_password(config), form=form)
def admin_add_user(): if request.method == 'POST': form_valid = True username = request.form['username'] if len(username) == 0: form_valid = False flash("Missing username", "error") password = request.form['password'] password_again = request.form['password_again'] if password != password_again: form_valid = False flash("Passwords didn't match", "error") is_admin = bool(request.form.get('is_admin')) if form_valid: try: otp_secret = None if request.form.get('is_hotp', False): otp_secret = request.form.get('otp_secret', '') new_user = Journalist(username=username, password=password, is_admin=is_admin, otp_secret=otp_secret) db_session.add(new_user) db_session.commit() except InvalidPasswordLength: form_valid = False flash( "Your password is too long (maximum length {} characters)". format(Journalist.MAX_PASSWORD_LEN), "error") except IntegrityError as e: form_valid = False if "username is not unique" in str(e): flash("That username is already in use", "error") else: flash("An error occurred saving this user to the database", "error") if form_valid: return redirect( url_for('admin_new_user_two_factor', uid=new_user.id)) return render_template("admin_add_user.html")
def add_admin(): while True: username = raw_input("Username: "******"Sorry, that username is already in use." else: break while True: password = getpass("Password: "******"Confirm Password: "******"Your password is too long (maximum length {} characters). " "Please pick a shorter password.".format( Journalist.MAX_PASSWORD_LEN)) continue if password == password_again: break print "Passwords didn't match!" hotp_input = raw_input("Is this admin using a YubiKey [HOTP]? (y/N): ") otp_secret = None if hotp_input.lower() == "y" or hotp_input.lower() == "yes": while True: otp_secret = raw_input( "Please configure your YubiKey and enter the secret: ") if otp_secret: break try: admin = Journalist(username=username, password=password, is_admin=True, otp_secret=otp_secret) db_session.add(admin) db_session.commit() except Exception, e: if "username is not unique" in str(e): print "ERROR: That username is already taken!" else: print "ERROR: An unexpected error occurred, traceback: \n{}".format( e)
def setUp(self): common.shared_setup() # Patch the two-factor verification so it always succeeds patcher = patch('db.Journalist.verify_token') self.addCleanup(patcher.stop) self.mock_journalist_verify_token = patcher.start() self.mock_journalist_verify_token.return_value = True self.username = "******" self.password = "******" self.user = Journalist(username=self.username, password=self.password) db_session.add(self.user) db_session.commit() # Use a patched login function to avoid dealing with two-factor tokens # (which are being ignored here anyway) self.login = lambda username, password: \ Journalist.login(username, password, "")
def setUp(self): utils.env.setup() self.source_app = source.app.test_client() self.journalist_app = journalist.app.test_client() self.gpg = gnupg.GPG(homedir=config.GPG_KEY_DIR) # Patch the two-factor verification to avoid intermittent errors patcher = mock.patch('db.Journalist.verify_token') self.addCleanup(patcher.stop) self.mock_journalist_verify_token = patcher.start() self.mock_journalist_verify_token.return_value = True # Add a test user to the journalist interface and log them in # print Journalist.query.all() self.user_pw = "longpassword" self.user = Journalist(username="******", password=self.user_pw) db_session.add(self.user) db_session.commit() self._login_user()
def add_admin(): while True: username = raw_input("Username: "******"Sorry, that username is already in use." else: break while True: password = getpass("Password: "******"Confirm Password: "******"Passwords didn't match!" hotp_input = raw_input("Is this admin using a YubiKey [HOTP]? (y/N): ") otp_secret = None if hotp_input.lower() == "y" or hotp_input.lower() == "yes": while True: otp_secret = raw_input( "Please configure your YubiKey and enter the secret: ") if otp_secret: break admin = Journalist(username=username, password=password, is_admin=True, otp_secret=otp_secret) try: db_session.add(admin) db_session.commit() except Exception, e: if "username is not unique" in str(e): print "ERROR: That username is already taken!" else: print "ERROR: An unknown error occurred, traceback:" print e
def _admin_logs_in(self): # Create a test admin user for logging in admin_user_info = dict(username='******', password='******', is_admin=True) admin_user = Journalist(**admin_user_info) db_session.add(admin_user) db_session.commit() # Stash the admin user on self so we can use it in later tests self.admin_user = admin_user_info self.admin_user['orm_obj'] = admin_user self._login_user(admin_user_info['username'], admin_user_info['password'], admin_user.totp.now()) # Admin user should log in to the same interface as a normal user, # since there may be users who wish to be both journalists and admins. headline = self.driver.find_element_by_css_selector('span.headline') self.assertIn('Sources', headline.text) # Admin user should have a link that take them to the admin page links = self.driver.find_elements_by_tag_name('a') self.assertIn('Admin', [el.text for el in links])
def _add_user(is_admin=False): # pragma: no cover while True: username = raw_input('Username: '******'Password: '******'Confirm Password: '******'Your password is too long (maximum length {} characters). ' 'Please pick a shorter ' 'password.'.format(Journalist.MAX_PASSWORD_LEN)) continue if len(password) < Journalist.MIN_PASSWORD_LEN: print('Error: Password needs to be at least {} characters.'.format( Journalist.MIN_PASSWORD_LEN )) continue if password == password_again: break print("Passwords didn't match!") hotp_input = raw_input('Will this user be using a YubiKey [HOTP]? (y/N): ') otp_secret = None if hotp_input.lower() in ('y', 'yes'): while True: otp_secret = raw_input( 'Please configure your YubiKey and enter the secret: ') if otp_secret: break try: user = Journalist(username=username, password=password, is_admin=is_admin, otp_secret=otp_secret) db_session.add(user) db_session.commit() except Exception as exc: db_session.rollback() if "UNIQUE constraint failed: journalists.username" in str(exc): print('ERROR: That username is already taken!') else: exc_type, exc_value, exc_traceback = sys.exc_info() print(repr(traceback.format_exception(exc_type, exc_value, exc_traceback))) return 1 else: print('User "{}" successfully added'.format(username)) if not otp_secret: # Print the QR code for FreeOTP/ Google Authenticator print('\nScan the QR code below with FreeOTP or Google ' 'Authenticator:\n') uri = user.totp.provisioning_uri(username, issuer_name='SecureDrop') qr = qrcode.QRCode() qr.add_data(uri) qr.print_ascii(tty=sys.stdout.isatty()) print('\nIf the barcode does not render correctly, try changing ' "your terminal's font (Monospace for Linux, Menlo for OS " 'X). If you are using iTerm on Mac OS X, you will need to ' 'change the "Non-ASCII Font", which is your profile\'s Text ' "settings.\n\nCan't scan the barcode? Enter following " 'shared secret ' 'manually:\n{}\n'.format(user.formatted_otp_secret)) return 0