Commit bef3bf46 authored by Kostas Papadimitriou's avatar Kostas Papadimitriou
Browse files

Fallback on HTTP_X_REAL_IP meta to retrieve client ip

thats where nginx sets the client ip
parent f53b6721
......@@ -61,7 +61,7 @@ def get_backend(request):
according to the INVITATIONS_ENABLED setting
(if True returns ``astakos.im.backends.InvitationsBackend`` and if False
returns ``astakos.im.backends.SimpleBackend``).
If the backend cannot be located ``django.core.exceptions.ImproperlyConfigured``
is raised.
"""
......@@ -93,10 +93,10 @@ class InvitationsBackend(object):
"""
self.request = request
self.invitation = get_invitation(request)
def get_signup_form(self, provider):
"""
Returns the form class name
Returns the form class name
"""
invitation = self.invitation
initial_data = self.get_signup_initial_data(provider)
......@@ -104,12 +104,14 @@ class InvitationsBackend(object):
main = provider.capitalize() if provider == 'local' else 'ThirdParty'
suffix = 'UserCreationForm'
formclass = '%s%s%s' % (prefix, main, suffix)
return globals()[formclass](initial_data, ip=self.request.META['REMOTE_ADDR'])
ip = self.request.META.get('REMOTE_ADDR',
self.request.META.get('HTTP_X_REAL_IP', None))
return globals()[formclass](initial_data, ip=ip)
def get_signup_initial_data(self, provider):
"""
Returns the necassary registration form depending the user is invited or not
Throws Invitation.DoesNotExist in case ``code`` is not valid.
"""
request = self.request
......@@ -128,7 +130,7 @@ class InvitationsBackend(object):
if provider == request.POST.get('provider', ''):
initial_data = request.POST
return initial_data
def _is_preaccepted(self, user):
"""
If there is a valid, not-consumed invitation code for the specific user
......@@ -141,7 +143,7 @@ class InvitationsBackend(object):
invitation.consume()
return True
return False
@transaction.commit_manually
def signup(self, form, admin_email_template_name='im/admin_notification.txt'):
"""
......@@ -149,7 +151,7 @@ class InvitationsBackend(object):
(has a valid invitation code) the user is activated and if the request
param ``next`` is present redirects to it.
In any other case the method returns the action status and a message.
The method uses commit_manually decorator in order to ensure the user
will be created only if the procedure has been completed successfully.
"""
......@@ -170,7 +172,7 @@ class InvitationsBackend(object):
except socket.error, e:
status = messages.ERROR
message = _(e.strerror)
# rollback in case of error
if status == messages.ERROR:
transaction.rollback()
......@@ -186,7 +188,7 @@ class SimpleBackend(object):
"""
def __init__(self, request):
self.request = request
def get_signup_form(self, provider):
"""
Returns the form class name
......@@ -199,28 +201,30 @@ class SimpleBackend(object):
if request.method == 'POST':
if provider == request.POST.get('provider', ''):
initial_data = request.POST
return globals()[formclass](initial_data, ip=self.request.META['REMOTE_ADDR'])
ip = self.request.META.get('REMOTE_ADDR',
self.request.META.get('HTTP_X_REAL_IP', None))
return globals()[formclass](initial_data, ip=ip)
@transaction.commit_manually
def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'):
"""
Creates an inactive user account and sends a verification email.
The method uses commit_manually decorator in order to ensure the user
will be created only if the procedure has been completed successfully.
** Arguments **
``email_template_name``
A custom template for the verification email body to use. This is
optional; if not specified, this will default to
``im/activation_email.txt``.
** Templates **
im/activation_email.txt or ``email_template_name`` keyword argument
** Settings **
* DEFAULT_CONTACT_EMAIL: service support email
* DEFAULT_FROM_EMAIL: from email
"""
......@@ -242,7 +246,7 @@ class SimpleBackend(object):
status = messages.ERROR
name = 'strerror'
message = getattr(e, name) if hasattr(e, name) else e
# rollback in case of error
if status == messages.ERROR:
transaction.rollback()
......
# Copyright 2011-2012 GRNET S.A. All rights reserved.
#
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
......@@ -25,7 +25,7 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
......@@ -49,7 +49,7 @@ from astakos.im.backends import get_backend
from astakos.im.settings import TWITTER_KEY, TWITTER_SECRET, INVITATIONS_ENABLED, IM_MODULES
# It's probably a good idea to put your consumer's OAuth token and
# OAuth secret into your project's settings.
# OAuth secret into your project's settings.
consumer = oauth.Consumer(TWITTER_KEY, TWITTER_SECRET)
client = oauth.Client(consumer)
......@@ -72,16 +72,16 @@ def login(request, extra_context={}):
request_token = dict(urlparse.parse_qsl(content))
if request.GET.get('next'):
request_token['next'] = request.GET['next']
# Step 2. Store the request token in a session for later use.
response = HttpResponse()
request.session['Twitter-Request-Token'] = value=json.dumps(request_token)
# Step 3. Redirect the user to the authentication URL.
url = "%s?oauth_token=%s" % (authenticate_url, request_token['oauth_token'])
response['Location'] = url
response.status_code = 302
return response
@requires_anonymous
......@@ -91,7 +91,7 @@ def authenticated(request, backend=None, login_template='im/login.html', on_sign
if not data:
raise Exception("Request token cookie not found.")
del request.session['Twitter-Request-Token']
request_token = json.loads(data)
if not hasattr(request_token, '__getitem__'):
raise BadRequest('Invalid data formating')
......@@ -101,41 +101,41 @@ def authenticated(request, backend=None, login_template='im/login.html', on_sign
except:
raise BadRequest('Invalid request token cookie formatting')
client = oauth.Client(consumer, token)
# Step 2. Request the authorized access token from Twitter.
resp, content = client.request(access_token_url, "GET")
if resp['status'] != '200':
raise Exception("Invalid response from Twitter.")
"""
This is what you'll get back from Twitter. Note that it includes the
user's user_id and screen_name.
{
'oauth_token_secret': 'IcJXPiJh8be3BjDWW50uCY31chyhsMHEhqJVsphC3M',
'user_id': '120889797',
'user_id': '120889797',
'oauth_token': '120889797-H5zNnM3qE0iFoTTpNEHIz3noL9FKzXiOxwtnyVOD',
'screen_name': 'heyismysiteup'
}
"""
access_token = dict(urlparse.parse_qsl(content))
# Step 3. Lookup the user or create them if they don't exist.
# When creating the user I just use their screen_name@twitter.com
# for their email and the oauth_token_secret for their password.
# These two things will likely never be used. Alternatively, you
# can prompt them for their email here. Either way, the password
# These two things will likely never be used. Alternatively, you
# can prompt them for their email here. Either way, the password
# should never be used.
screen_name = access_token['screen_name']
next = request_token.get('next')
# check first if user with that email is registered
# and if not create one
user = None
email = request.session.pop('email')
if email: # signup mode
if not reserved_screen_name(screen_name):
if not reserved_screen_name(screen_name):
try:
user = AstakosUser.objects.get(email = email)
except AstakosUser.DoesNotExist, e:
......@@ -166,8 +166,10 @@ def authenticated(request, backend=None, login_template='im/login.html', on_sign
return prepare_response(request, user, next)
elif user and not user.is_active:
messages.add_message(request, messages.ERROR, 'Inactive account: %s' % user.email)
ip = request.META.get('REMOTE_ADDR',
request.META.get('HTTP_X_REAL_IP', None))
return render_response(login_template,
form = LocalUserCreationForm(ip=request.META['REMOTE_ADDR']),
form = LocalUserCreationForm(ip=ip),
context_instance=get_context(request, extra_context))
def reserved_screen_name(screen_name):
......@@ -178,35 +180,35 @@ def reserved_screen_name(screen_name):
except AstakosUser.DoesNotExist, e:
return False
def create_user(request, form, backend=None, post_data={}, next = None, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}):
def create_user(request, form, backend=None, post_data={}, next = None, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}):
"""
Create a user.
The user activation will be delegated to the backend specified by the ``backend`` keyword argument
if present, otherwise to the ``astakos.im.backends.InvitationBackend``
if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.backends.SimpleBackend`` if not
(see backends);
Upon successful user creation if ``next`` url parameter is present the user is redirected there
otherwise renders the ``on_success`` template (if exists) or im/signup_complete.html.
On unsuccessful creation, renders the ``on_failure`` template (if exists) or im/signup.html with an error message.
**Arguments**
``on_failure``
A custom template to render in case of failure. This is optional;
if not specified, this will default to ``im/signup.html``.
``on_success``
A custom template to render in case of success. This is optional;
if not specified, this will default to ``im/signup_complete.html``.
``extra_context``
An dictionary of variables to add to the template context.
**Template:**
im/signup.html or ``on_failure`` keyword argument.
im/signup_complete.html or ``on_success`` keyword argument.
"""
......@@ -230,6 +232,8 @@ def create_user(request, form, backend=None, post_data={}, next = None, on_failu
messages.add_message(request, messages.ERROR, e)
for provider in IM_MODULES:
extra_context['%s_form' % provider] = backend.get_signup_form(provider)
ip = request.META.get('REMOTE_ADDR',
request.META.get('HTTP_X_REAL_IP', None))
return render_response(on_failure,
form = LocalUserCreationForm(ip=request.META['REMOTE_ADDR']),
context_instance=get_context(request, extra_context))
\ No newline at end of file
form = LocalUserCreationForm(ip=ip),
context_instance=get_context(request, extra_context))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment