openwisp / openwisp-radius

Administration web interface and REST API for freeradius 3 build in django & python. Supports captive portal authentication, WPA Enerprise (802.1x), freeradius rlm_rest, social login, Hotspot 2.0 / 802.11u, importing users from CSV, registration of new users and more.
https://openwisp.io/docs/dev/radius/
GNU General Public License v3.0
360 stars 176 forks source link

ERROR ImportError: cannot import name 'ProtectedAPIMixin' from 'openwisp_users.api.mixins' #538

Closed SapeNeCo closed 2 months ago

SapeNeCo commented 2 months ago

Hello. I'm new to OpenWISP, but would like to get the hang of it. I installed the latest release of OpenWISP-controller on my machine with ubuntu 22. For it I need to implement OpenWISP-wifi-login-pages. In fact, the controller already has Radius, but when I launch it I get the following error:

$ ./browser-test/wait_for_url.sh http://0.0.0.0:8080 http://localhost:8000/admin && jest browser-test --runInBand
Build successful: http://0.0.0.0:8080 is reachable.
Build successful: http://localhost:8000/admin is reachable.
OpenWISP RADIUS is not installed or python virtual environment is not activated correctly

  ●  process.exit called with "1"

      18 |   }
      19 |   if (result.status !== 0) {
    > 20 |     process.exit(result.status);
         |             ^
      21 |   }
      22 | };
      23 |

      at executeCommand (browser-test/utils.js:20:13)
      at _callee4$ (browser-test/utils.js:53:9)
      at tryCatch (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
      at Generator.<anonymous> (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
      at Generator.next (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
      at node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
      at apply (node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
      at initializeData (browser-test/utils.js:52:28)
      at _callee3$ (browser-test/mobile-phone-change.test.js:36:25)
      at tryCatch (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
      at Generator.<anonymous> (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
      at Generator.next (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
      at node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
      at node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12

 RUNS  browser-test/mobile-phone-change.test.js
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

It requires OpenWISP-Radius, which is strange. But okay, I installed OpenWISP-Radius, figured out the dependencies and my setup.py file began to look like this:

import sys

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DEBUG = True
TESTING = sys.argv[1:2] == ['test']
SELENIUM_HEADLESS = True if os.environ.get('SELENIUM_HEADLESS', False) else False
SHELL = 'shell' in sys.argv or 'shell_plus' in sys.argv
REDIS_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')

ALLOWED_HOSTS = ['*']

SPATIALITE_LIBRARY_PATH = '/usr/local/lib/mod_spatialite.dylib'
DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.spatialite',
        'NAME': os.path.join(BASE_DIR, 'openwisp-controller.db'),
    }
}

AUTH_USER_MODEL = 'openwisp_users.User'
SITE_ID = 1
AUTHENTICATION_BACKENDS = (
    'openwisp_users.backends.UsersAuthenticationBackend',
)

OPENWISP_RADIUS_FREERADIUS_ALLOWED_HOSTS = ['127.0.0.1']

SPATIALITE_LIBRARY_PATH = 'mod_spatialite.so'

SECRET_KEY = 'fn)t*+$)ugeyip6-#txyy$5wf2ervc0d2n#h)qb)y5@ly$t*@w'

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.gis',
    # all-auth
    'django.contrib.sites',
    'openwisp_users.accounts',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'django_extensions',
    # openwisp2 modules
    'openwisp_users',
    'openwisp_controller.config',
    'openwisp_controller.pki',
    'openwisp_controller.geo',
    'openwisp_controller.connection',
    'openwisp_controller.subnet_division',
    'openwisp_notifications',
    'openwisp_ipam',
    # openwisp2 admin theme
    # (must be loaded here)
    'openwisp_utils.admin_theme',
    'admin_auto_filters',
    # admin
    'django.contrib.admin',
    'django.forms',
    # other dependencies
    'sortedm2m',
    'reversion',
    'leaflet',
    'flat_json_widget',
    # rest framework
    'rest_framework',
    'rest_framework.authtoken',
    'rest_framework_gis',
    'django_filters',
    'drf_yasg',
    # channels
    'channels',
    'import_export',
    # 'debug_toolbar',
    'django.contrib.humanize',
    # registration
    'dj_rest_auth',
    'dj_rest_auth.registration',
    # openwisp radius
    'openwisp_radius',
    'private_storage',
    'allauth.socialaccount.providers.facebook',
    'allauth.socialaccount.providers.google',
]
EXTENDED_APPS = ('django_x509', 'django_loci')

AUTH_USER_MODEL = 'openwisp_users.User'
SITE_ID = 1

STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'openwisp_utils.staticfiles.DependencyFinder',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    # 'debug_toolbar.middleware.DebugToolbarMiddleware',
]

INTERNAL_IPS = ['127.0.0.1']

ROOT_URLCONF = 'openwisp2.urls'

ASGI_APPLICATION = 'openwisp2.asgi.application'
if not TESTING:
    CHANNEL_LAYERS = {
        'default': {
            'BACKEND': 'channels_redis.core.RedisChannelLayer',
            'CONFIG': {'hosts': [f'{REDIS_URL}/7']},
        }
    }
else:
    CHANNEL_LAYERS = {'default': {'BACKEND': 'channels.layers.InMemoryChannelLayer'}}

TIME_ZONE = 'Europe/Rome'
LANGUAGE_CODE = 'en-gb'
USE_TZ = True
USE_I18N = False
USE_L10N = False
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = f'{os.path.dirname(BASE_DIR)}/media/'
PRIVATE_STORAGE_ROOT = os.path.join(MEDIA_ROOT, 'private')

CORS_ORIGIN_ALLOW_ALL = True

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'OPTIONS': {
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'openwisp_utils.loaders.DependencyLoader',
                'django.template.loaders.app_directories.Loader',
            ],
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'openwisp_utils.admin_theme.context_processor.menu_groups',
                'openwisp_notifications.context_processors.notification_api_settings',
            ],
        },
    }
]

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

