OpenWISP Users

repository·master·Indexed 41 days ago

https://github.com/openwisp/openwisp-users

A Python and Django-based module providing user management and multi-tenancy features for the OpenWISP ecosystem. It includes tools for organization-based permissions, multi-tenant Django admin mixins, and REST API authentication via Bearer and Sesame tokens. The package provides specialized Django REST Framework mixins and serializers to enforce data isolation between organizations.

Tokens
13.4K
Snippets
42
Records
65
Agent score
51%

What's inside OpenWISP Users

  1. Overview of the OpenWISP Users module

    master

    The OpenWISP Users module is built on the Django Framework and provides core identity and access management features for OpenWISP. It enables:

    • User Account Management: Handling user profiles and credentials.
    • Permission Groups: Organizing users into groups to control access levels.
    • Authentication Schemes: Supporting various methods for verifying user identity.
    • Multi-tenancy: Allowing a single OpenWISP instance to host multiple organizations, each managed by distinct sets of users.
  2. Manage user accounts and data in OpenWISP Users

    master

    The OpenWISP Users module provides full CRUD (Create, Read, Update, Delete) capabilities for user accounts. It supports:

    • Custom User Fields: Extensible models allow for adding custom data to user profiles.
    • Lifecycle Policies: Enforcement of account expiration and password expiration policies.
    • Data Export: User data can be exported from the Linux shell using a management command.

    For developers looking to add custom fields, refer to the extension documentation.

  3. Access user organization data via organizations_dict

    master

    The User.organizations_dict property returns a dictionary containing the primary keys of organizations the user belongs to, along with their roles. This data is automatically cached to prevent multiple database queries across requests.

    Cache Invalidation Events:

    • Addition, change, or deletion of an OrganizationUser.
    • Addition, change, or deletion of an OrganizationOwner.
    • Change to the is_active field of an Organization.

    Dictionary Structure: { 'org_uuid': {'is_admin': bool, 'is_owner': bool}, ... }

    >>> user.organizations_dict
    ... {'20135c30-d486-4d68-993f-322b8acb51c4': {'is_admin': True, 'is_owner': False}}
  4. Enforce organization-based permissions

    master

    OpenWISP provides custom permission classes to ensure users can only access objects belonging to their organization. The following classes check for specific roles within an organization:

    • IsOrganizationMember: User must be a member of the object's organization.
    • IsOrganizationManager: User must be a manager of the object's organization.
    • IsOrganizationOwner: User must be an owner of the object's organization.

    By default, these classes look for an organization field on the object. If the organization is located on a related model (e.g., a parent object), you must override the organization_field attribute on your view using Django's double-underscore notation.

    from openwisp_users.api.permissions import IsOrganizationManager
    from rest_framework import generics
    
    class MyApiView(generics.APIView):
        permission_classes = (IsOrganizationManager,)
        # Use this if the organization is on a related object (e.g., obj.category.organization)
        organization_field = "category__organization"
    
    # Note: Use select_related() in your queryset to optimize performance when using organization_field
  5. Control access with Permissions and Roles

    master

    Access control is managed through granular permissions applied to both users and organizations.

    OpenWISP provides:

    • Default Roles: Pre-configured roles for administrators, managers, and regular users.
    • Customizable Permission Sets: Ability to define specific permission sets to meet unique organizational needs.
  6. Implement multi-tenancy with Organizations

    master

    OpenWISP supports multi-tenancy by allowing the creation of multiple Organizations (tenants).

    Key multi-tenancy behaviors:

    • User Association: Users can be associated with one or multiple organizations in different capacities: members, managers, or owners.
    • Data Isolation: Each organization is restricted to accessing only their own data.
    • Shared Data: Certain objects can be configured to be shared across multiple organizations.
  7. Configure Account Expiration

    master

    Account expiration is a lifecycle policy applied to individual users by setting an expiration_date. Once this date passes, the account is automatically deactivated unless the date is extended or removed.

    To manage the user experience during expiration, you can configure how many days in advance reminder emails are sent using the OPENWISP_USERS_EXPIRATION_WARNING_DAYS setting.

  8. Install openwisp-users from GitHub

    master

    You can install the latest development version directly from GitHub using either a tarball via HTTPS or the git protocol.

    Via HTTPS tarball:

    pip install https://github.com/openwisp/openwisp-users/tarball/master

    Via Git protocol (editable mode):

    pip install -e git+git://github.com/openwisp/openwisp-users#egg=openwisp_users
  9. Handle migrations for extended OpenWISP Users

    master

    After creating your custom models, follow these steps to ensure compatibility with other OpenWISP modules:

    1. Run ./manage.py makemigrations.
    2. Crucial: Manually create a migration file named 0004_default_groups.py in your migrations directory. This file is required because other OpenWISP modules depend on it. (Refer to the sample_users/migrations/0004_default_groups.py in the repository for the exact content).
    3. Run ./manage.py migrate.
    ./manage.py makemigrations
    # [Manually create 0004_default_groups.py here]
    ./manage.py migrate
  10. Customize the Django Admin for OpenWISP Users

    master

    You can customize the OpenWISP Users admin interface using two methods:

    1. Monkey Patching (For small changes)

    Use this to add fields to existing forms. OpenWISP provides helper functions to make this easier:

    • usermodel_add_form: Adds fields to the "Add user" form.
    • usermodel_change_form: Adds fields to the "Change user" profile section.
    • usermodel_list_and_search: Makes a field searchable and adds it to the user list view.

    2. Inheriting Admin Classes (For significant changes)

    Unregister the base OpenWISP admin classes and register your own custom classes that inherit from them. Use swapper.load_model to retrieve the correct models.

    # Method 2: Inheriting Admin Classes
    from django.contrib import admin
    from openwisp_users.admin import (
        UserAdmin as BaseUserAdmin,
        GroupAdmin as BaseGroupAdmin,
        OrganizationAdmin as BaseOrganizationAdmin,
        OrganizationOwnerAdmin as BaseOrganizationOwnerAdmin,
        OrganizationUserAdmin as BaseOrganizationUserAdmin,
    )
    from swapper import load_model
    from django.contrib.auth import get_user_model
    
    Group = load_model("openwisp_users", "Group")
    Organization = load_model("openwisp_users", "Organization")
    OrganizationOwner = load_model("openwisp_users", "OrganizationOwner")
    OrganizationUser = load_model("openwisp_users", "OrganizationUser")
    User = get_user_model()
    
    admin.site.unregister(Group)
    admin.site.unregister(Organization)
    admin.site.unregister(OrganizationOwner)
    admin.site.unregister(OrganizationUser)
    admin.site.unregister(User)
    
    @admin.register(Group)
    class GroupAdmin(BaseGroupAdmin):
        pass
    
    @admin.register(User)
    class UserAdmin(BaseUserAdmin):
        pass