Skip to content

01_user_authentication___authorization

Benedikt Kuehne edited this page Jan 7, 2026 · 2 revisions

Chapter 1: User Authentication & Authorization

Imagine EMBArk as a high-security building filled with important tools and confidential information about firmware analysis. Not everyone should have access to every room or every tool, right? That's where "User Authentication & Authorization" comes in. This system acts like the security guard and access control for our building.

The big problem it solves: How do we make sure that only the right people can get into EMBArk, and once they're inside, how do we control what they are allowed to do?

Let's say you're a new analyst joining the team. Your first task is to log in and upload a new firmware for analysis. This simple action involves both authentication (proving you are who you say you are) and authorization (being allowed to use the upload tool). Without these, anyone could potentially access sensitive analysis reports or even disrupt the system.

Understanding the Key Concepts

To manage access in EMBArk, we rely on two main concepts:

1. Authentication: "Who Are You?"

Authentication is like showing your ID card at the entrance of our high-security building. It's the process of verifying your identity. When you try to log into EMBArk, the system needs to know if you are a recognized user.

How EMBArk does it:

  • Username and Password: The most common way. You provide your username and a secret password. EMBArk checks if they match its records.
  • API Keys: For machines or automated scripts, an API key is like a special, unique badge. Instead of a username/password, a program presents this key to prove its identity.

2. Authorization: "What Are You Allowed to Do?"

Once the security guard (authentication) has confirmed who you are, authorization steps in. This is like your ID card having different access levels – maybe you can enter the "Analysis Lab" but not the "Server Room." Authorization determines what actions you are permitted to perform and what data you can see based on your identity and role.

How EMBArk does it:

  • Roles/Groups: Users are often assigned to groups (e.g., 'Admin', 'New_User'). Each group has a predefined set of permissions.
  • Permissions: These are specific rights, like "Can upload firmware" or "Can view all reports." Your role determines which permissions you get.

Let's look at the permissions defined in EMBArk's users/models.py:

Permission Name Description
user_permission Access user menus
tracker_permission Access tracker functionalities
uploader_permission_minimal Access basic uploader functionalities
uploader_permission_advanced Access all uploader functionalities
reporter_permission Access reporter functionalities
settings_permission Access settings functionalities
... and many more!

These permissions allow EMBArk administrators to finely control what each user can do within the platform.

Solving Our Use Case: Logging In and Uploading Firmware

Let's walk through how our new analyst logs in and uploads firmware, touching on the key authentication and authorization steps.

Step 1: Registering as a New User

Before logging in, a new user usually needs to register.

What happens: The user fills out a simple form with their desired username, email, and password.

Here's a simplified look at the form used for registration (from embark/users/forms.py):

# Simplified snippet from embark/users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from users.models import User

class SignUpForm(UserCreationForm):
    # These fields collect user information during registration
    first_name = forms.CharField(max_length=12, required=False)
    last_name = forms.CharField(max_length=12, required=False)
    email = forms.EmailField(max_length=50, help_text='Required. Inform a valid email address.')
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)
    username = forms.CharField(label='Username', max_length=150)

    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2',)

This SignUpForm helps EMBArk collect and validate the necessary information to create a new user account.

Once the form is submitted, a register function (in embark/users/views.py) handles creating the user:

# Simplified snippet from embark/users/views.py
from users.forms import SignUpForm
from users.models import User
from django.contrib.auth.models import Group # To assign roles

# ... other imports and code ...

def register(request):
    if request.method == "POST":
        signup_form = SignUpForm(data=request.POST)
        if signup_form.is_valid():
            # Create a new user in the database
            user = User.objects.create(
                username=signup_form.cleaned_data.get('username'),
                email=signup_form.cleaned_data.get('email')
            )
            user.set_password(signup_form.cleaned_data.get('password2'))
            user.is_active = False # User needs activation
            # Add user to 'New_User' group for initial permissions
            new_user_group = Group.objects.get(name='New_User')
            user.groups.add(new_user_group)
            user.save()
            # An activation email is sent, or activated directly if email is off.
            # ... handles email sending or direct activation ...
            return redirect(reverse('embark-login'))
    else:
        signup_form = SignUpForm()
    return render(request, 'user/register.html', {'form': signup_form})

