Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94f1a515b7 | ||
|
|
4dc0ce50e7 | ||
|
|
ee7e7b7bd7 |
@@ -73,6 +73,11 @@ def authenticate_ldap(username, password):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
real_user_dn = conn.entries[0].entry_dn
|
real_user_dn = conn.entries[0].entry_dn
|
||||||
|
user_groups = []
|
||||||
|
if hasattr(conn.entries[0], 'memberOf'):
|
||||||
|
user_groups = [str(g).lower() for g in conn.entries[0].memberOf.values]
|
||||||
|
log.debug(f"LDAP: Found memberOf groups on user: {user_groups}")
|
||||||
|
|
||||||
log.debug(f"LDAP: Canonical DN found: {real_user_dn}")
|
log.debug(f"LDAP: Canonical DN found: {real_user_dn}")
|
||||||
|
|
||||||
# Check roles based on group membership
|
# Check roles based on group membership
|
||||||
@@ -87,27 +92,39 @@ def authenticate_ldap(username, password):
|
|||||||
groups_dn = config.get("groups_dn", "ou=groups")
|
groups_dn = config.get("groups_dn", "ou=groups")
|
||||||
|
|
||||||
# Iterate through mappings to find the highest role
|
# Iterate through mappings to find the highest role
|
||||||
# Priority: admin > user
|
|
||||||
potential_roles = []
|
potential_roles = []
|
||||||
|
|
||||||
for mapping in role_mappings:
|
for mapping in role_mappings:
|
||||||
group_name = mapping["group"]
|
group_name = mapping["group"]
|
||||||
target_role = mapping["role"]
|
target_role = mapping["role"]
|
||||||
|
|
||||||
# Construct group DN if it's just a common name, else use as is
|
# Construct group DN if it's just a common name
|
||||||
if "=" not in group_name:
|
if "=" not in group_name:
|
||||||
full_group_dn = f"cn={group_name},{groups_dn},{base_dn}"
|
full_group_dn = f"cn={group_name},{groups_dn},{base_dn}"
|
||||||
else:
|
else:
|
||||||
full_group_dn = group_name
|
full_group_dn = group_name
|
||||||
|
|
||||||
|
full_group_dn_lower = full_group_dn.lower()
|
||||||
|
|
||||||
log.debug(f"LDAP: Checking membership in group: {full_group_dn}")
|
log.debug(f"LDAP: Checking membership in group: {full_group_dn}")
|
||||||
conn.search(full_group_dn, '(objectClass=*)', attributes=['member'])
|
|
||||||
|
# Method 1: Check memberOf if available (AD/LLDAP)
|
||||||
|
if full_group_dn_lower in user_groups:
|
||||||
|
log.debug(f"LDAP: Match found via memberOf for {target_role}")
|
||||||
|
potential_roles.append(target_role)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Method 2: Search group's member attribute (Standard LDAP)
|
||||||
|
conn.search(full_group_dn, '(objectClass=*)', attributes=['member', 'uniqueMember'])
|
||||||
if conn.entries:
|
if conn.entries:
|
||||||
members = conn.entries[0].member.values
|
members = []
|
||||||
if real_user_dn in members or user_dn in members or \
|
if hasattr(conn.entries[0], 'member'):
|
||||||
any(m.lower().replace(" ", "") == real_user_dn.lower().replace(" ", "") for m in members):
|
members = [str(m).lower() for m in conn.entries[0].member.values]
|
||||||
log.debug(f"LDAP: User is in group {group_name}, assigning role: {target_role}")
|
elif hasattr(conn.entries[0], 'uniqueMember'):
|
||||||
|
members = [str(m).lower() for m in conn.entries[0].uniqueMember.values]
|
||||||
|
|
||||||
|
if real_user_dn.lower() in members or user_dn.lower() in members:
|
||||||
|
log.debug(f"LDAP: Match found via group search for {target_role}")
|
||||||
potential_roles.append(target_role)
|
potential_roles.append(target_role)
|
||||||
|
|
||||||
if "admin" in potential_roles:
|
if "admin" in potential_roles:
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
# TFM aInventory - Caddy Explicit IP Configuration
|
# TFM aInventory - Caddy Patched IP Configuration
|
||||||
# Version 1.9.10 - Focused on resolving Protocol Errors on private IPs.
|
# Version 1.9.14 - Protocol Lock & Debug Mode
|
||||||
{
|
{
|
||||||
admin off
|
admin off
|
||||||
admin off
|
|
||||||
# Enable debug logging for SSL handshake diagnostics
|
# Enable debug logging for SSL handshake diagnostics
|
||||||
auto_https disable_redirects
|
debug
|
||||||
}
|
|
||||||
|
# Trust local CA for internal certificate issuance
|
||||||
|
local_certs
|
||||||
|
# Avoid errors if the user isn't root (though inside Docker we usually are)
|
||||||
|
skip_install_trust
|
||||||
|
}
|
||||||
|
|
||||||
# Explicit Frontend SSL Proxy (8919 -> 443)
|
# Explicit Frontend SSL Proxy (8919 -> 443)
|
||||||
https://{$SERVER_IP:192.168.84.113}:443 {
|
https://:443 {
|
||||||
tls internal
|
tls internal
|
||||||
reverse_proxy frontend:3000
|
reverse_proxy frontend:3000
|
||||||
|
|
||||||
|
# Security Headers for PWA
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Explicit Backend SSL Proxy (8918 -> 444)
|
# Explicit Backend SSL Proxy (8918 -> 444)
|
||||||
https://{$SERVER_IP:192.168.84.113}:444 {
|
https://:444 {
|
||||||
tls internal
|
tls internal
|
||||||
reverse_proxy backend:8000
|
reverse_proxy backend:8000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
config/proxy/Dockerfile
Normal file
8
config/proxy/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM caddy:2-alpine
|
||||||
|
|
||||||
|
# Install nss-tools to allow Caddy to manage its internal trust store (fixes certutil warning)
|
||||||
|
# Install ca-certificates to ensure Caddy can trust external sites if needed
|
||||||
|
RUN apk add --no-cache nss-tools ca-certificates
|
||||||
|
|
||||||
|
# Expose the internal proxy ports
|
||||||
|
EXPOSE 80 443 444
|
||||||
29
deploy.sh
29
deploy.sh
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# TFM aInventory - Bulletproof Deployment Script (v1.9.10)
|
# TFM aInventory - Bulletproof Deployment Script (v1.9.12)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -30,7 +30,7 @@ for arg in "$@"; do
|
|||||||
--help)
|
--help)
|
||||||
echo "Usage: ./deploy.sh [options]"
|
echo "Usage: ./deploy.sh [options]"
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " --reset-ssl Clear Caddy storage and reset certificates"
|
echo " --reset-ssl Clear Caddy storage and reset certificates (Aggressive)"
|
||||||
echo " --reset-admin Force reset Admin password to 'Admin123!'"
|
echo " --reset-admin Force reset Admin password to 'Admin123!'"
|
||||||
echo " --help Show this help message"
|
echo " --help Show this help message"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -39,19 +39,25 @@ for arg in "$@"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ "$RESET_SSL" = true ]; then
|
if [ "$RESET_SSL" = true ]; then
|
||||||
echo "🧹 Resetting SSL certificates..."
|
echo "🧹 Aggressive SSL Reset in progress..."
|
||||||
docker compose down
|
docker compose down
|
||||||
|
# Clear internal docker volumes
|
||||||
docker volume rm -f inventory_caddy_data 2>/dev/null || true
|
docker volume rm -f inventory_caddy_data 2>/dev/null || true
|
||||||
echo "✅ SSL data cleared."
|
docker volume rm -f inventory_caddy_config 2>/dev/null || true
|
||||||
|
# Clear persistent host volumes if they exist
|
||||||
|
rm -rf ./data/caddy_data/* 2>/dev/null || true
|
||||||
|
rm -rf ./data/caddy_config/* 2>/dev/null || true
|
||||||
|
echo "✅ SSL storage completely cleared."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🚀 Starting TFM aInventory Services..."
|
echo "🚀 Starting TFM aInventory Services..."
|
||||||
|
# Use --build to ensure the custom Caddy image is built
|
||||||
docker compose --env-file inventory.env up -d --build --remove-orphans
|
docker compose --env-file inventory.env up -d --build --remove-orphans
|
||||||
|
|
||||||
if [ "$RESET_ADMIN" = true ]; then
|
if [ "$RESET_ADMIN" = true ]; then
|
||||||
echo "🔐 Resetting Admin credentials..."
|
echo "🔐 Resetting Admin credentials..."
|
||||||
# Wait for container to be ready
|
# Wait for container to be ready
|
||||||
sleep 2
|
sleep 3
|
||||||
docker compose exec backend python3 -m backend.scripts.reset_admin
|
docker compose exec backend python3 -m backend.scripts.reset_admin
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -60,17 +66,18 @@ echo "🔍 Verifying port mapping..."
|
|||||||
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "🚀 DIAGNOSTIC LOGS (Proxy SSL Handshake):"
|
echo "🚀 DIAGNOSTIC LOGS (Proxy Status):"
|
||||||
docker compose logs proxy --tail 20
|
docker compose logs proxy --tail 20
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ Deployment complete."
|
echo "✅ Deployment complete (v1.9.12)."
|
||||||
echo " ------------------------------------------------------------"
|
echo " ------------------------------------------------------------"
|
||||||
echo " DEFAULT CREDENTIALS:"
|
echo " ACCESS COORDINATES:"
|
||||||
|
echo " 1. SECURE: https://${SERVER_IP:-localhost}:${FRONTEND_SSL_PORT:-8919}"
|
||||||
|
echo " 2. DIRECT: http://${SERVER_IP:-localhost}:${FRONTEND_PORT:-8917}"
|
||||||
|
echo " ------------------------------------------------------------"
|
||||||
|
echo " CREDENTIALS (if first run or reset):"
|
||||||
echo " User: Admin"
|
echo " User: Admin"
|
||||||
echo " Pass: Admin123!"
|
echo " Pass: Admin123!"
|
||||||
echo " ------------------------------------------------------------"
|
echo " ------------------------------------------------------------"
|
||||||
echo " 1. SECURE ACCESS: https://${SERVER_IP:-localhost}:${FRONTEND_SSL_PORT:-8919}"
|
|
||||||
echo " 2. DIRECT ACCESS: http://${SERVER_IP:-localhost}:${FRONTEND_PORT:-8917}"
|
|
||||||
echo " ------------------------------------------------------------"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
|
- ./config:/app/config
|
||||||
- ./scripts:/app/scripts:ro
|
- ./scripts:/app/scripts:ro
|
||||||
environment:
|
environment:
|
||||||
- DATA_DIR=/app/data
|
- DATA_DIR=/app/data
|
||||||
@@ -36,7 +37,9 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: caddy:alpine
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: config/proxy/Dockerfile
|
||||||
networks:
|
networks:
|
||||||
- inventory_net
|
- inventory_net
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version": "1.9.10", "last_build": "2026-04-13-2207", "codename": "AccessRecovery", "commit": "bdf6d605"}
|
{"version": "1.9.13", "last_build": "2026-04-13-2231", "codename": "BareMetal", "commit": "4dc0ce50"}
|
||||||
|
|||||||
Reference in New Issue
Block a user