456 lines
13 KiB
JavaScript
456 lines
13 KiB
JavaScript
/**
|
|
* @fileoverview Tests for public password management MCP tools
|
|
* Tests password reset, forgot password, and set password functionality
|
|
*/
|
|
|
|
import { describe, test, expect, beforeEach, afterEach } from "@jest/globals";
|
|
import { mockFactory } from "../mocks/mockFactory.js";
|
|
|
|
describe("Public Password Management Tools", () => {
|
|
let mockEnv;
|
|
let toolGenerator;
|
|
|
|
beforeEach(() => {
|
|
mockEnv = mockFactory.createMockEnvironment({
|
|
authTypes: ["public"],
|
|
enableHttpMocks: true,
|
|
});
|
|
|
|
toolGenerator = mockEnv.toolGenerator;
|
|
});
|
|
|
|
afterEach(() => {
|
|
mockFactory.resetAllMocks();
|
|
});
|
|
|
|
describe("public_create_forgotPassword", () => {
|
|
test("should successfully initiate password reset", async () => {
|
|
// Setup
|
|
const toolName = "public_create_forgotPassword";
|
|
const parameters = {
|
|
email: "user@test.com",
|
|
};
|
|
|
|
// Mock successful forgot password response
|
|
mockFactory.httpMocks.mockRequest("POST", "/api/forgot-password", {
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Password reset email sent successfully",
|
|
email: "user@test.com",
|
|
},
|
|
});
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Password reset email sent");
|
|
});
|
|
|
|
test("should validate email format", async () => {
|
|
const toolName = "public_create_forgotPassword";
|
|
const parameters = {
|
|
email: "invalid-email-format",
|
|
};
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
test("should handle non-existent email gracefully", async () => {
|
|
const toolName = "public_create_forgotPassword";
|
|
const parameters = {
|
|
email: "nonexistent@test.com",
|
|
};
|
|
|
|
// Mock response for non-existent email (should still return success for security)
|
|
mockFactory.httpMocks.mockRequest("POST", "/api/forgot-password", {
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "If the email exists, a reset link has been sent",
|
|
},
|
|
});
|
|
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("public_create_frontendforgotPassword", () => {
|
|
test("should successfully initiate patient password reset", async () => {
|
|
// Setup
|
|
const toolName = "public_create_frontendforgotPassword";
|
|
const parameters = {
|
|
email: "patient@test.com",
|
|
};
|
|
|
|
// Mock successful patient forgot password response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/frontend/forgot-password",
|
|
{
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Patient password reset email sent",
|
|
email: "patient@test.com",
|
|
},
|
|
}
|
|
);
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Patient password reset");
|
|
});
|
|
});
|
|
|
|
describe("public_create_providerforgotPassword", () => {
|
|
test("should successfully initiate provider password reset", async () => {
|
|
// Setup
|
|
const toolName = "public_create_providerforgotPassword";
|
|
const parameters = {
|
|
email: "provider@test.com",
|
|
};
|
|
|
|
// Mock successful provider forgot password response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/emr/provider/forgot-password",
|
|
{
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Provider password reset email sent",
|
|
email: "provider@test.com",
|
|
},
|
|
}
|
|
);
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Provider password reset");
|
|
});
|
|
});
|
|
|
|
describe("public_create_passwordReset", () => {
|
|
test("should successfully reset password with valid token", async () => {
|
|
// Setup
|
|
const toolName = "public_create_passwordReset";
|
|
const parameters = {
|
|
token: "valid_reset_token_123",
|
|
email: "user@test.com",
|
|
password: "NewSecurePass123!",
|
|
password_confirmation: "NewSecurePass123!",
|
|
};
|
|
|
|
// Mock successful password reset
|
|
mockFactory.httpMocks.mockRequest("POST", "/api/password-reset", {
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Password reset successfully",
|
|
email: "user@test.com",
|
|
},
|
|
});
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Password reset successfully");
|
|
});
|
|
|
|
test("should validate password confirmation match", async () => {
|
|
const toolName = "public_create_passwordReset";
|
|
const parameters = {
|
|
token: "valid_reset_token_123",
|
|
email: "user@test.com",
|
|
password: "NewSecurePass123!",
|
|
password_confirmation: "DifferentPassword123!",
|
|
};
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
test("should handle invalid reset token", async () => {
|
|
const toolName = "public_create_passwordReset";
|
|
const parameters = {
|
|
token: "invalid_token",
|
|
email: "user@test.com",
|
|
password: "NewSecurePass123!",
|
|
password_confirmation: "NewSecurePass123!",
|
|
};
|
|
|
|
// Mock invalid token response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/password-reset",
|
|
null,
|
|
true,
|
|
{
|
|
response: {
|
|
status: 400,
|
|
data: { error: "Invalid or expired reset token" },
|
|
},
|
|
}
|
|
);
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
test("should handle expired reset token", async () => {
|
|
const toolName = "public_create_passwordReset";
|
|
const parameters = {
|
|
token: "expired_token_456",
|
|
email: "user@test.com",
|
|
password: "NewSecurePass123!",
|
|
password_confirmation: "NewSecurePass123!",
|
|
};
|
|
|
|
// Mock expired token response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/password-reset",
|
|
null,
|
|
true,
|
|
{
|
|
response: {
|
|
status: 410,
|
|
data: { error: "Reset token has expired" },
|
|
},
|
|
}
|
|
);
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe("public_create_frontendresetPassword", () => {
|
|
test("should successfully reset patient password", async () => {
|
|
// Setup
|
|
const toolName = "public_create_frontendresetPassword";
|
|
const parameters = {
|
|
email: "patient@test.com",
|
|
password: "NewPatientPass123!",
|
|
password_confirmation: "NewPatientPass123!",
|
|
token: "patient_reset_token_789",
|
|
};
|
|
|
|
// Mock successful patient password reset
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/frontend/reset-password",
|
|
{
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Patient password reset successfully",
|
|
email: "patient@test.com",
|
|
},
|
|
}
|
|
);
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Patient password reset");
|
|
});
|
|
});
|
|
|
|
describe("public_create_setPassword", () => {
|
|
test("should successfully set password with valid token", async () => {
|
|
// Setup
|
|
const toolName = "public_create_setPassword";
|
|
const parameters = {
|
|
password: "NewPassword123!",
|
|
password_confirmation: "NewPassword123!",
|
|
token: "set_password_token_101",
|
|
};
|
|
|
|
// Mock successful password set
|
|
mockFactory.httpMocks.mockRequest("POST", "/api/set-password", {
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "Password set successfully",
|
|
},
|
|
});
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("Password set successfully");
|
|
});
|
|
|
|
test("should validate password strength requirements", async () => {
|
|
const toolName = "public_create_setPassword";
|
|
|
|
// Test weak passwords
|
|
const weakPasswords = [
|
|
"123", // Too short
|
|
"password", // No numbers/special chars
|
|
"12345678", // Only numbers
|
|
"PASSWORD", // Only uppercase
|
|
"password123", // No special characters
|
|
];
|
|
|
|
for (const weakPassword of weakPasswords) {
|
|
const parameters = {
|
|
password: weakPassword,
|
|
password_confirmation: weakPassword,
|
|
token: "valid_token",
|
|
};
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("public_create_emrsetPassword", () => {
|
|
test("should successfully set EMR password", async () => {
|
|
// Setup
|
|
const toolName = "public_create_emrsetPassword";
|
|
const parameters = {
|
|
password: "EMRPassword123!",
|
|
password_confirmation: "EMRPassword123!",
|
|
token: "emr_token_202",
|
|
};
|
|
|
|
// Mock successful EMR password set
|
|
mockFactory.httpMocks.mockRequest("POST", "/api/emr/set-password", {
|
|
status: 200,
|
|
data: {
|
|
success: true,
|
|
message: "EMR password set successfully",
|
|
},
|
|
});
|
|
|
|
// Execute
|
|
const result = await toolGenerator.executeTool(toolName, parameters);
|
|
|
|
// Assert
|
|
expect(result.success).toBe(true);
|
|
expect(result.data.message).toContain("EMR password set");
|
|
});
|
|
});
|
|
|
|
describe("Password Security Tests", () => {
|
|
test("should enforce password complexity requirements", async () => {
|
|
const toolName = "public_create_passwordReset";
|
|
|
|
// Test various password requirements
|
|
const testCases = [
|
|
{
|
|
password: "short",
|
|
description: "too short",
|
|
},
|
|
{
|
|
password: "nouppercase123!",
|
|
description: "no uppercase",
|
|
},
|
|
{
|
|
password: "NOLOWERCASE123!",
|
|
description: "no lowercase",
|
|
},
|
|
{
|
|
password: "NoNumbers!",
|
|
description: "no numbers",
|
|
},
|
|
{
|
|
password: "NoSpecialChars123",
|
|
description: "no special characters",
|
|
},
|
|
];
|
|
|
|
for (const testCase of testCases) {
|
|
const parameters = {
|
|
token: "valid_token",
|
|
email: "test@test.com",
|
|
password: testCase.password,
|
|
password_confirmation: testCase.password,
|
|
};
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
}
|
|
});
|
|
|
|
test("should handle rate limiting for password reset attempts", async () => {
|
|
const toolName = "public_create_forgotPassword";
|
|
const parameters = {
|
|
email: "ratelimited@test.com",
|
|
};
|
|
|
|
// Mock rate limit response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/forgot-password",
|
|
null,
|
|
true,
|
|
{
|
|
response: {
|
|
status: 429,
|
|
data: { error: "Too many password reset attempts" },
|
|
},
|
|
}
|
|
);
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
test("should not expose sensitive information in error messages", async () => {
|
|
const toolName = "public_create_passwordReset";
|
|
const parameters = {
|
|
token: "invalid_token",
|
|
email: "user@test.com",
|
|
password: "ValidPass123!",
|
|
password_confirmation: "ValidPass123!",
|
|
};
|
|
|
|
// Mock generic error response
|
|
mockFactory.httpMocks.mockRequest(
|
|
"POST",
|
|
"/api/password-reset",
|
|
null,
|
|
true,
|
|
{
|
|
response: {
|
|
status: 400,
|
|
data: { error: "Invalid request" }, // Generic error message
|
|
},
|
|
}
|
|
);
|
|
|
|
await expect(
|
|
toolGenerator.executeTool(toolName, parameters)
|
|
).rejects.toThrow("Invalid request");
|
|
});
|
|
});
|
|
});
|