This code creates a new User in the database, sets their password securely, and initially marks them as is_active=False (meaning they can't log in yet until activated). It also adds them to a New_User group, which might have minimal initial permissions.

Step 2: Logging In

After registration and activation, the analyst can log in.

What happens: The user visits the login page, enters their username and password, and clicks "Login."

The login form (from embark/users/forms.py) is designed to handle this:

# Simplified snippet from embark/users/forms.py
from django.contrib.auth.forms import AuthenticationForm

class LoginForm(AuthenticationForm):
    # This form is used for users to enter their username and password
    error_messages = {
        "invalid_login": "Please enter a correct username and password.",
        "inactive": "This account is not yet activated",
        # ... other messages
    }

This LoginForm simply asks for the username and password. When submitted, the embark_login function (in embark/users/views.py) takes over:

# Simplified snippet from embark/users/views.py
from users.forms import LoginForm
from django.contrib.auth import login # Django's built-in login function

# ... other imports and code ...

def embark_login(request):
    if request.method == "POST":
        login_form = LoginForm(request=request, data=request.POST)
        if login_form.is_valid():
            user = login_form.get_user() # Get the authenticated user
            if user:
                login(request, user) # This logs the user into Django's session system
                # ... sets user timezone, redirects to dashboard ...
                return redirect('embark-uploader-home')
        # ... handles invalid login or errors ...
    login_form = LoginForm()
    return render(request, 'user/login.html', {'form': login_form})

If the username and password are correct, the login(request, user) function essentially "opens the door" for the user, creating a secure session that allows them to interact with EMBArk.

Step 3: Accessing Protected Features (like Firmware Upload)

Now that our analyst is authenticated, they need authorization to upload firmware.

What happens: The analyst navigates to the "Uploader" section. EMBArk checks if they have the necessary permission.

In EMBArk's code, specific functions (called "views") are protected using special markers called "decorators."

# Simplified snippet from embark/users/views.py
from django.contrib.auth.decorators import login_required, permission_required

# ... other imports and code ...

# Example: A view function for uploading firmware
# (This would be in uploader/views.py, but shown here for illustration)
@login_required(login_url='/' + settings.LOGIN_URL)
@permission_required("uploader.uploader_permission_minimal", login_url='/')
def firmware_upload_view(request):
    # This code only runs if the user is logged in AND has 'uploader_permission_minimal'
    # ... logic to handle firmware upload ...
    return render(request, 'uploader/upload_form.html')
  • @login_required: This decorator makes sure that only users who have successfully logged in can access this page. If you're not logged in, it sends you to the login page.
  • @permission_required("uploader.uploader_permission_minimal"): This decorator goes a step further. It checks if the logged-in user has the specific permission named "uploader.uploader_permission_minimal". If they don't, they are redirected (usually to the login page or an error page).

This is how EMBArk ensures that our analyst, even after logging in, can only upload firmware if their assigned role/permissions allow it.

Step 4: Using API Keys for Automated Tasks

Sometimes, you might want another program or script to interact with EMBArk automatically, without a human logging in through a browser. For this, EMBArk uses API keys.

What happens: A user can generate a unique API key from their account settings. This key can then be used by scripts to authenticate.

# Simplified snippet from embark/users/views.py
import secrets
from django.contrib.auth.decorators import login_required
from users.models import User

# ... other imports and code ...

@login_required(login_url="/" + settings.LOGIN_URL)
@permission_required("users.user_permission", login_url="/")
def generate_api_key(request):
    user = get_user(request)
    new_api_key = secrets.token_urlsafe(32) # Generate a random, secure key
    user.api_key = new_api_key
    user.save()
    messages.success(request, f"Your new API key: {new_api_key}")
    return redirect('..')

# Simplified snippet from embark/users/decorators.py
from functools import wraps
from django.http import JsonResponse, HttpRequest
from users.models import User

def require_api_key(view_func):
    @wraps(view_func)
    def _wrapped_view(*args, **kwargs):
        request = args[0] if isinstance(args[0], HttpRequest) else args[1]
        api_key = request.headers.get("Authorization") or request.GET.get("api_key")
        if not api_key:
            return JsonResponse({"error": "Missing API key"}, status=401)
        try:
            user = User.objects.get(api_key=api_key) # Find user by API key
            request.api_user = user
            request.user = user # Set request.user for compatibility
        except User.DoesNotExist:
            return JsonResponse({'error': 'Invalid API key'}, status=401)
        return view_func(*args, **kwargs)
    return _wrapped_view

# Example: An API endpoint protected by an API key
# Simplified snippet from embark/users/views.py
@require_api_key
def api_test(request):
    api_user = request.api_user # The user object identified by the API key
    return JsonResponse({'message': f'Hello, {api_user.username}!'})
  • generate_api_key: This function allows a logged-in user to generate a new API key, which is then stored with their user account.
  • @require_api_key: This custom decorator checks if an API key is provided (in the request headers or URL) and if it belongs to a valid user. If so, the request is allowed to proceed, and the request.api_user (and request.user) is set to the user associated with that key.
  • api_test: An example of a function that can only be accessed by providing a valid API key.

Under the Hood: How EMBArk Manages Authentication

Let's quickly peek at the core components involved when a user logs into EMBArk.

The Login Process: A Simple Sequence

When you enter your username and password, here's a simplified sequence of what happens:

sequenceDiagram
    participant User
    participant Web Browser
    participant EMBArk Web Server
    participant Database

    User->>Web Browser: Enters Username & Password
    Web Browser->>EMBAIk Web Server: Sends Login Request (POST /login)
    EMBArk Web Server->>Database: Checks Username & Password
    Database-->>EMBArk Web Server: Valid User Found? (Yes/No)
    alt Valid User
        EMBArk Web Server->>EMBArk Web Server: Creates User Session
        EMBArk Web Server-->>Web Browser: Redirects to Dashboard (e.g., /dashboard)
        Web Browser->>User: Shows Dashboard (Logged In!)
    else Invalid User
        EMBArk Web Server-->>Web Browser: Shows Login Error
        Web Browser->>User: Display Login Error
    end
Loading

Note over EMBArk Web Server: During session creation, the user's permissions are also established for subsequent requests.

Key Configuration and Code Elements

EMBArk is built using Django, a powerful Python web framework. Django provides many built-in features for authentication and authorization.

  1. embark/embark/settings/deploy.py - The Brains of the Operation: This file defines global settings for EMBArk.

    # Simplified snippet from embark/embark/settings/deploy.py
    
    INSTALLED_APPS = [
        # ... other apps ...
        'django.contrib.admin',        # Django's admin interface
        'django.contrib.auth',         # Core authentication system
        'django.contrib.contenttypes', # Handles content types for permissions
        'django.contrib.sessions',     # Manages user sessions
        'django.contrib.messages',     # For displaying one-time messages
        'users',                       # Our custom user app
        # ... more apps ...
    ]
    
    # Middleware are processing hooks that run during request/response cycles
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware', # IMPORTANT for authenticating users
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    # Tells Django to use our custom User model instead of its default
    AUTH_USER_MODEL = 'users.User'
    
    LOGIN_URL = '' # The URL where users are redirected for login
    LOGOUT_REDIRECT_URL = '' # The URL users are redirected to after logout
    • INSTALLED_APPS: Lists all the "plugins" (apps) that EMBArk uses. django.contrib.auth, django.contrib.sessions, and our users app are crucial for managing users.
    • MIDDLEWARE: Think of these as checkpoints for every request. AuthenticationMiddleware is the one that checks if a user is logged in for each incoming request.
    • AUTH_USER_MODEL: This tells Django to use our special User model (defined in users/models.py) instead of its default one. This allows EMBArk to add custom fields to users (like timezone or api_key).
    • LOGIN_URL / LOGOUT_REDIRECT_URL: These settings tell Django where to send users for logging in and after logging out.
  2. embark/users/models.py - Defining Our Users: This file defines the User and Team models, which are blueprints for how user and team data is stored in the database.

    # Simplified snippet from embark/users/models.py
    from django.db import models
    from django.contrib.auth.models import AbstractUser # Django's base user model
    
    class Team(models.Model):
        name = models.CharField(primary_key=True, max_length=150, unique=True)
        is_active = models.BooleanField(default=True)
        # ... other fields ...
    
    class User(AbstractUser):
        # We extend Django's built-in user with our own fields
        timezone = models.CharField(max_length=32, default='UTC')
        email = models.EmailField(unique=True, blank=True)
        team = models.ForeignKey(Team, on_delete=models.SET_NULL, null=True, related_name='member_of_team')
        is_active_member = models.BooleanField(default=True)
        api_key = models.CharField(max_length=64, blank=True, null=True)
    
        class Meta:
            # We define custom permissions that EMBArk uses
            default_permissions = ()
            permissions = (
                ("user_permission", "Can access user menues of embark"),
                ("tracker_permission", "Can access tracker functionalities of embark"),
                ("uploader_permission_minimal", "Can access uploader functionalities of embark"),
                # ... many more custom permissions ...
            )
    • AbstractUser: By inheriting from AbstractUser, our User model gets all of Django's built-in user features (like username, password hashing, staff status) and allows us to add our own specific fields, like timezone, team, and api_key.
    • permissions: This is where EMBArk lists all the custom permissions that can be granted to users or groups, allowing for granular control over features.
  3. embark/embark/wsgi_auth.py - Bridging to External Servers: This file is special. It's used when EMBArk is deployed with a web server like Apache, allowing the web server to use EMBArk's user database for authentication.

    # Simplified snippet from embark/embark/wsgi_auth.py
    import os
    import django
    os.environ["DJANGO_SETTINGS_MODULE"] = "embark.settings.deploy"
    django.setup()
    
    from users.models import User
    from django import db
    
    def check_password(environ, user, password):
        # This function is called by the web server to verify a user's password
        try:
            user_obj = User.objects.get(username=user, is_active=True)
        except User.DoesNotExist:
            return None # User not found
        if user_obj.check_password(password):
            return True # Password matches
        return False # Password does not match
        finally:
            db.connection.close()
    
    def groups_for_user(environ, user):
        # This function is called by the web server to get a user's groups
        # ... logic to fetch user's groups ...
        group_list = user_obj.groups.values_list('name', flat=True)
        return group_list
    • check_password: If you're using a web server like Apache with mod_wsgi, this function allows Apache to ask EMBArk directly: "Is this username and password valid?"
    • groups_for_user: Similarly, this function allows the web server to ask: "What groups does this user belong to?" This helps the web server enforce access rules even before the request fully reaches the Django application.

Conclusion

User Authentication and Authorization are the bedrock of EMBArk's security. They ensure that your identity is verified (authentication) and that you only have access to the parts of the system you're supposed to (authorization). From simple logins to API keys for automation, EMBArk leverages robust mechanisms to protect its sensitive firmware analysis data.

In the next chapter, we'll dive into the core functionality of EMBArk: Firmware Analysis Management . You'll learn how EMBArk handles the firmware itself, from uploading to initiating complex analysis processes.


Generated by AI Codebase Knowledge Builder. References: [1], [2], [3], [4], [5], [6], [7], [8]

Clone this wiki locally