Changes between Version 1 and Version 2 of ContribAuthImprovements
- Timestamp:
- Mar 22, 2012, 2:01:45 AM (13 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
ContribAuthImprovements
v1 v2 13 13 However, there is also a use case for adding non-email, non-username identification marks to the base User object (e.g., an authentication identifier from another login system). This requires additional fields, and needing to perform a join to simply validate a user is wasteful. 14 14 15 The refore, there has been a long-lived requestto "fix" auth.User, either by removing the base limitations of the model, or making the User model user-configurable in some way.15 These use cases have driven a long-lived request (#3011) to "fix" auth.User, either by removing the base limitations of the model, or making the User model user-configurable in some way. 16 16 17 Some django-developer discussions that cover this topic (there aremany, over many years):17 Some django-developer discussions that cover this topic (there have been many, over many years): 18 18 19 19 * http://groups.google.com/group/django-developers/browse_thread/thread/6dadb540ca5f7d9b 20 20 * http://groups.google.com/group/django-developers/browse_thread/thread/61c15301a89d88be 21 21 22 A large number of solutions have also been proposed over the years. Here is a summary of the most viable candidates: 23 22 24 == Solution 1: Superminimal update == 23 25 24 Don't make any significant contribution to `contrib.auth` -- just make 2 changes to he User model, phased in over severalrelease cycles.26 Don't make any significant contribution to `contrib.auth` -- just make 2 changes to he User model, phased in over multiple release cycles. 25 27 26 * increase the length of the username field to 254 characters, so it can hold an email if necessary27 *Make the email field 254 characters long.28 1. Increase the length of the username field to 254 characters, so it can hold an email if necessary 29 2. Make the email field 254 characters long. 28 30 29 31 === Implementation === … … 41 43 42 44 * Doesn't actually fix the problem for any use case other than "email address as username" 43 * Introduces a setting that immediately becomes deprecated (since it won't be needed once the migration is complete)45 * Introduces a setting that immediately becomes deprecated (since it won't be needed once the migration cycle is complete) 44 46 * Doesn't address the problem with any other usage of EmailField having a max_length of 75. 45 47 * Introduces a circular dependency between settings and models. When settings are loaded, INSTALLED_APPS is inspected, and each models file is loaded. If a models file contains a reference to settings, hilarity can ensue. This isn't a problem *most* of the time, but it can lead to some interesting side effects. … … 47 49 == Solution 1a: Superminimal with forced migration == 48 50 49 As for Solution 1, but don't have the setting , and *require* the migration as part of the 1.5 upgrade path.51 As for Solution 1, but don't have the setting -- *require* the database migration as part of the 1.5 upgrade path. 50 52 51 53 === Advantages === … … 58 60 59 61 * Is a huge backwards incompatibility: Requires that every Django user upgrading read, understand, and act upon the instructions in the release notes. 60 * Poor failure modes. If users fail to act on the release notes, their projects won't fail until the first user enters an email that is longer than 75 characters, or a username longer than 30 characters, at which point DatabaseErrors will be raised.62 * Poor failure modes. If a users fail to read and act on the instructions in the release notes, their projects won't fail until the first user enters an email that is longer than 75 characters, or a username longer than 30 characters, at which point DatabaseErrors will be raised. 61 63 62 == Solution 2: USER_MODEL setting ==64 == Solution 2: AUTH_USER_MODEL setting == 63 65 64 * Allow users to specify a User model via a setting. 65 * This is essentially the original #3011 proposal. 66 Allow users to specify a User model via a setting. This is essentially the original #3011 proposal. 67 68 === Implementation === 69 70 Introduce a AUTH_USER_MODEL setting; instead of assuming that auth.User is the user model, the auth app dynamically swaps in the model described in AUTH_USER_MODEL, and calls it User. 66 71 67 72 === Advantages === 68 73 69 74 * Allows any user model, providing it adheres to some basic contract (defined by Django, probably using contrib.admin as a baseline use case) 75 * Existing apps require no migration -- references to auth.User continue to work as-is. 70 76 * Mirrors current usage in contrib.comments 71 77 … … 85 91 * Doesn't address the EmailField length problem for existing users. We could address this by having a User model (reflecting current field lengths) and a new SimpleUser (that reflects better defaults); then use global_settings and project template settings to define which User is the default for new vs existing projects. 86 92 * Doesn't solve the analogous problem for any other project. E.g., contrib.comments already has pluggable Comments models, and has invented a bespoke solution. Other projects will have similar needs; this solution doesn't address the duplication of code. 93 * Has unpredictable failure modes if a third-party app assumes that User has a certain attribute or property which the project-provided User model doesn't support (or supports in a way different to the core auth.User model). 87 94 88 95 === Solution 3: Leverage App Refactor === 89 96 90 * Land Arthur Koziel's App Refactor patch from GSoC 2010. This introduces a number of benefits --reliable hooks for app startup, configurable app labels, predictable module loading, amongst others -- but the one that matters for the purposes of auth.User is that it allows Apps to be treated as items that need to be configured as a runtime activity. In this case, we need to be able to specify, at a project level, which model is your "User" model in the auth app. 97 Use Arthur Koziel's App Refactor patch from GSoC 2010 as a way to define a configurable auth app. 98 99 === Implementation === 100 101 * Land the App Refactor patch. This introduces a number of benefits -- reliable hooks for app startup, configurable app labels, predictable module loading, amongst others -- but the one that matters for the purposes of auth.User is that it allows Apps to be treated as items that need to be configured as a runtime activity. In this case, we need to be able to specify, at a project level, which model is your "User" model in the auth app. 91 102 92 103 * Introduce the concept of a LazyForeignKey. LazyForeignKey is a normal foreign key, with all the usual foreign key behaviors; the only difference is that the model it links to isn't specified in the model -- it's a configuration item drawn from an application configuration. So, ForeignKey('auth.User') creates a foreign key to django.contrib.auth.User; LazyForeignKey('auth.User') asks the auth app for the model that is being used as the 'User' model, and creates a foreign key to that. This should just be a matter of slotting into the existing model reference resolution code, which is something that the app refactor cleans up. … … 105 116 === Problems === 106 117 107 * No transparent update path -- requires that third party apps be updated to be "pluggable a pp compatible". This means app authors need to make all ForeignKey(User) into LazyForeignKey('auth.User'), and modify any usage of forms/fields etc. This could be considered a benefit, however; Migrating User models is a nontrivial step, and it would118 * No transparent update path -- requires that third party apps be updated to be "pluggable auth compatible". This means app authors need to convert all ForeignKey(User) into LazyForeignKey('auth.User'), and modify any usage of forms/fields etc. This could be considered a benefit, however; Migrating User models is a nontrivial step, and it should probably involve some opt-in engineering. 108 119 109 120 * Doesn't address the immediate problem for EmailField. We could do the same User/SimpleUser conversion here; with the added benefit that we are also introducing apprefactor, so we can use the distinction between an "unconfigured" auth app and a "Django 1.5 AppRefactor Configured" auth app as the point for identifying whether User or SimpleUser is in use. 121 122 == Solution 3a: Transparent LazyForeignKeys == 123 124 As for Solution 3, but don't include an explicit LazyForeignKey class. Instead, use the "pluggable" marker in the Meta class; If you define a ForeignKey to a 'pluggable' model, you're indicating that this foreign key reference might be changed later on. 125 126 === Advantages === 127 128 * As for Solution 3, but provides a transparent migration path for apps -- no need to manually change ForeignKey(User). However, depending on your perspective, this might not actually be an advantage at all, because it removes the opt-in. 129 130 === Problems === 131 132 * As for Solution 3. 110 133 111 134 == Solution 4: contrib.newauth == … … 118 141 * It exhibits the settings-models dependency problem 119 142 * It introduces a new feature -- the ability to have *multiple* user models -- that isn't an obvious improvement. Additional discussion is required before being adopted. 143 144 === Advantages === 145 146 * Gives us a clean slate to examine authentication and authorisation issues. 120 147 121 148 === Problems === 122 149 123 150 * There's no pret-a-porter project ready as a candidate. Rebuilding contrib.auth is a big undertaking, and doesn't yet have a clear design (or even design requirements). 151 152 == Universal problems == 153 154 Regardless of the final 155 156 === The User Contract === 157 158 In order for code to actually be able to adapt to swappable User models, there needs to be some common ground on what a "User" object can actually do. Django is in a position to enforce this by convention -- contrib.admin is a good baseline case. 159 160 Consensus seems to be that the 'minimal contract' for User needs to be little more than that required basic identification -- you need to be able to authenticate using arbitrary credentials, and be able to service a request to print "Hello <user>" 161 162 This 'minimal' 163 164 === Separation of authentication from authorisation === 165 166 contrib.admin requires 167 168 === Forms === 169 170 Any form interaction with User model needs to be able to adapt as the User model changes. 171 172 * Does ModelForm need to automatically resolve model references for models marked as pluggable? 173 * Should Forms be configurable items for apps? 174 175 === Inheritance === 176 177 If the User model can change, then models inheriting from the User model need to be able to adapt to a variable base class. 178 179 As a first iteration, it may be necessary to prohibit inheritance from a User model that is marked as pluggable. 124 180 125 181 == Parallel concerns == … … 136 192 137 193 Discussion on django-developers suggests that complete consensus is unlikely; Currently awaiting BDFL mandate. 138