def test_csv_import():
    auth_client = AuthClient(
        constants.HOST,
        verify_certificate=False,
        username='******',
        password='******',
    )
    token_data = auth_client.token.new(expiration=300)
    token = token_data['token']
    auth_client.set_token(token)

    client = ConfdClient(
        constants.HOST,
        verify_certificate=False,
        token=token,
    )

    start = datetime.now()
    result = upload_csv(client, token_data['metadata']['tenant_uuid'])
    stop = datetime.now()

    assert 'created' in result, 'Result should contains the created users:\n{}'.format(result)
    assert len(result['created']) == 100, 'Should have created 100 users\n{}'.format(result)
    assert stop - start <= MAX_TIME, "CSV import exceeded max time ({})".format(MAX_TIME)

    # NOTE(fblackburn): wait until pjsip reload complete before starting next test
    time.sleep(5)
Exemple #2
0
    def validate(self):
        super().validate()
        try:
            auth_client = AuthClient(
                username=self.username.data,
                password=self.password.data,
                **app.config['auth'],
            )
            response = auth_client.token.new(expiration=60 * 60 * 12)
            auth_client.set_token(response['token'])
            user = auth_client.users.get(response['metadata']['uuid'])
            user['password'] = self.password.data
            user['instance_uuid'] = response['xivo_uuid']
            session['user'] = user
        except HTTPError as e:
            if unauthorized(e):
                self.username.errors.append(USERNAME_PASSWORD_ERROR)
                self.password.errors.append(USERNAME_PASSWORD_ERROR)
                return False
            raise ValidationError(l_('Error with Wazo authentication server: %(error)s', error=e.message))
        except requests.ConnectionError:
            raise ValidationError(l_('Wazo authentication server connection error'))

        self.user = UserUI(response['token'], response['auth_id'])
        self.user.set_tenant(response['metadata']['tenant_uuid'])

        return True
Exemple #3
0
def do_migration(config):
    with closing(psycopg2.connect(config['db_uri'])) as conn:
        tenants = _build_tenant_bodies_from_entities(conn.cursor())

    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new(expiration=36000)['token']
    auth_client.set_token(token)

    existing_tenants = _get_existing_tenants(auth_client)

    for tenant in tenants:
        if tenant['name'] in existing_tenants.keys():
            continue
        tenant = auth_client.tenants.new(**tenant)

        existing_tenants[tenant['name']] = tenant['uuid']

    with closing(psycopg2.connect(config['db_uri'])) as conn:
        cursor = conn.cursor()
        for name, tenant_uuid in existing_tenants.items():
            if not name:
                # wazo-auth allow tenants without names but those do not map to entities
                continue

            _upsert_tenant(cursor, tenant_uuid)
            conn.commit()
            _update_entity_tenant_uuid(cursor, name, tenant_uuid)
            conn.commit()

    auth_client.token.revoke(token)
Exemple #4
0
def migrate_tenants():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=5 * 60)['token']
    auth_client.set_token(token)

    body = [
        {"owner_user_uuid": user['uuid'], "owner_tenant_uuid": user['tenant_uuid']}
        for user in auth_client.users.list(recurse=True)["items"]
    ]

    with _migration_plugin(config['webhookd']):
        url = 'https://{host}:{port}/{version}/tenant-migration'.format(**config['webhookd'])
        result = requests.post(
            url,
            data=json.dumps(body),
            headers={'X-Auth-Token': token, 'Content-Type': 'application/json'},
            verify=False,
        )

        if result.status_code != 200:
            print(
                'webhookd tenant migration failed, status-code {}:\n'
                '{}\ncheck /var/log/wazo-webhookd.log for more info'
                .format(result.status_code, result.text)
            )
            sys.exit(2)
Exemple #5
0
def migrate_tenants():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=5 * 60)['token']
    auth_client.set_token(token)

    auth_tenants = auth_client.tenants.list()
    body = [{
        'uuid': t['uuid'],
        'name': t['name']
    } for t in auth_tenants['items']]

    with _migration_plugin(config['dird']):
        url = 'https://{host}:{port}/{version}/phonebook_move_tenant'.format(
            **config['dird'])
        result = requests.post(
            url,
            data=json.dumps(body),
            headers={
                'X-Auth-Token': token,
                'Content-Type': 'application/json'
            },
            verify=False,
        )

        if result.status_code != 200:
            print(
                'dird tenant migration failed, check /var/log/wazo-dird.log for more info'
            )
            sys.exit(2)
