Beispiel #1
0
 def show_associate(self, request, openid=None):
     "Screen that offers to associate an OpenID with a user's account"
     if not request.user.is_authenticated():
         return self.need_authenticated_user(request)
     try:
         next = signed.loads(request.REQUEST.get('next', ''),
                             extra_salt=self.salt_next)
     except ValueError:
         next = ''
     return self.render(
         request,
         self.show_associate_template,
         {
             'action':
             urljoin(request.path, '../associate/'),
             'user':
             request.user,
             'specific_openid':
             openid,
             'next':
             next and request.REQUEST.get('next', '') or None,
             'openid_token':
             signed.dumps(
                 # Use user.id as part of extra_salt to prevent attackers from
                 # creating their own openid_token for use in CSRF attack
                 openid,
                 extra_salt=self.associate_salt + str(request.user.id)),
         })
 def test_decode_detects_tampering(self):
     transforms = (lambda s: s.upper(), lambda s: s + "a", lambda s: "a" + s[1:], lambda s: s.replace(".", ""))
     value = {"foo": "bar", "baz": 1}
     encoded = signed.dumps(value)
     self.assertEqual(value, signed.loads(encoded))
     for transform in transforms:
         self.assertRaises(signed.BadSignature, signed.loads, transform(encoded))
Beispiel #3
0
 def get_user_session(self, request):
     try:
         user_session = signed.loads(
             request.COOKIES.get(self.cookie_user_session_key, ''))
     except ValueError:
         user_session = {}
     return user_session
Beispiel #4
0
 def redirect_if_valid_next(self, request):
     "Logic for checking if a signed ?next= token is included in request"
     try:
         next = signed.loads(request.REQUEST.get('next', ''),
                             extra_salt=self.salt_next)
         return HttpResponseRedirect(next)
     except ValueError:
         return None
Beispiel #5
0
 def do_debug(self, request):
     if not settings.DEBUG:
         raise Http404
     if self.cookie_key in request.COOKIES:
         obj = signed.loads(request.COOKIES[self.cookie_key],
                            extra_salt=self.extra_salt)
         assert False, (obj, obj.__dict__)
     assert False, 'no cookie named %s' % self.cookie_key
Beispiel #6
0
 def get_user_session(self, request):
     try:
         user_session = signed.loads(
             request.COOKIES.get(self.cookie_user_session_key, '')
         )
     except ValueError:
         user_session = {}
     return user_session
Beispiel #7
0
 def extract_incomplete_orequest(self, request):
     # Incomplete orequests are stashed in a cookie
     try:
         return signed.loads(request.COOKIES.get(
             self.incomplete_orequest_cookie_key, ''
         ), extra_salt = self.orequest_salt)
     except signed.BadSignature:
         return None
Beispiel #8
0
 def testLogin(self):
     "Simulate a successful login"
     request, response = self.login()
     self.assert_('openid' in response.cookies, 'openid cookie not set')
     self.assertEqual(response['Location'], '/')
     # Decrypt the cookie and check it's the right thing
     cookie = response.cookies['openid'].value
     openid = signed.loads(cookie)
     self.assertEqual(openid.openid, 'http://simonwillison.net/')
Beispiel #9
0
 def get_user_session(self, request):
     # By default Consumer uses Django sessions; here we over-ride so it
     # works using signed cookies instead.
     try:
         user_session = signed.loads(
             request.COOKIES.get(self.cookie_user_session_key, ''))
     except ValueError:
         user_session = {}
     return user_session
