Package turbogears :: Package identity :: Module visitor

Source Code for Module turbogears.identity.visitor

  1  """The visit and identity management *plugins* are defined here.""" 
  2   
  3  __all__ = [ 
  4      'IdentityVisitPlugin', 
  5      'create_extension_model', 
  6      'shutdown_extension', 
  7      'start_extension', 
  8  ] 
  9   
 10  import base64 
 11  import logging 
 12   
 13  from cherrypy import request 
 14   
 15  from turbogears import config, visit 
 16  from turbogears.identity import (create_default_provider, set_current_identity, 
 17      set_current_provider, set_login_attempted) 
 18  from turbogears.util import pop_request_params 
 19   
 20  from turbogears.identity.exceptions import * 
 21   
 22   
 23  log = logging.getLogger("turbogears.identity") 
 24   
 25   
 26  # Interface for the TurboGears extension 
 27   
28 -def start_extension():
29 """Register the IdentityVisitPluguin with the visit plug-in framework. 30 31 Also sets up the configured Identity provider. 32 33 """ 34 # Bail out if the application hasn't enabled this extension 35 if not config.get('identity.on', False): 36 return 37 38 # Identity requires that Visit tracking be enabled 39 if not config.get('visit.on', False): 40 raise IdentityConfigurationException( 41 "Visit tracking must be enabled (visit.on)") 42 43 log.info("Identity starting") 44 # Temporary until tg-admin can call create_extension_model 45 create_extension_model() 46 # Register the plugin for the Visit Tracking framework 47 visit.enable_visit_plugin(IdentityVisitPlugin())
48 49
50 -def shutdown_extension():
51 """Stops the IdentityVisitPlugin. 52 53 This is practically a no-op currently. 54 55 """ 56 # Bail out if the application hasn't enabled this extension 57 if not config.get('identity.on', False): 58 return 59 log.info("Identity shutting down")
60 61
62 -def create_extension_model():
63 """Create the identity provider object.""" 64 provider = create_default_provider() 65 provider.create_provider_model()
66 67
68 -class IdentityVisitPlugin(object):
69 """Visit plug-in tying the Identity framework to the visit management.""" 70
71 - def __init__(self):
72 log.info("Identity visit plugin initialized") 73 get = config.get 74 75 self.provider = create_default_provider() 76 77 # When retrieving identity information from the form, use the following 78 # form field names. These fields will be removed from the post data to 79 # prevent the controller from receiving unexpected fields. 80 self.user_name_field = get('identity.form.user_name', 'user_name').split('.') 81 self.password_field = get('identity.form.password', 'password').split('.') 82 self.submit_button_name = get('identity.form.submit', 'login').split('.') 83 84 # Sources for identity information and the order in which they should be 85 # checked. These terms are mapped to methods by prepending 86 # "identity_from_". 87 sources = filter(None, map(str.strip, 88 get('identity.source', 'form,http_auth,visit').split(','))) 89 if not sources: 90 raise IdentityConfigurationException( 91 "You must set some identity source (via identity.source).") 92 if 'http_auth' in sources and not get('identity.http_basic_auth'): 93 sources.remove('http_auth') 94 if 'visit' in sources and not get('visit.on'): 95 sources.remove('visit') 96 if not sources: 97 raise IdentityConfigurationException( 98 "You must activate at least one of the identity sources.") 99 self.identity_sources = list() 100 for s in sources: 101 if s: 102 try: 103 source_method = getattr(self, 'identity_from_' + s) 104 except AttributeError: 105 raise IdentityConfigurationException( 106 "Invalid identity source: %s" % s) 107 self.identity_sources.append(source_method)
108
109 - def identity_from_request(self, visit_key):
110 """Retrieve identity information from the HTTP request. 111 112 Checks first for form fields defining the identity then for a cookie. 113 If no identity is found, returns an anonymous identity. 114 115 """ 116 identity = None 117 log.debug("Retrieving identity for visit: %s", visit_key) 118 for source in self.identity_sources: 119 identity = source(visit_key) 120 if identity: 121 return identity 122 123 log.debug("No identity found") 124 # No source reported an identity 125 identity = self.provider.anonymous_identity() 126 return identity
127
128 - def decode_basic_credentials(self, credentials):
129 """Decode base64 user_name:password credentials used in Basic Auth. 130 131 Returns a list with username in element 0 and password in element 1. 132 133 """ 134 credentials = base64.decodestring(credentials.strip()) 135 try: 136 credentials = credentials.decode('utf-8') 137 except UnicodeError: 138 try: 139 credentials = credentials.decode('latin-1') 140 except UnicodeError: 141 credentials = '' 142 credentials = credentials.split(':', 1) 143 if len(credentials) < 2: 144 credentials.append('') 145 return credentials
146
147 - def identity_from_http_auth(self, visit_key):
148 """Try to get authentication data from Authorization request header. 149 150 Only HTTP basic auth is handled at the moment. 151 152 """ 153 try: 154 authorisation = request.headers['Authorization'] 155 except KeyError: 156 return None 157 158 authScheme, schemeData = authorisation.split(' ', 1) 159 # Only basic is handled at the moment 160 if authScheme.lower() != 'basic': 161 log.error("HTTP Auth is not basic") 162 return None 163 164 # decode credentials 165 user_name, password = self.decode_basic_credentials(schemeData) 166 set_login_attempted(True) 167 return self.provider.validate_identity(user_name, password, visit_key)
168
169 - def identity_from_visit(self, visit_key):
170 """Load identity from Identity provider.""" 171 return self.provider.load_identity(visit_key)
172
173 - def identity_from_form(self, visit_key):
174 """Inspect the request params to pull out identity information. 175 176 Must have fields for user name, password, and a login submit button. 177 178 Returns an identity object whose class depends on the current identity 179 provider or None if the form contained no identity information or the 180 information was incorrect. 181 182 """ 183 # only try to process credentials for login forms 184 if pop_request_params(self.submit_button_name) is None: 185 return None 186 # form data contains login credentials 187 pop_request_params(self.submit_button_name + ['x']) 188 pop_request_params(self.submit_button_name + ['y']) 189 user_name = pop_request_params(self.user_name_field) 190 password = pop_request_params(self.password_field) 191 if user_name is None: 192 log.error("Missing user name in login form") 193 return None 194 elif isinstance(user_name, list): 195 log.error("Multiple user names in login form") 196 return None 197 if password is None: 198 log.error("Missing password in login form") 199 return None 200 elif isinstance(password, list): 201 log.error("Multiple passwords in login form") 202 return None 203 set_login_attempted(True) 204 identity = self.provider.validate_identity( 205 user_name, password, visit_key) 206 if identity is None: 207 log.warning("The credentials specified weren't valid") 208 return None 209 return identity
210
211 - def record_request(self, visit):
212 """Authenticate request and try to associate the visit with an identity.""" 213 # This method is called by the visit plug-in mechanism on each request with a visit key. 214 # default to keeping the identity filter off 215 if not config.get('identity.on', True): 216 log.debug("Identity is not enabled. Setting current identity to None") 217 set_current_identity(None) 218 return 219 220 try: 221 identity = self.identity_from_request(visit.key) 222 except IdentityException, e: 223 log.exception("Caught exception while getting identity from request") 224 errors = [str(e)] 225 raise IdentityFailure(errors) 226 227 log.debug("Identity is available...") 228 # stash the user in the thread data for this request 229 set_current_identity(identity) 230 set_current_provider(self.provider)
231