Exemple #6
0
def migrate_tenants():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new(expiration=5 * 60)['token']
    auth_client.set_token(token)
    confd = ConfdClient(token=token, **config['confd'])

    body = {
        'contexts': [
            {"context": context['name'], "tenant_uuid": context['tenant_uuid']}
            for context in confd.contexts.list(recurse=True)["items"]
        ]
    }

    with _migration_plugin(config['call_logd']):
        url = 'https://{host}:{port}/{version}/tenant-migration'.format(**config['call_logd'])
        result = requests.post(
            url,
            data=json.dumps(body),
            headers={'X-Auth-Token': token, 'Content-Type': 'application/json'},
            verify=False,
        )

        if result.status_code != 200:
            print(
                'call_logd tenant migration failed, status-code {}:\n'
                '{}\ncheck /var/log/wazo-call-logd.log for more info'
                .format(result.status_code, result.text)
            )
            sys.exit(2)
Exemple #7
0
class WazoAuthKeys(App):

    DEFAULT_VERBOSE_LEVEL = 0

    def __init__(self):
        super().__init__(
            description='A wrapper to wazo-auth-cli to manage internal users',
            command_manager=CommandManager('wazo_auth_keys.commands'),
            version='1.0.0',
        )
        self._token = None
        self._client = None

    def build_option_parser(self, *args, **kwargs):
        parser = super().build_option_parser(*args, **kwargs)
        parser.add_argument(
            '--wazo-auth-cli-config',
            default=os.getenv('WAZO_AUTH_CLI_CONFIG',
                              '/root/.config/wazo-auth-cli'),
            help=
            'Extra configuration directory to override the wazo-auth-cli configuration',
        )
        parser.add_argument(
            '--base-dir',
            default='/var/lib/wazo-auth-keys',
            help='The base directory of the file keys',
        )
        parser.add_argument(
            '--config',
            default='/etc/wazo-auth-keys/config.yml',
            help='The wazo-auth-keys configuration file',
        )
        return parser

    @property
    def client(self):
        if not self._client:
            self._client = Client(**self._auth_config)

        if not self._token:
            self._token = self._client.token.new('wazo_user',
                                                 expiration=600)['token']

        self._client.set_token(self._token)
        return self._client

    def initialize_app(self, argv):
        self.LOG.debug('wazo-auth-keys')
        self.LOG.debug('options=%s', self.options)

        conf = config.build(self.options)
        self.LOG.debug('Starting with config: %s', conf)

        self.LOG.debug('client args: %s', conf['auth'])
        self._auth_config = dict(conf['auth'])

        with open(self.options.config, 'r') as f:
            self.services = yaml.safe_load(f)
        self.file_manager = FileManager(self, self.options.base_dir)
Exemple #8
0
def main():
    args = parse_args()
    verify_certificate = _extract_verify_certificate(args.verify_certificate)

    password = os.getenv('PORTAL_PASSWORD', None)
    if not password:
        password = getpass()

    kwargs = {}
    if args.timeout:
        kwargs['timeout'] = args.timeout

    auth_client = AuthClient(args.host,
                             port=443,
                             prefix='/api/auth',
                             verify_certificate=verify_certificate,
                             username=args.username,
                             password=password,
                             **kwargs)
    token = auth_client.token.new()['token']
    auth_client.set_token(token)

    confd_client = ConfdClient(args.host,
                               port=443,
                               prefix='/api/confd',
                               verify_certificate=verify_certificate,
                               token=token,
                               **kwargs)
    rcl = []
    if args.rcl:
        rcl = detect_desync_rcl(auth_client, confd_client)

    users = []
    if args.users:
        users = detect_desync_users(auth_client, confd_client)

    if args.delete_orphan_users:
        delete_desync_users(confd_client, users)

    if not rcl and not users:
        sys.exit(0)

    if args.output:
        output_file = open(args.output, "w")
    else:
        output_file = sys.stdout

    fieldnames = ['uuid', 'type', 'name']
    writer = csv.DictWriter(output_file, fieldnames=fieldnames)
    writer.writeheader()
    for row in rcl + users:
        writer.writerow(row)

    if args.output:
        output_file.close()

    sys.exit(1)
Exemple #9
0
 def get_auth(cls, config):
     auth_config = dict(config['auth'])
     # FIXME(sileht): Keep the certificate
     auth_config['verify_certificate'] = False
     auth = AuthClient(**auth_config)
     token = auth.token.new('wazo_user', expiration=3600)
     auth.set_token(token["token"])
     auth.username = None
     auth.password = None
     return auth
