Skip to content

Commit 912bdcb

Browse files
aakashH242Aakashcrivetimihai
authored
feat: #1336 Added toggles on password input textboxes to mask/unmask the entered value. (#1337)
* (Feature) #1336 Added toggles on password input textboxes to mask/unmask the entered value. Signed-off-by: Aakash <[email protected]> * Linting Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Aakash <[email protected]> Signed-off-by: Mihai Criveti <[email protected]> Co-authored-by: Aakash <[email protected]> Co-authored-by: Mihai Criveti <[email protected]>
1 parent 44ee927 commit 912bdcb

File tree

4 files changed

+131
-31
lines changed

4 files changed

+131
-31
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This release delivers **REST API Passthrough Capabilities**, **API & UI Paginati
1919
- **🧪 Quality & Testing** - Complete build pipeline verification, enhanced linting, mutation testing, and fuzzing
2020
- **⚡ Performance Optimizations** - Response compression middleware (Brotli, Zstd, GZip) reducing bandwidth by 30-70% + orjson JSON serialization providing 5-6x faster JSON encoding
2121
- **🦀 Rust Plugin Framework** - Optional Rust-accelerated plugins with 5-100x performance improvements
22+
- **💻 Admin UI** - Quality of life improvements for admins when managing MCP servers
2223

2324
### Added
2425

@@ -167,6 +168,10 @@ This release delivers **REST API Passthrough Capabilities**, **API & UI Paginati
167168
- **Implementation**: `mcpgateway/utils/orjson_response.py` configured as default FastAPI response class
168169
- **Test Coverage**: 29 comprehensive unit tests with 100% code coverage
169170

