Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-28 07:24:56

0001 """Sync user accounts from swf-monitor via the SSH tunnel.
0002 
0003 Calls swf-monitor's /api/users/ endpoint and creates matching local
0004 Django accounts. Sync is one-way (upstream → devcloud) and password
0005 sync only happens at initial provisioning: existing local users are
0006 never password-overwritten by sync, since devcloud account management
0007 is autonomous after creation.
0008 
0009 Usage:
0010     python manage.py sync_users
0011     python manage.py sync_users --set-password changeme   # fallback if no hash
0012 """
0013 
0014 import logging
0015 
0016 from django.contrib.auth import get_user_model
0017 from django.core.management.base import BaseCommand
0018 
0019 from remote_app import monitor_client
0020 
0021 logger = logging.getLogger(__name__)
0022 
0023 
0024 class Command(BaseCommand):
0025     help = 'Sync user accounts from swf-monitor'
0026 
0027     def add_arguments(self, parser):
0028         parser.add_argument(
0029             '--set-password',
0030             help='Fallback password for new accounts when no hash available from upstream',
0031         )
0032 
0033     def handle(self, *args, **options):
0034         # as_user sets X-Remote-User for TunnelAuthentication on upstream.
0035         # 'swf-remote-proxy' is the existing service-user convention
0036         # (see swf-monitor middleware.py).
0037         data = monitor_client._get('/api/users/', as_user='swf-remote-proxy')
0038         if 'error' in data:
0039             self.stderr.write(self.style.ERROR(f"Failed to fetch users: {data['error']}"))
0040             return
0041 
0042         users = data.get('users', [])
0043         if not users:
0044             self.stdout.write('No users returned from swf-monitor.')
0045             return
0046 
0047         User = get_user_model()
0048         created_count = 0
0049         unchanged_count = 0
0050 
0051         for u in users:
0052             username = u.get('username', '').strip()
0053             if not username:
0054                 continue
0055             pw_hash = u.get('password', '')
0056             user, created = User.objects.get_or_create(
0057                 username=username,
0058                 defaults={
0059                     'is_active': u.get('is_active', True),
0060                     'email': u.get('email', '') or '',
0061                     'first_name': u.get('first_name', '') or '',
0062                     'last_name': u.get('last_name', '') or '',
0063                 },
0064             )
0065             if created:
0066                 if pw_hash:
0067                     # Copy hash directly — same credentials, no plaintext
0068                     user.password = pw_hash
0069                     user.save(update_fields=['password'])
0070                 elif options['set_password']:
0071                     user.set_password(options['set_password'])
0072                     user.save(update_fields=['password'])
0073                 created_count += 1
0074                 self.stdout.write(self.style.SUCCESS(f'  Created: {username}'))
0075             else:
0076                 # Existing local user — never touch password, email, or names.
0077                 # Devcloud account management is autonomous after provisioning.
0078                 unchanged_count += 1
0079 
0080         self.stdout.write(
0081             f'Done. {created_count} created, '
0082             f'{unchanged_count} unchanged (of {len(users)} from swf-monitor).'
0083         )