Exemple #10
0
def _auto_create_config():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=36000)['token']
    auth_client.set_token(token)
    confd_client = ConfdClient(token=token, **config['confd'])

    tenants = auth_client.tenants.list()['items']

    base_url = 'https://{host}:{port}/{version}'.format(**config['dird'])
    profiles_url = '{}/profiles'.format(base_url)
    conference_url = '{}/backends/conference/sources'.format(base_url)
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-Auth-Token': token,
    }
    for tenant in tenants:
        name = tenant['name']
        if name == 'master':
            continue

        headers['Wazo-Tenant'] = tenant['uuid']

        conference_body = dict(name='auto_conference_{}'.format(name),
                               **CONFERENCE_SOURCE_BODY)
        conference = requests.post(
            conference_url,
            headers=headers,
            json=conference_body,
            verify=config['dird']['verify_certificate'],
        ).json()

        response = requests.get(
            profiles_url,
            headers={
                'Accept': 'application/json',
                'X-Auth-Token': token,
                'Wazo-Tenant': tenant['uuid'],
            },
            verify=config['dird']['verify_certificate'],
        ).json()

        for profile in response['items']:
            profile['services']['lookup']['sources'].append(conference)
            profile['services']['favorites']['sources'].append(conference)
            requests.put(
                '{}/{}'.format(profiles_url, profile['uuid']),
                json=profile,
                headers=headers,
                verify=config['dird']['verify_certificate'],
            )
Exemple #11
0
def _get_tenants_infos(tenants):
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=36000)['token']
    auth_client.set_token(token)
    tenant_infos = {}
    for tenant in tenants:
        try:
            tenant_infos[tenant] = auth_client.tenants.get(tenant)
        except requests.HTTPError as e:
            print('Error while getting tenant {}: {}'.format(tenant, e))

    return tenant_infos
Exemple #12
0
def _import_wazo_user(users):
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new(expiration=36000)['token']
    auth_client.set_token(token)

    with closing(psycopg2.connect(config['db_uri'])) as conn:
        cursor = conn.cursor()
        entity_to_tenant_map = _build_entity_tenant_map(cursor)

    print('migrating users to wazo-auth', end='', flush=True)
    for user in users:
        _create_user(auth_client, entity_to_tenant_map, user)
        print('.', end='', flush=True)
    print('\ndone')

    auth_client.token.revoke(token)
Exemple #13
0
def _import_wazo_user(users):
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=36000)['token']
    auth_client.set_token(token)

    with closing(psycopg2.connect(config['db_uri'])) as conn:
        cursor = conn.cursor()
        tenant_uuid = _find_older_tenant_uuid(cursor)

    print('migrating services access to wazo-auth', end='', flush=True)
    for user in users:
        _create_user(auth_client, tenant_uuid, user)
        print('.', end='', flush=True)
    print('\ndone')

    auth_client.token.revoke(token)
Exemple #14
0
    def get_visible_tenants(self, tenant):
        token = request.headers['X-Auth-Token']
        auth_client = AuthClient(**self.auth_config)
        auth_client.set_token(token)

        try:
            visible_tenants = auth_client.tenants.list(
                tenant_uuid=tenant)['items']
        except HTTPError as e:
            response = getattr(e, 'response', None)
            status_code = getattr(response, 'status_code', None)
            if status_code == 401:
                logger.warning(
                    'a user is doing multi-tenant queries without the tenant list ACL'
                )
                return [tenant]
            raise

        return [tenant['uuid'] for tenant in visible_tenants]
def test_csv_import():
    auth_client = AuthClient(constants.HOST,
                             verify_certificate=False,
                             username='******',
                             password='******')
    dird_client = DirdClient(constants.HOST,
                             https=True,
                             verify_certificate=False,
                             timeout=MAX_TIME)

    token_data = auth_client.token.new(expiration=300)
    token = token_data['token']
    auth_client.set_token(token)

    try:
        auth_client.users.new(
            username=USERNAME,
            password=PASSWORD,
            tenant_uuid=token_data['metadata']['tenant_uuid'],
        )
    except requests.HTTPError as e:
        if e.response.status_code == 409:
            pass
        else:
            raise

    user_auth_client = AuthClient(
        constants.HOST,
        verify_certificate=False,
        username=USERNAME,
        password=PASSWORD,
    )
    token = user_auth_client.token.new('wazo_user', expiration=300)['token']

    result, time_to_complete = upload_csv(dird_client, token)

    assert 'created' in result, 'The result does not contain created contacts'
    assert len(result['created']
               ) == 1000, 'expected 1000 created contacts: {}'.format(
                   len(result['created']))
    assert time_to_complete < MAX_TIME, 'The import took too long {}s > {}s'.format(
        time_to_complete, MAX_TIME)
