This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
portail-citoyen2/portail_citoyen/management/commands/load-wcs-users.py

171 lines
7.2 KiB
Python

import random
import string
import locale
from optparse import make_option
import os.path
import logging
try:
from django.contrib.auth import get_user_model
except ImportError:
from django.contrib.auth.models import User
get_user_model = lambda: User
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from authentic2.saml.models import LibertyProvider, LibertyFederation
import wcs
import publisher
import ConfigParser
from qommon.ident.password_accounts import PasswordAccount
from wcs.users import User as WcsUser
from wcs.formdata import get_dict_with_varnames
import lasso
logger = logging.getLogger()
class Command(BaseCommand):
args = '<wcs_data_path wcs_data_path ...>'
help = '''Load W.C.S. users'''
option_list = BaseCommand.option_list + (
make_option('--provider', action="store"),
make_option("--extra", action="append", default=[]),
make_option('--verbose', action="store_true"),
make_option('--fake', action="store_true"),
make_option('--debug', action="store_true"),
make_option('--allow-not-mapped', action="store_true"),
make_option('--help-mapping', action="store_true"),
make_option('--mapping', action="append", default=[]),
)
hashing_algo_mapping = {
'sha': 'sha1',
}
@transaction.commit_on_success
def handle(self, *args, **options):
locale.setlocale(locale.LC_ALL, '')
if options['verbose'] or options['debug']:
handler = logging.StreamHandler()
handler.setLevel(level=logging.DEBUG if options['debug'] else logging.INFO)
logger.addHandler(handler)
options['mapping'] = map(lambda s: s.split(':'), options['mapping'])
for wcs_data_path in args:
if not os.path.isdir(wcs_data_path):
raise CommandError('path %s does not exist', wcs_data_path)
self.handle_path(wcs_data_path, options)
def generate_name_id(self):
# example: _9903A47299512211F49F9E7931183761
alpha = string.ascii_uppercase + string.digits
name_id = ''.join(random.choice(alpha) for i in xrange(32))
return '_%s' % name_id
def handle_path(self, path, options):
logger.debug('==> %s' % path)
User = get_user_model()
publisher.WcsPublisher.configure(ConfigParser.RawConfigParser())
for extra in options['extra']:
publisher.WcsPublisher.register_extra_dir(extra)
pub = publisher.WcsPublisher.create_publisher()
pub.app_dir = path
pub.set_config()
formdef = WcsUser.get_formdef()
wcs_user_fields = get_dict_with_varnames(formdef.fields, {}).keys()
user_fields = User._meta.get_all_field_names()
if options.get('help_mapping', False):
print 'List of W.C.S. user fields:'
for wcs_user_field in wcs_user_fields:
print '-', wcs_user_field
print 'List of portail-citoyen user fields:'
for user_field in user_fields:
print '-', user_field
return
for wcs_user_field, user_field in options.get('mapping', []):
if wcs_user_field not in wcs_user_fields:
raise CommandError('wcs user field %r unknown' % wcs_user_field)
if user_field not in user_fields:
raise CommandError('idp user field %r unknown' % user_field)
not_mapped = False
mapping_dict = dict(options.get('mapping', ()))
for wcs_user_field in wcs_user_fields:
if wcs_user_field not in mapping_dict:
print 'W.C.S. user field %r not mapped' % wcs_user_field)
not_mapped = True
if not_mapped and not options['allow_not_mapped']:
raise CommandError('Some W.C.S. user fields are not mapped ! Aborting.')
try:
provider = LibertyProvider.objects.get(name=options['provider'])
except LibertyProvider.DoesNotExist:
raise CommandError('provider %s does not exist' % options['provider'])
to_save = []
to_store = []
for password_account in PasswordAccount.values():
new_user = None
new_federation = None
wcs_user = password_account.get_user()
if not wcs_user:
logger.info('no wcs user for password account %s' % password_account)
continue
try:
new_federation = LibertyFederation.objects.get(
sp_id=provider.entity_id,
name_id_content__in=getattr(wcs_user, 'name_identifiers', []) or [])
new_user = new_federation.user
logger.info('wcs account %r already linked to idp account %r, updating' % (password_account.id, new_federation.user.username))
except LibertyFederation.DoesNotExist:
pass
if User.objects.filter(username=password_account.id).exists():
if options['verbose']:
logger.info('wcs account %r cannot be linked as homonym account %r:%s exists' % (password_account.id,
federation.user.username, federation.user.id))
continue
algo = password_account.hashing_algo
algo = self.hashing_algo_mapping.get(algo, algo)
if algo:
new_password = '%s$$%s' % (algo, password_account.password)
if not new_user:
if User.objects.filter(username=password_account.id).exists():
logger.info('wcs account %r already exists in db' % (password_account.id,))
continue
new_user = User(username=password_account.id)
wcs_user_data = get_dict_with_varnames(formdef.fields, wcs_user.form_data)
for wcs_user_field, user_field in options['mapping']:
value = wcs_user_data.get(wcs_user_field)
if not value:
continue
logger.info('setting %s to %s' % (user_field, value))
setattr(new_user, user_field, str(value).decode('utf-8'))
if algo:
new_user.password = new_password
else:
new_user.set_password(password_account.password)
new_user.save()
name_id = self.generate_name_id()
if not new_federation:
new_federation = LibertyFederation.objects.create(user=new_user,
sp_id=provider.entity_id,
idp_id='',
name_id_qualifier=name_id,
name_id_sp_name_qualifier=provider.entity_id,
name_id_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
name_id_content=name_id,
name_id_sp_provided_id='')
wcs_user.name_identifiers.append(name_id)
logger.info('created new link %s %s' % (password_account.id, wcs_user.name_identifiers))
to_store.append(wcs_user)
if options['fake']:
raise CommandError('Fake...')
for user in to_store:
user.store()