Implement single sign on with egonomy - mobenfact
authorymh <ymh.work@gmail.com>
Fri, 21 Mar 2014 16:25:21 +0100
changeset 271 4e7178ce5688
parent 270 a76a79affb4a
child 272 383355e4caba
Implement single sign on with egonomy - mobenfact
src/egonomy/__init__.py
src/egonomy/auth/__init__.py
src/egonomy/auth/backends.py
src/egonomy/auth/middleware.py
src/egonomy/config.py.tmpl
src/egonomy/settings.py
src/egonomy/templates/egonomy_all_collections.html
src/egonomy/templates/egonomy_all_fragments.html
src/egonomy/templates/egonomy_all_pictures.html
src/egonomy/templates/egonomy_annotate_picture.html
src/egonomy/templates/egonomy_base.html
src/egonomy/templates/egonomy_create_fragment.html
src/egonomy/templates/egonomy_home.html
src/egonomy/templates/egonomy_newbase.html
src/egonomy/templates/egonomy_view_collection.html
src/egonomy/templates/egonomy_view_fragment.html
src/egonomy/templates/registration/activate.html
src/egonomy/templates/registration/activation_complete.html
src/egonomy/templates/registration/login.html
src/egonomy/templates/registration/password_change_done.html
src/egonomy/templates/registration/password_change_form.html
src/egonomy/templates/registration/password_reset_complete.html
src/egonomy/templates/registration/password_reset_confirm.html
src/egonomy/templates/registration/password_reset_done.html
src/egonomy/templates/registration/password_reset_form.html
src/egonomy/templates/registration/registration_complete.html
src/egonomy/templates/registration/registration_form.html
src/egonomy/urls.py
src/egonomy/utils/__init__.py
src/egonomy/utils/context_processors.py
src/egonomy/views.py
virtualenv/res/lib/lib_create_env.py
virtualenv/res/src/Django-1.5.tar.gz
virtualenv/res/src/Django-1.6.2.tar.gz
virtualenv/res/src/django-extensions-1.0.2.tar.gz
virtualenv/res/src/django-extensions-1.3.3.tar.gz
virtualenv/res/src/pycrypto-2.6.1.tar.gz
virtualenv/res/src/six-1.2.0.tar.gz
virtualenv/res/src/six-1.6.1.tar.gz
virtualenv/web/res/res_create_env.py
--- a/src/egonomy/__init__.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/__init__.py	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-VERSION = (0, 8, 9, "final", 1)
+VERSION = (0, 9, 0, "final", 0)
 
 VERSION_STR = unicode(".".join(map(lambda i:"%02d" % (i,), VERSION[:2])))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/egonomy/auth/__init__.py	Fri Mar 21 16:25:21 2014 +0100
@@ -0,0 +1,31 @@
+from django.conf import settings
+from django.utils.crypto import get_random_string
+
+from egonomy.utils import unix_time, encodeAES, decodeAES
+
+
+def get_egonomy_token(request):
+    
+    if request.user.is_authenticated():
+        sessionid = request.session.session_key
+        salt = get_random_string(length=getattr(settings, 'EGONOMY_SALT_LENGTH', 12))
+        
+        return encodeAES("|".join([sessionid,salt]))
+    else:
+        return None
+
+#TODO : check
+def parse_egonomy_token(token):
+    
+    #retore padding if needed
+    token += "=" * ((4 - len(token) % 4) % 4)
+    decoded_token =  decodeAES(str(token))
+    sessionid, salt = decoded_token.split("|")
+    
+    return {'sessionid': sessionid, 'salt': salt}
+
+
+def clean_egonomy_username(username, is_internal):
+    prefix = settings.EGONOMY_USER_PREFIX
+    return (prefix if ( prefix not in username and not is_internal) else "") + username
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/egonomy/auth/backends.py	Fri Mar 21 16:25:21 2014 +0100
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Mar 19, 2014
+
+@author: ymh
+'''
+
+import logging
+
+from django.conf import settings
+from django.contrib.auth import get_user_model
+import requests
+
+from egonomy.auth import clean_egonomy_username
+
+
+logger = logging.getLogger(__name__)
+
+class EgonomyBackend(object):
+    """
+    Authenticate against egonomy.
+    """
+
+    def authenticate(self, username=None, password=None):
+
+        
+        User = get_user_model()
+        login_url = getattr(settings, "EGONOMY_LOGIN_URL", None)
+        
+        if not login_url:
+            return None
+        
+        logger.debug("EgonomyBackend.authenticate Calling %s" % login_url)
+        res_login = requests.post(login_url, data={'user_name': username, 'user_password': password, 'login':'true'})
+        
+        logger.debug("EgonomyBackend.authenticate Response received %s" % res_login.text)
+        
+        try:
+            res_json = res_login.json()
+        except:
+            return None
+        
+        if res_json.get("success", False):
+            username = clean_egonomy_username(username, False)
+            user, _ = User.objects.get_or_create(**{
+                User.USERNAME_FIELD: username
+            })
+            return user
+        return None
+
+    def get_user(self, user_id):
+        User = get_user_model()
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/egonomy/auth/middleware.py	Fri Mar 21 16:25:21 2014 +0100
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Mar 19, 2014
+
+@author: ymh
+'''
+import logging
+
+from django.conf import settings
+from django.contrib import auth
+from django.contrib.auth import get_user_model
+from django.core.exceptions import ImproperlyConfigured
+import requests
+
+from egonomy.auth import clean_egonomy_username
+from django.http.response import HttpResponseBadRequest
+
+
+logger = logging.getLogger(__name__) 
+
+class EgonomyUserTokenMiddleware(object):
+
+    parameter = (getattr(settings, "EGONOMY_TOKEN_NAME", None) or "egonomytoken")
+
+    def process_request(self, request):
+        if not hasattr(request, 'user'):
+            raise ImproperlyConfigured(
+                "The Egonomy user token auth middleware requires the"
+                " authentication middleware to be installed.  Edit your"
+                " MIDDLEWARE_CLASSES setting to insert"
+                " 'django.contrib.auth.middleware.AuthenticationMiddleware'"
+                " before the EgonomyUserTokenMiddleware class.")
+
+        logger.debug("EgonomyUserTokenMiddleware called")
+        token = request.POST.get(self.parameter,request.GET.get(self.parameter,None))
+        if not token:
+            return
+
+        logger.debug("EgonomyUserTokenMiddleware token found %s" % token)
+        
+        token_check_url = getattr(settings, "EGONOMY_TOKEN_CHECK_URL", None)
+        if not token_check_url:
+            return
+        
+        res_check = requests.get(token_check_url, params={self.parameter:token})
+        logger.debug("EgonomyUserTokenMiddleware json raw %s" % res_check.text)
+        res_json = res_check.json()
+        
+        logger.debug("EgonomyUserTokenMiddleware json %s" % res_json )
+        if not res_json.get('success', False):
+            return
+        
+        username = res_json.get('username', None)
+        if not username :
+            return HttpResponseBadRequest("Empty username")
+
+        #"namespace" username
+        username = clean_egonomy_username(username, res_json.get('external', True))
+        # If the user is already authenticated and that user is the user we are
+        # getting passed in the headers, then the correct user is already
+        # persisted in the session and we don't need to continue.
+        if request.user.is_authenticated() and request.user.get_username() == username:
+                return
+        else:
+            auth.logout(request)
+        
+        # create user if not known
+        # login user
+        UserModel = get_user_model()
+
+        # Note that this could be accomplished in one try-except clause, but
+        # instead we use get_or_create when creating unknown users since it has
+        # built-in safeguards for multiple threads.
+        user, _ = UserModel.objects.get_or_create(**{
+                UserModel.USERNAME_FIELD: username
+        })
+        
+        if user:
+            user.backend = 'django.contrib.auth.backends.ModelBackend'
+            # User is valid.  Set request.user and persist user in the session
+            # by logging the user in.
+            request.user = user
+            
+            auth.login(request, user)
--- a/src/egonomy/config.py.tmpl	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/config.py.tmpl	Fri Mar 21 16:25:21 2014 +0100
@@ -151,4 +151,11 @@
 EMAIL_HOST = '%(email_host)s'
 EMAIL_HOST_USER = '%(email_host_user)s'
 EMAIL_HOST_PASSWORD = '%(email_host_password)s'