def migrate_new_status():
    config = _load_config()
    _wait_for_provd(config['provd'])

    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=5 * 60)
    auth_client.set_token(token['token'])

    master_tenant_uuid = token['metadata']['tenant_uuid']

    # Migrate devices
    for dir_entry in os.scandir(PROVD_JSONDB_DEVICES_DIR):
        device_id = dir_entry.name
        try:
            _migrate_device(device_id, master_tenant_uuid)
        except json.JSONDecodeError:
            print(device_id, 'is not a valid JSON file. Skipping.')
            continue

    subprocess.run(['systemctl', 'restart', 'xivo-provd'])
Exemple #17
0
def migrate_tenants():
    config = _load_config()
    _wait_for_provd(config['provd'])

    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=5*60)
    auth_client.set_token(token['token'])
    confd = ConfdClient(token=token['token'], **config['confd'])

    master_tenant_uuid = token['metadata']['tenant_uuid']

    # Migrate associated devices
    devices_migrated = []
    lines = confd.lines.list(recurse=True)['items']
    for line in lines:
        device_id = line['device_id']

        if device_id and device_id not in devices_migrated:
            try:
                _migrate_device(device_id, line['tenant_uuid'])
            except json.JSONDecodeError:
                print(device_id, 'is not a valid JSON file. Skipping.')
                continue
            except IOError as e:
                print('Skipping device "{}": {}'.format(device_id, e))
                continue
            devices_migrated.append(device_id)

    # Migrate autoprov devices
    for dir_entry in os.scandir(PROVD_JSONDB_DEVICES_DIR):
        device_id = dir_entry.name
        if device_id not in devices_migrated:
            try:
                _migrate_device(device_id, master_tenant_uuid)
            except json.JSONDecodeError:
                print(device_id, 'is not a valid JSON file. Skipping.')
                continue

    subprocess.run(['systemctl', 'restart', 'xivo-provd'])
Exemple #18
0
def main():
    config = _load_config()

    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=5 * 60)
    auth_client.set_token(token['token'])

    master_tenant_uuid = token['metadata']['tenant_uuid']
    all_tenants = [
        tenant['uuid'] for tenant in auth_client.tenants.list()['items']
    ]

    for dir_entry in os.scandir(PROVD_JSONDB_DEVICES_DIR):
        device_id = dir_entry.name
        try:
            _change_device_tenant_if_orphan(device_id, master_tenant_uuid,
                                            all_tenants)
        except json.JSONDecodeError:
            print(device_id, 'is not a valid JSON file. Skipping.')
            continue

    subprocess.run(['systemctl', 'restart', 'wazo-provd'])
Exemple #19
0
class TestInit(BaseTestCase):

    asset = 'base'

    def setUp(self):
        super().setUp()
        self.docker_exec(['wazo-auth-bootstrap'])
        self.key = self.docker_exec(['cat', '/var/lib/wazo-auth/init.key'
                                     ]).decode('utf-8')
        self.client = Client(self.auth_host,
                             port=self.auth_port,
                             verify_certificate=False)

    def test_post(self):
        body = {'username': '******', 'password': '******', 'key': INVALID_KEY}
        assert_http_error(401, self.client.init.run, **body)
        assert_http_error(400, self.client.init.run,
                          **copy_without(body, 'username'))
        assert_http_error(400, self.client.init.run,
                          **copy_without(body, 'password'))
        assert_http_error(400, self.client.init.run,
                          **copy_without(body, 'key'))

        result = self.client.init.run(username='******',
                                      password='******',
                                      key=self.key)
        assert_that(result,
                    has_entries(uuid=ANY_UUID, emails=empty(), username='******'))

        token_data = self._post_token('foo', 'bar', expiration=10)
        self.client.set_token(token_data['token'])

        user_tenants = self.client.users.get_tenants(result['uuid'])
        assert_that(
            user_tenants,
            has_entries(items=contains(self.get_top_tenant()), total=1))

    def get_top_tenant(self):
        return self.client.tenants.list(name='master')['items'][0]
