def test_purge_expired_tokens(self): """ Generate tokens with current time as expiration date/time. That is, tokens are expired as soon as they are generated. """ for user in self.users: token = generate_user_auth_token(user, 'password hash', timeout=0) auth_token = lookup_user_auth_token(user, token) self.assertEqual(None, auth_token) # As expired tokens are purged from the DB just before # they are generated, the above should leave us with one # expired token in the DB query = Session.gql("WHERE expire_date <= :1", api.utcnow()) expired_tokens = query.count() self.assertEqual(1, expired_tokens) # Generate another token to trigger cache purging which # should leave us with no expired sessions in the DB (as # this token is generated with a future expiration date.) token = generate_user_auth_token('fake user', 'password hash') query = Session.gql("WHERE expire_date <= :1", api.utcnow()) expired_tokens = query.count() self.assertEqual(0, expired_tokens)
def generate_user_auth_token(nick, password, timeout=(14 * 24 * 60 * 60)): """ Generates a user authentication token and stores it in the database for later retrieval. Why store tokens in the database? Because GAE flushes memcache quite aggressively and this was causing users to be logged out much more frequently than was acceptable. """ # Clear cache of expired tokens purge_expired_user_auth_token_keys() token = util.hash_generic(util.generate_uuid()) key = generate_user_auth_token_key(nick, token) # Set an expiration date to enable us to purge old, inactive # sessions from the database. Cookie expiration dates are what # actually govern how long sessions last. expire_date = (api.utcnow() + datetime.timedelta(seconds=timeout)) session = Session(key_name=key, session_data=db.Blob(password.encode("utf-8")), expire_date=expire_date) session.put() return token
def setUp(self): self.old_utcnow = api.utcnow self.now = api.utcnow() self.delta = datetime.timedelta(seconds=api.DEFAULT_TASK_EXPIRE) self.old_enabled = settings.QUEUE_ENABLED super(QueueTest, self).setUp() settings.QUEUE_ENABLED = True
def lookup_user_auth_token(request): """ Look up a user authentication token from the database cache. """ if not 'data' in request.session: return None elif request.session.get_expiry_date() <= api.utcnow(): return None else: return request.session['data'].decode("utf-8")
def lookup_user_auth_token(nick, token): """ Look up a user authentication token from the database cache. """ key = generate_user_auth_token_key(nick, token) user_auth_token_blob = Session.get_by_key_name(key) if not user_auth_token_blob: return None elif user_auth_token_blob.expire_date <= api.utcnow(): return None else: user_auth_token = user_auth_token_blob.session_data.decode("utf-8") return user_auth_token
def api_call(request, format="json"): """ the public api attempts to validate a request as a valid oauth request then builds the appropriate api_user object and tries to dispatch to the provided method """ servertime = api.utcnow() try: kwargs = oauth_util.get_method_kwargs(request) json_params = kwargs.pop('json_params', None) if json_params: parsed = simplejson.loads(json_params) # Turn the keys from unicode to str so that they can be used as method # parameters. kwargs.update( dict([(str(k), v) for k, v in parsed.iteritems()])) method = kwargs.pop('method', '').replace('.', '_') if method == 'presence_send': method = 'post' if not method: raise exception.ApiException(exception.NO_METHOD, "No method specified") # Allows us to turn off authentication for testing purposes if not settings.API_DISABLE_VERIFICATION: api_user = request.user else: api_user = api.ROOT method_ref = api.PublicApi.get_method(method, api_user) if not method_ref: raise exception.ApiException(exception.INVALID_METHOD, 'Invalid method: %s' % method) if not api_user: raise exception.ApiException(0x00, 'Invalid API user') if getattr(api_user, 'legacy', None) and method == 'post': kwargs['nick'] = api_user.nick rv = method_ref(api_user, **kwargs) if rv is None: raise exception.ApiException(0x00, 'method %s returned None'%(method)) return render_api_response(rv, format, servertime=servertime) except oauth_util.OAuthError, e: exc = exception.ApiException(exception.OAUTH_ERROR, e.message) return render_api_response(exc, format)
def api_call(request, format="json"): """ the public api attempts to validate a request as a valid oauth request then builds the appropriate api_user object and tries to dispatch to the provided method """ servertime = api.utcnow() try: kwargs = oauth_util.get_method_kwargs(request) json_params = kwargs.pop('json_params', None) if json_params: parsed = simplejson.loads(json_params) # Turn the keys from unicode to str so that they can be used as method # parameters. kwargs.update(dict([(str(k), v) for k, v in parsed.iteritems()])) method = kwargs.pop('method', '').replace('.', '_') if method == 'presence_send': method = 'post' if not method: raise exception.ApiException(exception.NO_METHOD, "No method specified") # Allows us to turn off authentication for testing purposes if not settings.API_DISABLE_VERIFICATION: api_user = request.user else: api_user = api.ROOT method_ref = api.PublicApi.get_method(method, api_user) if not method_ref: raise exception.ApiException(exception.INVALID_METHOD, 'Invalid method: %s' % method) if not api_user: raise exception.ApiException(0x00, 'Invalid API user') if getattr(api_user, 'legacy', None) and method == 'post': kwargs['nick'] = api_user.nick rv = method_ref(api_user, **kwargs) if rv is None: raise exception.ApiException(0x00, 'method %s returned None' % (method)) return render_api_response(rv, format, servertime=servertime) except oauth_util.OAuthError, e: exc = exception.ApiException(exception.OAUTH_ERROR, e.message) return render_api_response(exc, format)
def purge_expired_user_auth_token_keys(): """ Remove expired tokens from the database. """ #TODO: Remove hard coded limit limit = 10 try: query = Session.gql("WHERE expire_date <= :1", api.utcnow()) expired_tokens = query.count() if expired_tokens: db.delete(query.fetch(limit)) logging.info("Removed %d expired user authentication " "tokens (%d remaining)", min(limit, expired_tokens), max(0, expired_tokens-limit)) except Exception, e: logging.exception('Unhandled exception while removing expired tokens')
def api_call(request, format="json"): """ the public api attempts to validate a request as a valid oauth request then builds the appropriate api_user object and tries to dispatch to the provided method """ servertime = api.utcnow() try: kwargs = oauth_util.get_method_kwargs(request) json_params = kwargs.pop("json_params", None) if json_params: parsed = simplejson.loads(json_params) # Turn the keys from unicode to str so that they can be used as method # parameters. kwargs.update(dict([(str(k), v) for k, v in parsed.iteritems()])) method = kwargs.pop("method", "").replace(".", "_") if method == "presence_send": method = "post" if not method: raise exception.ApiNoMethod("No method specified") # Allows us to turn off authentication for testing purposes if not settings.API_DISABLE_VERIFICATION: api_user = request.user else: api_user = api.ROOT method_ref = api.PublicApi.get_method(method, api_user) if not method_ref: raise exception.ApiInvalidMethod("Invalid method: %s" % method) if not api_user: raise exception.ApiException("Invalid API user") if getattr(api_user, "legacy", None) and method == "post": kwargs["nick"] = api_user.nick rv = method_ref(api_user, **kwargs) if rv is None: raise exception.ApiException("method %s returned None" % (method)) return render_api_response(rv, format, servertime=servertime) except oauth_util.OAuthError, e: exc = exception.ApiOAuth(e.message) return render_api_response(exc, format)
def purge_expired_user_auth_token_keys(): """ Remove expired tokens from the database. """ #TODO: Remove hard coded limit limit = 10 try: objs = Session.objects.filter(expire_date__lte=api.utcnow()) expired_tokens = objs.count() if expired_tokens: for obj in objs[:limit]: obj.delete() logging.info("Removed %d expired user authentication " "tokens (%d remaining)", min(limit, expired_tokens), max(0, expired_tokens-limit)) except Exception, e: logging.exception('Unhandled exception while removing expired tokens')
def test_settings_upload_avatar(self): nick = 'obligated' self.login(nick) nick = clean.nick(nick) old_contact_avatars = api.actor_get_contacts_avatars_since(api.ROOT, nick) contacts = api.actor_get_contacts(api.ROOT, nick) self.assertEquals(len(old_contact_avatars), len(contacts) + 1) old_avatar = api.actor_get(api.ROOT, nick).extra.get('icon', 'avatar_default') start_time = api.utcnow() no_contact_avatars = api.actor_get_contacts_avatars_since(api.ROOT, nick, since_time=start_time) self.assertEquals(len(no_contact_avatars), 0) # TODO(teemu): add more tests for different file types (gif and jpg). # Alternatively, test those against api.avatar_upload. f = open('testdata/test_avatar.jpg') r = self.client.post('/user/obligated/settings/photo', { 'imgfile': f, '_nonce' : util.create_nonce('obligated', 'change_photo'), }) r = self.assertRedirectsPrefix(r, '/user/obligated/settings/photo') actor_ref = api.actor_get(api.ROOT, nick) new_avatar = actor_ref.extra.get('icon', 'avatar_default') self.assertNotEquals(old_avatar, new_avatar) self.assertTrue(actor_ref.avatar_updated_at >= start_time) new_contact_avatars = api.actor_get_contacts_avatars_since(api.ROOT, nick, since_time=start_time) self.assertEquals(len(new_contact_avatars), 1) self.assertEquals(new_contact_avatars.pop().nick, nick) self.assertContains(r, 'Avatar uploaded') self.assertTemplateUsed(r, 'actor/templates/settings_photo.html') self.assertTemplateUsed(r, 'common/templates/flash.html')
def test_settings_upload_avatar(self): nick = 'obligated' self.login(nick) nick = clean.nick(nick) old_contact_avatars = api.actor_get_contacts_avatars_since( api.ROOT, nick) contacts = api.actor_get_contacts(api.ROOT, nick) self.assertEquals(len(old_contact_avatars), len(contacts) + 1) old_avatar = api.actor_get(api.ROOT, nick).extra.get('icon', 'avatar_default') start_time = api.utcnow() no_contact_avatars = api.actor_get_contacts_avatars_since( api.ROOT, nick, since_time=start_time) self.assertEquals(len(no_contact_avatars), 0) # TODO(teemu): add more tests for different file types (gif and jpg). # Alternatively, test those against api.avatar_upload. f = open('testdata/test_avatar.jpg') r = self.client.post( '/user/obligated/settings/photo', { 'imgfile': f, '_nonce': util.create_nonce('obligated', 'change_photo'), }) r = self.assertRedirectsPrefix(r, '/user/obligated/settings/photo') actor_ref = api.actor_get(api.ROOT, nick) new_avatar = actor_ref.extra.get('icon', 'avatar_default') self.assertNotEquals(old_avatar, new_avatar) self.assertTrue(actor_ref.avatar_updated_at >= start_time) new_contact_avatars = api.actor_get_contacts_avatars_since( api.ROOT, nick, since_time=start_time) self.assertEquals(len(new_contact_avatars), 1) self.assertEquals(new_contact_avatars.pop().nick, nick) self.assertContains(r, 'Avatar uploaded') self.assertTemplateUsed(r, 'actor/templates/settings_photo.html') self.assertTemplateUsed(r, 'common/templates/flash.html')