EMAIL_PORT = '1025'  # for testing purposes
LOGIN_REDIRECT_URL = 'admin:index'
ACCOUNT_LOGOUT_REDIRECT_URL = LOGIN_REDIRECT_URL
OPENWISP_ORGANIZATION_USER_ADMIN = True  # tests will fail without this setting
OPENWISP_ADMIN_DASHBOARD_ENABLED = True
OPENWISP_CONTROLLER_GROUP_PIE_CHART = True
# during development only
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

if not TESTING:
    CACHES = {
        'default': {
            'BACKEND': 'django_redis.cache.RedisCache',
            'LOCATION': f'{REDIS_URL}/6',
            'OPTIONS': {
                'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            },
        }
    }

if not TESTING:
    CELERY_BROKER_URL = f'{REDIS_URL}/1'
else:
    CELERY_TASK_ALWAYS_EAGER = True
    CELERY_TASK_EAGER_PROPAGATES = True
    CELERY_BROKER_URL = 'memory://'

LOGGING = {
    'version': 1,
    'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}},
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        }
    },
}

if not TESTING and SHELL:
    LOGGING.update(
        {
            'loggers': {
                'django.db.backends': {
                    'level': 'DEBUG',
                    'handlers': ['console'],
                    'propagate': False,
                },
            }
        }
    )

DJANGO_LOCI_GEOCODE_STRICT_TEST = False
OPENWISP_CONTROLLER_CONTEXT = {'vpnserver1': 'vpn.testdomain.com'}
OPENWISP_USERS_AUTH_API = True

TEST_RUNNER = 'openwisp_utils.tests.TimeLoggingTestRunner'