-EMAIL_PORT = %(email_port)d 
+EMAIL_PORT = %(email_port)d
+
+EGONOMY_URL = '#'
+EGONOMY_LOGIN_URL =''
+EGONOMY_SALT_LENGTH = 12
+EGONOMY_TOKEN_NAME = 'egonomytoken'
+EGONOMY_TOKEN_CHECK_URL = ''
+
--- a/src/egonomy/settings.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/settings.py	Fri Mar 21 16:25:21 2014 +0100
@@ -102,6 +102,7 @@
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
+    'egonomy.auth.middleware.EgonomyUserTokenMiddleware'
     # Uncomment the next line for simple clickjacking protection:
     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 )
@@ -182,11 +183,24 @@
     }
 }
 
+AUTHENTICATION_BACKENDS = (
+    'django.contrib.auth.backends.ModelBackend',
+    'egonomy.auth.backends.EgonomyBackend',
+)
+
 
 HAYSTACK_SIGNAL_PROCESSOR = 'egonomy.search_indexes.EgonomySignalProcessor'
 ACCOUNT_ACTIVATION_DAYS = 7
 TASTYPIE_DEFAULT_FORMATS = ['json']
 
+EGONOMY_URL = '#'
+EGONOMY_LOGIN_URL =''
+EGONOMY_SALT_LENGTH = 12
+EGONOMY_TOKEN_NAME = 'egonomytoken'
+EGONOMY_TOKEN_CHECK_URL = ''
+
+EGONOMY_USER_PREFIX = 'egonomy:'
+
 from .config import * #@UnusedWildImport
 
 if not "SRC_BASE_URL" in locals():
--- a/src/egonomy/templates/egonomy_all_collections.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_all_collections.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/egonomy_all_fragments.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_all_fragments.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/egonomy_all_pictures.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_all_pictures.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/egonomy_annotate_picture.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_annotate_picture.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load absstatic %}
 {% load i18n %}
--- a/src/egonomy/templates/egonomy_base.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_base.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,68 +1,150 @@
 {% load static %}
 {% load i18n %}
