Skip to content

Commit 4557580

Browse files
AakashaakashH242
authored andcommitted
(Feature) #1336 Added toggles on password input textboxes to mask/unmask the entered value.
Signed-off-by: Aakash <[email protected]>
1 parent 58121a6 commit 4557580

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
@@ -10359,6 +10359,35 @@ window.updateAvailableTags = updateAvailableTags;
1035910359
// MULTI-HEADER AUTHENTICATION MANAGEMENT
1036010360
// ===================================================================
1036110361

10362+
/**
10363+
* Toggle masking for sensitive text inputs (passwords, tokens, headers)
10364+
* @param {HTMLElement|string} inputOrId - Target input element or its ID
10365+
* @param {HTMLElement} button - Button triggering the toggle
10366+
*/
10367+
function toggleInputMask(inputOrId, button) {
10368+
const input =
10369+
typeof inputOrId === "string"
10370+
? document.getElementById(inputOrId)
10371+
: inputOrId;
10372+
10373+
if (!input || !button) {
10374+
return;
10375+
}
10376+
10377+
const revealing = input.type === "password";
10378+
input.type = revealing ? "text" : "password";
10379+
10380+
const label = input.getAttribute("data-sensitive-label") || "value";
10381+
button.textContent = revealing ? "Hide" : "Show";
10382+
button.setAttribute("aria-pressed", revealing ? "true" : "false");
10383+
button.setAttribute(
10384+
"aria-label",
10385+
`${revealing ? "Hide" : "Show"} ${label}`.trim(),
10386+
);
10387+
}
10388+
10389+
window.toggleInputMask = toggleInputMask;
10390+
1036210391
/**
1036310392
* Global counter for unique header IDs
1036410393
*/
@@ -10376,6 +10405,7 @@ function addAuthHeader(containerId) {
1037610405
}
1037710406

1037810407
const headerId = `auth-header-${++headerCounter}`;
10408+
const valueInputId = `${headerId}-value`;
1037910409

1038010410
const headerRow = document.createElement("div");
1038110411
headerRow.className = "flex items-center space-x-2";
@@ -10391,12 +10421,25 @@ function addAuthHeader(containerId) {
1039110421
/>
1039210422
</div>
1039310423
<div class="flex-1">
10394-
<input
10395-
type="password"
10396-
placeholder="Header Value"
10397-
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"
10398-
oninput="updateAuthHeadersJSON('${containerId}')"
10399-
/>
10424+
<div class="relative">
10425+
<input
10426+
type="password"
10427+
id="${valueInputId}"
10428+
placeholder="Header Value"
10429+
data-sensitive-label="header value"
10430+
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"
10431+
oninput="updateAuthHeadersJSON('${containerId}')"
10432+
/>
10433+
<button
10434+
type="button"
10435+
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"
10436+
onclick="toggleInputMask('${valueInputId}', this)"
10437+
aria-pressed="false"
10438+
aria-label="Show header value"
10439+
>
10440+
Show
10441+
</button>
10442+
</div>
1040010443
</div>
1040110444
<button
1040210445
type="button"

mcpgateway/templates/admin.html

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4528,23 +4528,49 @@ <h3 class="text-lg font-bold mb-4 dark:text-gray-200">
45284528
<label class="block text-sm font-medium text-gray-700"
45294529
>Password</label
45304530
>
4531-
<input
4532-
type="password"
4533-
name="auth_password"
4534-
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"
4535-
/>
4531+
<div class="relative">
4532+
<input
4533+
type="password"
4534+
name="auth_password"
4535+
id="auth-password-gw"
4536+
data-sensitive-label="password"
4537+
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"
4538+
/>
4539+
<button
4540+
type="button"
4541+
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"
4542+
onclick="toggleInputMask('auth-password-gw', this)"
4543+
aria-pressed="false"
4544+
aria-label="Show password"
4545+
>
4546+
Show
4547+
</button>
4548+
</div>
45364549
</div>
45374550
</div>
45384551
<div id="auth-bearer-fields-gw" style="display: none">
45394552
<div>
45404553
<label class="block text-sm font-medium text-gray-700"
45414554
>Token</label
45424555
>
4543-
<input
4544-
type="password"
4545-
name="auth_token"
4546-
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"
4547-
/>
4556+
<div class="relative">
4557+
<input
4558+
type="password"
4559+
name="auth_token"
4560+
id="auth-token-gw"
4561+
data-sensitive-label="token"
4562+
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"
4563+
/>
4564+
<button
4565+
type="button"
4566+
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"
4567+
onclick="toggleInputMask('auth-token-gw', this)"
4568+
aria-pressed="false"
4569+
aria-label="Show token"
4570+
>
4571+
Show
4572+
</button>
4573+
</div>
45484574
</div>
45494575
</div>
45504576
<div id="auth-headers-fields-gw" style="display: none">
@@ -7602,29 +7628,55 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
76027628
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"
76037629
/>
76047630
</div>
7605-
<div>
7606-
<label class="block text-sm font-medium text-gray-700"
7607-
>Password</label
7608-
>
7631+
<div>
7632+
<label class="block text-sm font-medium text-gray-700"
7633+
>Password</label
7634+
>
7635+
<div class="relative">
76097636
<input
76107637
type="password"
76117638
name="auth_password"
7612-
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"
7639+
id="auth-password-gw-edit"
7640+
data-sensitive-label="password"
7641+
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"
76137642
/>
7643+
<button
7644+
type="button"
7645+
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"
7646+
onclick="toggleInputMask('auth-password-gw-edit', this)"
7647+
aria-pressed="false"
7648+
aria-label="Show password"
7649+
>
7650+
Show
7651+
</button>
76147652
</div>
76157653
</div>
7616-
<div id="auth-bearer-fields-gw-edit" style="display: none">
7617-
<div>
7618-
<label class="block text-sm font-medium text-gray-700"
7619-
>Token</label
7620-
>
7654+
</div>
7655+
<div id="auth-bearer-fields-gw-edit" style="display: none">
7656+
<div>
7657+
<label class="block text-sm font-medium text-gray-700"
7658+
>Token</label
7659+
>
7660+
<div class="relative">
76217661
<input
76227662
type="password"
76237663
name="auth_token"
7624-
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"
7664+
id="auth-token-gw-edit"
7665+
data-sensitive-label="token"
7666+
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"
76257667
/>
7668+
<button
7669+
type="button"
7670+
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"
7671+
onclick="toggleInputMask('auth-token-gw-edit', this)"
7672+
aria-pressed="false"
7673+
aria-label="Show token"
7674+
>
7675+
Show
7676+
</button>
76267677
</div>
76277678
</div>
7679+
</div>
76287680
<div id="auth-headers-fields-gw-edit" style="display: none">
76297681
<div class="space-y-3">
76307682
<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)