<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Licensed to Cloudera, Inc. under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  Cloudera, Inc. licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from future import standard_library
standard_library.install_aliases()
from builtins import object
import json
import ldap
import re
import sys
import time
import urllib.request, urllib.parse, urllib.error

from nose.plugins.skip import SkipTest
from nose.tools import assert_true, assert_equal, assert_false, assert_not_equal
from datetime import datetime
from django.contrib.sessions.models import Session
from django.db.models import Q
from django.urls import reverse
from django.test import override_settings
from django.test.client import Client

import desktop.conf

from desktop import appmanager
from desktop.auth.backend import is_admin
from desktop.conf import APP_BLACKLIST
from desktop.lib.django_test_util import make_logged_in_client
from desktop.lib.test_utils import grant_access
from desktop.views import home
from hadoop import pseudo_hdfs4
from hadoop.pseudo_hdfs4 import is_live_cluster

import useradmin.conf
import useradmin.ldap_access
from useradmin.forms import UserChangeForm
from useradmin.middleware import ConcurrentUserSessionMiddleware
from useradmin.models import HuePermission, GroupPermission, UserProfile, get_profile, get_default_user_group, User, Group
from useradmin.hue_password_policy import reset_password_policy

if sys.version_info[0] > 2:
  from django.utils.encoding import smart_text as smart_unicode
else:
  from django.utils.encoding import smart_unicode


def reset_all_users():
  """Reset to a clean state by deleting all users"""
  for user in User.objects.all():
    user.delete()


def reset_all_groups():
  """Reset to a clean state by deleting all groups"""

  useradmin.conf.DEFAULT_USER_GROUP.set_for_testing(None)
  for grp in Group.objects.all():
    grp.delete()