-{#% load analytics %#}
 <!DOCTYPE html>
-<html lang="fr">
-    {% block head %}
-    <head>
-        <meta charset="utf-8" />
-        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
-        <title>TagItAll by eGonomy &raquo; {% block title %}Base{% endblock %}</title>
-        {% block css_declaration %}{% endblock %}
-	    {% block css_import %}
-        <link rel="stylesheet" href="{% static 'egonomy/css/egonomy.css' %}" />
-	    {% endblock %}
-	    {% block css_page %}{% endblock %}
-        {% block js_import %}
-        <script type="text/javascript" src="{% static 'egonomy/lib/jquery.min.js' %}"></script>
-        {% endblock %}
-        {% block js_inline %}
-        <script type="text/javascript">
-            $(function() {
-                $(".search-type").change(function() {
-                    $(".search-form").attr("action", $(this).val());
-                    if ($(".search-field").val()) {
-                        $(".search-form").submit();
-                    }
-                });
-            });
-        </script>
-        {% endblock %}
-    </head>
+<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
+{% block head %}
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="description" content="eGonomy">
+    <title>TagItAll by eGonomy &raquo; {% block title %}Base{% endblock %}</title>
+    {% block css_declaration %}{% endblock %}
+    {% block css_import %}
+    <link rel="stylesheet" href="{% static 'egonomy/css/reset.css' %}" />
+    <link rel="stylesheet" href="{% static 'egonomy/css/fonts.css' %}" />
+    <link rel="stylesheet" href="{% static 'egonomy/css/style.css' %}" />
     {% endblock %}
-    <body>
-        <div class="header-wrap fullwidth">
+    {% block css_page %}{% endblock %}
+</head>
+{% endblock %}
+<body>
+    <div class="popin-wrap">
+      {% if current_user_collection_list %}
+        <div id="add-to-collection" class="popin popin-new-collection box-shadow">
             <header>
-                <h1 class="column column-third"><a href="{% url 'home' %}">TagItAll {% trans "by" %} eGonomy</a></h1>
-                <form class="search-form column column-third" action="{% if search_fragment %}{% url 'all_fragments' %}{% else %}{% url 'all_pictures' %}{% endif %}" method="GET">
-                    <input class="search-field" type="search" placeholder="{% trans 'Search' %}" id="id_search" name="search"/>
-                    <select class="search-type">
-                        <option value="{% url 'all_pictures' %}"{% if not search_fragment %} selected{% endif %}>Images</option>
-                        <option value="{% url 'all_fragments' %}"{% if search_fragment %} selected{% endif %}>Fragments</option>
-                    </select>
-                    <input type="hidden" value="all" name="field">
-                </form>
-                <nav class="column column-third">
-                  {% if user.is_authenticated %}
-		            <a href="{% url 'user_fragments' username=user %}">{{ user.username }}</a> : <a href="{% url 'logout' %}?next={% url 'home' %}">{% trans "Log out" %}</a>
-		          {% else %}
-		            <a href="{% url 'login' %}">{% trans "Log in" %}</a>
-		          {% endif %}
-                </nav>
+                <h2>{% trans "Add to the collection" %}</h2>
+                <a href="#" class="close-popin"></a>
             </header>
+            <section>
+                <form class="ajax-form" action="{% url 'add_item' %}" method="POST">
+                    <p>
+                        <label for="collection-name">{% trans "Add to" %} :</label>
+                        <label class="styled-select">
+                            <select name="collection-pk" id="collection-pk">
+                              {% for c in current_user_collection_list %}
+                                <option value="{{ c.pk }}">{{ c.title }}</option>
+                              {% endfor %}
+                            </select>
+                        </label>
+                    </p>
+                    <p>
+                        <label class="block" for="item-description">{% trans "Image comment" %} :</label>
+                        <textarea name="item-description" id="item-description"></textarea>
+                    </p>
+                    <div class="buttons">
+                        <a href="#" class="btn close-popin">{% trans "Cancel" %}</a>
+                        <input class="btn" type="submit" value="{% trans 'Submit' %}">
+                    </div>
+                    <input class="item-type" name="item-type" type="hidden" value="">
+                    <input class="item-id" name="item-id" type="hidden" value="">{% csrf_token %}
+                </form>
+            </section>
         </div>
-        <div class="main-wrap fullwidth">
-            <div class="main">
-                {% block content %}
-                {% endblock %}
-                <footer class="fullwidth">
-                    <ul class="footer-list">
-                        <li>&copy; IRI 2013</li>
-                        <li>v{{ VERSION }}</li>
+        <div class="popin additem-success box-shadow">
+            <h2>{% trans "The item was successfully added to the collection" %}</h2>
+            <h2><a class="collection-url" href="#">{% trans "See the collection" %}</a></h2>
+        </div>
+        <div class="popin additem-error box-shadow">
+            <h2>{% trans "An error occurred while adding the item to the collection" %}</h2>
+        </div>
+      {% endif %}
+      {% block popins %}{% endblock %}
+    </div>
+    <div class="wrap">
+        <header class="clearfix">
+            <h1><a href="{% url 'home' %}">egonomy</a></h1>
+            <div class="col-right">
+                <ul class="head-login clearfix">
+                    <li>
+                        <form id="search-form" action="{% if search_fragment %}{% url 'all_fragments' %}{% else %}{% url 'all_pictures' %}{% endif %}" method="GET">
+                            <p>
+			                    <input id="search-field" type="text" placeholder="{% trans 'Search' %}" name="search"/>
+			                    <label class="styled-select">
+				                    <select id="search-type">
+				                        <option value="{% url 'all_pictures' %}"{% if not search_fragment %} selected{% endif %}>Images</option>
+				                        <option value="{% url 'all_fragments' %}"{% if search_fragment %} selected{% endif %}>Fragments</option>
+				                    </select>
+			                    </label>
+			                    <input type="hidden" value="all" name="field">
+		                    </p>
+		                </form>
+                    </li>
+                  {% if user.is_authenticated %}
+                    <li class="hello-user">{% trans "Hello" %} <a href="{% url 'auth_password_change' %}">{{ user.username }}</a>
+                    <li><span class="dot-6"></span></li>
+                    <li><a href="{% url 'logout' %}?next={% url 'home' %}">{% trans "Log out" %}</a></li>
+                  {% else %}
+                    <li class="hello-user"><a href="{% url 'login' %}">{% trans "Log in" %}</a></li>
+                  {% endif %}
+                </ul>
+                <nav>
+                    <ul class="nav clearfix">
+                        <li><a href="{% url 'all_pictures' %}" {% if all_pictures %}class="active"{% endif %}>{% trans "explore" %}</a></li>
+                        <li><span class="dot-10"></span></li>
+                        <li><a href="{% url 'all_collections' %}" {% if all_collections %}class="active"{% endif %}>{% trans "collect" %}</a></li>
+                        {% if EGONOMY_URL %}
+                            <li><span class="dot-10"></span></li>
+                            <li><a href="{{ EGONOMY_URL }}" target="_blank">Egonomy</a></li>
+                        {% endif %}
                     </ul>
-                </footer>
+                  {% if user.is_authenticated %}
+                    <ul class="sub-nav clearfix">
+                        <li><a href="{% url 'user_collections' username=user %}" {% if user_collections %}class="active"{% endif %}>{% trans "my collections" %}</a></li>
+                        <li><span class="dot-6"></span></li>
+                        <li><a href="{% url 'user_fragments' username=user %}" {% if user_fragments %}class="active"{% endif %}>{% trans "my fragments" %}</a></li>
+                        <!--li><span class="dot-6"></span></li>
+                        <li><a href="#">mon profil</a></li-->
+                    </ul>
+                  {% endif %}
+                </nav>
             </div>
-        </div>
-    {#% analytics %#}
-    </body>
-</html>
+        </header>
+        <section>
+        {% block content %}
+        {% endblock %}
+        </section>
+        <footer class="clearfix">
+            <!--h6>EGONOMY est un projet de l’IRI et de la réunion des Musées Nationaux</h6-->
+            <p>&copy; IRI 2013 - v{{ VERSION }}</p>
+        </footer>
+    </div><!-- /.wrap -->
+    {% block js_common %}
+    <script type="text/javascript" src="{% static 'egonomy/lib/jquery.min.js' %}"></script>
+    <script type="text/javascript" src="{% static 'egonomy/js/masonry.min.js' %}"></script>
+    <script type="text/javascript" src="{% static 'egonomy/js/main.js' %}"></script>
+    {% endblock %}
+    <script type="text/javascript">
+    $(function() {
+        $("#search-type").change(function() {
+            $("#search-form").attr("action", $(this).val());
+            if ($("#search-field").val()) {
+                $("#search-form").submit();
+            }
+        });
+    });
+    </script>
+    {% block js_page %}
+    {% endblock %}
+<script> 
+(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 
+(i[r].q=i[r].q||[]).push(arguments)},
+i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 
+})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+ga('create', 'UA-30064213-3', 'iri-research.org'); 
+ga('send', 'pageview');
+</script>
+</body>
+</html>
\ No newline at end of file
--- a/src/egonomy/templates/egonomy_create_fragment.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_create_fragment.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/egonomy_home.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_home.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/egonomy_newbase.html	Mon Mar 17 16:18:45 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-{% load static %}
-{% load i18n %}
-<!DOCTYPE html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
-{% block head %}
-<head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="description" content="eGonomy">
-    <title>TagItAll by eGonomy &raquo; {% block title %}Base{% endblock %}</title>
-    {% block css_declaration %}{% endblock %}
-    {% block css_import %}
-    <link rel="stylesheet" href="{% static 'egonomy/css/reset.css' %}" />
-    <link rel="stylesheet" href="{% static 'egonomy/css/fonts.css' %}" />
-    <link rel="stylesheet" href="{% static 'egonomy/css/style.css' %}" />
-    {% endblock %}
-    {% block css_page %}{% endblock %}
-</head>
-{% endblock %}
-<body>
-    <div class="popin-wrap">
-      {% if current_user_collection_list %}
-        <div id="add-to-collection" class="popin popin-new-collection box-shadow">
-            <header>
-                <h2>{% trans "Add to the collection" %}</h2>
-                <a href="#" class="close-popin"></a>
-            </header>
-            <section>
-                <form class="ajax-form" action="{% url 'add_item' %}" method="POST">
-                    <p>
-                        <label for="collection-name">{% trans "Add to" %} :</label>
-                        <label class="styled-select">
-                            <select name="collection-pk" id="collection-pk">
-                              {% for c in current_user_collection_list %}
-                                <option value="{{ c.pk }}">{{ c.title }}</option>
-                              {% endfor %}
-                            </select>
-                        </label>
-                    </p>
-                    <p>
-                        <label class="block" for="item-description">{% trans "Image comment" %} :</label>
-                        <textarea name="item-description" id="item-description"></textarea>
-                    </p>
-                    <div class="buttons">
-                        <a href="#" class="btn close-popin">{% trans "Cancel" %}</a>
-                        <input class="btn" type="submit" value="{% trans 'Submit' %}">
-                    </div>
-                    <input class="item-type" name="item-type" type="hidden" value="">
-                    <input class="item-id" name="item-id" type="hidden" value="">{% csrf_token %}
-                </form>
-            </section>
-        </div>
-        <div class="popin additem-success box-shadow">
-            <h2>{% trans "The item was successfully added to the collection" %}</h2>
-            <h2><a class="collection-url" href="#">{% trans "See the collection" %}</a></h2>
-        </div>
-        <div class="popin additem-error box-shadow">
-            <h2>{% trans "An error occurred while adding the item to the collection" %}</h2>
-        </div>
-      {% endif %}
-      {% block popins %}{% endblock %}
-    </div>
-    <div class="wrap">
-        <header class="clearfix">
-            <h1><a href="{% url 'home' %}">egonomy</a></h1>
-            <div class="col-right">
-                <ul class="head-login clearfix">
-                    <li>
-                        <form id="search-form" action="{% if search_fragment %}{% url 'all_fragments' %}{% else %}{% url 'all_pictures' %}{% endif %}" method="GET">
-                            <p>
-			                    <input id="search-field" type="text" placeholder="{% trans 'Search' %}" name="search"/>
-			                    <label class="styled-select">
-				                    <select id="search-type">
-				                        <option value="{% url 'all_pictures' %}"{% if not search_fragment %} selected{% endif %}>Images</option>
-				                        <option value="{% url 'all_fragments' %}"{% if search_fragment %} selected{% endif %}>Fragments</option>
-				                    </select>
-			                    </label>
-			                    <input type="hidden" value="all" name="field">
-		                    </p>
-		                </form>
-                    </li>
-                  {% if user.is_authenticated %}
-                    <li class="hello-user">{% trans "Hello" %} <a href="{% url 'auth_password_change' %}">{{ user.username }}</a>
-                    <li><span class="dot-6"></span></li>
-                    <li><a href="{% url 'logout' %}?next={% url 'home' %}">{% trans "Log out" %}</a></li>
-                  {% else %}
-                    <li class="hello-user"><a href="{% url 'login' %}">{% trans "Log in" %}</a></li>
-                  {% endif %}
-                </ul>
-                <nav>
-                    <ul class="nav clearfix">
-                        <li><a href="{% url 'all_pictures' %}" {% if all_pictures %}class="active"{% endif %}>{% trans "explore" %}</a></li>
-                        <li><span class="dot-10"></span></li>
-                        <li><a href="{% url 'all_collections' %}" {% if all_collections %}class="active"{% endif %}>{% trans "collect" %}</a></li>
-                        <!--li><span class="dot-10"></span></li>
-                        <li><a href="#">créer</a></li>
-                        <li><span class="dot-10"></span></li>
-                        <li><a href="">mon profil</a></li-->
-                    </ul>
-                  {% if user.is_authenticated %}
-                    <ul class="sub-nav clearfix">
-                        <li><a href="{% url 'user_collections' username=user %}" {% if user_collections %}class="active"{% endif %}>{% trans "my collections" %}</a></li>
-                        <li><span class="dot-6"></span></li>
-                        <li><a href="{% url 'user_fragments' username=user %}" {% if user_fragments %}class="active"{% endif %}>{% trans "my fragments" %}</a></li>
-                        <!--li><span class="dot-6"></span></li>
-                        <li><a href="#">mon profil</a></li-->
-                    </ul>
-                  {% endif %}
-                </nav>
-            </div>
-        </header>
-        <section>
-        {% block content %}
-        {% endblock %}
-        </section>
-        <footer class="clearfix">
-            <!--h6>EGONOMY est un projet de l’IRI et de la réunion des Musées Nationaux</h6-->
-            <p>&copy; IRI 2013 - v{{ VERSION }}</p>
-        </footer>
-    </div><!-- /.wrap -->
-    {% block js_common %}
-    <script type="text/javascript" src="{% static 'egonomy/lib/jquery.min.js' %}"></script>
-    <script type="text/javascript" src="{% static 'egonomy/js/masonry.min.js' %}"></script>
-    <script type="text/javascript" src="{% static 'egonomy/js/main.js' %}"></script>
-    {% endblock %}
-    <script type="text/javascript">
-    $(function() {
-        $("#search-type").change(function() {
-            $("#search-form").attr("action", $(this).val());
-            if ($("#search-field").val()) {
-                $("#search-form").submit();
-            }
-        });
-    });
-    </script>
-    {% block js_page %}
-    {% endblock %}
-<script> 
-(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 
-(i[r].q=i[r].q||[]).push(arguments)},
-i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 
-})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-ga('create', 'UA-30064213-3', 'iri-research.org'); 
-ga('send', 'pageview');
-</script>
-</body>
-</html>
\ No newline at end of file
--- a/src/egonomy/templates/egonomy_view_collection.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_view_collection.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 
--- a/src/egonomy/templates/egonomy_view_fragment.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/egonomy_view_fragment.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 {% load thumbnail %}
--- a/src/egonomy/templates/registration/activate.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/activate.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/activation_complete.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/activation_complete.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/login.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/login.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load static %}
 {% load i18n %}
 
