#!/bin/bash
#
# Authelia Service

PATH=$HOME/.docker/cli-plugins:/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
get_appvars

config_authelia() {
  echo -ne "* Configuring authelia container.."

  if [ ! -d "/federated/apps/authelia" ]; then
    mkdir -p /federated/apps/authelia/data/config
    mkdir -p /federated/apps/authelia/data/secrets
  fi

cat > /federated/apps/authelia/docker-compose.yml <<EOF
services:
  authelia:
    image: authelia/authelia:\${IMAGE_VERSION}
    container_name: authelia
    hostname: authelia.$DOMAIN
    restart: always
    networks:
      core:
        ipv4_address: 192.168.0.42
    env_file:
      - ./.env
    volumes:
      - ./data/config:/config
      - ./data/secrets:/secrets
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia.rule=Host(\`authelia.$DOMAIN\`)"
      - "traefik.http.routers.authelia.entrypoints=websecure"
      - "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
      - "traefik.http.middlewares.authelia.forwardAuth.address=http://authelia.$DOMAIN:9091/api/authz/forward-auth"
      - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"

networks:
  core:
    external: true
EOF

tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > /federated/apps/authelia/data/secrets/JWT_SECRET 
tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > /federated/apps/authelia/data/secrets/SESSION_SECRET 
tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > /federated/apps/authelia/data/secrets/STORAGE_ENCRYPTION_KEY
echo "$LDAP_SECRET" > /federated/apps/authelia/data/secrets/AUTHENTICATION_BACKEND_LDAP_PASSWORD
echo "$ADMINPASS" > /federated/apps/authelia/data/secrets/NOTIFIER_SMTP_PASSWORD
openssl genrsa -out /federated/apps/authelia/data/secrets/private.pem 4096 2>/dev/null
openssl rsa -in /federated/apps/authelia/data/secrets/private.pem -outform PEM -pubout -out /federated/apps/authelia/data/secrets/public.pem 2>/dev/null
POWERDNS_CLIENT_SECRET=$(create_password);
POWERDNS_CLIENT_SECRET_HASH=$(docker run --rm authelia/authelia:latest authelia crypto hash generate pbkdf2 --password $POWERDNS_CLIENT_SECRET 2>/dev/null | awk '{ print $2 }')
[[ -d "/federated/apps/pdnsmysql/data/var/lib/mysql/pdnsadmin" ]] && POWERDNS_DB="pdnsadmin" || POWERDNS_DB="pdns"

cat > /federated/apps/authelia/.env <<EOF
IMAGE_VERSION=$(current_version authelia)
X_AUTHELIA_CONFIG_FILTERS=template
X_AUTHELIA_CONFIG=/config/configuration.yml,/config/idproviders.yml
AUTHELIA_TOTP_ISSUER=$DOMAIN
AUTHELIA_WEBAUTHN_DISPLAY_NAME=home
AUTHELIA_NOTIFIER_SMTP_ADDRESS=submission://mail.$DOMAIN:587
AUTHELIA_NOTIFIER_SMTP_USERNAME=$SMTPUSER
AUTHELIA_NOTIFIER_SMTP_SENDER="Authelia <authelia@$DOMAIN>"
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDRESS=ldaps://ldap.$DOMAIN
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_BASE_DN=dc=$LDAP_DOMAIN_FIRST,dc=$LDAP_DOMAIN_LAST
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USER=cn=admin,dc=$LDAP_DOMAIN_FIRST,dc=$LDAP_DOMAIN_LAST
AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE=/secrets/JWT_SECRET
AUTHELIA_SESSION_SECRET_FILE=/secrets/SESSION_SECRET
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/secrets/STORAGE_ENCRYPTION_KEY
AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/secrets/NOTIFIER_SMTP_PASSWORD
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE=/secrets/AUTHENTICATION_BACKEND_LDAP_PASSWORD
EOF
chmod 600 /federated/apps/authelia/.env

# Set the ldap configuration up for subdomain if we need to
if [ "${#LDAP_DOMAIN_ARRAY[@]}" -eq "3" ]; then
  sed -i "s#dc=$LDAP_DOMAIN_FIRST,dc=$LDAP_DOMAIN_LAST#dc=$LDAP_DOMAIN_FIRST,dc=$LDAP_DOMAIN_MIDDLE,dc=$LDAP_DOMAIN_LAST#g" /federated/apps/authelia/.env
fi

cat > /federated/apps/authelia/data/config/configuration.yml <<EOF
---
theme: auto
default_2fa_method: totp
server:
  address: tcp://0.0.0.0:9091/
log:
  level: info
totp:
  disable: false
  issuer: 'authelia.$DOMAIN'
  algorithm: sha1
  digits: 6
  period: 45
  skew: 1
  secret_size: 32
webauthn:
  disable: false
  timeout: 60s
  attestation_conveyance_preference: indirect
  user_verification: preferred
authentication_backend:
  password_reset:
    disable: false
  refresh_interval: 5m
  ldap:
    implementation: custom
    timeout: 5s
    start_tls: false
    attributes:
      username: mail
      display_name: uid
      group_name: gidNumber
      mail: mail
    additional_users_dn: ou=people
    users_filter: "(&({username_attribute}={input})(objectClass=person))"
    additional_groups_dn: ou=groups
    groups_filter: "(member={dn})"
password_policy:
  standard:
    enabled: false
    min_length: 8
    max_length: 0
    require_uppercase: true
    require_lowercase: true
    require_number: true
    require_special: false
access_control:
  default_policy: one_factor
session:
  name: 'authelia_session'
  same_site: 'lax'
  inactivity: '5m'
  expiration: '1h'
  remember_me: '1M'
  cookies:
    - domain: '$DOMAIN'
      authelia_url: 'https://authelia.$DOMAIN'
regulation:
  max_retries: 3
  find_time: 2m
  ban_time: 5m
storage:
  local:
    path: /config/db.sqlite3
notifier:
  disable_startup_check: false
EOF

cat > /federated/apps/authelia/data/config/idproviders.yml <<EOF
identity_providers:
  oidc:
    jwks:
      - key: {{ secret "/secrets/private.pem" | mindent 10 "|" | msquote }}
    ## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
    ## See: https://www.authelia.com/c/oidc
    clients:
      ### PowerDNS
      - client_id: 'powerdns'
        client_name: 'PowerDNS Admin'
        client_secret: $POWERDNS_CLIENT_SECRET_HASH
        consent_mode: 'implicit'
        public: false
        authorization_policy: 'one_factor'
        redirect_uris:
          - 'https://powerdns.$DOMAIN/oidc/authorized'
        scopes:
          - 'openid'
          - 'profile'
          - 'groups'
          - 'email'
        response_types:
          - 'code'
        grant_types:
          - 'authorization_code'
        userinfo_signed_response_alg: 'none'
EOF

# Insert PowerDNS configuration because we need an initial
# config for Authelia to run
PDNS_MYSQL_COMMAND1="insert into setting (name, value) values (\"oidc_oauth_enabled\", \"True\");insert into setting (name, value) values (\"oidc_oauth_key\", \"powerdns\");"
PDNS_MYSQL_COMMAND2="insert into setting (name, value) values (\"oidc_oauth_scope\", \"openid profile groups email\");insert into setting (name, value) values (\"oidc_oauth_api_url\", \"https://authelia.$DOMAIN/api/oidc/userinfo\");"
PDNS_MYSQL_COMMAND3="insert into setting (name, value) values (\"oidc_oauth_auto_configure\", \"True\");insert into setting (name, value) values (\"oidc_oauth_metadata_url\", \"https://authelia.$DOMAIN/.well-known/openid-configuration\");"
PDNS_MYSQL_COMMAND4="insert into setting (name, value) values (\"oidc_oauth_token_url\", \"\");insert into setting (name, value) values (\"oidc_oauth_authorize_url\", \"\");"
PDNS_MYSQL_COMMAND5="insert into setting (name, value) values (\"oidc_oauth_logout_url\", \"https://authelia.$DOMAIN/logout?rd=https://dashboard.$DOMAIN\");insert into setting (name, value) values (\"oidc_oauth_username\", \"preferred_username\");"
PDNS_MYSQL_COMMAND6="insert into setting (name, value) values (\"oidc_oauth_email\", \"email\");insert into setting (name, value) values (\"oidc_oauth_firstname\", \"preferred_username\");"
PDNS_MYSQL_COMMAND7="insert into setting (name, value) values (\"oidc_oauth_last_name\", \"name\");insert into setting (name, value) values (\"oidc_oauth_account_name_property\", \"preferred_username\");"
PDNS_MYSQL_COMMAND8="insert into setting (name, value) values (\"oidc_oauth_account_description_property\", \"name\");insert into setting (name, value) values (\"oidc_oauth_secret\", \"$POWERDNS_CLIENT_SECRET\");"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND1;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND2;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND3;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND4;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND5;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND6;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND7;'"
docker exec pdnsmysql bash -c "mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e '$PDNS_MYSQL_COMMAND8;'"
 
echo -ne "done.\n"
}
start_authelia() {
  # Start service with command to make sure it's up before proceeding
  start_service "authelia" "nc -z 192.168.0.42 9091 &> /dev/null" "7"

  docker exec pdns pdnsutil add-record $DOMAIN authelia A 86400 $EXTERNALIP &> /dev/null
  [ $? -ne 0 ] && fail "Couldn't add dns record for authelia"

  # If extra_hosts doesn't exist then insert extra_host configuration in pdnsadmin docker compose
  add_authelia_config_to_dockercompose "pdnsadmin" "$EXTERNALIP"

  # Stop and start pdnsadmin for internal dns externalhosts to work
  /federated/bin/stop pdnsadmin &> /dev/null
  [ $? -ne 0 ] && fail "Couldn't stop pdnsadmin"

  /federated/bin/start pdnsadmin &> /dev/null
  [ $? -ne 0 ] && fail "Couldn't start pdnsadmin"

  echo -ne "done.\n"
}
email_authelia() {
  echo -ne "* Sending email to customer.."

cat > /federated/apps/mail/data/root/certs/mailfile <<EOF
<html>
<img src="https://www.federated.computer/wp-content/uploads/2023/11/logo.png" alt="" /><br>
<p>
<h4>Authelia (SSO) is now installed on $DOMAIN, Your Federated Computer Single Sign On</h4>
<p>
Dear Customer,<br>
We’re excited to introduce your new Single Sign-On (SSO) for Federated Core.
<br>
<br>
Your Single Sign On is called Authelia. With Authelia, a single login grants you seamless access to multiple Federated applications.<br>
Authelia provides single sign-on (SSO) access to the following Federated applications:<br>
Nextcloud, Element/Matrix, Bookstack, Jitsi, Gitea, RoundCube (Web Mail), EspoCRM, PowerDNS, and WordPress<br>
<br>
How to use Authelia<br>
• Click on any application in your Federated Dashboard and login by clicking, “Login with Authelia”<br>
• Look for a pop up that will be labeled “https://authelia.YOUR.DOMAIN”<br>
• Enter your panel user@domain.com and password, then click, “Sign In”<br>
• That’s It! You can now access all of the Applications listed above.<br>
<br>
IMPORTANT: When logging into Nextcloud through traditional login (Not Authelia) use only your 'user' and not 'user@domain.com'.<br>
<br>
Using EspoCRM or Gitea?<br>
These applications need extra configuration to work with SSO.<br>
Reply to support@federated.computer, and we’ll send you step-by-step instructions to set up SSO for them.<br>
<br>
As always, We are here to make the process simple and straightforward. Reply now if you have any questions about Authelia and we will respond promptly.
<br>
Thank you for choosing Federated Computer. We’re committed to improving your experience every step of the way.
<br>
<br>
Best regards,<br>
Federated Computer Support Team
<br>
EOF

  # Send out e-mail from mail container with details
  docker exec mail bash -c "mail -r admin@$DOMAIN -a \"Content-type: text/html\" -s \"Authelia (SSO) is now installed on $DOMAIN\" $EMAIL < /root/certs/mailfile"
  rm /federated/apps/mail/data/root/certs/mailfile

  echo -ne "done.\n"
}
uninstall_authelia() {
  echo -ne "* Uninstalling authelia container.."

  # First stop the service
  cd /federated/apps/authelia && docker compose -f docker-compose.yml -p authelia down &> /dev/null

  # Delete the entries in the settings table
  [[ -d "/federated/apps/pdnsmysql/data/var/lib/mysql/pdnsadmin" ]] && POWERDNS_DB="pdnsadmin" || POWERDNS_DB="pdns"
  docker exec pdnsmysql mariadb -uroot -p$MYSQL_ROOTPASSWORD $POWERDNS_DB -e "delete from setting where name like '%oidc_oauth%';"

  # Delete the app directory
  rm -rf /federated/apps/authelia

  # Delete the image
  docker image rm authelia/authelia:$IMAGE_VERSION &> /dev/null

  # Delete the DNS record
  docker exec pdns pdnsutil delete-rrset $DOMAIN authelia A

  echo -ne "done.\n"
}
