docker-openldap/tests/test-container.sh
Patrick de Ruiter 3b8d3a0e85
Some checks failed
CI Pipeline / lint (push) Successful in 19s
CI Pipeline / build (push) Successful in 41s
CI Pipeline / security-scan (push) Successful in 1m21s
CI Pipeline / test (push) Failing after 1m1s
CI Pipeline / push (push) Has been skipped
CI Pipeline / update-cd (push) Has been skipped
Fix schema and overlay tests to use SASL EXTERNAL for cn=config access
2025-12-26 00:46:00 +01:00

413 lines
12 KiB
Bash
Executable File

#!/bin/sh
#
# OpenLDAP Container Integration Tests
# Runs a series of tests to verify the container works correctly
#
set -e
# Configuration
CONTAINER_NAME="${CONTAINER_NAME:-openldap-test}"
IMAGE_NAME="${IMAGE_NAME:-enterprise-openldap:test}"
LDAP_DOMAIN="${LDAP_DOMAIN:-test.local}"
LDAP_ORGANISATION="${LDAP_ORGANISATION:-Test Organisation}"
LDAP_ADMIN_PASSWORD="${LDAP_ADMIN_PASSWORD:-testpassword123}"
LDAP_BASE_DN="dc=test,dc=local"
MAX_WAIT="${MAX_WAIT:-60}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Counters
TESTS_PASSED=0
TESTS_FAILED=0
# Helper functions
log_info() {
echo "${YELLOW}[INFO]${NC} $1"
}
log_pass() {
echo "${GREEN}[PASS]${NC} $1"
TESTS_PASSED=$((TESTS_PASSED + 1))
}
log_fail() {
echo "${RED}[FAIL]${NC} $1"
TESTS_FAILED=$((TESTS_FAILED + 1))
}
cleanup() {
log_info "Cleaning up test container..."
docker rm -f "$CONTAINER_NAME" 2>/dev/null || true
}
# Ensure cleanup on exit
trap cleanup EXIT
# Start the container
start_container() {
log_info "Starting test container with image: $IMAGE_NAME"
docker run -d \
--name "$CONTAINER_NAME" \
-e LDAP_DOMAIN="$LDAP_DOMAIN" \
-e LDAP_ORGANISATION="$LDAP_ORGANISATION" \
-e LDAP_ADMIN_PASSWORD="$LDAP_ADMIN_PASSWORD" \
-e LDAP_TLS_ENABLED=false \
-e LDAP_CREATE_SERVICE_ACCOUNTS=true \
-e LDAP_LOG_LEVEL=256 \
"$IMAGE_NAME"
if [ $? -eq 0 ]; then
log_pass "Container started"
else
log_fail "Container failed to start"
return 1
fi
}
# Wait for LDAP to be ready
wait_for_ldap() {
log_info "Waiting for LDAP to be ready (max ${MAX_WAIT}s)..."
local count=0
while [ $count -lt $MAX_WAIT ]; do
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost -b "" -s base "objectClass=*" >/dev/null 2>&1; then
log_pass "LDAP is responding"
return 0
fi
count=$((count + 1))
sleep 1
done
log_fail "LDAP did not become ready within ${MAX_WAIT}s"
log_info "Container logs:"
docker logs "$CONTAINER_NAME" 2>&1 | tail -50
return 1
}
# Test: Verify base DN exists
test_base_dn() {
log_info "Testing base DN exists..."
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "$LDAP_BASE_DN" -s base "objectClass=*" >/dev/null 2>&1; then
log_pass "Base DN exists and admin can bind"
else
log_fail "Base DN test failed"
return 1
fi
}
# Test: Verify organizational units
test_organizational_units() {
log_info "Testing organizational units..."
local ous="People Groups Services Policies"
local failed=0
for ou in $ous; do
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "ou=$ou,$LDAP_BASE_DN" -s base "objectClass=organizationalUnit" 2>/dev/null | grep -q "dn: ou=$ou"; then
log_pass "OU=$ou exists"
else
log_fail "OU=$ou not found"
failed=1
fi
done
return $failed
}
# Test: Verify schemas are loaded
test_schemas() {
log_info "Testing schemas are loaded..."
local schemas="core cosine inetorgperson"
local failed=0
# Get loaded schemas using SASL EXTERNAL via ldapi (requires root in container)
local loaded_schemas=$(docker exec "$CONTAINER_NAME" ldapsearch -Y EXTERNAL -H ldapi://%2Frun%2Fopenldap%2Fldapi \
-b "cn=schema,cn=config" -s one "objectClass=*" cn 2>/dev/null | grep "^cn:" | tr -d ' ')
for schema in $schemas; do
if echo "$loaded_schemas" | grep -qi "$schema"; then
log_pass "Schema '$schema' is loaded"
else
log_fail "Schema '$schema' not found"
failed=1
fi
done
return $failed
}
# Test: Verify overlays are configured
test_overlays() {
log_info "Testing overlays are configured..."
local overlays="memberof refint unique ppolicy"
local failed=0
for overlay in $overlays; do
if docker exec "$CONTAINER_NAME" ldapsearch -Y EXTERNAL -H ldapi://%2Frun%2Fopenldap%2Fldapi \
-b "cn=config" "olcOverlay={*}$overlay" 2>/dev/null | grep -qi "olcOverlay.*$overlay"; then
log_pass "Overlay '$overlay' is configured"
else
log_fail "Overlay '$overlay' not found"
failed=1
fi
done
return $failed
}
# Test: Verify service accounts exist
test_service_accounts() {
log_info "Testing service accounts..."
local services="keycloak nextcloud gitea postfix dovecot sssd"
local failed=0
for service in $services; do
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "cn=$service,ou=Services,$LDAP_BASE_DN" -s base "objectClass=*" 2>/dev/null | grep -q "dn: cn=$service"; then
log_pass "Service account '$service' exists"
else
log_fail "Service account '$service' not found"
failed=1
fi
done
return $failed
}
# Test: Add a user
test_add_user() {
log_info "Testing add user..."
local user_ldif=$(cat <<EOF
dn: uid=testuser,ou=People,$LDAP_BASE_DN
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser
cn: Test User
sn: User
givenName: Test
mail: testuser@$LDAP_DOMAIN
uidNumber: 10001
gidNumber: 10000
homeDirectory: /home/testuser
loginShell: /bin/bash
userPassword: testuser123
EOF
)
if echo "$user_ldif" | docker exec -i "$CONTAINER_NAME" ldapadd -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" >/dev/null 2>&1; then
log_pass "User 'testuser' created"
else
log_fail "Failed to create user 'testuser'"
return 1
fi
}
# Test: Add a group with member
test_add_group() {
log_info "Testing add group with member..."
local group_ldif=$(cat <<EOF
dn: cn=testgroup,ou=Groups,$LDAP_BASE_DN
objectClass: groupOfMembers
objectClass: posixGroup
cn: testgroup
gidNumber: 10001
description: Test Group
member: uid=testuser,ou=People,$LDAP_BASE_DN
EOF
)
if echo "$group_ldif" | docker exec -i "$CONTAINER_NAME" ldapadd -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" >/dev/null 2>&1; then
log_pass "Group 'testgroup' created with member"
else
log_fail "Failed to create group 'testgroup'"
return 1
fi
}
# Test: Verify memberOf overlay works
test_memberof_overlay() {
log_info "Testing memberOf overlay..."
# Check if user has memberOf attribute
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "uid=testuser,ou=People,$LDAP_BASE_DN" memberOf 2>/dev/null | grep -q "memberOf: cn=testgroup"; then
log_pass "memberOf attribute correctly set on user"
else
log_fail "memberOf attribute not found on user"
return 1
fi
}
# Test: User authentication
test_user_authentication() {
log_info "Testing user authentication..."
if docker exec "$CONTAINER_NAME" ldapwhoami -x -H ldap://localhost \
-D "uid=testuser,ou=People,$LDAP_BASE_DN" -w "testuser123" 2>/dev/null | grep -q "testuser"; then
log_pass "User authentication successful"
else
log_fail "User authentication failed"
return 1
fi
}
# Test: Service account can search
test_service_account_search() {
log_info "Testing service account can search users..."
# Get keycloak password from the container
local keycloak_pass=$(docker exec "$CONTAINER_NAME" cat /var/lib/openldap/service-passwords.txt 2>/dev/null | grep keycloak | cut -d: -f2 | tr -d ' ')
if [ -z "$keycloak_pass" ]; then
log_fail "Could not retrieve keycloak service account password"
return 1
fi
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=keycloak,ou=Services,$LDAP_BASE_DN" -w "$keycloak_pass" \
-b "ou=People,$LDAP_BASE_DN" "(uid=testuser)" uid 2>/dev/null | grep -q "uid: testuser"; then
log_pass "Service account can search users"
else
log_fail "Service account search failed"
return 1
fi
}
# Test: Unique overlay (duplicate uid should fail)
test_unique_overlay() {
log_info "Testing unique overlay (duplicate uid should be rejected)..."
local dup_ldif=$(cat <<EOF
dn: uid=testuser2,ou=People,$LDAP_BASE_DN
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser
cn: Duplicate User
sn: Duplicate
uidNumber: 10002
gidNumber: 10000
homeDirectory: /home/testuser2
EOF
)
if echo "$dup_ldif" | docker exec -i "$CONTAINER_NAME" ldapadd -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" 2>&1 | grep -qi "constraint violation\|already exists\|unique"; then
log_pass "Unique overlay rejected duplicate uid"
else
# Check if it was rejected by checking entry doesn't exist
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "uid=testuser2,ou=People,$LDAP_BASE_DN" 2>/dev/null | grep -q "numEntries: 0\|No such object"; then
log_pass "Unique overlay rejected duplicate uid"
else
log_fail "Unique overlay did not reject duplicate uid"
return 1
fi
fi
}
# Test: Refint overlay (delete user should remove from group)
test_refint_overlay() {
log_info "Testing refint overlay (user deletion updates group)..."
# Delete the test user
if docker exec "$CONTAINER_NAME" ldapdelete -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
"uid=testuser,ou=People,$LDAP_BASE_DN" >/dev/null 2>&1; then
# Check if user was removed from group
if docker exec "$CONTAINER_NAME" ldapsearch -x -H ldap://localhost \
-D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "cn=testgroup,ou=Groups,$LDAP_BASE_DN" member 2>/dev/null | grep -q "member: uid=testuser"; then
log_fail "Refint overlay did not remove user from group"
return 1
else
log_pass "Refint overlay removed user from group"
fi
else
log_fail "Failed to delete test user"
return 1
fi
}
# Main test execution
main() {
echo "=============================================="
echo " OpenLDAP Container Integration Tests"
echo "=============================================="
echo ""
# Setup
cleanup
start_container || exit 1
wait_for_ldap || exit 1
echo ""
echo "--- Basic Structure Tests ---"
test_base_dn
test_organizational_units
echo ""
echo "--- Schema Tests ---"
test_schemas
echo ""
echo "--- Overlay Configuration Tests ---"
test_overlays
echo ""
echo "--- Service Account Tests ---"
test_service_accounts
echo ""
echo "--- Functional Tests ---"
test_add_user
test_add_group
test_memberof_overlay
test_user_authentication
test_service_account_search
test_unique_overlay
test_refint_overlay
echo ""
echo "=============================================="
echo " Test Results"
echo "=============================================="
echo " ${GREEN}Passed: $TESTS_PASSED${NC}"
echo " ${RED}Failed: $TESTS_FAILED${NC}"
echo "=============================================="
if [ $TESTS_FAILED -gt 0 ]; then
echo ""
log_info "Container logs (last 30 lines):"
docker logs "$CONTAINER_NAME" 2>&1 | tail -30
exit 1
fi
exit 0
}
main "$@"