--- a/src/egonomy/templates/registration/password_change_done.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_change_done.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/password_change_form.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_change_form.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/password_reset_complete.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_reset_complete.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/password_reset_confirm.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_reset_confirm.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/password_reset_done.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_reset_done.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/password_reset_form.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/password_reset_form.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/registration_complete.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/registration_complete.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/templates/registration/registration_form.html	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/templates/registration/registration_form.html	Fri Mar 21 16:25:21 2014 +0100
@@ -1,4 +1,4 @@
-{% extends "egonomy_newbase.html" %}
+{% extends "egonomy_base.html" %}
 {% load i18n %}
 
 {% block content %}
--- a/src/egonomy/urls.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/urls.py	Fri Mar 21 16:25:21 2014 +0100
@@ -39,6 +39,8 @@
     # login logout view
     url(r'^login/', 'django.contrib.auth.views.login', name='login'),
     url(r'^logout/', 'django.contrib.auth.views.logout', name='logout'),
+    url(r'^ajax-login/', 'egonomy.views.ajax_login', name='ajax_login'),
+    url(r'^check-egonomy-token/(?P<token>[\w\d\-_=]*)$', 'egonomy.views.check_egonomy_token', name='check_egonomy_token'),
     (r'^api/', include('egonomy.api.urls')),
     (r'^accounts/', include('registration.backends.default.urls')),
 )
