Per-host HTTP basic auth (#57)
Adds opt-in basic auth per Host, following the existing per-host controls
pattern:
- Host fields basicauth_enabled / basicauth_realm / basicauth_users
({user: base64(sha1(pw))}). Credentials are parsed to plaintext by the pure
host_features normalizer and hashed at the route layer (utils/basicauth.js),
so plaintext never reaches Redis.
- ops/nginx_conf/hostfeatures.lua enforces it in access phase: verifies the
Authorization header against base64(sha1(password)), fails closed with a 401
WWW-Authenticate challenge.
- hosts.ejs gains an enable toggle, realm, and a username:password textarea
(passwords never echoed back; blank keeps the current set).
Unit tests cover hashing (matches the htpasswd {SHA} vector), credential
parsing, and normalization. Note: the Lua path needs verification on a live
OpenResty box.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,12 @@
|
||||
$(".hostEditPanel textarea[name='ip_allow']").val(hostFeatureCidrsToText(host.ip_allow));
|
||||
$(".hostEditPanel textarea[name='ip_deny']").val(hostFeatureCidrsToText(host.ip_deny));
|
||||
|
||||
// Never echo basic-auth passwords back to the form; show the current
|
||||
// usernames as a hint and leave the textarea blank (blank = keep).
|
||||
$(".hostEditPanel textarea[name='basicauth_users']").val('');
|
||||
$(".hostEditPanel .basicauth-current").text(
|
||||
Object.keys(host.basicauth_users || {}).join(', ') || 'none');
|
||||
|
||||
$('.hostEditPanel').scrollTo();
|
||||
};
|
||||
|
||||
@@ -532,6 +538,37 @@
|
||||
<textarea name="resp_headers" class="form-control" rows="2" placeholder="Name: value, one per line"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Basic authentication</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="basicauth_enabled" id="basicauth_enabled-false" value="false" checked>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="basicauth_enabled" id="basicauth_enabled-true" value="true">
|
||||
Require username / password
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="basicauth_realm" class="form-label">Realm</label>
|
||||
<input type="text" name="basicauth_realm" class="form-control" value="Restricted" placeholder="Restricted" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="basicauth_users" class="form-label">Users</label>
|
||||
<textarea name="basicauth_users" class="form-control" rows="2" placeholder="username:password, one per line"></textarea>
|
||||
<small class="text-muted">
|
||||
Current: <span class="basicauth-current">none</span>.
|
||||
Passwords are stored hashed and never shown here. Leave blank to
|
||||
keep the current users; entering any lines replaces the whole list.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<hr class="buttonBreak" />
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
|
||||
Reference in New Issue
Block a user