#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Tests various schema replication scenarios
#
# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

#
# Usage:
#  export DC1=dc1_dns_name
#  export DC2=dc2_dns_name
#  export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
#  PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN replica_sync -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
#

import replica_sync
import samba.tests
import time

from ldb import (
    SCOPE_BASE, LdbError, ERR_NO_SUCH_OBJECT)

class DrsSamAccountNameSyncTestCase(replica_sync.DrsReplicaSyncTestCase):
    """Intended as a black box test case for DsReplicaSync
       implementation. It should test the behavior of this
       case in cases when inbound replication is disabled"""

    def setUp(self):
        super(DrsSamAccountNameSyncTestCase, self).setUp()

    def tearDown(self):
        super(DrsSamAccountNameSyncTestCase, self).tearDown()

    def get_user_guid(self, samdb, user, userou="CN=Users"):
        res = samdb.search(base="CN=%s,%s,%s" %(user, userou, self.domain_dn),
                           scope=SCOPE_BASE, attrs=["objectGUID"])
        return self._GUID_string(res[0]["objectGUID"][0])

    def test_duplicate_user_conflict(self):
        """
        The sAMAccountName attribute must be unique within the DB. Check that
        the sAMAccountName is unique after a duplicate user conflict.
        """
        self._disable_inbound_repl(self.dnsname_dc1)
        self._disable_inbound_repl(self.dnsname_dc2)

        # Create the same user on each DC
        username = "sameuser1"
        password1 = samba.generate_random_password(12, 16)
        self.ldb_dc1.newuser(username, password1)
        self.ou1 = self.get_user_guid(self.ldb_dc1, username)

        time.sleep(1)
        password2 = samba.generate_random_password(12, 16)
        self.ldb_dc2.newuser(username, password2)
        self.ou2 = self.get_user_guid(self.ldb_dc2, username)

        # replicate them from DC1 to DC2
        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1)

        res1 = self.ldb_dc2.search(base="<GUID=%s>" % self.ou1,
                                  scope=SCOPE_BASE, attrs=["name", "sAMAccountName"])
        res2 = self.ldb_dc2.search(base="<GUID=%s>" % self.ou2,
                                  scope=SCOPE_BASE, attrs=["name", "sAMAccountName"])

        print("%s sAMAccountName is: %s" %(res1[0]["name"][0],
                                           res1[0]["sAMAccountName"][0]))
        print("%s sAMAccountName is: %s" %(res2[0]["name"][0],
                                           res2[0]["sAMAccountName"][0]))

        # Check that the object DN conflict was resolved
        self.assertFalse('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
        self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))

        # Check that DC2 didn't allow a duplicate sAMAccountName in its DB
        self.assertTrue(res1[0]["sAMAccountName"][0] != res2[0]["sAMAccountName"][0],
                        "Duplicate sAMAccountName used by another user")

    def test_SAMAccountName_conflict(self):
        """
        Check that we don't get a duplicate sAMAccountName as a result of
        replication, even if there's no DN conflict.
        """
        self._disable_inbound_repl(self.dnsname_dc1)
        self._disable_inbound_repl(self.dnsname_dc2)

        # Create a user on each DC with different DNs but the same sAMAccountName
        username = "sameuser2"
        password1 = samba.generate_random_password(12, 16)
        self.ldb_dc1.newuser(username, password1)
        self.ou1 = self.get_user_guid(self.ldb_dc1, username)

        time.sleep(1)
        self.ou2 = self._create_ou(self.ldb_dc2, "OU=Different-DN")
        password2 = samba.generate_random_password(12, 16)
        self.ldb_dc2.newuser(username, password2, userou="OU=Different-DN")
        user_ou2 = self.get_user_guid(self.ldb_dc2, username, userou="OU=Different-DN")

        # replicate them from DC1 to DC2
        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1)

        res1 = self.ldb_dc2.search(base="<GUID=%s>" % self.ou1,
                                  scope=SCOPE_BASE, attrs=["name", "sAMAccountName"])
        res2 = self.ldb_dc2.search(base="<GUID=%s>" % user_ou2,
                                  scope=SCOPE_BASE, attrs=["name", "sAMAccountName"])

        print("%s sAMAccountName is: %s" %(res1[0]["name"][0],
                                           res1[0]["sAMAccountName"][0]))
        print("%s sAMAccountName is: %s" %(res2[0]["name"][0],
                                           res2[0]["sAMAccountName"][0]))

        self.assertFalse('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
        self.assertFalse('CNF:%s' % user_ou2 in str(res2[0]["name"][0]))

        # Check that DC2 didn't allow a duplicate sAMAccountName in its DB
        self.assertTrue(res1[0]["sAMAccountName"][0] != res2[0]["sAMAccountName"][0],
                        "Duplicate sAMAccountName used by another user")