--- a/src/egonomy/utils/__init__.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/utils/__init__.py	Fri Mar 21 16:25:21 2014 +0100
@@ -0,0 +1,30 @@
+import base64
+import datetime
+import hashlib
+
+from Crypto.Cipher import AES  # encryption library
+from django.conf import settings
+import pytz
+
+
+def unix_time(dt):
+    epoch = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.UTC)
+    delta = dt - epoch
+    return delta.total_seconds()
+
+BLOCK_SIZE = 32
+# the character used for padding--with a block cipher such as AES, the value
+# you encrypt must be a multiple of BLOCK_SIZE in length.  This character is
+# used to ensure that your value is always a multiple of BLOCK_SIZE
+PADDING = '{'
+
+# one-liner to sufficiently pad the text to be encrypted
+pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
+
+# create a cipher object using the random secret
+cipher = AES.new(hashlib.md5(settings.SECRET_KEY).hexdigest())
+
+# one-liners to encrypt/encode and decrypt/decode a string
+# encrypt with AES, encode with base64
+encodeAES = lambda s: base64.urlsafe_b64encode(cipher.encrypt(pad(s)))
+decodeAES = lambda e: cipher.decrypt(base64.urlsafe_b64decode(e)).rstrip(PADDING)
--- a/src/egonomy/utils/context_processors.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/utils/context_processors.py	Fri Mar 21 16:25:21 2014 +0100
@@ -1,5 +1,13 @@
+from django.conf import settings
+
 import egonomy
