171 lines
7.2 KiB
Python
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|