#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Keycloak
#
# Like what you see? Join us!
# https://www.univention.com/about-us/careers/vacancies/
#
# Copyright 2023 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.
"""Check Migration Status to the Keycloak app"""

import sys
import time
from argparse import ArgumentParser

import ldif

import univention.admin.uldap
from univention.config_registry import ucr


def create_ldif(objects, opt):
    print(f'Backing up objects to {opt.backup_path}\n')
    with open(opt.backup_path, 'w+') as f:
        ldif_writer = ldif.LDIFWriter(f)
        for dn, obj in objects:
            ldif_writer.unparse(dn, obj)


def delete_objects(sso_obj):
    lo, _ = univention.admin.uldap.getAdminConnection()
    for dn, obj in sso_obj:
        try:
            lo.delete(dn)
            print(f'Deleted {dn}')
        except univention.admin.uexceptions.base as e:
            print(f'Failed to delete {dn} due: {e}', file=sys.stderr)


def get_sso_client_objects():
    lo, _ = univention.admin.uldap.getMachineConnection()
    oidc_obj = lo.search(
        filter='(univentionObjectType=oidc/rpservice)',
        base=lo.base,
    )
    saml_obj = lo.search(
        filter='(univentionObjectType=saml/serviceprovider)',
        base=lo.base,
    )
    return oidc_obj + saml_obj


def migration_complete(opt):
    sso_obj = get_sso_client_objects()
    guide_url = "<https://docs.software-univention.de/keycloak-migration/index.html>"
    migrated = False
    if sso_obj:
        print(
            "\nStarting with UCS 5.2 the Keycloak app replaces SimpleSAMLphp"
            "\nand the Kopano Konnect app as the default identity provider in UCS."
            "\nBefore the update to 5.2 can start, this domain has to be migrated"
            "\nto Keycloak."
            "\n\nThis migration has not happend yet!"
            "\n\nThe following old SimpleSAMLphp/Kopano Konnect objects have been found:\n",
            file=sys.stderr
        )
        for dn, obj in sso_obj:
            print(f"\t* {dn}", file=sys.stderr)
        print(
            "\nPlease read the UCS 5.2 release notes"
            "\n\t<https://docs.software-univention.de/release-notes-5.2-0-en.html>"
            "\nand the Keycloak migration guide:"
            f"\n\t{guide_url}"
            "\nfor how to migrate your domain to Keycloak.",
            file=sys.stderr
        )
        if opt.delete:
            print(
                "\n\nDo you really want to delete the objects?"
                "\nSSO with SimpleSAMLphp or Kopano Connect will no longer work!"
                f"\nIn case you are unsure please read the migration guide: {guide_url}",
            )
            confirmed = False
            if not opt.force:
                confirmed = input('\nI want to remove all SSO objects: (y/N)').lower() == 'y'
            if confirmed or opt.force:
                create_ldif(sso_obj, opt)
                delete_objects(sso_obj)
                migrated = True
    else:
        migrated = True

    if migrated:
        print('\nMigration to Keycloak complete.')
        sys.exit(0)
    else:
        print('\nMigration to Keycloak incomplete, update to UCS 5.2 not possible', file=sys.stderr)
        sys.exit(1)


def parse_arguments(parser):
    parser.add_argument('-d', '--delete', action='store_true', help='Delete all saml/serviceprovider, and oic/rpservice UDM objects. A backup file will be created')
    parser.add_argument('-f', '--force', action='store_true', help='Force deletion of all SAML or OIDC related UDM objects')
    parser.add_argument('--backup-path', default=f'/var/univention-backup/saml_oidc_{time.time()}.ldif', help='Path where the backup file will be created')
    return parser.parse_args()


if __name__ == '__main__':
    parser = ArgumentParser(description=__doc__)
    opt = parse_arguments(parser)
    if opt.delete:
        server_role = ucr.get('server/role')
        if server_role != 'domaincontroller_master':
            print(f'ERROR: Server role is {server_role}, this script can only delete the objects, if must be executed on the DC primary', file=sys.stderr)
            sys.exit(1)
    migration_complete(opt)