+from egonomy.auth import get_egonomy_token
+
 
 def egonomy_context(request):
-    return {'VERSION': egonomy.get_version() }
+    egonomy_url = getattr(settings, 'EGONOMY_URL', '#')
+    egonomy_token = get_egonomy_token(request)
+    egonomy_token_name = ( getattr(settings, 'EGONOMY_TOKEN_NAME', 'egonomytoken') or 'egonomytoken')
 
+    return {'VERSION': egonomy.get_version(), 'EGONOMY_URL': "%s?%s=%s" % (egonomy_url, egonomy_token_name, egonomy_token) if egonomy_token else egonomy_url }
+
--- a/src/egonomy/views.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/src/egonomy/views.py	Fri Mar 21 16:25:21 2014 +0100
@@ -1,34 +1,42 @@
 from datetime import datetime
+import json
+import logging
+import os
+import subprocess
+from unicodedata import normalize
+import uuid
+
 from django.conf import settings
+from django.contrib.auth import authenticate, login, get_user_model, SESSION_KEY, \
+    load_backend, BACKEND_SESSION_KEY
 from django.contrib.auth.decorators import login_required
-from django.contrib.auth.models import User
 from django.contrib.contenttypes.models import ContentType
 from django.core.paginator import Paginator, InvalidPage, EmptyPage
 from django.core.urlresolvers import reverse
 from django.db.models.aggregates import Max
-from django.http.response import HttpResponseForbidden, HttpResponse
+from django.http.response import HttpResponseForbidden, HttpResponse, \
+    HttpResponseBadRequest
 from django.shortcuts import get_object_or_404, render_to_response, redirect
 from django.template import RequestContext
+from django.utils.importlib import import_module
 from django.utils.translation import ugettext as _
-from egonomy.models import ImageMetadata, Image, Fragment, ImageInfo, Collection,\
+from django.views.decorators.csrf import csrf_exempt
+from haystack.query import RelatedSearchQuerySet
+import requests
+from sorl.thumbnail import default, get_thumbnail
+from sorl.thumbnail.images import ImageFile
+
+from egonomy.auth import parse_egonomy_token
+from egonomy.models import ImageMetadata, Image, Fragment, ImageInfo, Collection, \
     CollectionItem
 from egonomy.search_indexes import QueryParser
 from egonomy.search_indexes.paginator import SearchPaginator
 from egonomy.search_indexes.query import ModelRelatedSearchQuerySet
 from egonomy.utils.queries import cache_generics
-from haystack.query import RelatedSearchQuerySet
-from sorl.thumbnail import default, get_thumbnail
-from sorl.thumbnail.images import ImageFile
-from unicodedata import normalize
-import json
-import os
-import requests
-import subprocess
-import uuid
+
 
-import logging
 logger = logging.getLogger(__name__)
-
+User = get_user_model()
 
 def home(request):
     
@@ -366,7 +374,7 @@
     frg.image = img
     frg.coordinates = frg_path
     # We build the svg xml
-    file_path = os.path.join(settings.MEDIA_ROOT, str(img.info.image_file))
+    filepath = os.path.join(settings.MEDIA_ROOT, str(img.info.image_file))
     image_file = default.kvstore.get_or_set(ImageFile(img.info.image_file))
     ratio = int(100 * frg.ratio * image_file.ratio)
     svg = '<svg preserveAspectRatio="none" width="' + str(ratio) + 'px" height="100px" viewBox="' + frg.viewbox +'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n\
@@ -375,10 +383,10 @@
            <path d="' + frg_path + '" />\n\
        </clipPath>\n\
     </defs>\n\
-    <image xlink:href="' + file_path + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" opacity=".1"/>\n\
-    <image xlink:href="' + file_path + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" clip-path="url(#fragment-clip)"/>\n\
+    <image xlink:href="' + filepath + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" opacity=".1"/>\n\
+    <image xlink:href="' + filepath + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" clip-path="url(#fragment-clip)"/>\n\
 </svg>'
-    # We save the svg file
+    # We save the svg filepath
     uid = str(uuid.uuid1())
     svg_file_path = os.path.join(settings.BATIK_RASTERIZER_TEMP_FOLDER, uid + '.svg')
     svg_file = open(svg_file_path,'w')
@@ -675,7 +683,7 @@
     try:
         col_pk = int(col_pk)
     except:
-        return HttpResponse("Collection number invalid.", status=400)
+        return HttpResponse("Collection number invalid.", status_code=400)
     col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
     # We check if the current user is the collection's author
     if col.author != request.user:
@@ -692,10 +700,10 @@
         try:
             item_id = int(item_id)
         except:
