Fix test user authentication issues
Fixed email validation and token hashing: - Changed test user emails from @test.local to @example.com (valid domain) - Replaced passlib bcrypt for JWT token hashing with SHA-256 (no length limit) - Improved error handling in SimpleLogin component for validation errors - Deleted old test users and recreated with valid emails Credentials: - Admin: admin@example.com / admin - User: user@example.com / user Note: bcrypt still used for password hashing (in auth_service.py), but SHA-256 for JWT token hashing to avoid 72-byte limit. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b284cadb86
commit
8149a98bd6
3 changed files with 32 additions and 21 deletions
|
|
@ -8,16 +8,13 @@ import logging
|
|||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Dict
|
||||
import jwt
|
||||
from passlib.context import CryptContext
|
||||
import hashlib
|
||||
|
||||
from app.config import get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
settings = get_settings()
|
||||
|
||||
# Password hashing context
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
|
||||
def create_access_token(
|
||||
data: Dict,
|
||||
|
|
@ -96,15 +93,15 @@ def decode_token(token: str) -> Optional[Dict]:
|
|||
|
||||
def hash_token(token: str) -> str:
|
||||
"""
|
||||
Hash token for secure storage
|
||||
Hash token for secure storage using SHA-256
|
||||
|
||||
Args:
|
||||
token: Token string to hash
|
||||
|
||||
Returns:
|
||||
Hashed token
|
||||
Hashed token (hex digest)
|
||||
"""
|
||||
return pwd_context.hash(token)
|
||||
return hashlib.sha256(token.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
def verify_token_hash(token: str, hashed: str) -> bool:
|
||||
|
|
@ -118,7 +115,7 @@ def verify_token_hash(token: str, hashed: str) -> bool:
|
|||
Returns:
|
||||
True if token matches hash
|
||||
"""
|
||||
return pwd_context.verify(token, hashed)
|
||||
return hash_token(token) == hashed
|
||||
|
||||
|
||||
def get_token_subject(token: str) -> Optional[str]:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ async def create_test_users():
|
|||
|
||||
# Admin user
|
||||
result = await session.execute(
|
||||
select(User).where(User.email == "admin@test.local")
|
||||
select(User).where(User.email == "admin@example.com")
|
||||
)
|
||||
admin = result.scalar_one_or_none()
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ async def create_test_users():
|
|||
admin = User(
|
||||
id=uuid.uuid4(),
|
||||
azure_ad_id="test_admin", # Special flag for test users
|
||||
email="admin@test.local",
|
||||
email="admin@example.com",
|
||||
display_name="Test Admin",
|
||||
given_name="Admin",
|
||||
surname="User",
|
||||
|
|
@ -58,13 +58,13 @@ async def create_test_users():
|
|||
}
|
||||
)
|
||||
session.add(admin)
|
||||
print(f"✅ Created admin user: admin@test.local / admin")
|
||||
print(f"✅ Created admin user: admin@example.com / admin")
|
||||
else:
|
||||
print(f"ℹ️ Admin user already exists")
|
||||
|
||||
# Regular user
|
||||
result = await session.execute(
|
||||
select(User).where(User.email == "user@test.local")
|
||||
select(User).where(User.email == "user@example.com")
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ async def create_test_users():
|
|||
user = User(
|
||||
id=uuid.uuid4(),
|
||||
azure_ad_id="test_user", # Special flag for test users
|
||||
email="user@test.local",
|
||||
email="user@example.com",
|
||||
display_name="Test User",
|
||||
given_name="Test",
|
||||
surname="User",
|
||||
|
|
@ -85,7 +85,7 @@ async def create_test_users():
|
|||
}
|
||||
)
|
||||
session.add(user)
|
||||
print(f"✅ Created regular user: user@test.local / user")
|
||||
print(f"✅ Created regular user: user@example.com / user")
|
||||
else:
|
||||
print(f"ℹ️ Regular user already exists")
|
||||
|
||||
|
|
@ -97,8 +97,8 @@ async def create_test_users():
|
|||
print("Test users created successfully!")
|
||||
print("="*60)
|
||||
print("\n📝 Login credentials:")
|
||||
print(" Admin: admin@test.local / admin")
|
||||
print(" User: user@test.local / user")
|
||||
print(" Admin: admin@example.com / admin")
|
||||
print(" User: user@example.com / user")
|
||||
print("\n🔗 Use these at: http://localhost:3000")
|
||||
print("="*60)
|
||||
|
||||
|
|
|
|||
|
|
@ -34,19 +34,33 @@ const SimpleLogin: React.FC<SimpleLoginProps> = ({ onLoginSuccess }) => {
|
|||
onLoginSuccess(response.data.access_token, response.data.user);
|
||||
} catch (err: any) {
|
||||
console.error('Login failed:', err);
|
||||
setError(err.response?.data?.detail || 'Login failed. Please check your credentials.');
|
||||
|
||||
// Handle validation errors from FastAPI
|
||||
if (err.response?.data?.detail) {
|
||||
const detail = err.response.data.detail;
|
||||
if (Array.isArray(detail)) {
|
||||
// Pydantic validation errors
|
||||
setError(detail.map((e: any) => e.msg).join(', '));
|
||||
} else if (typeof detail === 'string') {
|
||||
setError(detail);
|
||||
} else {
|
||||
setError('Login failed. Please check your credentials.');
|
||||
}
|
||||
} else {
|
||||
setError('Login failed. Please check your credentials.');
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fillAdmin = () => {
|
||||
setEmail('admin@test.local');
|
||||
setEmail('admin@example.com');
|
||||
setPassword('admin');
|
||||
};
|
||||
|
||||
const fillUser = () => {
|
||||
setEmail('user@test.local');
|
||||
setEmail('user@example.com');
|
||||
setPassword('user');
|
||||
};
|
||||
|
||||
|
|
@ -116,8 +130,8 @@ const SimpleLogin: React.FC<SimpleLoginProps> = ({ onLoginSuccess }) => {
|
|||
<div className="login-info">
|
||||
<p><strong>Test Accounts:</strong></p>
|
||||
<ul>
|
||||
<li>Admin: admin@test.local / admin</li>
|
||||
<li>User: user@test.local / user</li>
|
||||
<li>Admin: admin@example.com / admin</li>
|
||||
<li>User: user@example.com / user</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue