<reponame>GluuFederation/docker-oxtrust
import base64
import json
import logging.config
import os
import re
from string import Template

from pygluu.containerlib import get_manager
from pygluu.containerlib.persistence import render_salt
from pygluu.containerlib.persistence import render_gluu_properties
from pygluu.containerlib.persistence import render_ldap_properties
from pygluu.containerlib.persistence import render_couchbase_properties
from pygluu.containerlib.persistence import render_hybrid_properties
from pygluu.containerlib.persistence import sync_ldap_truststore
from pygluu.containerlib.persistence import sync_couchbase_truststore
from pygluu.containerlib.persistence import render_spanner_properties
from pygluu.containerlib.persistence import render_sql_properties
from pygluu.containerlib.utils import cert_to_truststore
from pygluu.containerlib.utils import get_server_certificate
from pygluu.containerlib.utils import as_boolean

from settings import LOGGING_CONFIG

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("entrypoint")

manager = get_manager()


def modify_jetty_xml():
    fn = "/opt/jetty/etc/jetty.xml"
    with open(fn) as f:
        txt = f.read()

    # disable contexts
    updates = re.sub(
        r'<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>',
        r'<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler">\n\t\t\t\t <Set name="showContexts">false</Set>\n\t\t\t </New>',
        txt,
        flags=re.DOTALL | re.M,
    )

    with open(fn, "w") as f:
        f.write(updates)


def modify_webdefault_xml():
    fn = "/opt/jetty/etc/webdefault.xml"
    with open(fn) as f:
        txt = f.read()

    # disable dirAllowed
    updates = re.sub(
        r'(<param-name>dirAllowed</param-name>)(\s*)(<param-value>)true(</param-value>)',
        r'\1\2\3false\4',
        txt,
        flags=re.DOTALL | re.M,
    )

    with open(fn, "w") as f:
        f.write(updates)


def modify_server_ini():
    with open("/opt/gluu/jetty/identity/start.d/server.ini", "a") as f:
        updates = "\n".join([
            # disable server version info
            "jetty.httpConfig.sendServerVersion=false",
        ])
        f.write(updates)


def configure_logging():
    # default config
    config = {
        "oxtrust_log_target": "STDOUT",
        "oxtrust_log_level": "INFO",
        "http_log_target": "FILE",
        "http_log_level": "INFO",
        "persistence_log_target": "FILE",
        "persistence_log_level": "INFO",
        "persistence_duration_log_target": "FILE",
        "persistence_duration_log_level": "INFO",
        "ldap_stats_log_target": "FILE",
        "ldap_stats_log_level": "INFO",
        "script_log_target": "FILE",
        "script_log_level": "INFO",
        "audit_log_target": "FILE",
        "audit_log_level": "INFO",
        "cleaner_log_target": "FILE",
        "cleaner_log_level": "INFO",
        "velocity_log_target": "FILE",
        "velocity_log_level": "INFO",
        "cache_refresh_log_target": "FILE",
        "cache_refresh_log_level": "INFO",
        "cache_refresh_python_log_target": "FILE",
        "cache_refresh_python_log_level": "INFO",
        "apachehc_log_target": "FILE",
        "apachehc_log_level": "OFF",
    }

    # pre-populate custom config; format is JSON string of ``dict``
    try:
        custom_config = json.loads(os.environ.get("GLUU_OXTRUST_APP_LOGGERS", "{}"))
    except json.decoder.JSONDecodeError as exc:
        logger.warning(f"Unable to load logging configuration from environment variable; reason={exc}; fallback to defaults")
        custom_config = {}

    # ensure custom config is ``dict`` type
    if not isinstance(custom_config, dict):
        logger.warning("Invalid data type for GLUU_OXTRUST_APP_LOGGERS; fallback to defaults")
        custom_config = {}

    log_levels = ("OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE",)

    # list of supported outputs
    log_targets = ("STDOUT", "FILE",)

    for k, v in custom_config.items():
        if k not in config:
            continue

        if k.endswith("_log_level") and v not in log_levels:
            logger.warning(f"Invalid {v} log level for {k}; fallback to defaults")
            v = config[k]

        if k.endswith("_log_target") and v not in log_targets:
            logger.warning(f"Invalid {v} log output for {k}; fallback to defaults")
            v = config[k]

        # update the config
        config[k] = v

    # mapping between the ``log_target`` value and their appenders
    file_aliases = {
        "oxtrust_log_target": "FILE",
        "http_log_target": "OX_HTTP_REQUEST_RESPONSE_FILE",
        "persistence_log_target": "OX_PERSISTENCE_FILE",
        "persistence_duration_log_target": "OX_PERSISTENCE_DURATION_FILE",
        "ldap_stats_log_target": "OX_PERSISTENCE_LDAP_STATISTICS_FILE",
        "script_log_target": "OX_SCRIPT_LOG_FILE",
        "audit_log_target": "OXTRUST_AUDIT",
        "cleaner_log_target": "CLEANER",
        "velocity_log_target": "VELOCITY",
        "cache_refresh_log_target": "OX_CACHE_REFRESH_FILE",
        "cache_refresh_python_log_target": "OX_CACHE_REFRESH_PYTHON_FILE",
        "apachehc_log_target": "OX_APACHEHC_LOG_FILE",
    }
    for key, value in file_aliases.items():
        if config[key] == "FILE":
            config[key] = value

    logfile = "/opt/gluu/jetty/identity/resources/log4j2.xml"
    with open(logfile) as f:
        txt = f.read()

    tmpl = Template(txt)
    with open(logfile, "w") as f:
        f.write(tmpl.safe_substitute(config))


