diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 01b92ef8b..0e5caa330 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -8,6 +8,25 @@ env: REPO: ${{ github.repository }} jobs: + run_gssapi_test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Pull tests + run: cd integration_tests/gssapi && docker compose pull + - name: run test enviroment + run: cd integration_tests/gssapi && docker compose up -d + - name: set execute permission + run: cd integration_tests/gssapi && chmod +x run.sh + - name: run gssapi test + run: cd integration_tests/gssapi && ./run.sh + ruff_linter: runs-on: ubuntu-latest steps: diff --git a/integration_tests/gssapi/docker-compose.yaml b/integration_tests/gssapi/docker-compose.yaml new file mode 100644 index 000000000..82eb2dc69 --- /dev/null +++ b/integration_tests/gssapi/docker-compose.yaml @@ -0,0 +1,283 @@ +# For local development +# Copyright (c) 2024 MultiFactor +# License: https://github.com/MultiDirectoryLab/MultiDirectory/blob/main/LICENSE +services: + traefik: + image: "traefik:v2.6" + container_name: "traefik" + command: + - "--log.level=INFO" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.ldap.address=:389" + - "--entrypoints.ldaps.address=:636" + - "--entrypoints.kadmind.address=:749" + - "--entrypoints.kpasswd.address=:464" + - "--entrypoints.bind_dns.address=:53" + ports: + - "80:80" + - "8080:8080" + - "389:389" + - "636:636" + - "749:749" + - "464:464" + - "530:53" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + + ldap_server: + image: ghcr.io/multidirectorylab/multidirectory:beta + restart: unless-stopped + # container_name: multidirectory + volumes: + - certs:/certs + - ldap_keytab:/LDAP_keytab/ + environment: + DOCKER_DEFAULT_PLATFORM: linux/arm64 + DOMAIN: md.localhost + DEBUG: 1 + POSTGRES_USER: user + POSTGRES_PASSWORD: test_pwd + SECRET_KEY: 6a0452ae20cab4e21b6e9d18fa4b7bf397dd66ec3968b2d74 + MFA_API_SOURCE: dev + command: python -OO multidirectory.py --ldap + tty: true + depends_on: + migrations: + condition: service_completed_successfully + cert_local_check: + condition: service_completed_successfully + deploy: + mode: replicated + replicas: 2 + endpoint_mode: dnsrr + resources: + limits: + cpus: '1.0' + memory: 100M + reservations: + cpus: '0.25' + memory: 20M + labels: + - traefik.enable=true + + - traefik.tcp.routers.ldap.rule=HostSNI(`*`) + - traefik.tcp.routers.ldap.entrypoints=ldap + - traefik.tcp.routers.ldap.service=ldap + - traefik.tcp.services.ldap.loadbalancer.server.port=389 + + - traefik.tcp.routers.ldaps.rule=HostSNI(`*`) + - traefik.tcp.routers.ldaps.entrypoints=ldaps + - traefik.tcp.routers.ldaps.service=ldaps + - traefik.tcp.services.ldaps.loadbalancer.server.port=636 + healthcheck: + test: ["CMD-SHELL", "nc -zv 127.0.0.1 389 636"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 3s + + api: + image: ghcr.io/multidirectorylab/multidirectory:beta + container_name: multidirectory_api + volumes: + - certs:/certs + - dns_server_file:/DNS_server_file/ + - dns_server_config:/DNS_server_configs/ + - ldap_keytab:/LDAP_keytab/ + environment: + USE_CORE_TLS: 0 + DOMAIN: md.localhost + DEBUG: 1 + POSTGRES_USER: user + POSTGRES_PASSWORD: test_pwd + SECRET_KEY: 6a0452ae20cab4e21b6e9d18fa4b7bf397dd66ec3968b2d74 + MFA_API_SOURCE: dev + command: python multidirectory.py --http + tty: true + labels: + - "traefik.enable=true" + - "traefik.http.routers.api.rule=Host(`md.localhost`) && PathPrefix(`/api`)" + - "traefik.http.routers.api.entrypoints=web" + - "traefik.http.services.api.loadbalancer.server.port=8000" + - "traefik.http.routers.api.service=api" + - "traefik.http.routers.api.middlewares=api_strip" + - "traefik.http.middlewares.api_strip.stripprefix.prefixes=/api" + - "traefik.http.middlewares.api_strip.stripprefix.forceslash=false" + depends_on: + migrations: + condition: service_completed_successfully + + deploy: + mode: global + resources: + limits: + cpus: '0.50' + memory: 150M + + migrations: + image: ghcr.io/multidirectorylab/multidirectory:beta + container_name: multidirectory_migrations + restart: "no" + environment: + DOMAIN: md.localhost + DEBUG: 1 + POSTGRES_USER: user + POSTGRES_PASSWORD: test_pwd + SECRET_KEY: 6a0452ae20cab4e21b6e9d18fa4b7bf397dd66ec3968b2d74 + command: alembic upgrade head + depends_on: + postgres: + condition: service_healthy + + cert_check: + image: ghcr.io/multidirectorylab/multidirectory:beta + container_name: multidirectory_certs_check + restart: "no" + volumes: + - certs:/certs + command: ./extra/generate_cert.sh + + cert_local_check: + image: ghcr.io/multidirectorylab/multidirectory:beta + container_name: multidirectory_local_certs_check + restart: "no" + volumes: + - certs:/certs + command: bash -c "test -f /certs/cert.pem && echo 'CERT EXISTS, SKIPPING...' || openssl req -nodes -new -x509 -keyout /certs/privkey.pem -out /certs/cert.pem -subj '/C=RU/ST=Moscow/L=Moscow/O=Global Security/OU=Multifactor/CN=md.multifactor.dev'"; + + postgres: + container_name: MD-gssapi-postgres + image: postgres:16 + restart: unless-stopped + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: test_pwd + PGDATA: /data/postgres + volumes: + - postgres:/data/postgres + ports: + - 5432:5432 + + healthcheck: + test: ["CMD-SHELL", "pg_isready -d postgres -U user"] + interval: 1s + timeout: 15s + retries: 10 + start_period: 3s + + kadmin_api: + image: ghcr.io/multidirectorylab/multidirectory_kerberos:beta + container_name: kadmin_api + restart: unless-stopped + volumes: + - certs:/certs + - kdc:/etc + tty: true + depends_on: + ldap_server: + condition: service_healthy + restart: true + cert_check: + condition: service_completed_successfully + ports: + - 8000:8000 + working_dir: /server + command: uvicorn --factory config_server:create_app + --host 0.0.0.0 --ssl-keyfile=/certs/krbkey.pem + --ssl-certfile=/certs/krbcert.pem + --reload + + bind_dns: + image: ubuntu/bind9:latest + container_name: bind9 + hostname: bind9 + restart: unless-stopped + volumes: + - dns_server_file:/opt/ + - dns_server_config:/etc/bind/ + tty: true + depends_on: + ldap_server: + condition: service_healthy + restart: true + command: bash -c "chown bind:bind /opt && test -f /opt/zone.key && echo 'KEY EXISTS, SKIPPING...' || tsig-keygen zone. > /opt/zone.key && source docker-entrypoint.sh" + labels: + - traefik.enable=true + - traefik.tcp.routers.bind_dns.rule=HostSNI(`*`) + - traefik.tcp.routers.bind_dns.entrypoints=bind_dns + - traefik.tcp.routers.bind_dns.service=bind_dns + - traefik.tcp.services.bind_dns.loadbalancer.server.port=53 + + kdc: + container_name: kdc + hostname: kerberos + restart: unless-stopped + volumes: + - kdc:/etc + image: ghcr.io/multidirectorylab/multidirectory_kerberos:beta + tty: true + command: krb5kdc -n -w 4 + ports: + - "88:88" + - "88:88/udp" + depends_on: + ldap_server: + condition: service_healthy + restart: true + + kadmind: + container_name: kadmind + restart: unless-stopped + hostname: kerberos + volumes: + - kdc:/etc + - psync_queue:/var/spool/krb5-sync + image: ghcr.io/multidirectorylab/multidirectory_kerberos:beta + tty: true + command: kadmind -nofork + depends_on: + ldap_server: + condition: service_healthy + restart: true + kdc: + condition: service_started + labels: + - traefik.enable=true + - traefik.tcp.routers.kadmind.rule=HostSNI(`*`) + - traefik.tcp.routers.kadmind.entrypoints=kadmind + - traefik.tcp.routers.kadmind.service=kadmind + - traefik.tcp.services.kadmind.loadbalancer.server.port=749 + + - traefik.tcp.routers.kpasswd.rule=HostSNI(`*`) + - traefik.tcp.routers.kpasswd.entrypoints=kpasswd + - traefik.tcp.routers.kpasswd.service=kpasswd + - traefik.tcp.services.kpasswd.loadbalancer.server.port=464 + + dragonfly: + image: 'docker.dragonflydb.io/dragonflydb/dragonfly' + container_name: dragonfly + expose: + - 6379 + deploy: + resources: + limits: + cpus: '1.0' + memory: 2GiB + reservations: + cpus: '0.75' + memory: 0.5GiB + +volumes: + certs: + postgres: + pgadmin: + wireshark: + kdc: + psync_queue: + dns_server_file: + dns_server_config: + ldap_keytab: + dragonflydata: diff --git a/integration_tests/gssapi/run.sh b/integration_tests/gssapi/run.sh new file mode 100644 index 000000000..f07736735 --- /dev/null +++ b/integration_tests/gssapi/run.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +apt-get update && apt-get -y install ldap-utils krb5-user iproute2; + +touch /etc/krb5.conf && echo """\ +[libdefaults]\n\ + default_realm = MD.LOCALHOST\n\ + dns_lookup_realm = false\n\ + dns_lookup_kdc = false\n\ + realm_try_domains = 1\n\ + ticket_lifetime = 24h\n\ + renew_lifetime = 7d\n\ + forwardable = true\n\ +\n\ +[realms]\n\ + MD.LOCALHOST = {\n\ + kdc = md.localhost\n\ + admin_server = md.localhost\n\ + default_domain = md.localhost\n\ + }\n\ + +[domain_realm]\n\ + .md.localhost = MD.LOCALHOST\n\ + md.localhost = MD.LOCALHOST\n\ +""" > /etc/krb5.conf; + +echo "127.0.0.1 md.localhost" >> /etc/hosts; + +curl -X 'POST' \ + 'http://md.localhost:8000/auth/setup' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "domain": "md.localhost", + "username": "admin", + "user_principal_name": "admin", + "display_name": "admin", + "mail": "admin@example.com", + "password": "Password123" +}' -m 30; + +echo "Password123" | kinit admin; +echo -e "Performing LDAP authentication via GSSAPI"; + +ldapwhoami -H ldap://md.localhost:389 -Y GSSAPI; + +exit $?; \ No newline at end of file