Changes between Version 6 and Version 7 of MultipleAuthBackends
- Timestamp:
- Feb 27, 2006, 4:05:24 PM (19 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
MultipleAuthBackends
v6 v7 11 11 Instead of hard-coding checks for a cookie, or a username/password etc. etc. let's let different callables just grab the credentials from the request. In fact, let's put a bunch of these plugins in a list, so if the first one fails, we can try another. 12 12 13 13 14 {{{ 14 15 #!python 15 16 16 class UsernamePasswordPlugin: 17 def extract_credentials(self, request): 18 return {'username': request.POST['username'], 'password': request.POST['password']} 17 # in settings.py 18 CREDENTIALS_EXTRACTORS = ( 19 'django.contrib.auth.SessionCredentials', 20 # etc, etc. 21 ) 22 }}} 23 24 {{{ 25 #!python 26 27 class SessionCredentials: 28 def __init__(self): 29 self.cred_key = '_credentials' 30 31 def extract_credentials(self, request): 32 # get the credentials from the request and save them to the session 33 # if they exist 34 login = request.POST.get('login', None) 35 # we probably want to go ahead and enrypt the password here since 36 # we're going to store it in the session. 37 password = request.POST.get('password', None) 38 if login and password: 39 credentials = {'login': login, 'password': password} 40 request.session[self.cred_key] = credentials 41 else: 42 credentials = request.session.get(self.cred_key, None) 43 return credentials 44 45 def logout(self, request): 46 del self.session[self.credentials_key] 19 47 20 48 }}} 21 49 22 We can add plugins for extracting credentials from a sessions, getting an api key, whatever, and configure them like so:23 50 24 Add this to settings.py:25 {{{26 #!python27 28 CREDENTIALS_PLUGINS = (29 'django.contrib.auth.SessionCredentials',30 'django.contrib.auth.UsernamePasswordCredentials',31 )32 }}}33 51 34 52 == Authentication == … … 46 64 }}} 47 65 48 And now for the plugin:49 66 {{{ 50 67 #!python … … 52 69 from django.contrib.auth.models import User 53 70 54 class ModelAuthenticator 55 def authenticate_credentials(self, credentials): 56 #we need a username and password in the credentials, if they're not there, return None 57 #keep in mind that other authenticators can look for different types of credentials 58 #if the username or password or bad, return None 59 #if everything is kosher, return the USER 71 class ModelAuthenticator: 72 def authenticate(self, credentials): 73 from django.contrib.auth.models import User 74 75 user = User.objects.get(username=credentials['login']) 76 if user.password == credentials['password']: 77 return user 78 return None 60 79 }}} 61 80 … … 65 84 == Multiple Backends == 66 85 67 Um, so what if I want to use LDAP '''and''' Django models? Funny you should ask. 86 Um, so what if I want to use LDAP '''and''' Django models? Funny you should ask. By the way, this is main interface to the authentication system. You won't use credentials and authenticators directly. 68 87 69 88 {{{ 70 89 #!python 71 90 72 class AuthenticationUtility: 73 def authenticate(self, request): 74 #psuedocode ahead! 75 for cred_plugin in credentials_plugins: 76 credentials = cred_plugin.extract_credentials(request) 77 if credentials is not None: 78 for auth_plugin in auth plugins: 79 user = auth_plugin.authenticate_credentials(credentials) 80 if user is not None: 81 return user 91 class AuthUtil: 92 def __init__(self): 93 # XXX: these will be configurable in settings.py 94 self.cred_extractors = (SessionCredentials(),) 95 self.authenticators = (ModelAuthenticator(),) 96 97 def authenticate(self, request): 98 for cred_extractor in self.cred_extractors: 99 credentials = cred_extractor.extract_credentials(request) 100 for authenticator in self.authenticators: 101 user = authenticator.authenticate(credentials) 102 user.cred_extractor = cred_extractor 103 user.authenticator = authenticator 104 return user 105 return None 106 107 def logout(self, request): 108 for cred_extractor in self.cred_extractors: 109 if hasattr(cred_extractor, 'logout'): 110 cred_extractor.logout(request) 82 111 }}} 83 112 84 This is the main interface to the auth system. In english, check for credentials, if we find them, try to authenticate them against every auth backend in settings.py, if none of them authenticate, do it all again with the next type of credentials.85 113 86 Credentials plugins should probably have a logout method. I didn't give any examples, but it shouldn't be hard. 114 == Integration == 87 115 88 That's most of it. Think you have a use case this won't work for? Please tell django-developers. 116 How will this integrate into Django? I think either the handlers (mod_python, etc.) should start using AuthUtil, or this can be done in decorators. My vote is certainly for the first option. 117 89 118 90 119 == Suggestions == … … 97 126 To me it doesn't make sense for credentials to be stored as a model... they are just a dict or string or object or whatever that get extracted/assembled from the request. You just pass to the auth backends for checking. The auth backend already persists them. The username/password combo isn't blessed. Credentials could just as well be an api key similar to backpack, or whatever. 98 127 99 I think these abstractions allow for the use cases you mention, but the details certainly need to be worked out better. I explicitly want to ''avoid'' coupling this to django models, but it should ''easy'' to do so since it's most likely the default case. -- 128 I think these abstractions allow for the use cases you mention, but the details certainly need to be worked out better. I explicitly want to ''avoid'' coupling this to django models, but it should ''easy'' to do so since it's most likely the default case. --Joseph Kocherhans 100 129 101 130 102 131 Here is how they approached this problem in Zope3: [http://www.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/Zope3Book/principalplugin.html]. You can find additional resources here: [http://www.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/Zope3Book] -- Linicks 132 133 I don't believe zope does things that way anymore. That first link looks to be more a step along the way than a final implementation. --Joseph Kocherhans