if os.environ.get('SAMPLE_APP', False):
    # Replace Config
    config_index = INSTALLED_APPS.index('openwisp_controller.config')
    INSTALLED_APPS.remove('openwisp_controller.config')
    INSTALLED_APPS.insert(config_index, 'openwisp2.sample_config')
    # Replace Pki
    pki_index = INSTALLED_APPS.index('openwisp_controller.pki')
    INSTALLED_APPS.remove('openwisp_controller.pki')
    INSTALLED_APPS.insert(pki_index, 'openwisp2.sample_pki')
    # Replace Geo
    geo_index = INSTALLED_APPS.index('openwisp_controller.geo')
    INSTALLED_APPS.remove('openwisp_controller.geo')
    INSTALLED_APPS.insert(geo_index, 'openwisp2.sample_geo')
    # Replace Connection
    connection_index = INSTALLED_APPS.index('openwisp_controller.connection')
    INSTALLED_APPS.remove('openwisp_controller.connection')
    INSTALLED_APPS.insert(connection_index, 'openwisp2.sample_connection')
    # Replace Openwisp_Users
    users_index = INSTALLED_APPS.index('openwisp_users')
    INSTALLED_APPS.remove('openwisp_users')
    INSTALLED_APPS.insert(users_index, 'openwisp2.sample_users')
    # Replace Subnet Division
    subnet_division_index = INSTALLED_APPS.index('openwisp_controller.subnet_division')
    INSTALLED_APPS.remove('openwisp_controller.subnet_division')
    INSTALLED_APPS.insert(subnet_division_index, 'openwisp2.sample_subnet_division')
    # Extended apps
    EXTENDED_APPS = (
        'django_x509',
        'django_loci',
        'openwisp_controller.config',
        'openwisp_controller.pki',
        'openwisp_controller.geo',
        'openwisp_controller.connection',
        'openwisp_controller.subnet_division',
        'openwisp_users',
    )
    # Swapper
    AUTH_USER_MODEL = 'sample_users.User'
    OPENWISP_USERS_GROUP_MODEL = 'sample_users.Group'
    OPENWISP_USERS_ORGANIZATION_MODEL = 'sample_users.Organization'
    OPENWISP_USERS_ORGANIZATIONUSER_MODEL = 'sample_users.OrganizationUser'
    OPENWISP_USERS_ORGANIZATIONOWNER_MODEL = 'sample_users.OrganizationOwner'
    OPENWISP_USERS_ORGANIZATIONINVITATION_MODEL = 'sample_users.OrganizationInvitation'
    CONFIG_DEVICE_MODEL = 'sample_config.Device'
    CONFIG_DEVICEGROUP_MODEL = 'sample_config.DeviceGroup'
    CONFIG_CONFIG_MODEL = 'sample_config.Config'
    CONFIG_TEMPLATETAG_MODEL = 'sample_config.TemplateTag'
    CONFIG_TAGGEDTEMPLATE_MODEL = 'sample_config.TaggedTemplate'
    CONFIG_TEMPLATE_MODEL = 'sample_config.Template'
    CONFIG_VPN_MODEL = 'sample_config.Vpn'
    CONFIG_VPNCLIENT_MODEL = 'sample_config.VpnClient'
    CONFIG_ORGANIZATIONCONFIGSETTINGS_MODEL = 'sample_config.OrganizationConfigSettings'
    CONFIG_ORGANIZATIONLIMITS_MODEL = 'sample_config.OrganizationLimits'
    DJANGO_X509_CA_MODEL = 'sample_pki.Ca'
    DJANGO_X509_CERT_MODEL = 'sample_pki.Cert'
    GEO_LOCATION_MODEL = 'sample_geo.Location'
    GEO_FLOORPLAN_MODEL = 'sample_geo.FloorPlan'
    GEO_DEVICELOCATION_MODEL = 'sample_geo.DeviceLocation'
    CONNECTION_CREDENTIALS_MODEL = 'sample_connection.Credentials'
    CONNECTION_DEVICECONNECTION_MODEL = 'sample_connection.DeviceConnection'
    CONNECTION_COMMAND_MODEL = 'sample_connection.Command'
    SUBNET_DIVISION_SUBNETDIVISIONRULE_MODEL = (
        'sample_subnet_division.SubnetDivisionRule'
    )
    SUBNET_DIVISION_SUBNETDIVISIONINDEX_MODEL = (
        'sample_subnet_division.SubnetDivisionIndex'
    )
else:
    # not needed, these are the default values, left here only for example purposes
    # DJANGO_X509_CA_MODEL = 'pki.Ca'
    # DJANGO_X509_CERT_MODEL = 'pki.Cert'
    pass

if os.environ.get('SAMPLE_APP', False) and TESTING:
    # Required for openwisp-users tests
    OPENWISP_ORGANIZATION_USER_ADMIN = True
    OPENWISP_ORGANIZATION_OWNER_ADMIN = True
    OPENWISP_USERS_AUTH_API = True

# local settings must be imported before test runner otherwise they'll be ignored
try:
    from .local_settings import *
except ImportError:
    pass

But when I start it, I get this problem and I don’t understand why:

Traceback (most recent call last):
  File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.10/threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/utils/autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/core/management/commands/runserver.py", line 125, in inner_run
    autoreload.raise_last_exception()
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/utils/autoreload.py", line 87, in raise_last_exception
    raise _exception[1]
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/core/management/__init__.py", line 398, in execute
    autoreload.check_errors(django.setup)()
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/utils/autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/apps/registry.py", line 124, in populate
    app_config.ready()
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/contrib/admin/apps.py", line 27, in ready
    self.module.autodiscover()
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/contrib/admin/__init__.py", line 50, in autodiscover
    autodiscover_modules("admin", register_to=site)
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/django/utils/module_loading.py", line 58, in autodiscover_modules
    import_module("%s.%s" % (app_config.name, module_to_search))
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/user/openwisp_controller/openwisp_controller/subnet_division/admin.py", line 5, in <module>
    from openwisp_ipam.admin import IpAddressAdmin as BaseIpAddressAdmin
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/openwisp_ipam/admin.py", line 22, in <module>
    from .api.views import HostsSet
  File "/home/user/openwisp_controller/env/lib/python3.10/site-packages/openwisp_ipam/api/views.py", line 8, in <module>
    from openwisp_users.api.mixins import (
ImportError: cannot import name 'ProtectedAPIMixin' from 'openwisp_users.api.mixins' (/home/user/openwisp_controller/env/lib/python3.10/site-packages/openwisp_users/api/mixins.py)

I tried different versions of openwisp-users, openwisp-utils (because with ./manage.py migrate OpenWISP-Radius complained about them, supposedly the versions were incompatible), in the end nothing changed.