Beispiel #10
0
def selected(request):
    "Should only ever be POSTed to with a list of photo IDs in the 'photo'"
    photos_to_add = []
    for photo in request.POST.getlist('photo'):
        try:
            photos_to_add.append(signed.loads(photo))
        except ValueError:
            continue # Skip any that don't pass the signature check
    # Moderation is currently disabled:
    # is_visible = (
    #     request.user.get_profile().is_not_brand_new_account() or \
    #     request.user.is_staff
    # )
    is_visible = True
    added_ids = []
    set_id = None
    for photo in photos_to_add:
        if Photo.objects.filter(flickr_id = photo['id']).count():
            continue
        p = Photo.objects.create(
            created_by = request.user,
            created_at = datetime.datetime.now(),
            title = photo['title'],
            photo = '',
            flickr_id = photo['id'],
            flickr_secret = photo['secret'],
            flickr_server = photo['server'],
            width_max_500 = int(photo['width_m']),
            height_max_500 = int(photo['height_m']),
            is_visible = is_visible,
            taken_at = parser.parse(photo['taken_at']),
        )
        added_ids.append(p.id)
        # Should we add it to a set as well?
        if 'set_id' in photo:
            flickr_set, created = FlickrSet.objects.get_or_create(
                flickr_id = photo['set_id'],
                defaults = {
                    'title': photo['set_title'],
                    'description': photo['set_description'],
                    'user': request.user,
                }
            )
            flickr_set.photos.add(p)
            set_id = photo['set_id']
    
    url = '/%s/photos/unassigned/' % request.user.username
    if set_id:
        url = '/%s/photos/unassigned/by-flickr-set/%s/' % (
            request.user.username,
            set_id
        )
    
    if added_ids:
        url += '?ids=' + (','.join(map(str, added_ids)))
    
    return HttpResponseRedirect(url)
 def testLoginBegin(self):
     "Can log in with an OpenID"
     openid_consumer = MyConsumer()
     post = rf.post('/openid/', {'openid_url': 'http://simonwillison.net/'})
     post.session = MockSession()
     response = openid_consumer(post)
     self.assertEqual(response['Location'], 'http://url-of-openid-server/')
     oid_session = signed.loads(response.cookies['o_user_session'].value)
     self.assert_('openid_bits' in oid_session)
 def testLogin(self):
     "Simulate a successful login"
     request, response = self.login()
     self.assert_('openid' in response.cookies, 'openid cookie not set')
     self.assertEqual(response['Location'], '/')
     # Decrypt the cookie and check it's the right thing
     cookie = response.cookies['openid'].value
     openid = signed.loads(cookie, extra_key=MyCookieConsumer().extra_salt)
     self.assertEqual(openid.openid, 'http://simonwillison.net/')
Beispiel #13
0
 def redirect_if_valid_next(self, request):
     "Logic for checking if a signed ?next= token is included in request"
     try:
         next = signed.loads(
             request.REQUEST.get('next', ''), extra_salt=self.salt_next
         )
         return HttpResponseRedirect(next)
     except ValueError:
         return None
Beispiel #14
0
 def do_debug(self, request):
     if not settings.DEBUG:
         raise Http404
     if self.cookie_key in request.COOKIES:
         obj = signed.loads(
             request.COOKIES[self.cookie_key], extra_salt = self.extra_salt
         )
         assert False, (obj, obj.__dict__)
     assert False, 'no cookie named %s' % self.cookie_key
Beispiel #15
0
 def get_user_session(self, request):
     # By default Consumer uses Django sessions; here we over-ride so it 
     # works using signed cookies instead.
     try:
         user_session = signed.loads(
             request.COOKIES.get(self.cookie_user_session_key, '')
         )
     except ValueError:
         user_session = {}
     return user_session
Beispiel #16
0
 def test_encode_decode(self):
     objects = (
         ('a', 'tuple'),
         'a string',
         u'a unicode string \u2019',
         {'a': 'dictionary'},
     )
     for o in objects:
         self.assert_(o != signed.dumps(o))
         self.assertEqual(o, signed.loads(signed.dumps(o)))
 def testLoginBegin(self):
     "Can log in with an OpenID"
     openid_consumer = MyConsumer()
     post = rf.post('/openid/', {
         'openid_url': 'http://simonwillison.net/'
     })
     post.session = MockSession()
     response = openid_consumer(post)
     self.assertEqual(response['Location'], 'http://url-of-openid-server/')
     oid_session = signed.loads(response.cookies['o_user_session'].value)
     self.assert_('openid_bits' in oid_session)
 def test_encode_decode(self):
     objects = (
         ('a', 'tuple'),
         'a string',
         u'a unicode string \u2019',
         {
             'a': 'dictionary'
         },
     )
     for o in objects:
         self.assert_(o != signed.dumps(o))
         self.assertEqual(o, signed.loads(signed.dumps(o)))
Beispiel #19
0
 def process_request(self, request):
     self._cookie_needs_deleting = False
     request.openid = None
     request.openids = []
     cookie_value = request.COOKIES.get(self.cookie_key, '')
     if cookie_value:
         try:
             request.openid = signed.loads(cookie_value,
                                           extra_salt=self.extra_salt)
             request.openids = [request.openid]
         except ValueError:  # Signature failed
             self._cookie_needs_deleting = True
