Authorization Plugin

The Authorization plugin provides fine-grained access control for HTTP requests based on paths, methods, users, roles, and CSS selectors. It supports DOM-aware authorization, allowing you to control access to specific HTML elements within documents.

Overview

The authorization plugin evaluates incoming requests against a set of rules defined in an HTML configuration file. It integrates seamlessly with the basic-auth plugin to enforce authentication and authorization policies.

Key Features

Configuration

The authorization plugin is configured as part of the plugin pipeline in your host configuration:

<li itemprop="plugin" itemscope itemtype="https://rustybeam.net/schema/Plugin">
    <span itemprop="library">file://./plugins/authorization.so</span>
    <meta itemprop="authfile" content="file://./auth/users.html">
</li>

Configuration Parameters

Parameter Type Required Description
authfile String (URL) Yes Path to the HTML file containing users and authorization rules. Supports file:// URLs.

Authorization Rules

Authorization rules are defined using the AuthorizationRule schema in your auth configuration file. Each rule specifies:

Rule Evaluation Priority

Rules are evaluated with the following priority (highest to lowest):

  1. Exact username match: Rules for specific usernames
  2. Dynamic username match: Rules using :username parameter
  3. Role match: Rules for user roles
  4. Wildcard match: Rules with username "*" (anonymous)
Note: The plugin evaluates all matching rules and uses the highest priority match. Within the same priority level, the action (allow/deny) of the matching rule is applied.

DOM-Aware Selector Authorization

The authorization plugin supports CSS selector-based access control, allowing you to restrict access to specific HTML elements within documents. This feature works in conjunction with the selector-handler plugin.

How Selector Authorization Works

  1. Client sends a request with Range: selector={css-selector} header
  2. Authorization plugin extracts the selector from the request
  3. Plugin loads and parses the target HTML document
  4. Checks if the requested elements are allowed by the rules
  5. Uses semantic matching: if rule allows "h1", then "h1.title", "article h1", etc. are also allowed

Selector Matching Semantics

The plugin follows CSS selector semantics:

Dynamic Username Placeholders

The authorization plugin supports dynamic username placeholders in CSS selectors, allowing you to create user-specific authorization rules without having to define separate rules for each user.

Using ${username} in Selectors

