Opened 7 years ago

Closed 5 years ago

Last modified 5 years ago

#27801 closed New feature (fixed)

Make createsuperuser inspect environment variables for username and password

Reported by: Markus Holtermann Owned by: Hasan Ramezani
Component: contrib.auth Version: dev
Severity: Normal Keywords:
Cc: James Pic Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The createsuperuser management command is not quite suitable for scripting, even with the --no-input flag, as it doesn't set a password. The management command should inspect some environment variables (e.g. DJANGO_SUPERUSER_{USERNAME_FIELD.upper()} and DJANGO_SUPERUSER_PASSWORD) to pick up the username, password and possibly all other required fields.

Change History (16)

comment:1 by lsmag, 7 years ago

Owner: changed from nobody to lsmag
Status: newassigned

comment:2 by Tim Graham, 7 years ago

I'm not certain if using createsuperuser in non-interactive mode with environment variables is simpler than writing a standalone script to handle this use case. Did you give any thought to this?

in reply to:  2 comment:3 by Markus Holtermann, 7 years ago

Replying to Tim Graham:

I'm not certain if using createsuperuser in non-interactive mode with environment variables is simpler than writing a standalone script to handle this use case. Did you give any thought to this?

Yes, I gave it some thought. The logic in createsuperuser for ensuring all required fields are present, selecting the right database, etc is already there. With more and more automated deployments for Django projects I think having this feature built-in is essential.

I think I'd have createsuperuser fallback to the environment variables if they are present unless fields are overridden by command line arguments:

user_data = {}
for field in required_fields:
    if field in options:
        user_data[field] = options[field]
    elif 'DJANGO_SUPERUSER_' + field.upper() in os.environ:
        user_data[field] = os.environ['DJANGO_SUPERUSER_' + field.upper()]
    elif options['interactive']:
        user_data[field] = ask_for_field_value(field)
    else:
        raise CommandError('Missing value for %s' % field)

That's a rough draft!

comment:4 by Tim Graham, 7 years ago

I guess it could help to define the scope of the use case. Would this be meant for creating one initial superuser. Should it ease creating many superusers?

That might help clarify the need to have all fields pulled from environment variables rather than just the password. This seems to add some complication and I'd like to keep things as simple as possible.

I think the minimal script for anything more complicated is straightforward. If you're running in non-interactive mode, error handling doesn't seem like a priority.

import django
django.setup()

from django.contrib.auth import get_user_model
UserModel = get_user_model()

UserModel._default_manager.db_manager('default').create_superuser()

comment:5 by Markus Holtermann, 7 years ago

It's for the initial superuser when you can't run the management command in interactive mode. The only field as for AbstractBaseUser is password that needs to be passed via environment variables. However, if you have another required field that contains sensitive parameters (e.g. API key) and that is a required field you want to have that handled through environment variables as well.

Hence my though, let's use the command arguments in the first place (e.g. for username), fallback to environment variables (that allows for sensitive values) and fail if that's not defined. I'm not sure if we _need_ support for env vars in the interactive mode, i believe it wouldn't hurt, though. Not sure how complex that change might get if that's added.

comment:6 by Tim Graham, 7 years ago

Triage Stage: UnreviewedAccepted

comment:7 by Jon Dufresne, 6 years ago

Another potential script friendly solution would be to read the password from a file. Other non-Django commands implement such a feature. For example, ldapsearch -y passwdfile and the PostgreSQL password file.

comment:8 by James Pic, 5 years ago

Cc: James Pic added
Easy pickings: set
Has patch: set
Owner: changed from lsmag to James Pic

For our use case, SUPERUSER_PASSWORD works to drop the dependency to expect in automation code.

PR

Last edited 5 years ago by Tim Graham (previous) (diff)

comment:9 by Tim Graham, 5 years ago

Easy pickings: unset
Needs documentation: set
Needs tests: set

Not sure if that would completely address the ticket, but the patch is incomplete without tests and documentation.

comment:10 by James Pic, 5 years ago

FTR there is an external solution for this that you can install with PyPi package djcli. As such this is a wontfix for me.

Last edited 5 years ago by James Pic (previous) (diff)

comment:11 by Hasan Ramezani, 5 years ago

Owner: changed from James Pic to Hasan Ramezani

@Tim Graham, do we still need this? do you prefer to read the password from the file or environment variable?

comment:12 by Hasan Ramezani, 5 years ago

Needs documentation: unset
Needs tests: unset

I made a PR to read the password from environment variables in the non-interactive mode.
Based on the use case proposed on ticket, this feature could be used in scripting. and the only thing that we can not provide it in non-interactive mode is password.

comment:13 by Mariusz Felisiak, 5 years ago

Patch needs improvement: set

comment:14 by Hasan Ramezani, 5 years ago

Patch needs improvement: unset

comment:15 by Mariusz Felisiak <felisiak.mariusz@…>, 5 years ago

Resolution: fixed
Status: assignedclosed

In a530851:

Fixed #27801 -- Made createsuperuser fall back to environment variables for password and required fields.

comment:16 by James Pic, 5 years ago

FTR, I fixed my issue among others in an external package: https://pypi.org/project/djcli/

Note: See TracTickets for help on using tickets.
Back to Top