Index: /extensions/oAuth/admin/template/providers.tpl
===================================================================
--- /extensions/oAuth/admin/template/providers.tpl	(revision 26604)
+++ /extensions/oAuth/admin/template/providers.tpl	(revision 26605)
@@ -128,5 +128,11 @@
       </ol>
     {else}
-      <p>{'No registration required for OpenID based providers'|translate}</p> 
+      <p style="text-align:left;">
+      {if $p=='Flickr' or $p=='Steam' or $p=='Wordpress'}
+        {'Based on OpenID.'|translate}</br>
+      {/if}
+      {'No registration required.'|translate}<br>
+      <a href="{$provider.about_link}" target="_blank">{'About'|translate}</a>
+      </p>
     {/if}
     </div>
Index: /extensions/oAuth/admin/template/style.css
===================================================================
--- /extensions/oAuth/admin/template/style.css	(revision 26604)
+++ /extensions/oAuth/admin/template/style.css	(revision 26605)
@@ -48,5 +48,5 @@
     margin:5px;
   }
-.Wordpress, .OpenID, .Flickr, .Steam {
+.Wordpress, .OpenID, .Flickr, .Steam, .Persona {
   display:inline-block;
 }
Index: /extensions/oAuth/auth.php
===================================================================
--- /extensions/oAuth/auth.php	(revision 26604)
+++ /extensions/oAuth/auth.php	(revision 26605)
@@ -10,5 +10,5 @@
 try {
   // inputs
-  if ( $provider == 'OpenID' and !isset($_GET['openid_identifier']) )
+  if ($provider == 'OpenID' and !isset($_GET['openid_identifier']))
   {
     throw new Exception('Invalid OpenID!', 1003);
@@ -25,18 +25,38 @@
   }
   
-  $hybridauth = new Hybrid_Auth($hybridauth_conf);
+  if ($provider == 'Persona')
+  {
+    $response = persona_verify($_POST['assertion']);
+    
+    if ($response === false || $response['status'] != 'okay')
+    {
+      header('HTTP/1.1 503 Service Unavailable');
+      exit;
+    }
+    else
+    {
+      $oauth_id = array($provider, $response['email']);
+    }
+  }
+  else
+  {
+    $hybridauth = new Hybrid_Auth($hybridauth_conf);
+    
+    // connected
+    if ($hybridauth->isConnectedWith($provider))
+    {
+      $adapter = $hybridauth->getAdapter($provider);
+      $remote_user = $adapter->getUserProfile();
+      
+      $oauth_id = array($provider, $remote_user->identifier);
+    }
+  }
   
-  // connected
-  if ($hybridauth->isConnectedWith($provider))
+  if (!empty($oauth_id))
   {
-    $adapter = $hybridauth->getAdapter($provider);
-    $remote_user = $adapter->getUserProfile();
-    
-    $oauth_id = $provider.'---'.$remote_user->identifier;
-    
     // check is already registered
     $query = '
-SELECT id FROM '.USERS_TABLE.'
-  WHERE oauth_id = "'.$oauth_id.'"
+SELECT id FROM ' . USERS_TABLE . '
+  WHERE oauth_id = "' . implode('---', $oauth_id) . '"
 ;';
     $result = pwg_query($query);
@@ -47,5 +67,5 @@
       log_user($user_id, false);
       
-      $template->assign('REDIRECT_TO', 'default');
+      $redirect_to = 'default';
     }
     // not registered : redirect to register page
@@ -54,13 +74,24 @@
       if ($conf['allow_user_registration'])
       {
-        pwg_set_session_var('oauth_new_user', array($provider,$remote_user->identifier));
-        $template->assign('REDIRECT_TO', 'register');
+        pwg_set_session_var('oauth_new_user', $oauth_id);
+        $redirect_to = 'register';
       }
       else
       {
         $_SESSION['page_errors'][] = l10n('Sorry, new registrations are blocked on this gallery.');
-        $adapter->logout();
-        $template->assign('REDIRECT_TO', 'identification');
+        if (isset($adapter)) $adapter->logout();
+        $redirect_to = 'identification';
       }
+    }
+    
+    if ($provider == 'Persona')
+    {
+      echo json_encode(compact('redirect_to'));
+      header('HTTP/1.1 200 OK');
+      exit;
+    }
+    else
+    {
+      $template->assign('REDIRECT_TO', $redirect_to);
     }
   }
