Implemented IP authentication
libraries get associated with a library_block table (IP ranges) moved superlogin here IP stuff mostly copied from https://github.com/benliles/django-ipauth/blob/master/ipauth/models.py The model is that you need to be in an allowed IP range to "join" a library. Once you've joined, you can use your login from anywhere. to use that library. Asign IP ranges in adminpull/1/head
parent
2f703a7815
commit
439169a1ab
5
admin.py
5
admin.py
|
@ -41,8 +41,8 @@ from regluit.core.lookups import (
|
||||||
OwnerLookup,
|
OwnerLookup,
|
||||||
EditionLookup
|
EditionLookup
|
||||||
)
|
)
|
||||||
from regluit.libraryauth.models import Library
|
from regluit.libraryauth.models import Library, Block
|
||||||
from regluit.libraryauth.admin import LibraryAdmin
|
from regluit.libraryauth.admin import LibraryAdmin, BlockAdmin
|
||||||
|
|
||||||
class RegluitAdmin(AdminSite):
|
class RegluitAdmin(AdminSite):
|
||||||
login_template = 'registration/login.html'
|
login_template = 'registration/login.html'
|
||||||
|
@ -214,6 +214,7 @@ admin_site = RegluitAdmin("Admin")
|
||||||
|
|
||||||
admin_site.register(User, UserAdmin)
|
admin_site.register(User, UserAdmin)
|
||||||
admin_site.register(Library, LibraryAdmin)
|
admin_site.register(Library, LibraryAdmin)
|
||||||
|
admin_site.register(Block, BlockAdmin)
|
||||||
admin_site.register(models.Work, WorkAdmin)
|
admin_site.register(models.Work, WorkAdmin)
|
||||||
admin_site.register(models.Claim, ClaimAdmin)
|
admin_site.register(models.Claim, ClaimAdmin)
|
||||||
admin_site.register(models.RightsHolder, RightsHolderAdmin)
|
admin_site.register(models.RightsHolder, RightsHolderAdmin)
|
||||||
|
|
|
@ -13,7 +13,6 @@ from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.global_settings import LANGUAGES
|
from django.conf.global_settings import LANGUAGES
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
|
||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms.widgets import RadioSelect
|
from django.forms.widgets import RadioSelect
|
||||||
|
@ -622,14 +621,6 @@ class FeedbackForm(forms.Form):
|
||||||
|
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
class AuthForm(AuthenticationForm):
|
|
||||||
def __init__(self, request=None, *args, **kwargs):
|
|
||||||
if request and request.method == 'GET':
|
|
||||||
saved_un= request.COOKIES.get('un', None)
|
|
||||||
super(AuthForm, self).__init__(initial={"username":saved_un},*args, **kwargs)
|
|
||||||
else:
|
|
||||||
super(AuthForm, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
class MsgForm(forms.Form):
|
class MsgForm(forms.Form):
|
||||||
msg = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please specify a message.'})
|
msg = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please specify a message.'})
|
||||||
|
|
||||||
|
|
|
@ -84,9 +84,9 @@ function highlightTarget(targetdiv) {
|
||||||
{% with supporter.profile.tagline as tagline %}{% if tagline %}{{ tagline }}{% else %} {% endif %}{% endwith %}
|
{% with supporter.profile.tagline as tagline %}{% if tagline %}{{ tagline }}{% else %} {% endif %}{% endwith %}
|
||||||
</span>
|
</span>
|
||||||
{% if supporter.library.group in request.user.groups.all %}
|
{% if supporter.library.group in request.user.groups.all %}
|
||||||
<i>This is MY Library!</i>
|
<i>This is {{ request.user }}'s Library!</i>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url join_library supporter.username %}" class="fakeinput">Make this my Library</a>
|
{% include supporter.library.join_template %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ function highlightTarget(targetdiv) {
|
||||||
{% block topsection %}
|
{% block topsection %}
|
||||||
<div id="locationhash">{{ activetab }}</div>
|
<div id="locationhash">{{ activetab }}</div>
|
||||||
{% if supporter.library %}
|
{% if supporter.library %}
|
||||||
<div class="launch_top pale">{{ supporter.username }} is a Library participating in Unglue.it. <a href="{% url library supporter.username %}">Click here</a> to use {{ supporter.username }}'s books.
|
<div class="launch_top pale">{{ supporter.username }} is a Library participating in Unglue.it. <a href="{% url join_library supporter.username %}">Click here</a> to use {{ supporter.username }}'s books.
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,7 @@ urlpatterns = patterns(
|
||||||
url(r"^supporter/(?P<supporter_username>[^/]+)/$", "supporter", {'template_name': 'supporter.html'}, name="supporter"),
|
url(r"^supporter/(?P<supporter_username>[^/]+)/$", "supporter", {'template_name': 'supporter.html'}, name="supporter"),
|
||||||
url(r"^supporter/(?P<userlist>[^/]+)/marc/$", "marc", name="user_marc"),
|
url(r"^supporter/(?P<userlist>[^/]+)/marc/$", "marc", name="user_marc"),
|
||||||
url(r"^library/(?P<supporter_username>[^/]+)/$", "supporter", {'template_name': 'library.html'}, name="library"),
|
url(r"^library/(?P<supporter_username>[^/]+)/$", "supporter", {'template_name': 'library.html'}, name="library"),
|
||||||
url(r"^library/(?P<library>[^/]+)/join/$", "join_library", name="join_library"),
|
|
||||||
url(r"^accounts/manage/$", login_required(ManageAccount.as_view()), name="manage_account"),
|
url(r"^accounts/manage/$", login_required(ManageAccount.as_view()), name="manage_account"),
|
||||||
url(r'^accounts/superlogin/$', 'superlogin', name='superlogin'),
|
|
||||||
url(r"^search/$", "search", name="search"),
|
url(r"^search/$", "search", name="search"),
|
||||||
url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"),
|
url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"),
|
||||||
name="privacy"),
|
name="privacy"),
|
||||||
|
|
|
@ -107,7 +107,6 @@ from regluit.frontend.forms import (
|
||||||
WorkForm,
|
WorkForm,
|
||||||
OtherWorkForm,
|
OtherWorkForm,
|
||||||
MsgForm,
|
MsgForm,
|
||||||
AuthForm,
|
|
||||||
PressForm,
|
PressForm,
|
||||||
KindleEmailForm,
|
KindleEmailForm,
|
||||||
MARCUngluifyForm,
|
MARCUngluifyForm,
|
||||||
|
@ -136,6 +135,7 @@ from regluit.payment.parameters import (
|
||||||
|
|
||||||
from regluit.utils.localdatetime import now, date_today
|
from regluit.utils.localdatetime import now, date_today
|
||||||
from regluit.booxtream.exceptions import BooXtreamError
|
from regluit.booxtream.exceptions import BooXtreamError
|
||||||
|
from regluit.libraryauth.views import Authenticator
|
||||||
from regluit.libraryauth.models import Library
|
from regluit.libraryauth.models import Library
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -297,18 +297,6 @@ def stub(request):
|
||||||
def acks(request, work):
|
def acks(request, work):
|
||||||
return render(request,'front_matter.html', {'campaign': work.last_campaign()})
|
return render(request,'front_matter.html', {'campaign': work.last_campaign()})
|
||||||
|
|
||||||
def superlogin(request, **kwargs):
|
|
||||||
extra_context = None
|
|
||||||
if request.method == 'POST' and request.user.is_anonymous():
|
|
||||||
username=request.POST.get("username", "")
|
|
||||||
try:
|
|
||||||
user=models.User.objects.get(username=username)
|
|
||||||
extra_context={"socials":user.profile.social_auths}
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if request.GET.has_key("add"):
|
|
||||||
request.session["add_wishlist"]=request.GET["add"]
|
|
||||||
return login(request, extra_context=extra_context, authentication_form=AuthForm, **kwargs)
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def social_auth_reset_password(request):
|
def social_auth_reset_password(request):
|
||||||
|
@ -316,15 +304,6 @@ def social_auth_reset_password(request):
|
||||||
request.user.set_password('%010x' % random.randrange(16**10))
|
request.user.set_password('%010x' % random.randrange(16**10))
|
||||||
request.user.save()
|
request.user.save()
|
||||||
return password_reset(request)
|
return password_reset(request)
|
||||||
|
|
||||||
def join_library(request, library):
|
|
||||||
library=get_object_or_404(Library, user__username=library)
|
|
||||||
if library.authenticate(request.user):
|
|
||||||
request.user.groups.add(library.group)
|
|
||||||
return HttpResponseRedirect(reverse('library',args=[str(library)]))
|
|
||||||
else:
|
|
||||||
return library.authenticator(request)
|
|
||||||
return render(request, 'join_library.html', {'library': library})
|
|
||||||
|
|
||||||
def work(request, work_id, action='display'):
|
def work(request, work_id, action='display'):
|
||||||
work = safe_get_work(work_id)
|
work = safe_get_work(work_id)
|
||||||
|
@ -1871,6 +1850,10 @@ def supporter(request, supporter_username, template_name):
|
||||||
librarything_id = None
|
librarything_id = None
|
||||||
|
|
||||||
process_kindle_email(request)
|
process_kindle_email(request)
|
||||||
|
try:
|
||||||
|
authenticator = Authenticator(request,supporter.library)
|
||||||
|
except Library.DoesNotExist:
|
||||||
|
authenticator=None
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"supporter": supporter,
|
"supporter": supporter,
|
||||||
|
@ -1888,7 +1871,8 @@ def supporter(request, supporter_username, template_name):
|
||||||
"goodreads_auth_url": reverse('goodreads_auth'),
|
"goodreads_auth_url": reverse('goodreads_auth'),
|
||||||
"goodreads_id": goodreads_id,
|
"goodreads_id": goodreads_id,
|
||||||
"librarything_id": librarything_id,
|
"librarything_id": librarything_id,
|
||||||
"activetab": activetab
|
"activetab": activetab,
|
||||||
|
"authenticator": authenticator
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, template_name, context)
|
return render(request, template_name, context)
|
||||||
|
|
|
@ -1,5 +1,37 @@
|
||||||
|
'''import logging
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from .views import superlogin
|
||||||
|
|
||||||
from . import backends
|
from . import backends
|
||||||
|
|
||||||
def authenticate(user,library):
|
logger = logging.getLogger(__name__)
|
||||||
backend= getattr(backends, library.backend + '_authenticate')
|
|
||||||
return backend(user, library)
|
class Authenticator:
|
||||||
|
request=None
|
||||||
|
library=None
|
||||||
|
|
||||||
|
def __init__(self, request, library):
|
||||||
|
self.request=request
|
||||||
|
self.library=library
|
||||||
|
|
||||||
|
def process(self, success_url, deny_url):
|
||||||
|
logger.info('authenticator for %s at %s.'%(self.request.user, self.library))
|
||||||
|
if self.library.has_user(self.request.user):
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
||||||
|
if backend_test(self.request, self.library):
|
||||||
|
if self.request.user.is_authenticated():
|
||||||
|
self.library.add_user(self.request.user)
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
else:
|
||||||
|
return superlogin(self.request, extra_context={'library':self.library}, template_name='libraryauth/library_login.html')
|
||||||
|
|
||||||
|
else:
|
||||||
|
backend_authenticator= getattr(backends, self.library.backend + '_authenticator')
|
||||||
|
return backend_authenticator(self.request, self.library, success_url, deny_url)
|
||||||
|
|
||||||
|
def allowed(self):
|
||||||
|
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
||||||
|
return backend_test(self.request, self.library)
|
||||||
|
'''
|
|
@ -28,4 +28,7 @@ class LibraryAdmin(ModelAdmin):
|
||||||
form = LibraryAdminForm
|
form = LibraryAdminForm
|
||||||
search_fields = ['user__username']
|
search_fields = ['user__username']
|
||||||
|
|
||||||
|
class BlockAdmin(ModelAdmin):
|
||||||
|
list_display = ('library', 'lower', 'upper',)
|
||||||
|
search_fields = ('library__user__username', 'lower', 'upper',)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
|
import logging
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
def IP_authenticate(user, library):
|
from .models import Block, IP
|
||||||
return True
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def ip_authenticate(request, library):
|
||||||
|
try:
|
||||||
|
ip = IP(request.META['REMOTE_ADDR'])
|
||||||
|
print str(ip)
|
||||||
|
blocks = Block.objects.filter(Q(lower=ip) | Q(lower__lte=ip, upper__gte=ip))
|
||||||
|
for block in blocks:
|
||||||
|
if block.library==library:
|
||||||
|
logger.info('%s authenticated for %s from %s'%(request.user, library, ip))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def ip_authenticator(request, library, success_url, deny_url):
|
||||||
|
return HttpResponseRedirect(deny_url)
|
||||||
|
|
||||||
def cardnum_authenticate(user, library):
|
def cardnum_authenticate(request, library):
|
||||||
|
# test params
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def cardnum_authenticator(request, library, success_url, deny_url):
|
||||||
|
#send a form
|
||||||
|
return render(request, 'cardnum.html', context)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
|
|
||||||
|
class AuthForm(AuthenticationForm):
|
||||||
|
def __init__(self, request=None, *args, **kwargs):
|
||||||
|
if request and request.method == 'GET':
|
||||||
|
saved_un= request.COOKIES.get('un', None)
|
||||||
|
super(AuthForm, self).__init__(initial={"username":saved_un},*args, **kwargs)
|
||||||
|
else:
|
||||||
|
super(AuthForm, self).__init__(*args, **kwargs)
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core import validators
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.forms import IPAddressField as BaseIPAddressField
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def ip_to_long(value):
|
||||||
|
validators.validate_ipv4_address(value)
|
||||||
|
|
||||||
|
lower_validator = validators.MinValueValidator(0)
|
||||||
|
upper_validator = validators.MinValueValidator(255)
|
||||||
|
|
||||||
|
value = value.split('.')
|
||||||
|
output = 0
|
||||||
|
|
||||||
|
for i in range(0, 4):
|
||||||
|
validators.validate_integer(value[i])
|
||||||
|
lower_validator(value[i])
|
||||||
|
upper_validator(value[i])
|
||||||
|
output += int(value[i]) * (256**(3-i))
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def long_to_ip(value):
|
||||||
|
validators.validate_integer(value)
|
||||||
|
value = int(value)
|
||||||
|
|
||||||
|
validators.MinValueValidator(0)(value)
|
||||||
|
validators.MaxValueValidator(4294967295)(value)
|
||||||
|
|
||||||
|
return '%d.%d.%d.%d' % (value >> 24, value >> 16 & 255,
|
||||||
|
value >> 8 & 255, value & 255)
|
||||||
|
|
||||||
|
class IP(object):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.int = value
|
||||||
|
|
||||||
|
def _set_int(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
self._int = IP.int
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._int = int(value)
|
||||||
|
except ValueError:
|
||||||
|
self._int = ip_to_long(value)
|
||||||
|
except (TypeError, ValidationError):
|
||||||
|
self._int = None
|
||||||
|
|
||||||
|
def _get_int(self):
|
||||||
|
return self._int
|
||||||
|
|
||||||
|
int = property(_get_int, _set_int)
|
||||||
|
|
||||||
|
def _get_str(self):
|
||||||
|
if self.int:
|
||||||
|
return long_to_ip(self.int)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
string = property(_get_str, _set_int)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, IP):
|
||||||
|
try:
|
||||||
|
other = IP(other)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.int == other.int
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
if not isinstance(other, IP):
|
||||||
|
other = IP(other)
|
||||||
|
|
||||||
|
if self.int and other.int:
|
||||||
|
return self.int.__cmp__(other.int)
|
||||||
|
|
||||||
|
raise ValueError('Invalid arguments')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.string
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.string
|
||||||
|
|
||||||
|
class IPAddressFormField(BaseIPAddressField):
|
||||||
|
default_validators = []
|
||||||
|
|
||||||
|
def prepare_value(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value.string
|
||||||
|
|
||||||
|
try:
|
||||||
|
return IP(value).string
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if value in validators.EMPTY_VALUES:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return IP(value)
|
||||||
|
except ValidationError:
|
||||||
|
raise ValidationError(self.default_error_messages['invalid'],
|
||||||
|
code='invalid')
|
||||||
|
|
||||||
|
class IPAddressModelField(models.IPAddressField):
|
||||||
|
__metaclass__ = models.SubfieldBase
|
||||||
|
empty_strings_allowed = False
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
models.Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_internal_type(self):
|
||||||
|
return "PositiveIntegerField"
|
||||||
|
|
||||||
|
def get_prep_value(self, value):
|
||||||
|
if not value:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value.int
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value
|
||||||
|
try:
|
||||||
|
return IP(value)
|
||||||
|
except ValidationError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {'form_class': IPAddressFormField}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(models.IPAddressField, self).formfield(**defaults)
|
||||||
|
|
||||||
|
|
||||||
|
class Range(models.Model):
|
||||||
|
user = models.ForeignKey(User, related_name='+')
|
||||||
|
lower = IPAddressModelField(db_index=True, unique=True)
|
||||||
|
upper = IPAddressModelField(db_index=True, blank=True, null=True)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
try:
|
||||||
|
if self.lower >= self.upper:
|
||||||
|
raise ValidationError('Lower end of the range must be less '
|
||||||
|
'than the upper end')
|
||||||
|
except ValueError, e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
others = Range.objects.exclude(pk=self.pk)
|
||||||
|
query = Q(lower__lte=self.lower, upper__gte=self.lower) | \
|
||||||
|
Q(lower=self.lower)
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
textual = u'%s-%s' % (self.lower, self.upper)
|
||||||
|
query = query | Q(lower__range=(self.lower, self.upper)) | \
|
||||||
|
Q(lower__lte=self.upper, upper__gte=self.upper)
|
||||||
|
else:
|
||||||
|
textual = str(self.lower)
|
||||||
|
|
||||||
|
query = others.filter(query)
|
||||||
|
|
||||||
|
if query.exists():
|
||||||
|
values = query.distinct().values_list('user__username', flat=True)
|
||||||
|
raise ValidationError('%s overlaps a range in in use by: %s' % (textual,
|
||||||
|
', '.join(list(frozenset(values))[:5])))
|
||||||
|
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
return u'%s %s-%s' % (self.user.get_full_name(), self.lower,
|
||||||
|
self.upper)
|
||||||
|
return u'%s %s' % (self.user.get_full_name(), self.lower)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['lower',]
|
|
@ -12,15 +12,27 @@ class Migration(SchemaMigration):
|
||||||
db.create_table('libraryauth_library', (
|
db.create_table('libraryauth_library', (
|
||||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='library', unique=True, to=orm['auth.User'])),
|
('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='library', unique=True, to=orm['auth.User'])),
|
||||||
('backend', self.gf('django.db.models.fields.CharField')(default='IP', max_length=10)),
|
('backend', self.gf('django.db.models.fields.CharField')(default='ip', max_length=10)),
|
||||||
))
|
))
|
||||||
db.send_create_signal('libraryauth', ['Library'])
|
db.send_create_signal('libraryauth', ['Library'])
|
||||||
|
|
||||||
|
# Adding model 'Block'
|
||||||
|
db.create_table('libraryauth_block', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('library', self.gf('django.db.models.fields.related.ForeignKey')(related_name='block', to=orm['libraryauth.Library'])),
|
||||||
|
('lower', self.gf('regluit.libraryauth.models.IPAddressModelField')(unique=True, db_index=True)),
|
||||||
|
('upper', self.gf('regluit.libraryauth.models.IPAddressModelField')(db_index=True, null=True, blank=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('libraryauth', ['Block'])
|
||||||
|
|
||||||
|
|
||||||
def backwards(self, orm):
|
def backwards(self, orm):
|
||||||
# Deleting model 'Library'
|
# Deleting model 'Library'
|
||||||
db.delete_table('libraryauth_library')
|
db.delete_table('libraryauth_library')
|
||||||
|
|
||||||
|
# Deleting model 'Block'
|
||||||
|
db.delete_table('libraryauth_block')
|
||||||
|
|
||||||
|
|
||||||
models = {
|
models = {
|
||||||
'auth.group': {
|
'auth.group': {
|
||||||
|
@ -59,9 +71,16 @@ class Migration(SchemaMigration):
|
||||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
},
|
},
|
||||||
|
'libraryauth.block': {
|
||||||
|
'Meta': {'ordering': "['lower']", 'object_name': 'Block'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'library': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'block'", 'to': "orm['libraryauth.Library']"}),
|
||||||
|
'lower': ('regluit.libraryauth.models.IPAddressModelField', [], {'unique': 'True', 'db_index': 'True'}),
|
||||||
|
'upper': ('regluit.libraryauth.models.IPAddressModelField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
'libraryauth.library': {
|
'libraryauth.library': {
|
||||||
'Meta': {'object_name': 'Library'},
|
'Meta': {'object_name': 'Library'},
|
||||||
'backend': ('django.db.models.fields.CharField', [], {'default': "'IP'", 'max_length': '10'}),
|
'backend': ('django.db.models.fields.CharField', [], {'default': "'ip'", 'max_length': '10'}),
|
||||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'library'", 'unique': 'True', 'to': "orm['auth.User']"})
|
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'library'", 'unique': 'True', 'to': "orm['auth.User']"})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
from . import authenticate
|
# IP address part of this of this copied from https://github.com/benliles/django-ipauth/blob/master/ipauth/models.py
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core import validators
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.forms import IPAddressField as BaseIPAddressField
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
class Library(models.Model):
|
class Library(models.Model):
|
||||||
'''
|
'''
|
||||||
name and other things derive from the User
|
name and other things derive from the User
|
||||||
'''
|
'''
|
||||||
user = models.OneToOneField(User, related_name='library')
|
user = models.OneToOneField(User, related_name='library')
|
||||||
backend = models.CharField(max_length=10, default='IP')
|
backend = models.CharField(max_length=10, default='ip')
|
||||||
|
|
||||||
def authenticate(self, enduser):
|
|
||||||
for group in enduser.groups.all():
|
|
||||||
if enduser.username == group.name:
|
|
||||||
return true
|
|
||||||
return authenticate(enduser, self)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def group(self):
|
def group(self):
|
||||||
(libgroup, created)=Group.objects.get_or_create(name=self.user.username)
|
(libgroup, created)=Group.objects.get_or_create(name=self.user.username)
|
||||||
|
@ -23,5 +22,192 @@ class Library(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
|
|
||||||
|
def add_user(self, user):
|
||||||
|
user.groups.add(self.group)
|
||||||
|
|
||||||
|
def has_user(self, user):
|
||||||
|
return self.group in user.groups.all()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def join_template(self):
|
||||||
|
return 'libraryauth/' + self.backend + '_join.html'
|
||||||
|
|
||||||
|
|
||||||
|
def ip_to_long(value):
|
||||||
|
validators.validate_ipv4_address(value)
|
||||||
|
|
||||||
|
lower_validator = validators.MinValueValidator(0)
|
||||||
|
upper_validator = validators.MinValueValidator(255)
|
||||||
|
|
||||||
|
value = value.split('.')
|
||||||
|
output = 0
|
||||||
|
|
||||||
|
for i in range(0, 4):
|
||||||
|
validators.validate_integer(value[i])
|
||||||
|
lower_validator(value[i])
|
||||||
|
upper_validator(value[i])
|
||||||
|
output += int(value[i]) * (256**(3-i))
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def long_to_ip(value):
|
||||||
|
validators.validate_integer(value)
|
||||||
|
value = int(value)
|
||||||
|
|
||||||
|
validators.MinValueValidator(0)(value)
|
||||||
|
validators.MaxValueValidator(4294967295)(value)
|
||||||
|
|
||||||
|
return '%d.%d.%d.%d' % (value >> 24, value >> 16 & 255,
|
||||||
|
value >> 8 & 255, value & 255)
|
||||||
|
|
||||||
|
class IP(object):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.int = value
|
||||||
|
|
||||||
|
def _set_int(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
self._int = IP.int
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._int = int(value)
|
||||||
|
except ValueError:
|
||||||
|
self._int = ip_to_long(value)
|
||||||
|
except (TypeError, ValidationError):
|
||||||
|
self._int = None
|
||||||
|
|
||||||
|
def _get_int(self):
|
||||||
|
return self._int
|
||||||
|
|
||||||
|
int = property(_get_int, _set_int)
|
||||||
|
|
||||||
|
def _get_str(self):
|
||||||
|
if self.int!=None:
|
||||||
|
return long_to_ip(self.int)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
string = property(_get_str, _set_int)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, IP):
|
||||||
|
try:
|
||||||
|
other = IP(other)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.int == other.int
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
if not isinstance(other, IP):
|
||||||
|
other = IP(other)
|
||||||
|
|
||||||
|
if self.int and other.int:
|
||||||
|
return self.int.__cmp__(other.int)
|
||||||
|
|
||||||
|
raise ValueError('Invalid arguments')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.string
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.string
|
||||||
|
|
||||||
|
class IPAddressFormField(BaseIPAddressField):
|
||||||
|
default_validators = []
|
||||||
|
|
||||||
|
def prepare_value(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value.string
|
||||||
|
|
||||||
|
try:
|
||||||
|
return IP(value).string
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if value==0:
|
||||||
|
return IP(0)
|
||||||
|
if value in validators.EMPTY_VALUES:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return IP(value)
|
||||||
|
except ValidationError:
|
||||||
|
raise ValidationError(self.default_error_messages['invalid'],
|
||||||
|
code='invalid')
|
||||||
|
|
||||||
|
class IPAddressModelField(models.IPAddressField):
|
||||||
|
__metaclass__ = models.SubfieldBase
|
||||||
|
empty_strings_allowed = False
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
models.Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_internal_type(self):
|
||||||
|
return "PositiveIntegerField"
|
||||||
|
|
||||||
|
def get_prep_value(self, value):
|
||||||
|
if not value:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value.int
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if isinstance(value, IP):
|
||||||
|
return value
|
||||||
|
try:
|
||||||
|
return IP(value)
|
||||||
|
except ValidationError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {'form_class': IPAddressFormField}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(models.IPAddressField, self).formfield(**defaults)
|
||||||
|
|
||||||
|
class Block(models.Model):
|
||||||
|
library = models.ForeignKey(Library, related_name='block')
|
||||||
|
lower = IPAddressModelField(db_index=True, unique=True)
|
||||||
|
upper = IPAddressModelField(db_index=True, blank=True, null=True)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
try:
|
||||||
|
if self.lower > self.upper:
|
||||||
|
raise ValidationError('Lower end of the Block must be less '
|
||||||
|
'than or equal to the upper end')
|
||||||
|
except ValueError, e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
others = Block.objects.exclude(pk=self.pk)
|
||||||
|
query = Q(lower__lte=self.lower, upper__gte=self.lower) | \
|
||||||
|
Q(lower=self.lower)
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
textual = u'%s-%s' % (self.lower, self.upper)
|
||||||
|
query = query | Q(lower__range=(self.lower, self.upper)) | \
|
||||||
|
Q(lower__lte=self.upper, upper__gte=self.upper)
|
||||||
|
else:
|
||||||
|
textual = str(self.lower)
|
||||||
|
|
||||||
|
query = others.filter(query)
|
||||||
|
|
||||||
|
if query.exists():
|
||||||
|
values = query.distinct().values_list('library__user__username', flat=True)
|
||||||
|
raise ValidationError('%s overlaps a block in in use by: %s' % (textual,
|
||||||
|
', '.join(list(frozenset(values))[:5])))
|
||||||
|
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
if self.upper and self.upper.int:
|
||||||
|
return u'%s %s-%s' % (self.library, self.lower, self.upper)
|
||||||
|
return u'%s %s' % (self.library, self.lower)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['lower',]
|
||||||
|
|
||||||
|
from south.modelsinspector import add_introspection_rules
|
||||||
|
add_introspection_rules([], ["^regluit\.libraryauth\.models\.IPAddressModelField"])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Denied authentication for {{ request.user }} at {{ request.META.REMOTE_ADDR }}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% if authenticator.allowed %}
|
||||||
|
<a href="{% url join_library authenticator.library %}?next={% url join_library authenticator.library %}" class="fakeinput">Make this my Library</a>
|
||||||
|
{% else %}
|
||||||
|
You can't join {{ authenticator.library }} at your current location.
|
||||||
|
{% endif %}
|
|
@ -0,0 +1 @@
|
||||||
|
{{params.library}}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends "registration/from_pledge.html" %}
|
||||||
|
{% block login_pitch %}<h3>Before you can join {{library}} on unglue.it, please login or make an unglue.it account. </h3>{% endblock %}
|
|
@ -0,0 +1,11 @@
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.views.generic.simple import direct_to_template
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
"",
|
||||||
|
url(r"^libraryauth/(?P<library>[^/]+)/join/$", views.join_library, name="join_library"),
|
||||||
|
url(r"^libraryauth/(?P<library>[^/]+)/deny/$", direct_to_template, {'template':'libraryauth/denied.html'}, name="bad_library"),
|
||||||
|
url(r'^accounts/superlogin/$', 'superlogin', name='superlogin'),
|
||||||
|
)
|
|
@ -0,0 +1,59 @@
|
||||||
|
import logging
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.contrib.auth.views import login
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from . import backends
|
||||||
|
|
||||||
|
from .models import Library
|
||||||
|
from .forms import AuthForm
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def join_library(request, library):
|
||||||
|
library=get_object_or_404(Library, user__username=library)
|
||||||
|
return Authenticator(request,library).process(
|
||||||
|
reverse('library',args=[str(library)]),
|
||||||
|
reverse('bad_library',args=[str(library)]),
|
||||||
|
)
|
||||||
|
|
||||||
|
def superlogin(request, extra_context=None, **kwargs):
|
||||||
|
if request.method == 'POST' and request.user.is_anonymous():
|
||||||
|
username=request.POST.get("username", "")
|
||||||
|
try:
|
||||||
|
user=models.User.objects.get(username=username)
|
||||||
|
extra_context={"socials":user.profile.social_auths}
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if request.GET.has_key("add"):
|
||||||
|
request.session["add_wishlist"]=request.GET["add"]
|
||||||
|
return login(request, extra_context=extra_context, authentication_form=AuthForm, **kwargs)
|
||||||
|
|
||||||
|
class Authenticator:
|
||||||
|
request=None
|
||||||
|
library=None
|
||||||
|
|
||||||
|
def __init__(self, request, library):
|
||||||
|
self.request=request
|
||||||
|
self.library=library
|
||||||
|
|
||||||
|
def process(self, success_url, deny_url):
|
||||||
|
logger.info('authenticator for %s at %s.'%(self.request.user, self.library))
|
||||||
|
if self.library.has_user(self.request.user):
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
||||||
|
if backend_test(self.request, self.library):
|
||||||
|
if self.request.user.is_authenticated():
|
||||||
|
self.library.add_user(self.request.user)
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
else:
|
||||||
|
return superlogin(self.request, extra_context={'library':self.library}, template_name='libraryauth/library_login.html')
|
||||||
|
|
||||||
|
else:
|
||||||
|
backend_authenticator= getattr(backends, self.library.backend + '_authenticator')
|
||||||
|
return backend_authenticator(self.request, self.library, success_url, deny_url)
|
||||||
|
|
||||||
|
def allowed(self):
|
||||||
|
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
||||||
|
return backend_test(self.request, self.library)
|
4
urls.py
4
urls.py
|
@ -4,7 +4,8 @@ from django.conf.urls.defaults import *
|
||||||
from django.views.generic.simple import direct_to_template
|
from django.views.generic.simple import direct_to_template
|
||||||
|
|
||||||
from frontend.forms import ProfileForm
|
from frontend.forms import ProfileForm
|
||||||
from frontend.views import superlogin, social_auth_reset_password
|
from frontend.views import social_auth_reset_password
|
||||||
|
from libraryauth.views import superlogin
|
||||||
from regluit.admin import admin_site
|
from regluit.admin import admin_site
|
||||||
from regluit.core.sitemaps import WorkSitemap, PublisherSitemap
|
from regluit.core.sitemaps import WorkSitemap, PublisherSitemap
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ urlpatterns = patterns('',
|
||||||
(r'^api/', include('regluit.api.urls')),
|
(r'^api/', include('regluit.api.urls')),
|
||||||
(r'', include('regluit.frontend.urls')),
|
(r'', include('regluit.frontend.urls')),
|
||||||
(r'', include('regluit.payment.urls')),
|
(r'', include('regluit.payment.urls')),
|
||||||
|
(r'', include('regluit.libraryauth.urls')),
|
||||||
(r'^selectable/', include('selectable.urls')),
|
(r'^selectable/', include('selectable.urls')),
|
||||||
url(r'^admin/', include(admin_site.urls)),
|
url(r'^admin/', include(admin_site.urls)),
|
||||||
(r'^comments/', include('django.contrib.comments.urls')),
|
(r'^comments/', include('django.contrib.comments.urls')),
|
||||||
|
|
Loading…
Reference in New Issue