feat: integrate proxy config with OpenBao for secure secret storage
This commit is contained in:
@@ -90,5 +90,42 @@ router.post('/', async (req, res, next) => {
|
|||||||
next(err);
|
next(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
router.get('/proxy', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const proxyConf = await baoConf.get('proxy/conf') || {};
|
||||||
|
const editable = JSON.parse(JSON.stringify(proxyConf));
|
||||||
|
if (editable.oidc && editable.oidc.clientSecret) editable.oidc.clientSecret = MASK;
|
||||||
|
if (editable.ldap && editable.ldap.bindPassword) editable.ldap.bindPassword = MASK;
|
||||||
|
res.json(editable);
|
||||||
|
} catch(err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/proxy', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const existing = await baoConf.get('proxy/conf') || {};
|
||||||
|
const incoming = req.body || {};
|
||||||
|
|
||||||
|
if (incoming.oidc && incoming.oidc.clientSecret !== undefined) {
|
||||||
|
if (incoming.oidc.clientSecret === '' || incoming.oidc.clientSecret === MASK) delete incoming.oidc.clientSecret;
|
||||||
|
}
|
||||||
|
if (incoming.ldap && incoming.ldap.bindPassword !== undefined) {
|
||||||
|
if (incoming.ldap.bindPassword === '' || incoming.ldap.bindPassword === MASK) delete incoming.ldap.bindPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of Object.keys(incoming)) {
|
||||||
|
if (typeof incoming[key] === 'object' && incoming[key] !== null && !Array.isArray(incoming[key])) {
|
||||||
|
existing[key] = { ...(existing[key] || {}), ...incoming[key] };
|
||||||
|
} else {
|
||||||
|
existing[key] = incoming[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await baoConf.set('proxy/conf', existing);
|
||||||
|
res.json({ success: true });
|
||||||
|
} catch(err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
loadConf();
|
loadConf();
|
||||||
|
loadProxyConf();
|
||||||
loadTos();
|
loadTos();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -88,6 +89,47 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadProxyConf() {
|
||||||
|
try {
|
||||||
|
const data = await app.api.get('conf/proxy');
|
||||||
|
if (data.oidc) {
|
||||||
|
$('#proxy-issuer').val(data.oidc.issuer || '');
|
||||||
|
$('#proxy-client-id').val(data.oidc.clientId || '');
|
||||||
|
$('#proxy-client-secret').val(data.oidc.clientSecret || '');
|
||||||
|
}
|
||||||
|
if (data.ldap) {
|
||||||
|
$('#proxy-ldap-bindpass').val(data.ldap.bindPassword || '');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load Proxy conf:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveProxyConf() {
|
||||||
|
const btn = $('#btn-save-proxy');
|
||||||
|
btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Saving...');
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
oidc: {
|
||||||
|
issuer: $('#proxy-issuer').val(),
|
||||||
|
clientId: $('#proxy-client-id').val(),
|
||||||
|
clientSecret: $('#proxy-client-secret').val()
|
||||||
|
},
|
||||||
|
ldap: {
|
||||||
|
bindPassword: $('#proxy-ldap-bindpass').val()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await app.api.post('conf/proxy', payload);
|
||||||
|
app.messages.toast('Proxy configuration saved securely to OpenBao!', 'success');
|
||||||
|
} catch (error) {
|
||||||
|
app.messages.toast('Failed to save Proxy configuration: ' + error.message, 'danger');
|
||||||
|
} finally {
|
||||||
|
btn.prop('disabled', false).html('<i class="fas fa-save"></i> Save Proxy Secrets');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Terms of Service editor ──────────────────────────────────────────
|
// ── Terms of Service editor ──────────────────────────────────────────
|
||||||
// Moved here from the admin Overview dashboard — it's a configuration
|
// Moved here from the admin Overview dashboard — it's a configuration
|
||||||
// control, so it belongs on the System Configuration page. The API is
|
// control, so it belongs on the System Configuration page. The API is
|
||||||
@@ -165,6 +207,9 @@
|
|||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="tos-tab" data-bs-toggle="tab" data-bs-target="#tos" type="button" role="tab">Terms of Service</button>
|
<button class="nav-link" id="tos-tab" data-bs-toggle="tab" data-bs-target="#tos" type="button" role="tab">Terms of Service</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="proxy-tab" data-bs-toggle="tab" data-bs-target="#proxy" type="button" role="tab">Proxy Secrets</button>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content" id="confTabsContent">
|
<div class="tab-content" id="confTabsContent">
|
||||||
@@ -266,6 +311,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Proxy Secrets Tab -->
|
||||||
|
<div class="tab-pane fade" id="proxy" role="tabpanel">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-header bg-white border-bottom-0 pt-4 pb-0">
|
||||||
|
<h5 class="mb-0"><i class="fas fa-shield-alt text-warning me-2"></i> Proxy Secrets (OpenBao)</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="form-text">These secrets are stored directly in OpenBao (`secret/proxy/conf`) and read by the Proxy at boot.</p>
|
||||||
|
|
||||||
|
<h6 class="mt-3 mb-2">OAuth / OIDC Integration</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Issuer URL</label>
|
||||||
|
<input type="text" class="form-control" id="proxy-issuer" placeholder="https://sso.example.com">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Client ID</label>
|
||||||
|
<input type="text" class="form-control" id="proxy-client-id">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Client Secret</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="password" class="form-control" id="proxy-client-secret" placeholder="********">
|
||||||
|
<button class="btn btn-outline-secondary" type="button" onclick="togglePassword('proxy-client-secret')"><i class="fas fa-eye"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h6 class="mt-4 mb-2">LDAP Integration</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Bind Password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="password" class="form-control" id="proxy-ldap-bindpass" placeholder="********">
|
||||||
|
<button class="btn btn-outline-secondary" type="button" onclick="togglePassword('proxy-ldap-bindpass')"><i class="fas fa-eye"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="form-text">Password for the Proxy's LDAP service account.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="btn-save-proxy" class="btn btn-warning mt-2" onclick="saveProxyConf()"><i class="fas fa-save"></i> Save Proxy Secrets</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- ToS Tab -->
|
<!-- ToS Tab -->
|
||||||
<div class="tab-pane fade" id="tos" role="tabpanel">
|
<div class="tab-pane fade" id="tos" role="tabpanel">
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user