class WazoAsteriskCLI(App):

    DEFAULT_VERBOSE_LEVEL = 0

    def __init__(self):
        super().__init__(
            description='A CLI for the asterisk service',
            command_manager=CommandManager('wazo_asterisk_cli.commands'),
            version='0.0.1',
        )
        self._current_token = None
        self._remove_token = False
        self._auth_client = None
        self._client = None
        self._backend = None

    def build_option_parser(self, *args, **kwargs):
        parser = super(WazoAsteriskCLI,
                       self).build_option_parser(*args, **kwargs)
        config_path_from_env = os.getenv('WAZO_ASTERISK_CLI_CONFIG', None)
        config_path_default = os.path.expanduser(
            os.path.join('~', '.config', 'wazo-asterisk-cli'))
        parser.add_argument(
            '--config',
            default=(config_path_from_env or config_path_default),
            help=
            'Extra configuration directory to override the system configuration',
        )
        parser.add_argument('--hostname', help='The wazo-auth hostname')
        parser.add_argument('--port', help='The wazo-auth port')

        https_verification = parser.add_mutually_exclusive_group()
        https_verification.add_argument('--ssl', help="Use ssl")
        https_verification.add_argument('--no-ssl', help="Don't use ssl")
        https_verification.add_argument(
            '--verify',
            action='store_true',
            help='Verify the HTTPS certificate or not')
        https_verification.add_argument('--insecure',
                                        action='store_true',
                                        help='Bypass certificate verification')
        https_verification.add_argument('--cacert',
                                        help='Specify the ca bundle file')

        auth_or_token = parser.add_mutually_exclusive_group()
        auth_or_token.add_argument('--token',
                                   help='The wazo-auth token to use')

        username_password = auth_or_token.add_argument_group()
        username_password.add_argument(
            '--auth-username',
            metavar='auth_username',
            help='The username to use to retrieve a token',
        )
        username_password.add_argument(
            '--auth-password',
            metavar='auth_password',
            help='The password to use to retrieve a token',
        )
        username_password.add_argument(
            '--backend', help='The backend to use when authenticating')

        return parser

    @property
    def client(self):
        if not self._auth_client:
            self._auth_client = Auth(**self._auth_config)

        if not self._current_token:
            self._backend = self._auth_config.pop('backend',
                                                  None) or self._backend
            self._auth_client = Auth(**self._auth_config)
            args = {'expiration': 3600}
            if self._backend:
                args['backend'] = self._backend
            token_data = self._auth_client.token.new(**args)
            self._current_token = token_data['token']

        self._auth_client.set_token(self._current_token)

        self._client = Amid(**self._amid_config)
        self._client.set_token(self._current_token)

        return self._client

    @property
    def client_without_token(self):
        if not self._client:
            self._client = Auth(**self._auth_config)
        return self._client

    def initialize_app(self, argv):
        self.LOG.debug('Wazo Asterisk CLI')
        self.LOG.debug('options=%s', self.options)
        conf = config.build(self.options)
        self.LOG.debug('Starting with config: %s', conf)
        self._current_token = self.options.token

        self.LOG.debug('client args: %s', conf['auth'])
        self._auth_config = dict(conf['auth'])
        self._amid_config = dict(conf['amid'])

    def clean_up(self, cmd, result, err):
        if err:
            self.LOG.debug('got an error: %s', err)

        if self._remove_token:
            self._auth_client.token.revoke(self._current_token)
            self._remove_token = False