Beispiel #20
0
 def show_login(self, request, message=None):
     try:
         next = signed.loads(
             request.REQUEST.get('next', ''), extra_salt=self.salt_next
         )
     except ValueError:
         next = ''
     return self.render(request, self.login_template, {
         'action': request.path,
         'logo': self.logo_path or (request.path + 'logo/'),
         'message': message,
         'next': next and request.REQUEST.get('next', '') or None,
     })
Beispiel #21
0
 def show_login(self, request, message=None):
     try:
         next = signed.loads(request.REQUEST.get('next', ''),
                             extra_salt=self.salt_next)
     except ValueError:
         next = ''
     return self.render(
         request, self.login_template, {
             'action': request.path,
             'logo': self.logo_path or (request.path + 'logo/'),
             'message': message,
             'next': next and request.REQUEST.get('next', '') or None,
         })
Beispiel #22
0
 def process_request(self, request):
     self._cookie_needs_deleting = False
     request.openid = None
     request.openids = []
     cookie_value = request.COOKIES.get(self.cookie_key, '')
     if cookie_value:
         try:
             request.openid = signed.loads(
                 cookie_value, extra_key = self.extra_salt
             )
             request.openids = [request.openid]
         except ValueError: # Signature failed
             self._cookie_needs_deleting = True
 def test_decode_detects_tampering(self):
     transforms = (
         lambda s: s.upper(),
         lambda s: s + 'a',
         lambda s: 'a' + s[1:],
         lambda s: s.replace('.', ''),
     )
     value = {'foo': 'bar', 'baz': 1}
     encoded = signed.dumps(value)
     self.assertEqual(value, signed.loads(encoded))
     for transform in transforms:
         self.assertRaises(signed.BadSignature, signed.loads,
                           transform(encoded))
Beispiel #24
0
    def do_associate(self, request):
        if request.method == 'POST':
            try:
                openid = signed.loads(request.POST.get('openid_token', ''),
                                      extra_key=self.associate_salt +
                                      str(request.user.id))
            except signed.BadSignature:
                return self.show_error(request, self.csrf_failed_message)
            # Associate openid with their account, if it isn't already
            if not request.user.openids.filter(openid=openid):
                request.user.openids.create(openid=openid)
            return self.show_associate_done(request, openid)

        return self.show_error(request, 'Should POST to here')
Beispiel #25
0
 def test_decode_detects_tampering(self):
     transforms = (
         lambda s: s.upper(),
         lambda s: s + 'a',
         lambda s: 'a' + s[1:],
         lambda s: s.replace('.', ''),
     )
     value = {'foo': 'bar', 'baz': 1}
     encoded = signed.dumps(value)
     self.assertEqual(value, signed.loads(encoded))
     for transform in transforms:
         self.assertRaises(
             signed.BadSignature, signed.loads, transform(encoded)
         )
Beispiel #26
0
    def process_decide(self, request):
        try:
            orequest = signed.loads(request.POST.get("orequest", ""), self.secret_key)
        except ValueError:
            return self.show_error(request, self.invalid_decide_post_message)

        they_said_yes = bool(("yes_once" in request.POST) or ("yes_always" in request.POST))
        if "yes_always" in request.POST:
            self.save_trusted_root(request, orequest.identity, orequest.trust_root)

        # TODO: Double check what we should be passing as identity= here:
        oresponse = orequest.answer(they_said_yes, identity=orequest.identity)
        self.add_sreg_data(request, orequest, oresponse)
        return self.server_response(request, oresponse)
Beispiel #27
0
 def redirect_if_valid_next(self, request):
     "Logic for checking if a signed ?next= token is included in request"
     if self.sign_next_param:
         try:
             next = signed.loads(request.REQUEST.get('next', ''),
                                 extra_key=self.salt_next)
             return HttpResponseRedirect(next)
         except ValueError:
             return None
     else:
         next = request.REQUEST.get('next', '')
         if next.startswith('/'):
             return HttpResponseRedirect(next)
         else:
             return None
Beispiel #28
0
 def do_associate(self, request):
     if request.method == 'POST':
         try:
             openid = signed.loads(
                 request.POST.get('openid_token', ''),
                 extra_salt = self.associate_salt + str(request.user.id)
             )
         except signed.BadSignature:
             return self.show_error(request, self.csrf_failed_message)
         # Associate openid with their account, if it isn't already
         if not request.user.openids.filter(openid = openid):
             request.user.openids.create(openid = openid)
         return self.show_associate_done(request, openid)
         
     return self.show_error(request, 'Should POST to here')