class LdapTestConnection(object):
  """
  Test class which mimics the behaviour of LdapConnection (from ldap_access.py).
  It also includes functionality to fake modifications to an LDAP server.  It is designed
  as a singleton, to allow for changes to persist across discrete connections.

  This class assumes uid is the user_name_attr.
  """
  def __init__(self):
    self._instance = LdapTestConnection.Data()

  def add_user_group_for_test(self, user, group):
    self._instance.groups[group]['members'].append(user)

  def remove_user_group_for_test(self, user, group):
    self._instance.groups[group]['members'].remove(user)

  def add_posix_user_group_for_test(self, user, group):
    self._instance.groups[group]['posix_members'].append(user)

  def remove_posix_user_group_for_test(self, user, group):
    self._instance.groups[group]['posix_members'].remove(user)

  def find_users(self, username_pattern, search_attr=None, user_name_attr=None, find_by_dn=False, scope=ldap.SCOPE_SUBTREE):
    """ Returns info for a particular user via a case insensitive search """
    if find_by_dn:
      data = [attrs for attrs in list(self._instance.users.values()) if attrs['dn'] == username_pattern]
    else:
      username_pattern = "^%s$" % username_pattern.replace('.','\\.').replace('*', '.*')
      username_fsm = re.compile(username_pattern, flags=re.I)
      usernames = [username for username in list(self._instance.users.keys()) if username_fsm.match(username)]
      data = [self._instance.users.get(username) for username in usernames]
    return data

  def find_groups(self, groupname_pattern, search_attr=None, group_name_attr=None, group_member_attr=None, group_filter=None, find_by_dn=False, scope=ldap.SCOPE_SUBTREE):
    """ Return all groups in the system with parents and children """
    if find_by_dn:
      data = [attrs for attrs in list(self._instance.groups.values()) if attrs['dn'] == groupname_pattern]
      # SCOPE_SUBTREE means we return all sub-entries of the desired entry along with the desired entry.
      if data and scope == ldap.SCOPE_SUBTREE:
        sub_data = [attrs for attrs in list(self._instance.groups.values()) if attrs['dn'].endswith(data[0]['dn'])]
        data.extend(sub_data)
    else:
      groupname_pattern = "^%s$" % groupname_pattern.replace('.','\\.').replace('*', '.*')
      groupnames = [username for username in list(self._instance.groups.keys()) if re.match(groupname_pattern, username)]
      data = [self._instance.groups.get(groupname) for groupname in groupnames]
    return data

  def find_members_of_group(self, dn, search_attr, ldap_filter, scope=ldap.SCOPE_SUBTREE):
    members = []
    for group_info in self._instance.groups:
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    members = set(members)
    users = []
    for user_info in self._instance.users:
      if user_info['dn'] in members:
        users.append(user_info)

    groups = []
    for group_info in self._instance.groups:
      if group_info['dn'] in members:
        groups.append(group_info)

    return users + groups

  def find_users_of_group(self, dn):
    members = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    members = set(members)
    users = []
    for user_info in list(self._instance.users.values()):
      if user_info['dn'] in members:
        users.append(user_info)

    return users

  def find_groups_of_group(self, dn):
    members = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    groups = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] in members:
        groups.append(group_info)

    return groups

  class Data(object):
    def __init__(self):
      self.users = {
        'moe': {'dn': 'uid=moe,ou=People,dc=example,dc=com', 'username':'moe', 'first':'Moe', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'lårry': {'dn': 'uid=lårry,ou=People,dc=example,dc=com', 'username':'lårry', 'first':'Larry', 'last':'Stooge', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com', 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'curly': {'dn': 'uid=curly,ou=People,dc=example,dc=com', 'username':'curly', 'first':'Curly', 'last':'Stooge', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com', 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'Rock': {'dn': 'uid=Rock,ou=People,dc=example,dc=com', 'username':'Rock', 'first':'rock', 'last':'man', 'email':'<EMAIL>', 'groups': ['cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'nestedguy': {'dn': 'uid=nestedguy,ou=People,dc=example,dc=com', 'username':'nestedguy', 'first':'nested', 'last':'guy', 'email':'<EMAIL>', 'groups': ['cn=NestedGroup,ou=Groups,dc=example,dc=com']},
        'otherguy': {'dn': 'uid=otherguy,ou=People,dc=example,dc=com', 'username':'otherguy', 'first':'Other', 'last':'Guy', 'email':'<EMAIL>'},
        'posix_person': {'dn': 'uid=posix_person,ou=People,dc=example,dc=com', 'username': 'posix_person', 'first': 'pos', 'last': 'ix', 'email': '<EMAIL>'},
        'posix_person2': {'dn': 'uid=posix_person2,ou=People,dc=example,dc=com', 'username': 'posix_person2', 'first': 'pos', 'last': 'ix', 'email': '<EMAIL>'},
        'user with space': {'dn': 'uid=user with space,ou=People,dc=example,dc=com', 'username': 'user with space', 'first': 'user', 'last': 'space', 'email': '<EMAIL>'},
        'spaceless': {'dn': 'uid=user without space,ou=People,dc=example,dc=com', 'username': 'spaceless', 'first': 'user', 'last': 'space', 'email': '<EMAIL>'},
        'test_toolongusernametoolongusername': {'dn': 'uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com', 'username': 'test_toolongusernametoolongusername', 'first': 'toolong', 'last': 'username', 'email': '<EMAIL>'},
        'test_longfirstname': {'dn': 'uid=test_longfirstname,ou=People,dc=example,dc=com', 'username': 'test_longfirstname', 'first': 'test_longfirstname_test_longfirstname', 'last': 'username', 'email': '<EMAIL>'},}

      self.groups = {
        'TestUsers': {
          'dn': 'cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'TestUsers',
          'members':['uid=moe,ou=People,dc=example,dc=com','uid=lårry,ou=People,dc=example,dc=com','uid=curly,ou=People,dc=example,dc=com','uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com'],
          'posix_members':[]},
        'Test Administrators': {
          'dn': 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'Test Administrators',
          'members':['uid=Rock,ou=People,dc=example,dc=com','uid=lårry,ou=People,dc=example,dc=com','uid=curly,ou=People,dc=example,dc=com','uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com'],
          'posix_members':[]},
        'OtherGroup': {
          'dn': 'cn=OtherGroup,cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'OtherGroup',
          'members':[],
          'posix_members':[]},
        'NestedGroups': {
          'dn': 'cn=NestedGroups,ou=Groups,dc=example,dc=com',
          'name':'NestedGroups',
          'members':['cn=NestedGroup,ou=Groups,dc=example,dc=com'],
          'posix_members':[]
        },
        'NestedGroup': {
          'dn': 'cn=NestedGroup,ou=Groups,dc=example,dc=com',
          'name':'NestedGroup',
          'members':['uid=nestedguy,ou=People,dc=example,dc=com'],
          'posix_members':[]
        },
        'NestedPosixGroups': {
          'dn': 'cn=NestedPosixGroups,ou=Groups,dc=example,dc=com',
          'name':'NestedPosixGroups',
          'members':['cn=PosixGroup,ou=Groups,dc=example,dc=com'],
          'posix_members':[]
        },
        'PosixGroup': {
          'dn': 'cn=PosixGroup,ou=Groups,dc=example,dc=com',
          'name':'PosixGroup',
          'members':[],
          'posix_members':['posix_person','lårry']},
        'PosixGroup1': {
          'dn': 'cn=PosixGroup1,cn=PosixGroup,ou=Groups,dc=example,dc=com',
          'name':'PosixGroup1',
          'members':[],
          'posix_members':['posix_person2']},
        }


def test_invalid_username():
  BAD_NAMES = ('-foo', 'foo:o', 'foo o', ' foo')

  c = make_logged_in_client(username="test", is_superuser=True)

  for bad_name in BAD_NAMES:
    assert_true(c.get('/useradmin/users/new'))
    response = c.post('/useradmin/users/new', dict(username=bad_name, password1="<PASSWORD>", password2="<PASSWORD>"))
    assert_true('not allowed' in response.context[0]["form"].errors['username'][0])


class BaseUserAdminTests(object):

  @classmethod
  def setUpClass(cls):
    cls._class_resets = [
      useradmin.conf.DEFAULT_USER_GROUP.set_for_testing(None),
    ]

  @classmethod
  def tearDownClass(cls):
    for reset in cls._class_resets:
      reset()

  def setUp(self):
    reset_all_users()
    reset_all_groups()

  def tearDown(self):
    pass


class TestUserProfile(BaseUserAdminTests):

  @override_settings(AUTHENTICATION_BACKENDS=['desktop.auth.backend.AllowFirstUserDjangoBackend'])
  def test_get_profile(self):
    '''Ensure profiles are created after get_profile is called.'''
    c = make_logged_in_client(username='test', password='<PASSWORD>', is_superuser=True, recreate=True)
    assert_equal(0, UserProfile.objects.count())
    p = get_profile(User.objects.get(username='test'))
    assert_equal(1, UserProfile.objects.count())


  @override_settings(AUTHENTICATION_BACKENDS=['desktop.auth.backend.AllowFirstUserDjangoBackend'])
  def test_get_and_update_profile(self):
    c = make_logged_in_client(username='test', password='<PASSWORD>', is_superuser=False, recreate=True)

    user = User.objects.get(username='test')
    userprofile = get_profile(user)
    assert_false(userprofile.data.get('language_preference'))

    userprofile.update_data({'language_preference': 'en'})
    userprofile.save()
    assert_equal('en', userprofile.data['language_preference'])

    userprofile.update_data({'language_preference': 'es'})
    userprofile.save()
    assert_equal('es', userprofile.data['language_preference'])<commit_msg>HUE-8758 [auth] Update test_get_profile to be more robust<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Licensed to Cloudera, Inc. under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  Cloudera, Inc. licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from future import standard_library
standard_library.install_aliases()
from builtins import object
import json
import ldap
import re
import sys
import time
import urllib.request, urllib.parse, urllib.error

from nose.plugins.skip import SkipTest
from nose.tools import assert_true, assert_equal, assert_false, assert_not_equal
from datetime import datetime
from django.contrib.sessions.models import Session
from django.db.models import Q
from django.urls import reverse
from django.test import override_settings
from django.test.client import Client

import desktop.conf

from desktop import appmanager
from desktop.auth.backend import is_admin, create_user
from desktop.conf import APP_BLACKLIST
from desktop.lib.django_test_util import make_logged_in_client
from desktop.lib.test_utils import grant_access
from desktop.views import home
from hadoop import pseudo_hdfs4
from hadoop.pseudo_hdfs4 import is_live_cluster

import useradmin.conf
import useradmin.ldap_access
from useradmin.forms import UserChangeForm
from useradmin.middleware import ConcurrentUserSessionMiddleware
from useradmin.models import HuePermission, GroupPermission, UserProfile, get_profile, get_default_user_group, User, Group
from useradmin.hue_password_policy import reset_password_policy

if sys.version_info[0] > 2:
  from django.utils.encoding import smart_text as smart_unicode
else:
  from django.utils.encoding import smart_unicode


def reset_all_users():
  """Reset to a clean state by deleting all users"""
  for user in User.objects.all():
    user.delete()


def reset_all_groups():
  """Reset to a clean state by deleting all groups"""
  useradmin.conf.DEFAULT_USER_GROUP.set_for_testing(None)
  for grp in Group.objects.all():
    grp.delete()


class LdapTestConnection(object):
  """
  Test class which mimics the behaviour of LdapConnection (from ldap_access.py).
  It also includes functionality to fake modifications to an LDAP server.  It is designed
  as a singleton, to allow for changes to persist across discrete connections.

  This class assumes uid is the user_name_attr.
  """
  def __init__(self):
    self._instance = LdapTestConnection.Data()

  def add_user_group_for_test(self, user, group):
    self._instance.groups[group]['members'].append(user)

  def remove_user_group_for_test(self, user, group):
    self._instance.groups[group]['members'].remove(user)

  def add_posix_user_group_for_test(self, user, group):
    self._instance.groups[group]['posix_members'].append(user)

  def remove_posix_user_group_for_test(self, user, group):
    self._instance.groups[group]['posix_members'].remove(user)

  def find_users(self, username_pattern, search_attr=None, user_name_attr=None, find_by_dn=False, scope=ldap.SCOPE_SUBTREE):
    """ Returns info for a particular user via a case insensitive search """
    if find_by_dn:
      data = [attrs for attrs in list(self._instance.users.values()) if attrs['dn'] == username_pattern]
    else:
      username_pattern = "^%s$" % username_pattern.replace('.','\\.').replace('*', '.*')
      username_fsm = re.compile(username_pattern, flags=re.I)
      usernames = [username for username in list(self._instance.users.keys()) if username_fsm.match(username)]
      data = [self._instance.users.get(username) for username in usernames]
    return data

  def find_groups(self, groupname_pattern, search_attr=None, group_name_attr=None, group_member_attr=None, group_filter=None, find_by_dn=False, scope=ldap.SCOPE_SUBTREE):
    """ Return all groups in the system with parents and children """
    if find_by_dn:
      data = [attrs for attrs in list(self._instance.groups.values()) if attrs['dn'] == groupname_pattern]
      # SCOPE_SUBTREE means we return all sub-entries of the desired entry along with the desired entry.
      if data and scope == ldap.SCOPE_SUBTREE:
        sub_data = [attrs for attrs in list(self._instance.groups.values()) if attrs['dn'].endswith(data[0]['dn'])]
        data.extend(sub_data)
    else:
      groupname_pattern = "^%s$" % groupname_pattern.replace('.','\\.').replace('*', '.*')
      groupnames = [username for username in list(self._instance.groups.keys()) if re.match(groupname_pattern, username)]
      data = [self._instance.groups.get(groupname) for groupname in groupnames]
    return data

  def find_members_of_group(self, dn, search_attr, ldap_filter, scope=ldap.SCOPE_SUBTREE):
    members = []
    for group_info in self._instance.groups:
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    members = set(members)
    users = []
    for user_info in self._instance.users:
      if user_info['dn'] in members:
        users.append(user_info)

    groups = []
    for group_info in self._instance.groups:
      if group_info['dn'] in members:
        groups.append(group_info)

    return users + groups

  def find_users_of_group(self, dn):
    members = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    members = set(members)
    users = []
    for user_info in list(self._instance.users.values()):
      if user_info['dn'] in members:
        users.append(user_info)

    return users

  def find_groups_of_group(self, dn):
    members = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] == dn:
        members.extend(group_info['members'])

    groups = []
    for group_info in list(self._instance.groups.values()):
      if group_info['dn'] in members:
        groups.append(group_info)

    return groups

  class Data(object):
    def __init__(self):
      self.users = {
        'moe': {'dn': 'uid=moe,ou=People,dc=example,dc=com', 'username':'moe', 'first':'Moe', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'lårry': {'dn': 'uid=lårry,ou=People,dc=example,dc=com', 'username':'lårry', 'first':'Larry', 'last':'Stooge', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com', 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'curly': {'dn': 'uid=curly,ou=People,dc=example,dc=com', 'username':'curly', 'first':'Curly', 'last':'Stooge', 'email':'<EMAIL>', 'groups': ['cn=TestUsers,ou=Groups,dc=example,dc=com', 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'Rock': {'dn': 'uid=Rock,ou=People,dc=example,dc=com', 'username':'Rock', 'first':'rock', 'last':'man', 'email':'<EMAIL>', 'groups': ['cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com']},
        'nestedguy': {'dn': 'uid=nestedguy,ou=People,dc=example,dc=com', 'username':'nestedguy', 'first':'nested', 'last':'guy', 'email':'<EMAIL>', 'groups': ['cn=NestedGroup,ou=Groups,dc=example,dc=com']},
        'otherguy': {'dn': 'uid=otherguy,ou=People,dc=example,dc=com', 'username':'otherguy', 'first':'Other', 'last':'Guy', 'email':'<EMAIL>'},
        'posix_person': {'dn': 'uid=posix_person,ou=People,dc=example,dc=com', 'username': 'posix_person', 'first': 'pos', 'last': 'ix', 'email': '<EMAIL>'},
        'posix_person2': {'dn': 'uid=posix_person2,ou=People,dc=example,dc=com', 'username': 'posix_person2', 'first': 'pos', 'last': 'ix', 'email': '<EMAIL>'},
        'user with space': {'dn': 'uid=user with space,ou=People,dc=example,dc=com', 'username': 'user with space', 'first': 'user', 'last': 'space', 'email': '<EMAIL>'},
        'spaceless': {'dn': 'uid=user without space,ou=People,dc=example,dc=com', 'username': 'spaceless', 'first': 'user', 'last': 'space', 'email': '<EMAIL>'},
        'test_toolongusernametoolongusername': {'dn': 'uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com', 'username': 'test_toolongusernametoolongusername', 'first': 'toolong', 'last': 'username', 'email': '<EMAIL>'},
        'test_longfirstname': {'dn': 'uid=test_longfirstname,ou=People,dc=example,dc=com', 'username': 'test_longfirstname', 'first': 'test_longfirstname_test_longfirstname', 'last': 'username', 'email': '<EMAIL>'},}

      self.groups = {
        'TestUsers': {
          'dn': 'cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'TestUsers',
          'members':['uid=moe,ou=People,dc=example,dc=com','uid=lårry,ou=People,dc=example,dc=com','uid=curly,ou=People,dc=example,dc=com','uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com'],
          'posix_members':[]},
        'Test Administrators': {
          'dn': 'cn=Test Administrators,cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'Test Administrators',
          'members':['uid=Rock,ou=People,dc=example,dc=com','uid=lårry,ou=People,dc=example,dc=com','uid=curly,ou=People,dc=example,dc=com','uid=test_toolongusernametoolongusername,ou=People,dc=example,dc=com'],
          'posix_members':[]},
        'OtherGroup': {
          'dn': 'cn=OtherGroup,cn=TestUsers,ou=Groups,dc=example,dc=com',
          'name':'OtherGroup',
          'members':[],
          'posix_members':[]},
        'NestedGroups': {
          'dn': 'cn=NestedGroups,ou=Groups,dc=example,dc=com',
          'name':'NestedGroups',
          'members':['cn=NestedGroup,ou=Groups,dc=example,dc=com'],
          'posix_members':[]
        },
        'NestedGroup': {
          'dn': 'cn=NestedGroup,ou=Groups,dc=example,dc=com',
          'name':'NestedGroup',
          'members':['uid=nestedguy,ou=People,dc=example,dc=com'],
          'posix_members':[]
        },
        'NestedPosixGroups': {
          'dn': 'cn=NestedPosixGroups,ou=Groups,dc=example,dc=com',
          'name':'NestedPosixGroups',
          'members':['cn=PosixGroup,ou=Groups,dc=example,dc=com'],
          'posix_members':[]
        },
        'PosixGroup': {
          'dn': 'cn=PosixGroup,ou=Groups,dc=example,dc=com',
          'name':'PosixGroup',
          'members':[],
          'posix_members':['posix_person','lårry']},
        'PosixGroup1': {
          'dn': 'cn=PosixGroup1,cn=PosixGroup,ou=Groups,dc=example,dc=com',
          'name':'PosixGroup1',
          'members':[],
          'posix_members':['posix_person2']},
        }


def test_invalid_username():
  BAD_NAMES = ('-foo', 'foo:o', 'foo o', ' foo')

  c = make_logged_in_client(username="test", is_superuser=True)

  for bad_name in BAD_NAMES:
    assert_true(c.get('/useradmin/users/new'))
    response = c.post('/useradmin/users/new', dict(username=bad_name, password1="<PASSWORD>", password2="<PASSWORD>"))
    assert_true('not allowed' in response.context[0]["form"].errors['username'][0])


class BaseUserAdminTests(object):

  @classmethod
  def setUpClass(cls):
    cls._class_resets = [
      useradmin.conf.DEFAULT_USER_GROUP.set_for_testing(None),
    ]

  @classmethod
  def tearDownClass(cls):
    for reset in cls._class_resets:
      reset()

  def setUp(self):
    reset_all_users()
    reset_all_groups()

  def tearDown(self):
    pass


class TestUserProfile(BaseUserAdminTests):

  @override_settings(AUTHENTICATION_BACKENDS=['desktop.auth.backend.AllowFirstUserDjangoBackend'])
  def test_get_profile(self):
    '''Ensure profiles are created after get_profile is called.'''
    user = create_user(username='test', password='<PASSWORD>', is_superuser=False)

    assert_equal(0, UserProfile.objects.filter(user=user).count())

    p = get_profile(user)

    assert_equal(1, UserProfile.objects.filter(user=user).count())


  @override_settings(AUTHENTICATION_BACKENDS=['desktop.auth.backend.AllowFirstUserDjangoBackend'])
  def test_get_and_update_profile(self):
    c = make_logged_in_client(username='test', password='<PASSWORD>', is_superuser=False, recreate=True)

    user = User.objects.get(username='test')
    userprofile = get_profile(user)
    assert_false(userprofile.data.get('language_preference'))

    userprofile.update_data({'language_preference': 'en'})
    userprofile.save()
    assert_equal('en', userprofile.data['language_preference'])

    userprofile.update_data({'language_preference': 'es'})
    userprofile.save()
    assert_equal('es', userprofile.data['language_preference'])
{'fraction_non_alphanumeric': 0.15079641902104407, 'fraction_numerical': 0.001937759175289695, 'mean_word_length': 4.779171332586786, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2348797', 'n_tokens_mistral': 8414, 'n_tokens_neox': 8260, 'n_words': 1706}