@@ -92,10 +123,14 @@
      5 : Authentication aborded
      6 : User profile request failed
+   404 : User not found
  other errors :
+   503 : Persona error
   1002 : Invalid provider
   1003 : Missing openid_identifier
 */
-catch (Exception $e) {
-  switch ($e->getCode()) {
+catch (Exception $e)
+{
+  switch ($e->getCode())
+  {
     case 5:
       $template->assign('ERROR', l10n('Authentication canceled')); break;
Index: /extensions/oAuth/include/functions.inc.php
===================================================================
--- /extensions/oAuth/include/functions.inc.php	(revision 26604)
+++ /extensions/oAuth/include/functions.inc.php	(revision 26605)
@@ -25,5 +25,5 @@
 function oauth_assign_template_vars($u_redirect=null)
 {
-  global $template, $conf, $hybridauth_conf;
+  global $template, $conf, $hybridauth_conf, $user;
   
   $conf['oauth']['include_common_template'] = true;
@@ -31,8 +31,18 @@
   if ($template->get_template_vars('OAUTH') == null)
   {
+    if (!empty($user['oauth_id']))
+    {
+      list($provider, $identifier) = explode('---', $user['oauth_id'], 2);
+      if ($provider == 'Persona')
+      {
+        $persona_email = $identifier;
+      }
+    }
+    
     $template->assign('OAUTH', array(
       'conf' => $conf['oauth'],
       'u_login' => get_root_url() . OAUTH_PATH . 'auth.php?provider=',
       'providers' => $hybridauth_conf['providers'],
+      'persona_email' => @$persona_email,
       ));
     $template->assign(array(
@@ -70,2 +80,52 @@
   }
 }
+
+// http://www.sitepoint.com/authenticate-users-with-mozilla-persona/
+function persona_verify()
+{
+  $url = 'https://verifier.login.persona.org/verify';
+
+  $assert = filter_input(
+    INPUT_POST,
+    'assertion',
+    FILTER_UNSAFE_RAW,
+    FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH
+    );
+
+  $scheme = 'http';
+  if ( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443 )
+  {
+    $scheme = 'https';
+  }
+  $audience = sprintf(
+    '%s://%s:%s',
+    $scheme,
+    $_SERVER['HTTP_HOST'],
+    $_SERVER['SERVER_PORT']
+    );
+
+  $params = 'assertion=' . urlencode($assert) . '&audience=' . urlencode($audience);
+
+  $options = array(
+    CURLOPT_URL => $url,
+    CURLOPT_RETURNTRANSFER => true,
+    CURLOPT_POST => true,
+    CURLOPT_POSTFIELDS => $params,
+    CURLOPT_SSL_VERIFYPEER => true,
+    CURLOPT_SSL_VERIFYHOST => 2,
+    );
+
+  $ch = curl_init();
+  curl_setopt_array($ch, $options);
+  $result = curl_exec($ch);
+  curl_close($ch);
+  
+  if ($result === false)
+  {
+    return false;
+  }
+  else
+  {
+    return json_decode($result, true);
+  }
+}
Index: /extensions/oAuth/include/providers_stats.inc.php
===================================================================
--- /extensions/oAuth/include/providers_stats.inc.php	(revision 26604)
+++ /extensions/oAuth/include/providers_stats.inc.php	(revision 26605)
@@ -55,4 +55,5 @@
     'provider_name'     => 'OpenID',
     'new_app_link'      => null,
+    'about_link'        => 'http://openid.net/get-an-openid/what-is-openid/',
   ),
   'Flickr' => array( 
@@ -60,4 +61,5 @@
     'provider_name'     => 'Flickr',
     'new_app_link'      => null,
+    'about_link'        => 'http://openid.net/get-an-openid/what-is-openid/',
   ),
   'Steam' => array( 
@@ -65,4 +67,5 @@
     'provider_name'     => 'Steam',
     'new_app_link'      => null,
+    'about_link'        => 'http://openid.net/get-an-openid/what-is-openid/',
   ),
   'Wordpress' => array( 
@@ -70,4 +73,11 @@
     'provider_name'     => 'Wordpress',
     'new_app_link'      => null,
+    'about_link'        => 'http://openid.net/get-an-openid/what-is-openid/',
   ),
+  'Persona' => array(
+    'label'             => 'Persona',
+    'provider_name'     => 'Persona',
+    'new_app_link'      => null,
+    'about_link'        => 'https://login.persona.org/about',
+    ),
 );
Index: /extensions/oAuth/include/public_events.inc.php
===================================================================
--- /extensions/oAuth/include/public_events.inc.php	(revision 26604)
+++ /extensions/oAuth/include/public_events.inc.php	(revision 26605)
@@ -9,5 +9,5 @@
   global $template, $conf, $hybridauth_conf;
   
-  if ($hybridauth_conf['enabled'] > 0)
+  if ($hybridauth_conf['enabled'] == 0)
   {
     return;
@@ -37,5 +37,5 @@
   {
     list($oauth_id) = pwg_db_fetch_row($result);
-    list($provider) = explode('---', $oauth_id);
+    list($provider) = explode('---', $oauth_id, 2);
     $_SESSION['page_errors'][] = l10n('You registered with a %s account, please sign in with the same account.', $provider);
     
@@ -65,28 +65,45 @@
     list($provider, $user_identifier) = pwg_get_session_var('oauth_new_user');
     
-    require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
-    
     try {
-      $hybridauth = new Hybrid_Auth($hybridauth_conf);
-      $adapter = $hybridauth->authenticate($provider);
-      $remote_user = $adapter->getUserProfile();
-      
-      // security, check remote identifier
-      if ($remote_user->identifier != $user_identifier)
+      if ($provider == 'Persona')
       {
-        pwg_unset_session_var('oauth_new_user');
-        throw new Exception('Hacking attempt!', 403);
+        $template->assign('OAUTH_USER', array(
+          'provider' => $provider,
+          'username' => $user_identifier,
+          'u_profile' => null,
+          'avatar' => null,
+          ));
+        
+        oauth_assign_template_vars();
+        $template->append('OAUTH', array('persona_email'=>$user_identifier), true);
+      
+        $conf['oauth']['include_common_template'] = true;
       }
-    
-      $template->assign('OAUTH_USER', array(
-        'provider' => $provider,
-        'username' => $remote_user->displayName,
-        'u_profile' => $remote_user->profileURL,
-        'avatar' => $remote_user->photoURL,
-        ));
+      else
+      {
+        require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
         
+        $hybridauth = new Hybrid_Auth($hybridauth_conf);
+        $adapter = $hybridauth->authenticate($provider);
+        $remote_user = $adapter->getUserProfile();
+        
+        // security, check remote identifier
+        if ($remote_user->identifier != $user_identifier)
+        {
+          pwg_unset_session_var('oauth_new_user');
+          throw new Exception('Hacking attempt!', 403);
+        }
+      
+        $template->assign('OAUTH_USER', array(
+          'provider' => $provider,
+          'username' => $remote_user->displayName,
+          'u_profile' => $remote_user->profileURL,
+          'avatar' => $remote_user->photoURL,
+          ));
+      }
+      
+      $oauth_id = $provider.'---'.$user_identifier;
+      
       $page['infos'][] = l10n('Your registration is almost done, please complete the registration form.');
-      
-      $oauth_id = $provider.'---'.$remote_user->identifier;
       
       // form submited
@@ -124,6 +141,14 @@
       {
         // overwrite fields with remote datas
-        $_POST['login'] = $remote_user->displayName;
-        $_POST['mail_address'] = $remote_user->email;
+        if ($provider == 'Persona')
+        {
+          $_POST['login'] = '';
+          $_POST['mail_address'] = $user_identifier;
+        }
+        else
+        {
+          $_POST['login'] = $remote_user->displayName;
+          $_POST['mail_address'] = $remote_user->email;
+        }
       }
       
@@ -133,5 +158,6 @@
       $template->set_prefilter('register', 'oauth_remove_password_fields_prefilter');
     }
-    catch (Exception $e) {
+    catch (Exception $e)
+    {
       $page['errors'][] = l10n('An error occured, please contact the gallery owner. <i>Error code : %s</i>', $e->getCode());
     }
@@ -152,28 +178,38 @@
 function oauth_begin_profile()
 {
-  global $template, $user, $hybridauth_conf, $page;
-  
-  $oauth_id = get_oauth_id($user['id']);
-  
-  if (!isset($oauth_id))
-  {
-    return;
-  }
-  
-  list($provider) = explode('---', $oauth_id);
-  
-  require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
+  global $template, $user, $hybridauth_conf, $page, $user;
+  
+  if (empty($user['oauth_id']))
+  {
+    return;
+  }
+  
+  list($provider, $user_identifier) = explode('---', $user['oauth_id'], 2);
   
   try {
-    $hybridauth = new Hybrid_Auth($hybridauth_conf);
-    $adapter = $hybridauth->getAdapter($provider);
-    $remote_user = $adapter->getUserProfile();
-    
-    $template->assign('OAUTH_USER', array(
-      'provider' => $provider,
-      'username' => $remote_user->displayName,
-      'u_profile' => $remote_user->profileURL,
-      'avatar' => $remote_user->photoURL,
-      ));
+    if ($provider == 'Persona')
+    {
+      $template->assign('OAUTH_USER', array(
+        'provider' => $provider,
+        'username' => $user_identifier,
+        'u_profile' => null,
+        'avatar' => null,
+        ));
+    }
+    else
+    {
+      require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
+      
+      $hybridauth = new Hybrid_Auth($hybridauth_conf);
+      $adapter = $hybridauth->getAdapter($provider);
+      $remote_user = $adapter->getUserProfile();
+      
+      $template->assign('OAUTH_USER', array(
+        'provider' => $provider,
+        'username' => $remote_user->displayName,
+        'u_profile' => $remote_user->profileURL,
+        'avatar' => $remote_user->photoURL,
+        ));
+    }
     
     $template->assign('OAUTH_PATH', OAUTH_PATH);
@@ -181,5 +217,6 @@
     $template->set_prefilter('profile_content', 'oauth_remove_password_fields_prefilter');
   }
-  catch (Exception $e) {
+  catch (Exception $e)
+  {
     $page['errors'][] = l10n('An error occured, please contact the gallery owner. <i>Error code : %s</i>', $e->getCode());
   }
@@ -201,15 +238,19 @@
   }
 
-  list($provider) = explode('---', $oauth_id);
-  
-  require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
-  
-  try {
-    $hybridauth = new Hybrid_Auth($hybridauth_conf);
-    $adapter = $hybridauth->getAdapter($provider);
-    $adapter->logout();
-  }
-  catch (Exception $e) {
-    $_SESSION['page_errors'][] = l10n('An error occured, please contact the gallery owner. <i>Error code : %s</i>', $e->getCode());
+  list($provider, $identifier) = explode('---', $oauth_id, 2);
+  
+  
+  if ($provider != 'Persona')
+  {
+    require_once(OAUTH_PATH . 'include/hybridauth/Hybrid/Auth.php');
+    
+    try {
+      $hybridauth = new Hybrid_Auth($hybridauth_conf);
+      $adapter = $hybridauth->getAdapter($provider);
+      $adapter->logout();
+    }
+    catch (Exception $e) {
+      $_SESSION['page_errors'][] = l10n('An error occured, please contact the gallery owner. <i>Error code : %s</i>', $e->getCode());
+    }
   }
 }
@@ -233,13 +274,18 @@
   }
   
-  oauth_assign_template_vars(get_gallery_home_url());
+  $u_redirect = !empty($_GET['redirect']) ? urldecode($_GET['redirect']) : get_gallery_home_url();
+  oauth_assign_template_vars($u_redirect);
   
   $template->set_prefilter('menubar', 'oauth_add_menubar_buttons_prefilter');
 }
 
-function oauth_include_template()
+
+/**
+ * load common javascript
+ */
+function oauth_page_header()
 {
   global $conf, $template;
-  
+
   if (isset($conf['oauth']['include_common_template']))
   {
Index: /extensions/oAuth/main.inc.php
===================================================================
--- /extensions/oAuth/main.inc.php	(revision 26604)
+++ /extensions/oAuth/main.inc.php	(revision 26605)
@@ -20,7 +20,7 @@
 
 
+global $hybridauth_conf, $conf;
+
 // try to load hybridauth config
-global $hybridauth_conf;
-
 include_once(OAUTH_PATH . 'include/functions.inc.php');
 
@@ -29,4 +29,7 @@
   load_hybridauth_conf();
 }
+
+// force getuserdata() to retrieve 'oauth_id' field
+$conf['user_fields']['oauth_id'] = 'oauth_id';
 
 
@@ -43,5 +46,5 @@
   add_event_handler('loc_begin_profile', 'oauth_begin_profile');
   
-  add_event_handler('loc_after_page_header', 'oauth_include_template');
+  add_event_handler('loc_after_page_header', 'oauth_page_header');
   
   add_event_handler('try_log_user', 'oauth_try_log_user', EVENT_HANDLER_PRIORITY_NEUTRAL-30, 2);
@@ -98,4 +101,6 @@
     // }
   // }
+  
+  // pwg_unset_session_var('persona_logout');
 }
 
Index: /extensions/oAuth/template/identification_common.tpl
===================================================================
--- /extensions/oAuth/template/identification_common.tpl	(revision 26604)
+++ /extensions/oAuth/template/identification_common.tpl	(revision 26605)
@@ -3,4 +3,8 @@
 {combine_script id='jquery.colorbox' load='footer' require='jquery' path='themes/default/js/plugins/jquery.colorbox.min.js'}
 {combine_css id='colorbox' path="themes/default/js/plugins/colorbox/style2/colorbox.css"}
+
+{if $OAUTH.providers.Persona.enabled}
+  {combine_script id='persona' path='https://login.persona.org/include.js' load='footer'}
+{/if}
 
 {html_style}
@@ -31,5 +35,5 @@
 
 // click on a button
-jQuery('a.oauth').click(function(e) {
+jQuery('a.oauth:not(.persona)').click(function(e) {
   e.preventDefault();
   
@@ -100,4 +104,39 @@
   jQuery.colorbox.close();
 });
+
+{if $OAUTH.providers.Persona.enabled}
+jQuery('a.oauth.persona').click(function(e) {
+  e.preventDefault();
+  navigator.id.request();
+});
+
+jQuery('a[href$="act=logout"]').click(function(e) {
+  e.preventDefault();
+  navigator.id.logout();
+});
+
+navigator.id.watch({
+  loggedInUser: {if not empty($OAUTH.persona_email)}'{$OAUTH.persona_email}'{else}null{/if},
+  
+  onlogin: function(assertion) {
+    jQuery.ajax({
+      type: 'POST',
+      url: '{$OAUTH.u_login}Persona',
+      dataType: 'json',
+      data: { assertion: assertion },
+      success: function(data) {
+        oauth_redirect(data.redirect_to);
+      },
+      error: function() {
+        alert('Unknown error');
+      }
+    });
+  },
+  
+  onlogout: function() {
+    window.location.href = '{$U_LOGOUT}';
+  }
+});
+{/if}
 {/footer_script}
 
Index: /extensions/oAuth/template/oauth_sprites.css
===================================================================
--- /extensions/oAuth/template/oauth_sprites.css	(revision 26604)
+++ /extensions/oAuth/template/oauth_sprites.css	(revision 26605)
@@ -17,4 +17,5 @@
 .oauth_16px.yahoo { background-position: -160px 0px; }
 .oauth_16px.steam { background-position: -176px 0px; }
+.oauth_16px.persona { background-position: -192px 0px; }
 
 .oauth_26px {
@@ -36,4 +37,5 @@
 .oauth_26px.yahoo { background-position: -260px 0px; }
 .oauth_26px.steam { background-position: -286px 0px; }
+.oauth_26px.persona { background-position: -312px 0px; }
 
 .oauth_38px {
@@ -55,2 +57,3 @@
 .oauth_38px.yahoo { background-position: -380px 0px; }
 .oauth_38px.steam { background-position: -418px 0px; }
+.oauth_38px.persona { background-position: -456px 0px; }
