1 """The TurboGears identity management package."""
2
3
4 __all__ = ['_encrypt_password', 'create_default_provider',
5 'current', 'current_provider',
6 'encrypt_password', 'encrypt_pw_with_algorithm',
7 'get_identity_errors', 'get_failure_url',
8 'set_current_identity', 'set_current_provider',
9 'set_identity_errors', 'set_login_attempted',
10 'was_login_attempted', 'verify_identity_status']
11
12
13 import logging
14 try:
15 from hashlib import md5, sha1
16 except ImportError:
17 from sha import new as sha1
18 from md5 import new as md5
19
20 import cherrypy
21 import pkg_resources
22 import turbogears
23
24 from turbogears.util import deprecated, request_available, load_class
25 from turbogears.identity.exceptions import (IdentityConfigurationException,
26 RequestRequiredException, IdentityManagementNotEnabledException)
27
28
29 log = logging.getLogger('turbogears.identity')
30
31
33 """Create default identity provider.
34
35 Creates an identity provider according to what is found in
36 the configuration file for the current TurboGears application
37
38 Returns an identity provider instance or
39 raises an IdentityConfigurationException.
40
41 """
42 provider_plugin = turbogears.config.get('identity.provider', 'sqlalchemy')
43 plugins = pkg_resources.iter_entry_points(
44 'turbogears.identity.provider', provider_plugin)
45
46 log.debug("Loading provider from plugin: %s", provider_plugin)
47
48 for entrypoint in plugins:
49 try:
50 provider_class = entrypoint.load()
51 except Exception, load_error:
52 raise IdentityConfigurationException(
53 "IdentityProvider plugin can't be loaded: %s\n%s"
54 % (provider_plugin, load_error))
55 break
56 else:
57 provider_class = load_class(provider_plugin)
58
59 if not provider_class:
60 raise IdentityConfigurationException(
61 "IdentityProvider plugin missing: %s" % provider_plugin)
62
63 return provider_class()
64
65
67 try:
68 return cherrypy.request.identity_login_attempted
69 except AttributeError:
70 return False
71
72
74 cherrypy.request.identity_login_attempted = flag
75
76
84
85
87 cherrypy.request.identityProvider = provider
88
89
91 """Hash the given password with the specified algorithm.
92
93 Valid values for algorithm are 'md5' and 'sha1' or 'custom'. If the
94 algorithm is 'custom', the config setting 'identity.custom_encryption'
95 needs to be set to a dotted-notation path to a callable that takes
96 an unencrypted password and gives back the password hash.
97
98 All other algorithms values will be essentially a no-op.
99
100 """
101 hashed_password = password
102
103 if isinstance(password, unicode):
104 password_8bit = password.encode('utf-8')
105 else:
106 password_8bit = password
107 if algorithm == 'md5':
108 hashed_password = md5(password_8bit).hexdigest()
109 elif algorithm == 'sha1':
110 hashed_password = sha1(password_8bit).hexdigest()
111 elif algorithm == 'custom':
112 custom_encryption_path = turbogears.config.get(
113 'identity.custom_encryption', None)
114 if custom_encryption_path:
115 custom_encryption = turbogears.util.load_class(
116 custom_encryption_path)
117 if custom_encryption:
118 hashed_password = custom_encryption(password_8bit)
119
120
121 if not isinstance(hashed_password, unicode):
122 hashed_password = hashed_password.decode('utf-8')
123 return hashed_password
124
125 _encrypt_password = deprecated(
126 "Use identity.encrypt_pw_with_algorithm instead."
127 )(encrypt_pw_with_algorithm)
128
129
132
133
135 """A wrapper class for the thread local data.
136
137 This allows developers to access the current user information via
138 turbogears.identity.current and get the identity for the current request.
139
140 """
141
155
167
172
173
193
194
195 current = IdentityWrapper()
196 current_provider = ProviderWrapper()
197
198
200 """A tool that sets response status based on identity's success or failure.
201
202 This is necessary since the status will be overridden by the result of
203 forwarding the user to the login page.
204
205 Does not override status if the login controller errors out.
206
207 """
208 status = cherrypy.response.status
209 if not status or str(status) < '400':
210 new_status = cherrypy.request.wsgi_environ.get('identity.status')
211 if new_status:
212 cherrypy.response.status = new_status
213 auth_realm = cherrypy.request.wsgi_environ.get('identity.auth_realm')
214 if auth_realm:
215 cherrypy.response.headers['WWW-Authenticate'] = auth_realm
216
217
218 if not cherrypy.response.header_list:
219 cherrypy.response.header_list = []
220 cherrypy.response.header_list.append(('WWW-Authenticate', auth_realm))
221