171+
#### **💻 Admin UI enhancements** (#1336)
172+
* **Inspectable auth passwords, tokens and headers** (#1336) - Admins can now view and verify passwords, tokens and custom headers they set when creating or editing MCP servers.
173+
174+
170175
### Fixed
171176

172177
#### **🐛 Critical Multi-Tenancy & RBAC Bugs**

mcpgateway/static/admin.js

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10941,6 +10941,35 @@ window.updateAvailableTags = updateAvailableTags;
1094110941
// MULTI-HEADER AUTHENTICATION MANAGEMENT
1094210942
// ===================================================================
1094310943

10944+
/**
10945+
* Toggle masking for sensitive text inputs (passwords, tokens, headers)
10946+
* @param {HTMLElement|string} inputOrId - Target input element or its ID
10947+
* @param {HTMLElement} button - Button triggering the toggle
10948+
*/
10949+
function toggleInputMask(inputOrId, button) {
10950+
const input =
10951+
typeof inputOrId === "string"
10952+
? document.getElementById(inputOrId)
10953+
: inputOrId;
10954+
10955+
if (!input || !button) {
10956+
return;
10957+
}
10958+
10959+
const revealing = input.type === "password";
10960+
input.type = revealing ? "text" : "password";
10961+
10962+
const label = input.getAttribute("data-sensitive-label") || "value";
10963+
button.textContent = revealing ? "Hide" : "Show";
10964+
button.setAttribute("aria-pressed", revealing ? "true" : "false");
10965+
button.setAttribute(
10966+
"aria-label",
10967+
`${revealing ? "Hide" : "Show"} ${label}`.trim(),
10968+
);
10969+
}
10970+
10971+
window.toggleInputMask = toggleInputMask;
10972+
1094410973
/**
1094510974
* Global counter for unique header IDs
1094610975
*/
@@ -10958,6 +10987,7 @@ function addAuthHeader(containerId) {
1095810987
}
1095910988

1096010989
const headerId = `auth-header-${++headerCounter}`;
10990+
const valueInputId = `${headerId}-value`;
1096110991

1096210992
const headerRow = document.createElement("div");
1096310993
headerRow.className = "flex items-center space-x-2";
@@ -10973,12 +11003,25 @@ function addAuthHeader(containerId) {
1097311003
/>
1097411004
</div>
1097511005
<div class="flex-1">
10976-
<input
10977-
type="password"
10978-
placeholder="Header Value"
10979-
class="auth-header-value block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 text-sm"
10980-
oninput="updateAuthHeadersJSON('${containerId}')"
10981-
/>
11006+
<div class="relative">
11007+
<input
11008+
type="password"
11009+
id="${valueInputId}"
11010+
placeholder="Header Value"
11011+
data-sensitive-label="header value"
11012+
class="auth-header-value block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 text-sm pr-16"
11013+
oninput="updateAuthHeadersJSON('${containerId}')"
11014+
/>
11015+
<button
11016+
type="button"
11017+
class="absolute inset-y-0 right-0 flex items-center px-2 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-indigo-300"
11018+
onclick="toggleInputMask('${valueInputId}', this)"
11019+
aria-pressed="false"
11020+
aria-label="Show header value"
11021+
>
11022+
Show
11023+
</button>
11024+
</div>
1098211025
</div>
1098311026
<button
1098411027
type="button"

mcpgateway/templates/admin.html

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4581,23 +4581,49 @@ <h3 class="text-lg font-bold mb-4 dark:text-gray-200">
45814581
<label class="block text-sm font-medium text-gray-700"
45824582
>Password</label
45834583
>
4584-
<input
4585-
type="password"
4586-
name="auth_password"
4587-
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
4588-
/>
4584+
<div class="relative">
4585+
<input
4586+
type="password"
4587+
name="auth_password"
4588+
id="auth-password-gw"
4589+
data-sensitive-label="password"
4590+
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 pr-16"
4591+
/>
4592+
<button
4593+
type="button"
4594+
class="absolute inset-y-0 right-0 flex items-center px-3 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-indigo-300"
4595+
onclick="toggleInputMask('auth-password-gw', this)"
4596+
aria-pressed="false"
4597+
aria-label="Show password"
4598+
>
4599+
Show
4600+
</button>
4601+
</div>
45894602
</div>
45904603
</div>
45914604
<div id="auth-bearer-fields-gw" style="display: none">
45924605
<div>
45934606
<label class="block text-sm font-medium text-gray-700"
45944607
>Token</label
45954608
>
4596-
<input
4597-
type="password"
4598-
name="auth_token"
4599-
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
4600-
/>
4609+
<div class="relative">
4610+
<input
4611+
type="password"
4612+
name="auth_token"
4613+
id="auth-token-gw"
4614+
data-sensitive-label="token"
4615+
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 pr-16"
4616+
/>
4617+
<button
4618+
type="button"
4619+
class="absolute inset-y-0 right-0 flex items-center px-3 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-indigo-300"
4620+
onclick="toggleInputMask('auth-token-gw', this)"
4621+
aria-pressed="false"
4622+
aria-label="Show token"
4623+
>
4624+
Show
4625+
</button>
4626+
</div>
46014627
</div>
46024628
</div>
46034629
<div id="auth-headers-fields-gw" style="display: none">
@@ -7655,29 +7681,55 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
76557681
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
76567682
/>
76577683
</div>
7658-
<div>
7659-
<label class="block text-sm font-medium text-gray-700"
7660-
>Password</label
7661-
>
7684+
<div>
7685+
<label class="block text-sm font-medium text-gray-700"
7686+
>Password</label
7687+
>
7688+
<div class="relative">
76627689
<input
76637690
type="password"
76647691
name="auth_password"
7665-
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
7692+
id="auth-password-gw-edit"
7693+
data-sensitive-label="password"
7694+
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 pr-16"
76667695
/>
7696+
<button
7697+
type="button"
7698+
class="absolute inset-y-0 right-0 flex items-center px-3 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-indigo-300"
7699+
onclick="toggleInputMask('auth-password-gw-edit', this)"
7700+
aria-pressed="false"
7701+
aria-label="Show password"
7702+
>
7703+
Show
7704+
</button>
76677705
</div>
76687706
</div>
7669-
<div id="auth-bearer-fields-gw-edit" style="display: none">
7670-
<div>
7671-
<label class="block text-sm font-medium text-gray-700"
7672-
>Token</label
7673-
>
7707+
</div>
7708+
<div id="auth-bearer-fields-gw-edit" style="display: none">
7709+
<div>
7710+
<label class="block text-sm font-medium text-gray-700"
7711+
>Token</label
7712+
>
7713+
<div class="relative">
76747714
<input
76757715
type="password"
76767716
name="auth_token"
7677-
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
7717+
id="auth-token-gw-edit"
7718+
data-sensitive-label="token"
7719+
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300 pr-16"
76787720
/>
7721+
<button
7722+
type="button"
7723+
class="absolute inset-y-0 right-0 flex items-center px-3 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-indigo-300"
7724+
onclick="toggleInputMask('auth-token-gw-edit', this)"
7725+
aria-pressed="false"
7726+
aria-label="Show token"
7727+
>
7728+
Show
7729+
</button>
76797730
</div>
76807731
</div>
7732+
</div>
76817733
<div id="auth-headers-fields-gw-edit" style="display: none">
76827734
<div class="space-y-3">
76837735
<div class="flex items-center justify-between">

tests/security/test_security_performance_compatibility.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ def test_endpoint():
5050

5151
# Time without security
5252
client_no_security = TestClient(app_no_security)
53-
start_time = time.time()
53+
start_time = time.perf_counter()
5454
for i in range(iterations):
5555
response = client_no_security.get("/test")
5656
assert response.status_code == 200
57-
time_without_security = time.time() - start_time
57+
time_without_security = time.perf_counter() - start_time
5858

5959
# Time with security
6060
client_with_security = TestClient(app_with_security)
61-
start_time = time.time()
61+
start_time = time.perf_counter()
6262
for i in range(iterations):
6363
response = client_with_security.get("/test")
6464
assert response.status_code == 200
65-
time_with_security = time.time() - start_time
65+
time_with_security = time.perf_counter() - start_time
6666

6767
# Security overhead should be reasonable (< 3x increase)
6868
overhead_ratio = time_with_security / time_without_security

0 commit comments

Comments
 (0)