handle association failure (#9415)
This commit is contained in:
parent
c73a731a76
commit
cacbe34d2b
|
@ -3,7 +3,9 @@
|
|||
*.log
|
||||
*.sh
|
||||
*.swp
|
||||
|
||||
./static
|
||||
*.patch
|
||||
local_settings*
|
||||
cookies.txt
|
||||
./static/
|
||||
uwsgi*
|
||||
*.sqlite3
|
||||
|
|
15
README
15
README
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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++ ) {
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
]
|
|
@ -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' }
|
||||
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
});
|
Reference in New Issue