You can use ${username} as a placeholder in selector rules, which will be replaced with the authenticated user's username at runtime:

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">user</td>
    <td itemprop="path">/*</td>
    <td itemprop="selector">li:has(meta[content="${username}"])</td>
    <td itemprop="method">GET</td>
    <td itemprop="action">allow</td>
</tr>

This rule allows users with the "user" role to access only <li> elements that contain a <meta> tag with their username in the content attribute.

Features

Example Use Cases

User-Specific Todo Lists

<!-- HTML structure -->
<ul id="todos">
    <li><meta content="alice@example.com">Alice's task</li>
    <li><meta content="bob@example.com">Bob's task</li>
</ul>

<!-- Authorization rule -->
<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">user</td>
    <td itemprop="path">/todos/</td>
    <td itemprop="selector">li:has(meta[content="${username}"])</td>
    <td itemprop="method">GET</td>
    <td itemprop="action">allow</td>
</tr>

With this rule, when alice@example.com requests the todo list, she will only see her own tasks.

User-Specific Form Elements

<!-- Authorization rule for user-specific form fields -->
<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">user</td>
    <td itemprop="path">/profile/</td>
    <td itemprop="selector">.user-${username}-section</td>
    <td itemprop="method">*</td>
    <td itemprop="action">allow</td>
</tr>

This allows users to access only elements with their username in the class name.

Note: The ${username} placeholder is replaced with the exact username as authenticated by the basic-auth or oauth2 plugin. For security, quotes and backslashes in usernames are automatically escaped.

Plugin Pipeline Order

Important: The order of plugins in the pipeline matters! The authorization plugin should typically be placed:
  1. After the basic-auth plugin (which sets the authenticated user)
  2. Before the selector-handler and file-handler plugins (which serve content)

Typical pipeline order:

1. basic-auth.so      → Authenticates user
2. authorization.so   → Checks permissions
3. selector-handler.so → Processes selector requests
4. file-handler.so    → Serves files
5. access-log.so      → Logs requests

Examples

Basic Authorization Configuration

Here's a complete example of an authorization configuration file:

<!DOCTYPE html>
<html>
<head>
    <title>Authorization Configuration</title>
</head>
<body>
    <!-- Credential definitions -->
    <table>
        <thead>
            <tr>
                <th>Username</th>
                <th>Password</th>
                <th>Roles</th>
                <th>Encryption</th>
            </tr>
        </thead>
        <tbody>
            <tr itemscope itemtype="https://rustybeam.net/schema/Credential">
                <td itemprop="username">admin</td>
                <td itemprop="password">admin123</td>
                <td>
                    <ul>
                        <li itemprop="role">administrators</li>
                        <li itemprop="role">users</li>
                    </ul>
                </td>
                <td itemprop="encryption">plaintext</td>
            </tr>
        </tbody>
    </table>
    
    <!-- Authorization rules -->
    <table>
        <thead>
            <tr>
                <th>User/Role</th>
                <th>Path</th>
                <th>Selector</th>
                <th>Methods</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <!-- Administrators have full access -->
            <tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
                <td itemprop="role">administrators</td>
                <td itemprop="path">/*</td>
                <td></td>
                <td>
                    <ul>
                        <li itemprop="method">GET</li>
                        <li itemprop="method">PUT</li>
                        <li itemprop="method">POST</li>
                        <li itemprop="method">DELETE</li>
                    </ul>
                </td>
                <td itemprop="action">allow</td>
            </tr>
            
            <!-- Allow specific selectors for anonymous users -->
            <tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
                <td itemprop="username">*</td>
                <td itemprop="path">/*</td>
                <td itemprop="selector">h1</td>
                <td itemprop="method">GET</td>
                <td itemprop="action">allow</td>
            </tr>
        </tbody>
    </table>
</body>
</html>

Common Authorization Patterns

User-Specific Directories

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">:username</td>
    <td itemprop="path">/users/:username/*</td>
    <td itemprop="method">*</td>
    <td itemprop="action">allow</td>
</tr>

Selector-Based Access for Forms

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">*</td>
    <td itemprop="path">/guestbook/</td>
    <td itemprop="selector">ul.entries</td>
    <td itemprop="method">POST</td>
    <td itemprop="action">allow</td>
</tr>

Deny Access to Sensitive Elements

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">*</td>
    <td itemprop="path">/*</td>
    <td itemprop="selector">.private</td>
    <td itemprop="method">GET</td>
    <td itemprop="action">deny</td>
</tr>

User-Specific Content with ${username}

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">user</td>
    <td itemprop="path">/dashboard/</td>
    <td itemprop="selector">[data-user="${username}"]</td>
    <td itemprop="method">*</td>
    <td itemprop="action">allow</td>
</tr>

This pattern allows users to only access elements that have their username in a data attribute, enabling fine-grained content filtering without creating individual rules for each user.

Integration with Other Plugins

Basic-Auth Plugin

The authorization plugin relies on the basic-auth plugin to authenticate users. The basic-auth plugin sets the authenticated_user metadata, which the authorization plugin uses to identify the user.

Selector-Handler Plugin

The selector-handler plugin processes Range headers with CSS selectors. The authorization plugin intercepts these requests to enforce element-level access control.

Security Considerations

Troubleshooting

Common Issues

Issue Cause Solution
403 Forbidden for all requests No matching authorization rules Add appropriate rules for your users/paths
Authorization not working Plugin order incorrect Ensure authorization comes after basic-auth
Selector authorization failing File not found or not HTML Check file paths and ensure target is HTML
Anonymous access not working Basic-auth rejecting anonymous Use directory plugin or configure basic-auth appropriately
${username} not being replaced User is anonymous or placeholder syntax incorrect Ensure user is authenticated and use exact syntax: ${username}
Email addresses in ${username} not matching Special characters being escaped incorrectly Check logs for the exact selector being used; @ and . are preserved

Debug Logging

Run the server with -v flag to see detailed authorization decisions:

./rusty-beam -v config.html

See Also