def _auto_create_config():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=36000)['token']
    auth_client.set_token(token)

    tenants = auth_client.tenants.list()['items']

    base_url = 'https://{host}:{port}/{version}'.format(
        **config['dird']
    )
    conference_url = '{}/backends/conference/sources'.format(base_url)
    profiles_url = '{}/profiles'.format(base_url)
    displays_url = '{}/displays'.format(base_url)
    personal_url = '{}/backends/personal/sources'.format(base_url)
    wazo_url = '{}/backends/wazo/sources'.format(base_url)
    office365_url = '{}/backends/office365/sources'.format(base_url)
    sources_url = '{}/sources'.format(base_url)
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-Auth-Token': token,
    }
    for tenant in tenants:
        name = tenant['name']
        if name == 'master':
            continue

        headers['Wazo-Tenant'] = tenant['uuid']

        def post(*args, **kwargs):
            return requests.post(
                *args,
                headers=headers,
                verify=config['dird']['verify_certificate'],
                **kwargs
            )

        post(conference_url, json=CONFERENCE_SOURCE_BODY)
        post(personal_url, json=PERSONAL_SOURCE_BODY)
        wazo_body = dict(name='auto_wazo_{}'.format(name), **WAZO_SOURCE_BODY)
        post(wazo_url, json=wazo_body)

        # add office365 is the plugin is installed
        office365_body = dict(name='auto_office365_{}'.format(name), **OFFICE_365_SOURCE_BODY)
        post(office365_url, json=office365_body)

        display_name = 'auto_{}'.format(name)
        display_body = {
            'name': display_name,
            'columns': DEFAULT_DISPLAY_COLUMNS,
        }
        post(displays_url, json=display_body).json()

        # GET all auto created sources before or during this migration
        response = requests.get(
            sources_url,
            headers=headers,
            verify=config['dird']['verify_certificate'],
        )
        sources = []
        if response.status_code == 200:
            for source in response.json()['items']:
                if source['name'] == 'personal':
                    sources.append(source)
                    continue

                if not source['name'].startswith('auto_'):
                    continue
                if not source['name'].endswith(name):
                    continue
                sources.append(source)

        # GET the display because the POST could return a 409 if it already exists
        response = requests.get(
            displays_url,
            headers=headers,
            verify=config['dird']['verify_certificate'],
        )
        display = None
        if response.status_code == 200:
            for d in response.json()['items']:
                if d['name'] == display_name:
                    display = d
                    break

        profile_body = {
            'name': 'default',
            'display': display,
            'services': {
                'lookup': {'sources': sources},
                'favorites': {'sources': sources},
                'reverse': {'sources': sources, 'timeout': 0.5},
            },
        }
        post(profiles_url, json=profile_body)
Exemple #22
0
def _auto_create_config():
    config = _load_config()
    auth_client = AuthClient(**config['auth'])
    token = auth_client.token.new('wazo_user', expiration=36000)['token']
    auth_client.set_token(token)
    confd_client = ConfdClient(token=token, **config['confd'])

    tenants = auth_client.tenants.list()['items']

    base_url = 'https://{host}:{port}/{version}'.format(**config['dird'])
    profiles_url = '{}/profiles'.format(base_url)
    displays_url = '{}/displays'.format(base_url)
    personal_url = '{}/backends/personal/sources'.format(base_url)
    wazo_url = '{}/backends/wazo/sources'.format(base_url)
    office365_url = '{}/backends/office365/sources'.format(base_url)
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-Auth-Token': token,
    }
    for tenant in tenants:
        name = tenant['name']
        if name == 'master':
            continue

        headers['Wazo-Tenant'] = tenant['uuid']

        def post(*args, **kwargs):
            return requests.post(*args,
                                 headers=headers,
                                 verify=config['dird']['verify_certificate'],
                                 **kwargs)

        personal_body = PERSONAL_SOURCE_BODY
        personal = post(personal_url, json=personal_body)
        if personal.status_code == 409:
            # Default configuration already exists
            return

        wazo_body = dict(name='auto_wazo_{}'.format(name), **WAZO_SOURCE_BODY)
        wazo = post(wazo_url, json=wazo_body)

        sources = [personal.json(), wazo.json()]

        # add office365 is the plugin is installed
        office365_body = dict(name='auto_office365_{}'.format(name),
                              **OFFICE_365_SOURCE_BODY)
        office365 = post(office365_url, json=office365_body)
        if office365.status_code == 201:
            sources.append(office365)

        display_body = {
            'name': 'auto_{}'.format(name),
            'columns': DEFAULT_DISPLAY_COLUMNS,
        }
        display = post(displays_url, json=display_body).json()

        contexts = confd_client.contexts.list(
            tenant_uuid=tenant['uuid'])['items']
        for context in contexts:
            if context['type'] != 'internal':
                continue

            profile_body = {
                'name': context['name'],
                'display': display,
                'services': {
                    'lookup': {
                        'sources': sources
                    },
                    'favorites': {
                        'sources': sources
                    },
                    'reverse': {
                        'sources': sources,
                        'timeout': 0.5
                    },
                },
            }
            post(profiles_url, json=profile_body)
 def from_config(cls, *args, **kwargs):
     client = AuthClient(*args, **kwargs)
     # 30 minutes should be enought to import all users
     token = client.token.new(expiration=30 * 30)['token']
     client.set_token(token)
     return cls(client)