-            return HttpResponse("Fragment number invalid.", status=400)
+            return HttpResponse("Fragment number invalid.", status_code=400)
         item = get_object_or_404(Fragment, pk=item_id)
     else:
-        return HttpResponse("item-type must be 'image' or 'fragment'.", status=400)
+        return HttpResponse("item-type must be 'image' or 'fragment'.", status_code=400)
     
     col_item = CollectionItem()
     col_item.collection = col
@@ -729,7 +737,7 @@
     try:
         col_pk = int(col_pk)
     except:
-        return HttpResponse("Collection number invalid.", status=400)
+        return HttpResponse("Collection number invalid.", status_code=400)
     col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
     # We check if the current user is the collection's author
     if col.author != request.user:
@@ -740,7 +748,7 @@
     
     # Test item's pk
     if not item_pk:
-        return HttpResponse("item_pk must be set.", status=400)
+        return HttpResponse("item_pk must be set.", status_code=400)
     # Get item
     item = get_object_or_404(CollectionItem, pk=item_pk)
     # Everything has been checked, we can delete the item
@@ -764,7 +772,7 @@
     try:
         col_pk = int(col_pk)
     except:
-        return HttpResponse("Collection number invalid.", status=400)
+        return HttpResponse("Collection number invalid.", status_code=400)
     col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
     # We check if the current user is the collection's author
     if col.author != request.user:
@@ -775,11 +783,11 @@
     
     # Test item's pk
     if not item_pk:
-        return HttpResponse("item_pk must be set.", status=400)
+        return HttpResponse("item_pk must be set.", status_code=400)
     # Get item
     item = get_object_or_404(CollectionItem, pk=item_pk)
     if item.collection != col:
-        return HttpResponse("Item and collection are not related.", status=400)
+        return HttpResponse("Item and collection are not related.", status_code=400)
     # Everything has been checked, we can modify and save the item
     item.description = description
     item.save()
@@ -787,8 +795,6 @@
     # It is an ajax call, we juste return "ok"
     return HttpResponse("modifyok")
 
-
-
 @login_required
 def import_collection(request):
     
@@ -855,3 +861,91 @@
 
 
 
