Revision 672d445a
b/snf-astakos-app/README | ||
---|---|---|
40 | 40 |
|
41 | 41 |
Configure in ``settings.py`` or a ``.conf`` file in ``/etc/synnefo`` if using snf-webproject. |
42 | 42 |
|
43 |
============================== ============================================================================= ===========================================================================================
|
|
43 |
================================= ============================================================================= ===========================================================================================
|
|
44 | 44 |
Name Default value Description |
45 |
============================== ============================================================================= ===========================================================================================
|
|
45 |
================================= ============================================================================= ===========================================================================================
|
|
46 | 46 |
ASTAKOS_AUTH_TOKEN_DURATION one month Expiration time of newly created auth tokens |
47 | 47 |
ASTAKOS_DEFAULT_USER_LEVEL 4 Default (not-invited) user level |
48 | 48 |
ASTAKOS_INVITATIONS_PER_LEVEL {0:100, 1:2, 2:0, 3:0, 4:0} Number of user invitations per user level |
... | ... | |
78 | 78 |
e.g. {'warning': 'Warning message (can contain html)'} |
79 | 79 |
ASTAKOS_PROFILE_EXTRA_LINKS {} messages to display as extra actions in account forms |
80 | 80 |
e.g. {'https://cms.okeanos.grnet.gr/': 'Back to ~okeanos'} |
81 |
============================== ============================================================================= =========================================================================================== |
|
81 |
ASTAKOS_RATELIMIT_RETRIES_ALLOWED 3 Number of unsuccessful login requests allowed for a specific account. |
|
82 |
When this number exceeds and ASTAKOS_RECAPTCHA_ENABLED is set the user has to solve a |
|
83 |
captcha challenge. |
|
84 |
================================= ============================================================================= =========================================================================================== |
|
82 | 85 |
|
83 | 86 |
Administrator functions |
84 | 87 |
----------------------- |
b/snf-astakos-app/astakos/im/activation_backends.py | ||
---|---|---|
208 | 208 |
if request.method == 'POST': |
209 | 209 |
if provider == request.POST.get('provider', ''): |
210 | 210 |
initial_data = request.POST |
211 |
ip = self.request.META.get('REMOTE_ADDR', |
|
212 |
self.request.META.get('HTTP_X_REAL_IP', None)) |
|
213 |
return globals()[formclass](initial_data, instance=instance, ip=ip) |
|
211 |
return globals()[formclass](initial_data, instance=instance, request=request) |
|
214 | 212 |
|
215 | 213 |
def _is_preaccepted(self, user): |
216 | 214 |
if super(SimpleBackend, self)._is_preaccepted(user): |
b/snf-astakos-app/astakos/im/forms.py | ||
---|---|---|
76 | 76 |
""" |
77 | 77 |
Changes the order of fields, and removes the username field. |
78 | 78 |
""" |
79 |
if 'ip' in kwargs: |
|
80 |
self.ip = kwargs['ip'] |
|
81 |
kwargs.pop('ip') |
|
79 |
request = kwargs.get('request', None) |
|
80 |
if request: |
|
81 |
kwargs.pop('request') |
|
82 |
self.ip = request.META.get('REMOTE_ADDR', |
|
83 |
request.META.get('HTTP_X_REAL_IP', None)) |
|
84 |
|
|
82 | 85 |
super(LocalUserCreationForm, self).__init__(*args, **kwargs) |
83 | 86 |
self.fields.keyOrder = ['email', 'first_name', 'last_name', |
84 | 87 |
'password1', 'password2'] |
... | ... | |
186 | 189 |
""" |
187 | 190 |
Changes the order of fields, and removes the username field. |
188 | 191 |
""" |
189 |
if 'ip' in kwargs: |
|
190 |
kwargs.pop('ip') |
|
191 | 192 |
super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs) |
192 | 193 |
self.fields.keyOrder = ['email', 'first_name', 'last_name', |
193 | 194 |
'provider', 'third_party_identifier'] |
... | ... | |
284 | 285 |
|
285 | 286 |
class LoginForm(AuthenticationForm): |
286 | 287 |
username = forms.EmailField(label=_("Email")) |
288 |
recaptcha_challenge_field = forms.CharField(widget=DummyWidget) |
|
289 |
recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='') |
|
290 |
|
|
291 |
def __init__(self, *args, **kwargs): |
|
292 |
was_limited = kwargs.get('was_limited', False) |
|
293 |
request = kwargs.get('request', None) |
|
294 |
if request: |
|
295 |
self.ip = request.META.get('REMOTE_ADDR', |
|
296 |
request.META.get('HTTP_X_REAL_IP', None)) |
|
297 |
|
|
298 |
t = ('request', 'was_limited') |
|
299 |
for elem in t: |
|
300 |
if elem in kwargs.keys(): |
|
301 |
kwargs.pop(elem) |
|
302 |
super(LoginForm, self).__init__(*args, **kwargs) |
|
303 |
|
|
304 |
self.fields.keyOrder = ['username', 'password'] |
|
305 |
if was_limited and RECAPTCHA_ENABLED: |
|
306 |
self.fields.keyOrder.extend(['recaptcha_challenge_field', |
|
307 |
'recaptcha_response_field',]) |
|
308 |
|
|
309 |
def clean_recaptcha_response_field(self): |
|
310 |
if 'recaptcha_challenge_field' in self.cleaned_data: |
|
311 |
self.validate_captcha() |
|
312 |
return self.cleaned_data['recaptcha_response_field'] |
|
313 |
|
|
314 |
def clean_recaptcha_challenge_field(self): |
|
315 |
if 'recaptcha_response_field' in self.cleaned_data: |
|
316 |
self.validate_captcha() |
|
317 |
return self.cleaned_data['recaptcha_challenge_field'] |
|
318 |
|
|
319 |
def validate_captcha(self): |
|
320 |
rcf = self.cleaned_data['recaptcha_challenge_field'] |
|
321 |
rrf = self.cleaned_data['recaptcha_response_field'] |
|
322 |
check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip) |
|
323 |
if not check.is_valid: |
|
324 |
raise forms.ValidationError(_('You have not entered the correct words')) |
|
287 | 325 |
|
288 | 326 |
class ProfileForm(forms.ModelForm): |
289 | 327 |
""" |
b/snf-astakos-app/astakos/im/settings.py | ||
---|---|---|
80 | 80 |
# e.g. {'https://cms.okeanos.grnet.gr/': 'Back to ~okeanos'} |
81 | 81 |
PROFILE_EXTRA_LINKS = getattr(settings, 'ASTAKOS_PROFILE_EXTRA_LINKS', {}) |
82 | 82 |
|
83 |
# The number of unsuccessful login requests per minute allowed for a specific email |
|
84 |
RATELIMIT_RETRIES_ALLOWED = getattr(settings, 'ASTAKOS_RATELIMIT_RETRIES_ALLOWED', 3) |
|
85 |
|
b/snf-astakos-app/astakos/im/target/local.py | ||
---|---|---|
42 | 42 |
from astakos.im.views import requires_anonymous |
43 | 43 |
from astakos.im.models import AstakosUser |
44 | 44 |
from astakos.im.forms import LoginForm |
45 |
from astakos.im.settings import RATELIMIT_RETRIES_ALLOWED |
|
46 |
|
|
47 |
from ratelimit.decorators import ratelimit |
|
48 |
|
|
49 |
retries = RATELIMIT_RETRIES_ALLOWED-1 |
|
50 |
rate = str(retries)+'/m' |
|
45 | 51 |
|
46 | 52 |
@requires_anonymous |
53 |
@ratelimit(field='username', method='POST', rate=rate) |
|
47 | 54 |
def login(request, on_failure='im/login.html'): |
48 | 55 |
""" |
49 | 56 |
on_failure: the template name to render on login failure |
50 | 57 |
""" |
51 |
form = LoginForm(data=request.POST) |
|
58 |
was_limited = getattr(request, 'limited', False) |
|
59 |
form = LoginForm(data=request.POST, was_limited=was_limited, request=request) |
|
52 | 60 |
next = request.POST.get('next') |
53 | 61 |
if not form.is_valid(): |
54 | 62 |
return render_to_response(on_failure, |
b/snf-astakos-app/astakos/im/target/shibboleth.py | ||
---|---|---|
84 | 84 |
message = _('Inactive account') |
85 | 85 |
messages.add_message(request, messages.ERROR, message) |
86 | 86 |
return render_response(on_login_template, |
87 |
login_form = LoginForm(), |
|
87 |
login_form = LoginForm(request=request),
|
|
88 | 88 |
context_instance=RequestContext(request)) |
89 | 89 |
except AstakosUser.DoesNotExist, e: |
90 | 90 |
user = AstakosUser(third_party_identifier=eppn, realname=realname, |
b/snf-astakos-app/astakos/im/views.py | ||
---|---|---|
135 | 135 |
if request.user.is_authenticated(): |
136 | 136 |
return HttpResponseRedirect(reverse('astakos.im.views.edit_profile')) |
137 | 137 |
return render_response(template_name, |
138 |
login_form = LoginForm(), |
|
138 |
login_form = LoginForm(request=request),
|
|
139 | 139 |
context_instance = get_context(request, extra_context)) |
140 | 140 |
|
141 | 141 |
@login_required |
b/snf-astakos-app/setup.py | ||
---|---|---|
79 | 79 |
'South>=0.7, <=0.7.3', |
80 | 80 |
'httplib2>=0.6.0', |
81 | 81 |
'snf-common>=0.9.0', |
82 |
'recaptcha-client>=1.0.5' |
|
82 |
'recaptcha-client>=1.0.5', |
|
83 |
'django-ratelimit==0.1' |
|
83 | 84 |
] |
84 | 85 |
|
85 | 86 |
EXTRAS_REQUIRES = { |
Also available in: Unified diff