Beispiel #29
0
 def redirect_if_valid_next(self, request):
     "Logic for checking if a signed ?next= token is included in request"
     if self.sign_next_param:
         try:
             next = signed.loads(
                 request.REQUEST.get('next', ''), extra_key=self.salt_next
             )
             return HttpResponseRedirect(next)
         except ValueError:
             return None
     else:
         next = request.REQUEST.get('next', '')
         if next.startswith('/'):
             return HttpResponseRedirect(next)
         else:
             return None
Beispiel #30
0
    def get_on_complete_url(self, request, on_complete_url=None):
        "Derives an appropriate on_complete_url from the request"
        on_complete_url = on_complete_url or self.on_complete_url or \
            (request.path + 'complete/')
        on_complete_url = self.ensure_absolute_url(request, on_complete_url)
        try:
            next = signed.loads(request.POST.get('next', ''),
                                extra_salt=self.salt_next)
        except ValueError:
            return on_complete_url

        if '?' not in on_complete_url:
            on_complete_url += '?next=' + self.sign_next(next)
        else:
            on_complete_url += '&next=' + self.sign_next(next)
        return on_complete_url
Beispiel #31
0
 def do_associations(self, request):
     "Interface for managing your account's associated OpenIDs"
     if not request.user.is_authenticated():
         return self.need_authenticated_user(request)
     message = None
     if request.method == 'POST':
         if 'todelete' in request.POST:
             # Something needs deleting; find out what
             try:
                 todelete = signed.loads(
                     request.POST['todelete'],
                     extra_key=self.associate_delete_salt)
                 if todelete['user_id'] != request.user.id:
                     message = self.associate_tampering_message
                 else:
                     # It matches! Delete the OpenID relationship
                     request.user.openids.filter(
                         pk=todelete['association_id']).delete()
                     message = self.association_deleted_message % (
                         todelete['openid'])
             except signed.BadSignature:
                 message = self.associate_tampering_message
     # We construct a button to delete each existing association
     openids = []
     for association in request.user.openids.all():
         openids.append({
             'openid':
             association.openid,
             'button':
             signed.dumps(
                 {
                     'user_id': request.user.id,
                     'association_id': association.id,
                     'openid': association.openid,
                 },
                 extra_key=self.associate_delete_salt),
         })
     return self.render(
         request, self.associations_template, {
             'openids': openids,
             'user': request.user,
             'action': request.path,
             'logo': self.logo_path or (request.path + '../logo/'),
             'message': message,
             'action_new': '../',
             'associate_next': self.sign_next(request.path),
         })
Beispiel #32
0
    def process_decide(self, request):
        try:
            orequest = signed.loads(request.POST.get('orequest', ''),
                                    self.secret_key)
        except ValueError:
            return self.show_error(request, self.invalid_decide_post_message)

        they_said_yes = bool(('yes_once' in request.POST)
                             or ('yes_always' in request.POST))
        if 'yes_always' in request.POST:
            self.save_trusted_root(request, orequest.identity,
                                   orequest.trust_root)

        # TODO: Double check what we should be passing as identity= here:
        oresponse = orequest.answer(they_said_yes, identity=orequest.identity)
        self.add_sreg_data(request, orequest, oresponse)
        return self.server_response(request, oresponse)
Beispiel #33
0
 def get_on_complete_url(self, request, on_complete_url=None):
     "Derives an appropriate on_complete_url from the request"
     on_complete_url = on_complete_url or self.on_complete_url or \
         (request.path + 'complete/')
     on_complete_url = self.ensure_absolute_url(request, on_complete_url)
     try:
         next = signed.loads(
             request.POST.get('next', ''), extra_salt=self.salt_next
         )
     except ValueError:
         return on_complete_url
     
     if '?' not in on_complete_url:
         on_complete_url += '?next=' + self.sign_done(next)
     else:
         on_complete_url += '&next=' + self.sign_done(next)
     return on_complete_url
Beispiel #34
0
 def do_associations(self, request):
     "Interface for managing your account's associated OpenIDs"
     if not request.user.is_authenticated():
         return self.need_authenticated_user(request)
     message = None
     if request.method == 'POST':
         if 'todelete' in request.POST:
             # Something needs deleting; find out what
             try:
                 todelete = signed.loads(
                     request.POST['todelete'],
                     extra_key = self.associate_delete_salt
                 )
                 if todelete['user_id'] != request.user.id:
                     message = self.associate_tampering_message
                 else:
                     # It matches! Delete the OpenID relationship
                     request.user.openids.filter(
                         pk = todelete['association_id']
                     ).delete()
                     message = self.association_deleted_message % (
                         todelete['openid']
                     )
             except signed.BadSignature:
                 message = self.associate_tampering_message
     # We construct a button to delete each existing association
     openids = []
     for association in request.user.openids.all():
         openids.append({
             'openid': association.openid,
             'button': signed.dumps({
                 'user_id': request.user.id,
                 'association_id': association.id,
                 'openid': association.openid,
             }, extra_key = self.associate_delete_salt),
         })
     return self.render(request, self.associations_template, {
         'openids': openids,
         'user': request.user,
         'action': request.path,
         'logo': self.logo_path or (request.path + '../logo/'),
         'message': message,
         'action_new': '../',
         'associate_next': self.sign_next(request.path),
     })
Beispiel #35
0
 def show_associate(self, request, openid=None):
     "Screen that offers to associate an OpenID with a user's account"
     if not request.user.is_authenticated():
         return self.need_authenticated_user(request)
     try:
         next = signed.loads(
             request.REQUEST.get('next', ''), extra_salt=self.salt_next
         )
     except ValueError:
         next = ''
     return self.render(request, self.show_associate_template, {
         'action': urljoin(request.path, '../associate/'),
         'user': request.user,
         'specific_openid': openid,
         'next': next and request.REQUEST.get('next', '') or None,
         'openid_token': signed.dumps(
            # Use user.id as part of extra_salt to prevent attackers from
            # creating their own openid_token for use in CSRF attack
            openid, extra_salt = self.associate_salt + str(request.user.id)
         ),
     })
 def test_encode_decode(self):
     objects = (("a", "tuple"), "a string", u"a unicode string \u2019", {"a": "dictionary"})
     for o in objects:
         self.assert_(o != signed.dumps(o))
         self.assertEqual(o, signed.loads(signed.dumps(o)))
Beispiel #37
0
def process_submission(request):
    # Process the previous submission
    try:
        options = signed.loads(request.POST.get('options', ''))
    except ValueError:
        return {}
    if (int(time.time()) - options['time']) > (5 * 60):
        return {} # Form is too old
    if not utils.check_token(options['token']):
        return {} # Token invalid
    
    species_pk = options['species']
    contestants = options['contestants']
    
    winner = int(request.POST.get('winner', ''))
    if not winner:
        return {}
    
    loser = (set(contestants) - set([winner])).pop()
    
    # Record a win!
    context = utils.record_win(species_pk, winner, loser)
    if not request.user.is_anonymous():
        utils.record_contribution_from(request.user.username)
    
    photos = Photo.objects.select_related(
        'created_by'
    ).in_bulk([winner, loser])
    
    last_species = Species.objects.get(pk = species_pk)
    
    description = '''
        %s: <a href="%s">%s</a>: <a href="%s"><img src="%s"></a> beat 
        <a href="%s"><img src="%s"></a>
        ''' % (
            str(datetime.datetime.now()),
            last_species.get_absolute_url(),
            last_species.common_name,
            photos[winner].get_absolute_url(),
            photos[winner].thumb_75_url(),
            photos[loser].get_absolute_url(),
            photos[loser].thumb_75_url(),
        )
    if not request.user.is_anonymous():
        description += ' (rated by <a href="%s">%s</a>)' % (
            request.user.username, request.user.username
        )
        # And record the species so we don't show it to them multiple times
        set_key = utils.USER_SEEN_SET % request.user.username
        list_key = utils.USER_SEEN_LIST % request.user.username
        r.push(list_key, species_pk, head=True)
        r.sadd(set_key, species_pk)
        if r.scard(set_key) >= SEEN_SPECIES_COUNT:
            r.srem(set_key, r.pop(list_key, tail=True))
    
    r.push('bestpic-activity', description, head=True)
    r.ltrim('bestpic-activity', 0, 200)
    
    context.update({
        'last_species': last_species,
        'last_winner': photos[winner],
        'last_loser': photos[loser],
        'show_link_to_best': utils.species_has_top_10(last_species),
    })
    return context