+@csrf_exempt
+def ajax_login(request):
+    if request.method == 'POST':
+        username = request.POST.get('username', '').strip()
+        password = request.POST.get('password', '').strip()
+        if username and password:
+            # Test username/password combination
+            user = authenticate(username=username, password=password)
+            # Found a match
+            if user is not None:
+                # User is active
+                if user.is_active:
+                    # Officially log the user in
+                    login(request, user)
+                    data = {'success': True}
+                else:
+                    data = {'success': False, 'error': 'User is not active'}
+            else:
+                data = {'success': False, 'error': 'Wrong username and/or password'}
+
+            return HttpResponse(json.dumps(data), mimetype='application/json')
+
+    # Request method is not POST or one of username or password is missing
+    return HttpResponseBadRequest()
+
+
+
+def check_egonomy_token(request, token):
+    
+    logger.debug("TOKEN : " + token)
+    if not token:
+        return HttpResponseBadRequest("token must be provided")
+    
+    token_items = parse_egonomy_token(token)
+    
+    session_key = token_items.get('sessionid', None)
+    salt = token_items.get('salt', None)
+    
+    error_msg = None
+    
+    if len(token_items) != 2:
+        error_msg = "Bad token size"
+    elif not session_key:
+        error_msg = 'No session id in token'
+    elif not salt or len(salt) != getattr(settings, 'EGONOMY_SALT_LENGTH', 12):
+        error_msg = 'Bad token format'
+        
+    if error_msg:
+        return HttpResponseBadRequest("Bad token format : %s" % error_msg)
+
+    res_msg = {}
+
+    #get session
+    engine = import_module(settings.SESSION_ENGINE)
+    session = engine.SessionStore(session_key)
+    
+    user_id = session.get(SESSION_KEY)
+    auth_backend = load_backend(session.get(BACKEND_SESSION_KEY))
+
+    if session.get_expiry_age() < 0:
+        res_msg['success'] = False
+        res_msg['message'] = "Token expired"
+    elif not user_id or not auth_backend:
+        res_msg['success'] = False
+        res_msg['message'] = "no user"
+    else:
+        user = None
+        try:
+            user = auth_backend.get_user(user_id)
+        except:
+            pass
+
+        if not user:
+            res_msg['success'] = False
+            res_msg['message'] = "user unknown"
+        else:
+            username = getattr(user,User.USERNAME_FIELD)
+            res_msg['success'] = True
+            res_msg['message'] = ""
+            res_msg['username'] = username.replace(settings.EGONOMY_USER_PREFIX,"")
+            res_msg['external'] = username.startswith(settings.EGONOMY_USER_PREFIX)
+            
+    return HttpResponse(json.dumps(res_msg), mimetype='application/json')
+
+
+
+
+
--- a/virtualenv/res/lib/lib_create_env.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/virtualenv/res/lib/lib_create_env.py	Fri Mar 21 16:25:21 2014 +0100
@@ -17,8 +17,8 @@
 URLS = {
     #'': {'setup': '', 'url':'', 'local':''},
     'DISTRIBUTE': {'setup': 'distribute', 'url':'http://pypi.python.org/packages/source/d/distribute/distribute-0.6.31.tar.gz', 'local':"distribute-0.6.31.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
-    'DJANGO': {'setup': 'django', 'url': 'https://www.djangoproject.com/download/1.5/tarball/', 'local':"Django-1.5.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
-    'DJANGO-EXTENSIONS': { 'setup': 'django-extensions', 'url':'https://github.com/django-extensions/django-extensions/archive/1.0.2.tar.gz', 'local':"django-extensions-1.0.2.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'DJANGO': {'setup': 'django', 'url': 'https://www.djangoproject.com/download/1.6.2/tarball/', 'local':"Django-1.6.2.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'DJANGO-EXTENSIONS': { 'setup': 'django-extensions', 'url':'https://github.com/django-extensions/django-extensions/archive/1.3.3.tar.gz', 'local':"django-extensions-1.3.3.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
     'DJANGO-REGISTRATION': { 'setup': 'django-registration', 'url':'https://bitbucket.org/ubernostrum/django-registration/downloads/django-registration-1.0.tar.gz', 'local':"django-registration-1.0.tar.gz", 'install': {'method': 'easy_install', 'option_str': '-Z', 'dict_extra_env': None}},
     'SOUTH': { 'setup': 'South', 'url':'http://www.aeracode.org/releases/south/south-0.7.5.tar.gz', 'local':"south-0.7.5.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
     'SORL_THUMBNAIL' : { 'setup': 'sorl-thumbnail', 'url':'https://github.com/sorl/sorl-thumbnail/archive/master.tar.gz', 'local':"sorl-thumbnail-v11.12.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
@@ -38,7 +38,7 @@
     'PYTZ' : {'setup': 'pytz', 'url':'http://pypi.python.org/packages/source/p/pytz/pytz-2012j.tar.gz', 'local' : 'pytz-2012j.tar.gz', 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
     # dependencies for Tastypie : mimeparse>=0.1.3, python-dateutil>=2.1, lxml, PyYAML (not necessary but we never know), python-digest
     'MIMEPARSE' : {'setup':'mimeparse', 'url':'http://pypi.python.org/packages/source/m/mimeparse/mimeparse-0.1.3.tar.gz', 'local': 'mimeparse-0.1.3.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
-    'SIX' : {'setup':'six', 'url':'http://pypi.python.org/packages/source/s/six/six-1.2.0.tar.gz', 'local': 'six-1.2.0.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},    
+    'SIX' : {'setup':'six', 'url':'https://pypi.python.org/packages/source/s/six/six-1.6.1.tar.gz', 'local': 'six-1.6.1.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},    
     'PYTHON-DATEUTIL' : {'setup':'python-dateutil', 'url':'http://pypi.python.org/packages/source/p/python-dateutil/python-dateutil-2.1.tar.gz', 'local': 'python-dateutil-2.1.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
     'PYYAML' : {'setup':'pyyaml', 'url':'http://pypi.python.org/packages/source/P/PyYAML/PyYAML-3.10.tar.gz', 'local': 'PyYAML-3.10.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
     'PYTHON-DIGEST' : {'setup':'python-digest', 'url':'http://pypi.python.org/packages/source/p/python-digest/python-digest-1.7.tar.gz', 'local': 'python-digest-1.7.tar.gz', 'install' : {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
@@ -46,6 +46,7 @@
     'ISODATE' : {'setup': 'isodate', 'url': 'https://github.com/gweis/isodate/archive/0.4.9.tar.gz', 'local': 'isodate-0.4.9.tar.gz', 'install': {'method':'pip', 'option_str': None, 'dict_extra_env': None}}, 
     'HTML5LIB' : {'setup': 'html5lib', 'url': 'https://html5lib.googlecode.com/files/html5lib-0.95.tar.gz', 'local': 'html5lib-0.95.tar.gz', 'install': {'method':'pip', 'option_str': None, 'dict_extra_env': None}}, 
     'RDFLIB' : {'setup': 'rdflib', 'url': 'https://nodeload.github.com/RDFLib/rdflib/tar.gz/master', 'local': 'rdflib-2.4.0.tar.gz', 'install': {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
+    'PYCRYPTO' : {'setup': 'pycrypto', 'url': 'http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.6.1.tar.gz', 'local': 'pycrypto-2.6.1.tar.gz', 'install': {'method':'pip', 'option_str': None, 'dict_extra_env': None}},
 }
 
 if system_str == 'Windows':
@@ -300,7 +301,12 @@
                     extra_env = {}
                     
                 if 'TMPDIR' not in extra_env:
-                    extra_env['TMPDIR'] = os.path.abspath(tmp_dir)          
+                    extra_env['TMPDIR'] = os.path.abspath(tmp_dir)
+                if system_str == 'Darwin':
+                    archflags = extra_env.get('ARCHFLAGS', '')
+                    if '-Wno-error=unused-command-line-argument-hard-error-in-future' not in archflags:
+                        archflags += " -Wno-error=unused-command-line-argument-hard-error-in-future"
+                        extra_env['ARCHFLAGS'] = archflags.strip()
                 #isinstance(lst, (list, tuple))
                 if key not in ignore_packages:
                     logger.notify("install %s with method %s" % (key, repr(method)))
Binary file virtualenv/res/src/Django-1.5.tar.gz has changed
Binary file virtualenv/res/src/Django-1.6.2.tar.gz has changed
Binary file virtualenv/res/src/django-extensions-1.0.2.tar.gz has changed
Binary file virtualenv/res/src/django-extensions-1.3.3.tar.gz has changed
Binary file virtualenv/res/src/pycrypto-2.6.1.tar.gz has changed
Binary file virtualenv/res/src/six-1.2.0.tar.gz has changed
Binary file virtualenv/res/src/six-1.6.1.tar.gz has changed
--- a/virtualenv/web/res/res_create_env.py	Mon Mar 17 16:18:45 2014 +0100
+++ b/virtualenv/web/res/res_create_env.py	Fri Mar 21 16:25:21 2014 +0100
@@ -28,6 +28,7 @@
     'ISODATE',
     'HTML5LIB',
     'RDFLIB',
+    'PYCRYPTO',
 ]
 
 #if system_str == "Linux" and 'PIL' in INSTALLS: