208 lines
8.9 KiB
HTML
208 lines
8.9 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>LDAP Authentication</title>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
}
|
|
.container {
|
|
background: white;
|
|
padding: 40px;
|
|
border-radius: 10px;
|
|
box-shadow: 0 15px 35px rgba(0,0,0,0.1);
|
|
max-width: 700px;
|
|
width: 100%;
|
|
}
|
|
h2 { color: #333; margin-bottom: 8px; text-align: center; }
|
|
.subtitle { text-align: center; color: #666; margin-bottom: 25px; font-size: 14px; }
|
|
.form-group { margin-bottom: 20px; }
|
|
label { display: block; margin-bottom: 8px; color: #555; font-weight: 500; }
|
|
input[type="text"], input[type="password"] {
|
|
width: 100%;
|
|
padding: 12px 15px;
|
|
border: 2px solid #ddd;
|
|
border-radius: 6px;
|
|
font-size: 16px;
|
|
transition: border-color 0.3s;
|
|
}
|
|
input:focus { border-color: #667eea; outline: none; }
|
|
button {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 15px 30px;
|
|
border: none;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
width: 100%;
|
|
transition: transform 0.2s;
|
|
margin-top: 10px;
|
|
}
|
|
button:hover { transform: translateY(-2px); }
|
|
.result {
|
|
margin-top: 25px;
|
|
padding: 20px;
|
|
border-radius: 6px;
|
|
display: none;
|
|
}
|
|
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
|
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
|
.user-info { background: #f8f9fa; padding: 15px; border-radius: 6px; margin-top: 15px; }
|
|
.user-info p { margin: 8px 0; color: #333; }
|
|
.loading { display: none; text-align: center; color: #667eea; margin: 10px 0; font-size: 16px; }
|
|
.mode-selector { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin: 15px 0; }
|
|
.mode-option {
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 10px; background: #f8f9fa; border-radius: 6px; cursor: pointer;
|
|
transition: background-color 0.2s;
|
|
}
|
|
.mode-option:hover { background: #e9ecef; }
|
|
.mode-option.active { background: #667eea; color: white; }
|
|
.mode-option input[type="radio"] { margin: 0; }
|
|
.json-preview {
|
|
background: #2d3748; color: #e2e8f0; padding: 15px; border-radius: 6px; margin-top: 10px;
|
|
font-family: 'Courier New', monospace; font-size: 12px; overflow-x: auto;
|
|
white-space: pre-wrap; max-height: 300px; overflow-y: auto;
|
|
}
|
|
.admin-link { text-align: center; margin-top: 20px; }
|
|
.admin-link a { color: #667eea; text-decoration: none; font-size: 14px; }
|
|
.admin-link a:hover { text-decoration: underline; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h2>LDAP Authentication</h2>
|
|
<p class="subtitle">Check user credentials against Active Directory</p>
|
|
|
|
<form id="authForm">
|
|
<div class="form-group">
|
|
<label>Username:</label>
|
|
<input type="text" id="username" name="username" placeholder="user" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Password:</label>
|
|
<input type="password" id="password" name="password" placeholder="••••••••" required>
|
|
</div>
|
|
|
|
<div class="mode-selector">
|
|
<label class="mode-option active" id="modeBasic">
|
|
<input type="radio" name="mode" value="basic" checked>
|
|
<span>Basic Info</span>
|
|
</label>
|
|
<label class="mode-option" id="modeDescription">
|
|
<input type="radio" name="mode" value="description">
|
|
<span>Description Only</span>
|
|
</label>
|
|
<label class="mode-option" id="modeGroups">
|
|
<input type="radio" name="mode" value="groups">
|
|
<span>Groups Only</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mode-selector">
|
|
<label class="mode-option" id="modeAll">
|
|
<input type="radio" name="mode" value="all">
|
|
<span>All Information</span>
|
|
</label>
|
|
</div>
|
|
|
|
<button type="submit">Authenticate</button>
|
|
</form>
|
|
|
|
<div class="loading" id="loading">Authenticating with Active Directory...</div>
|
|
|
|
<div class="result" id="result"></div>
|
|
|
|
<div class="admin-link">
|
|
<a href="/admin">Administrator panel</a>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let currentMode = 'basic';
|
|
|
|
document.querySelectorAll('.mode-option').forEach(option => {
|
|
option.addEventListener('click', function () {
|
|
document.querySelectorAll('.mode-option').forEach(opt => opt.classList.remove('active'));
|
|
this.classList.add('active');
|
|
const radio = this.querySelector('input[type="radio"]');
|
|
radio.checked = true;
|
|
currentMode = radio.value;
|
|
});
|
|
});
|
|
|
|
function escapeHtml(str) {
|
|
return String(str).replace(/[&<>"']/g, c => ({
|
|
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
|
}[c]));
|
|
}
|
|
|
|
document.getElementById('authForm').addEventListener('submit', async function (e) {
|
|
e.preventDefault();
|
|
|
|
const username = document.getElementById('username').value;
|
|
const password = document.getElementById('password').value;
|
|
const resultDiv = document.getElementById('result');
|
|
const loadingDiv = document.getElementById('loading');
|
|
|
|
loadingDiv.style.display = 'block';
|
|
resultDiv.style.display = 'none';
|
|
|
|
try {
|
|
let url = '/api/auth';
|
|
if (currentMode === 'description') url += '?description=1';
|
|
else if (currentMode === 'groups') url += '?groups=1';
|
|
else if (currentMode === 'all') url += '?all=1';
|
|
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
resultDiv.className = 'result success';
|
|
let html = '<h3>Authentication Successful</h3><div class="user-info">';
|
|
if (result.username) html += `<p><strong>Username:</strong> ${escapeHtml(result.username)}</p>`;
|
|
if (result.full_name) html += `<p><strong>Full Name:</strong> ${escapeHtml(result.full_name)}</p>`;
|
|
if (result.email) html += `<p><strong>Email:</strong> ${escapeHtml(result.email)}</p>`;
|
|
if (result.description !== undefined) html += `<p><strong>Description:</strong> ${escapeHtml(result.description || 'Not set')}</p>`;
|
|
if (result.groups) {
|
|
html += `<p><strong>Groups (${result.groups.length}):</strong> ${
|
|
result.groups.length > 0 ? result.groups.map(escapeHtml).join(', ') : 'No groups'
|
|
}</p>`;
|
|
}
|
|
html += '</div>';
|
|
if (result.all_info) {
|
|
html += '<h4 style="margin-top:15px;">All LDAP Attributes:</h4>';
|
|
}
|
|
html += `<div class="json-preview">${escapeHtml(JSON.stringify(result, null, 2))}</div>`;
|
|
resultDiv.innerHTML = html;
|
|
} else {
|
|
resultDiv.className = 'result error';
|
|
resultDiv.innerHTML = `<h3>Authentication Failed</h3><p><strong>Error:</strong> ${escapeHtml(result.error || 'Unknown error')}</p>`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.className = 'result error';
|
|
resultDiv.innerHTML = `<h3>Network Error</h3><p><strong>Error:</strong> ${escapeHtml(error.message)}</p>`;
|
|
} finally {
|
|
loadingDiv.style.display = 'none';
|
|
resultDiv.style.display = 'block';
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |