handle association failure (#9415)

This commit is contained in:
Josue Kouka 2015-12-24 10:48:54 +01:00
parent c73a731a76
commit cacbe34d2b
11 changed files with 144 additions and 48 deletions

6
.gitignore vendored
View File

@ -3,7 +3,9 @@
*.log
*.sh
*.swp
./static
*.patch
local_settings*
cookies.txt
./static/
uwsgi*
*.sqlite3

15
README
View File

@ -76,12 +76,24 @@ Example of local_settings.py
'help': ''
},
]
# List of javascript scripts running on every pages
# loaded in panel.html
SITE_SCRIPTS = [
'js/example.com.js',
]
# JS Script asserting authentication through phantomjs
# The authentication assertion function must be into
# a var such as :
#
# window.auth_success = function(){
# // your code
# }
#
SITE_AUTH_CHECKER = 'js/vincennes_auth_checker.js'
# JS/CSS for the association page (/_mandaye/associate)
SITE_ASSOCIATE_STATIC = {
'css': 'css/example_associate.css',
'js': 'js/example_associate.js',
@ -95,5 +107,4 @@ Example of local_settings.py
]
MELLON_VERIFY_SSL_CERTIFICATE = False

View File

@ -33,11 +33,20 @@ page.onResourceReceived = function(response){
page.open(input.address, function() {
page.onLoadFinished = function() {
if (page.injectJs(input.auth_checker)){
input.auth_success = page.evaluate(function(){
return auth_success();
});
}
if (!input.auth_success){
console.log(JSON.stringify({'result': 'failure', 'reason': 'authentication failed'}));
phantom.exit();
}
page.render('login.png');
console.log(JSON.stringify({'result': 'ok', 'cookies': page.cookies, 'headers': headers_list, 'url': page.frameUrl}));
phantom.exit();
}
page.injectJs('static/js/jquery.min.js');
page.evaluate(function(input) {
var locators = input.locators;
for ( var i=0; i < locators.length; i++ ) {

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('mandaye', '0005_auto_20151126_1413'),
]
operations = [
migrations.AddField(
model_name='usercredentials',
name='linked',
field=models.BooleanField(default=True, verbose_name='associated'),
preserve_default=True,
),
]

View File

@ -22,12 +22,14 @@ from django.utils.translation import ugettext_lazy as _
class UserCredentials(models.Model):
user = models.ForeignKey('auth.User')
locators = JSONField(_('locators'), default={}, blank=True)
linked = models.BooleanField(_('associated'), default=True, blank=True)
class Meta:
unique_together = ('user',)
def __str__(self):
return self.user.email
return self.user.get_full_name() or self.user.email or self.user.username
def to_login_info(self):
return {'#'+k : v for k,v in self.locators.items() if k != 'csrfmiddlewaretoken' }

View File

@ -9,6 +9,13 @@
<body>
<div id="main-div">
<h1>{{ associate|capfirst }}</h1>
{%if messages %}
<ul class="messages">
{%for message in messages%}
<li>{{message}}</li>
{%endfor%}
</ul>
{%endif%}
<form id='associate' method="post">
{% csrf_token %}
{{ form.as_p }}

View File

@ -2,10 +2,6 @@
<html>
<head>
<script src="{% xstatic 'jquery' 'jquery.min.js' %}"></script>
<script src="{% static 'mandaye.post.js' %}"></script>
<script type='text/javascript'>
var url = "{{ address }}" ;
</script>
</head>
<body>
Please wait...

View File

@ -13,14 +13,28 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import json
import subprocess
from django.conf import settings
import urlparse
from Cookie import SimpleCookie
def exec_phantom(data):
phantom = subprocess.Popen(['/usr/bin/phantomjs',
'--ignore-ssl-errors=yes',
'--ssl-protocol=any',
'--cookies-file=cookies.txt',
os.path.join(settings.BASE_DIR, 'mandayejs', 'do_login.js')],
close_fds=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout, stderr = phantom.communicate(json.dumps(data))
result = json.loads(stdout)
return result
def cookie_builder(headers):
"""Build Cookies from list of headers
"""

View File

@ -14,10 +14,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import os
import json
import logging
import subprocess
import urlparse
import urllib
@ -26,6 +27,7 @@ from django.contrib.auth import views as auth_views
from django.contrib.auth import logout as auth_logout
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.forms import PasswordInput
from django.forms import models as model_forms
from django.http import HttpResponseRedirect, HttpResponse
@ -35,10 +37,13 @@ from django.views.generic.base import TemplateView
from django.views.decorators.csrf import csrf_exempt
from django.db import IntegrityError
from django.utils.translation import ugettext_lazy as _
from django.template import RequestContext, Template
from .models import UserCredentials
from mandayejs.mandaye.forms import FormFactory
from mandayejs.mandaye.utils import cookie_builder, get_location
from mandayejs.mandaye.utils import exec_phantom, cookie_builder, get_location
logger = logging.getLogger(__name__)
def login(request, *args, **kwargs):
return auth_views.login(request, *args, **kwargs)
@ -63,10 +68,11 @@ class Panel(TemplateView):
def is_account_linked(self):
"""Check if user account is associated
"""
try:
UserCredentials.objects.get(user=self.request.user)
return True
except :
try:
User = get_user_model()
user = User.objects.get(username=self.request.user.username)
return user.usercredentials_set.get().linked
except (User.DoesNotExist, UserCredentials.DoesNotExist) as e:
return False
@ -75,9 +81,13 @@ panel = Panel.as_view()
@login_required
def post_login(request, *args, **kwargs):
try:
user = get_user_model().objects.get(username=request.user.username)
logger.debug(user)
credentials = UserCredentials.objects.get(
user=request.user)
except UserCredentials.DoesNotExist:
user=user,
linked=True)
logger.debug(credentials)
except (UserCredentials.DoesNotExist,):
return HttpResponseRedirect(resolve_url('associate'))
context = {}
@ -88,14 +98,15 @@ def post_login(request, *args, **kwargs):
@csrf_exempt
def associate(request, *args, **kwargs):
if request.POST:
credentials = UserCredentials()
credentials.user = request.user
credentials, created = UserCredentials.objects.get_or_create(user=request.user)
credentials.locators = request.POST
credentials.linked = True
credentials.save()
form = FormFactory(request.POST, auto_id=True, locators=settings.SITE_LOCATORS)
else:
form = FormFactory(auto_id=True, locators=settings.SITE_LOCATORS)
if not form.is_valid():
return render(request, 'mandaye/associate.html', {
response = render(request, 'mandaye/associate.html', {
'form': form,
'submit': _('submit'),
'associate': _('associate your account'),
@ -103,20 +114,19 @@ def associate(request, *args, **kwargs):
'SITE_ASSOCIATE_STATIC',
{'css':'', 'js':''})
})
try:
credentials.save()
except (IntegrityError,) as e:
pass
return response
return HttpResponseRedirect(resolve_url('post-login'))
@login_required
def dissociate(request, *args, **kwargs):
try:
User = get_user_model()
User.objects.get(username=request.user).delete()
c_user = UserCredentials.objects.get(
user__username=request.user.username)
c_user.linked = False
c_user.save()
return HttpResponseRedirect(resolve_url('mellon_logout'))
except (User.DoesNotExist,) as e:
except (UserCredentials.DoesNotExist,):
return HttpResponseRedirect(resolve_url('associate'))
@login_required
@ -125,25 +135,32 @@ def post_login_do(request, *args, **kwargs):
login_info = {
'address': request.build_absolute_uri(settings.SITE_LOGIN_PATH),
'cookies': [],
'locators': [ credentials.to_login_info() ]
'locators': [ credentials.to_login_info() ],
'homepath': getattr(settings, 'SITE_HOME_PATH', '/'),
'auth_checker': os.path.join(settings.STATIC_ROOT, getattr(settings, 'SITE_AUTH_CHECKER'))
}
logger.debug(login_info)
result = exec_phantom(login_info)
logger.debug(result)
if result.get('result') != 'ok':
return HttpResponseRedirect('/')
location = get_location(result.get('url','/'))
response = HttpResponseRedirect(location)
response.cookies = cookie_builder(result.get('headers'))
logger.debug('authentication failed')
User = get_user_model()
user = User.objects.get(username=request.user.username)
c_user = user.usercredentials_set.get()
c_user.linked = False
c_user.save()
logger.debug("redirecting to {}".format(resolve_url('associate')))
messages.error(request, _('wrong user credentials'))
url = resolve_url('associate')
else:
url = getattr(settings, 'SITE_HOME_PATH', '/')
template = Template('<script type="text/javascript">\
window.top.location = "{{url}}";</script>')
context = RequestContext(request, {'url': url})
response = HttpResponse(template.render(context))
if result.get('headers',None):
response.cookies = cookie_builder(result.get('headers'))
return response
def exec_phantom(data):
phantom = subprocess.Popen(['/usr/bin/phantomjs',
'--ignore-ssl-errors=yes',
'--ssl-protocol=any',
'--cookies-file=cookies.txt',
os.path.join(settings.BASE_DIR,'mandayejs/do_login.js')],
close_fds=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout, stderr = phantom.communicate(json.dumps(data))
result = json.loads(stdout)
return result

View File

@ -13,6 +13,16 @@ h1 {
font-size: x-small;
}
.messages {
font-size: small;
text-align: left;
postion: relative;
margin-left: 90px;
color: red;
}
.messages li { list-style-type: none }
.errorlist {
font-size: small;
text-align: left;

View File

@ -0,0 +1,8 @@
$(function(){
window.auth_success = function(){
var found = $("body").text().indexOf('Les informations de connexion');
if (found == -1)
return true;
return false;
};
});