if __name__ == "__main__":
    persistence_type = os.environ.get("GLUU_PERSISTENCE_TYPE", "ldap")

    render_salt(manager, "/app/templates/salt.tmpl", "/etc/gluu/conf/salt")
    render_gluu_properties("/app/templates/gluu.properties.tmpl", "/etc/gluu/conf/gluu.properties")

    if persistence_type in ("ldap", "hybrid"):
        render_ldap_properties(
            manager,
            "/app/templates/gluu-ldap.properties.tmpl",
            "/etc/gluu/conf/gluu-ldap.properties",
        )
        manager.secret.to_file(
            "ldap_ssl_cert",
            "/etc/certs/opendj.crt",
            decode=True,
        )
        sync_ldap_truststore(manager)

    if persistence_type in ("couchbase", "hybrid"):
        render_couchbase_properties(
            manager,
            "/app/templates/gluu-couchbase.properties.tmpl",
            "/etc/gluu/conf/gluu-couchbase.properties",
        )
        sync_couchbase_truststore(manager)

    if persistence_type == "hybrid":
        render_hybrid_properties("/etc/gluu/conf/gluu-hybrid.properties")

    if persistence_type == "sql":
        render_sql_properties(
            manager,
            "/app/templates/gluu-sql.properties.tmpl",
            "/etc/gluu/conf/gluu-sql.properties",
        )

    if persistence_type == "spanner":
        render_spanner_properties(
            manager,
            "/app/templates/gluu-spanner.properties.tmpl",
            "/etc/gluu/conf/gluu-spanner.properties",
        )

    if not os.path.isfile("/etc/certs/gluu_https.crt"):
        if as_boolean(os.environ.get("GLUU_SSL_CERT_FROM_SECRETS", False)):
            manager.secret.to_file("ssl_cert", "/etc/certs/gluu_https.crt")
        else:
            get_server_certificate(manager.config.get("hostname"), 443, "/etc/certs/gluu_https.crt")

    cert_to_truststore(
        "gluu_https",
        "/etc/certs/gluu_https.crt",
        "/usr/java/latest/jre/lib/security/cacerts",
        "changeit",
    )

    if not os.path.isfile("/etc/certs/shibIDP.crt"):
        manager.secret.to_file("shibIDP_cert", "/etc/certs/shibIDP.crt", decode=True)

    if not os.path.isfile("/etc/certs/shibIDP.key"):
        manager.secret.to_file("shibIDP_key", "/etc/certs/shibIDP.key", decode=True)

    if not os.path.isfile("/etc/certs/idp-signing.crt"):
        manager.secret.to_file("idp3SigningCertificateText", "/etc/certs/idp-signing.crt")

    if not os.path.isfile("/etc/certs/idp-encryption.crt"):
        manager.secret.to_file("idp3EncryptionCertificateText", "/etc/certs/idp-encryption.crt")

    # manager.secret.to_file(
    #     "scim_rs_jks_base64",
    #     manager.config.get("scim_rs_client_jks_fn"),
    #     decode=True,
    #     binary_mode=True,
    # )
    manager.secret.to_file(
        "passport_rs_jks_base64",
        manager.config.get("passport_rs_client_jks_fn"),
        decode=True,
        binary_mode=True,
    )

    manager.secret.to_file(
        "api_rs_jks_base64",
        manager.config.get("api_rs_client_jks_fn"),
        decode=True,
        binary_mode=True,
    )
    with open(manager.config.get("api_rs_client_jwks_fn"), "w") as f:
        f.write(
            base64.b64decode(manager.secret.get("api_rs_client_base64_jwks")).decode()
        )

    manager.secret.to_file(
        "api_rp_jks_base64",
        manager.config.get("api_rp_client_jks_fn"),
        decode=True,
        binary_mode=True,
    )
    with open(manager.config.get("api_rp_client_jwks_fn"), "w") as f:
        f.write(
            base64.b64decode(manager.secret.get("api_rp_client_base64_jwks")).decode()
        )

    # manager.secret.to_file("scim_rs_jks_base64", "/etc/certs/scim-rs.jks",
    #                        decode=True, binary_mode=True)
    # with open(manager.config.get("scim_rs_client_jwks_fn"), "w") as f:
    #     f.write(
    #         base64.b64decode(manager.secret.get("scim_rs_client_base64_jwks")).decode()
    #     )

    # manager.secret.to_file("scim_rp_jks_base64", "/etc/certs/scim-rp.jks",
    #                        decode=True, binary_mode=True)
    # with open(manager.config.get("scim_rp_client_jwks_fn"), "w") as f:
    #     f.write(
    #         base64.b64decode(manager.secret.get("scim_rp_client_base64_jwks")).decode()
    #     )

    modify_jetty_xml()
    modify_webdefault_xml()
    modify_server_ini()
    configure_logging()
