summaryrefslogtreecommitdiffstats
path: root/plugins/luci-plugin-auth-example/README.md
blob: 23580e19e666a554e207839021895a8d9afffdee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# LuCI Authentication Plugin Example

This package demonstrates how to create authentication plugins for LuCI
that integrate with the plugin UI architecture (System > Plugins).

## Architecture

Authentication plugins consist of two components:

### 1. Backend Plugin (ucode)
**Location**: `/usr/share/ucode/luci/plugins/auth/login/<uuid>.uc`

The backend plugin implements the authentication logic. It must:
- Return a plugin object
- Provide a `check(http, user)` method to determine if auth is required
- Provide a `verify(http, user)` method to validate the auth response
- Use a 32-character hexadecimal UUID as the filename

**Example structure**:
```javascript
return {
    priority: 10,  // Optional: execution order (lower = first)
    
    check: function(http, user) {
        // Return { required: true/false, fields: [...], message: '...', html: '...', assets: [...] }
    },
    
    verify: function(http, user) {
        // Return { success: true/false, message: '...' }
    }
};
```

### 2. UI Plugin (JavaScript)
**Location**: `/www/luci-static/resources/view/plugins/<uuid>.js`

The UI plugin provides configuration interface in System > Plugins. It must:
- Extend `baseclass`
- Define `class: 'auth'` and `type: 'login'`
- Use the same UUID as the backend plugin (without .uc extension)
- Implement `addFormOptions(s)` to add configuration fields
- Optionally implement `configSummary(section)` to show current config

**Example structure**:
```javascript
return baseclass.extend({
    class: 'auth',
    class_i18n: _('Authentication'),
    type: 'login',
    type_i18n: _('Login'),
    
    id: 'd0ecde1b009d44ff82faa8b0ff219cef',
    name: 'My Auth Plugin',
    title: _('My Auth Plugin'),
    description: _('Description of what this plugin does'),
    
    addFormOptions(s) {
        // Add configuration options using form.*
    },
    
    configSummary(section) {
        // Return summary string to display in plugin list
    }
});
```

## Configuration

Plugins are configured through the `luci_plugins` UCI config:

```
config global 'global'
    option enabled '1'                    # Global plugin system
    option auth_login_enabled '1'         # Auth plugin class

config auth_login 'd0ecde1b009d44ff82faa8b0ff219cef'
    option name 'Example Auth Plugin'
    option enabled '1'
    option priority '10'
    option challenge_field 'verification_code'
    option help_text 'Enter your code'
    option test_code '123456'
```

## Integration with Login Flow

1. User enters username/password
2. If password is correct, `check()` is called on each enabled auth plugin
3. If any plugin returns `required: true`, the login form shows additional fields
   and optional raw HTML/JS assets
4. User submits the additional fields
5. `verify()` is called to validate the response
6. If verification succeeds, session is granted
7. If verification fails, user must try again

The dispatcher stores the required plugin UUID list in session state before
verification, then clears it by setting `pending_auth_plugins` to `null` after
successful verification.

Priority is configurable via `luci_plugins.<uuid>.priority` (lower values run first).
If changed at runtime, reload plugin cache or restart services to apply.

## Raw HTML + JS Assets

Plugins may return:

- `html`: raw HTML snippet inserted into the login form
- `assets`: script URLs for challenge UI behavior

Asset security rules:

- URLs must be under `/luci-static/plugins/<plugin-uuid>/`
- Invalid asset URLs are ignored by the framework
- Keep `html` static or generated from trusted values only

## Generating a UUID

Use one of these methods:
```bash
# Linux
cat /proc/sys/kernel/random/uuid | tr -d '-'

# macOS
uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]'

# Online
# Visit https://www.uuidgenerator.net/ and remove dashes
```

## Plugin Types

Common authentication plugin types:
- **TOTP/OTP**: Time-based one-time passwords (Google Authenticator, etc.)
- **SMS**: SMS verification codes
- **Email**: Email verification codes
- **WebAuthn**: FIDO2/WebAuthn hardware keys
- **Biometric**: Fingerprint, face recognition (mobile apps)
- **Push Notification**: Approve/deny on mobile device
- **Security Questions**: Additional security questions

## Testing

1. Install the plugin package
2. Navigate to System > Plugins
3. Enable "Global plugin system"
4. Enable "Authentication > Login"
5. Enable the specific auth plugin and configure it
6. Log out and try logging in
7. After entering correct password, you should see the auth challenge

## Real Implementation Examples

For production use, integrate with actual authentication systems:

- **TOTP**: Use `oathtool` command or liboath library
- **SMS**: Integrate with SMS gateway API
- **WebAuthn**: Use WebAuthn JavaScript API and verify on server
- **LDAP 2FA**: Query LDAP server for 2FA attributes

## See Also

- LuCI Plugin Architecture: commit 617f364
- HTTP Header Plugins: `plugins/luci-plugin-examples/`
- LuCI Dispatcher: `modules/luci-base/ucode/dispatcher.uc`