From a840c4ad53f6075f3b562ed4346a319e72b852b9 Mon Sep 17 00:00:00 2001
From: Rob Loach <robloach@gmail.com>
Date: Wed, 6 Apr 2011 16:56:51 -0400
Subject: [PATCH] Issue #423684: Disqus Single Sign-On for Drupal.

---
 disqus.admin.inc |   46 ++++++++++++++++++++++++++++++++++---
 disqus.install   |    3 ++
 disqus.js        |   19 +++++++++++----
 disqus.module    |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 121 insertions(+), 12 deletions(-)

diff --git a/disqus.admin.inc b/disqus.admin.inc
index b67892a..ec15728 100644
--- a/disqus.admin.inc
+++ b/disqus.admin.inc
@@ -11,6 +11,7 @@ function disqus_admin_settings() {
     '#description' => t('The domain that you registered Disqus with. If you registered http://example.disqus.com, you would enter "example" here.'),
     '#default_value' => variable_get('disqus_domain', ''),
   );
+  // Visibility settings.
   $form['visibility'] = array(
     '#type' => 'fieldset',
     '#title' => t('Visibility'),
@@ -42,29 +43,66 @@ function disqus_admin_settings() {
     '#default_value' => variable_get('disqus_weight', 50),
     '#options' => drupal_map_assoc(array(-100, -75, -50, -25, 0, 25, 50, 75, 100)),
   );
-  $form['disqus_behavior'] = array(
+  // Behavior settings.
+  $form['behavior'] = array(
     '#type' => 'fieldset',
     '#title' => t('Behavior'),
     '#collapsed' => TRUE,
     '#collapsible' => TRUE,
   );
-  $form['disqus_behavior']['disqus_userapikey'] = array(
+  $form['behavior']['disqus_userapikey'] = array(
     '#type' => 'textfield',
     '#title' => t('User API Key'),
     '#description' => t('The API key of the administrator account on Disqus. You can get yours <a href="@key">here</a>.', array('@key' => 'http://disqus.com/api/get_my_key/')),
     '#default_value' => variable_get('disqus_userapikey', ''),
   );
-  $form['disqus_behavior']['disqus_localization'] = array(
+  $form['behavior']['disqus_localization'] = array(
     '#type' => 'checkbox',
     '#title' => t('Localization support'),
     '#description' => t("When enabled, overrides the language set by Disqus with the language provided by the site."),
     '#default_value' => variable_get('disqus_localization', FALSE),
   );
-  $form['disqus_behavior']['disqus_developer'] = array(
+  $form['behavior']['disqus_developer'] = array(
     '#type' => 'checkbox',
     '#title' => t('Testing'),
     '#description' => t('When enabled, uses the <a href="http://disqus.com/help/#faq-14">disqus_developer</a> flag to tell Disqus that you are in a testing environment. Threads will not display on the public community page with this set.'),
     '#default_value' => variable_get('disqus_developer', FALSE),
   );
+  // Advanced settings.
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced'),
+    '#collapsed' => TRUE,
+    '#collapsible' => TRUE,
+    '#description' => t('Use these settings to configure the more advanced uses of Disqus. You can find ore information about these in the <a href="@applications">Applications</a> section of Disqus.', array(
+      '@applications' => 'http://disqus.com/api/applications/',
+    )),
+  );
+  $form['advanced']['disqus_publickey'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Public Key'),
+    '#default_value' => variable_get('disqus_publickey', ''),
+  );
+  $form['advanced']['disqus_secretkey'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Secret Key'),
+    '#default_value' => variable_get('disqus_secretkey', ''),
+  );
+  $form['advanced']['disqus_sso'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Single Sign-On'),
+    '#description' => t('Provide <a href="@sso">Single Sign-On</a> access to your site.', array(
+      '@sso' => 'http://disqus.com/api/sso/',
+    )),
+    '#default_value' => variable_get('disqus_sso', FALSE),
+  );
   return system_settings_form($form);
 }
+
+/**
+ * Menu callback; Automatically closes the window after the user logs in.
+ */
+function disqus_closewindow() {
+  drupal_add_js('window.close();', 'inline');
+  return t('Thank you for logging in. Please close this window, or <a href="@clickhere">click here</a> to continue.', array('@clickhere' => 'javascript:window.close();'));
+}
diff --git a/disqus.install b/disqus.install
index 4abe791..819d75d 100644
--- a/disqus.install
+++ b/disqus.install
@@ -13,6 +13,9 @@ function disqus_uninstall() {
   variable_del('disqus_userapikey');
   variable_del('disqus_nodetypes');
   variable_del('disqus_developer');
+  variable_del('disqus_sso');
+  variable_del('disqus_secretkey');
+  variable_del('disqus_publickey');
   drupal_uninstall_schema('disqus');
 }
 
diff --git a/disqus.js b/disqus.js
index 2ad38aa..50512c5 100644
--- a/disqus.js
+++ b/disqus.js
@@ -39,12 +39,21 @@ Drupal.behaviors.disqus = function(context) {
       disqus_def_name = disqus.name || null;
       disqus_def_email = disqus.email || null;
 
-      // Assign the language.
-      if (disqus.language || false) {
-        disqus_config = function() {
+      // Language and SSO settings are passed in through disqus_config().
+      disqus_config = function() {
+        if (disqus.language || false) {
           this.language = disqus.language;
-        };
-      }
+        }
+        if (disqus.remote_auth_s3 || false) {
+          this.page.remote_auth_s3 = disqus.remote_auth_s3;
+        }
+        if (disqus.api_key || false) {
+          this.page.api_key = disqus.api_key;
+        }
+        if (disqus.sso || false) {
+          this.sso = disqus.sso;
+        }
+      };
 
       // Make the AJAX call for the comment thread.
       jQuery.ajax({
diff --git a/disqus.module b/disqus.module
index 6960357..ac04e80 100644
--- a/disqus.module
+++ b/disqus.module
@@ -47,6 +47,14 @@ function disqus_menu() {
     'description' => 'Provides general configuration options for the Disqus comment system.',
     'weight' => -10,
   );
+  $items['disqus/closewindow'] = array(
+    'title' => 'Please wait',
+    'description' => 'Once the user logs in through the Disqus login workflow, they are redirected here to automatically close the popup window.',
+    'access arguments' => array('access content'),
+    'page callback' => 'disqus_closewindow',
+    'file' => 'disqus.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
@@ -160,9 +168,9 @@ function disqus_form_alter(&$form, $form_state, $form_id) {
     $form['comment_settings']['disqus'] = array(
       '#tree' => TRUE,
       'status' => array(
-          '#type' => 'checkbox',
-          '#title' => t('Enable Disqus comments'),
-          '#default_value' => isset($node->disqus['status']) ? $node->disqus['status'] : TRUE,
+        '#type' => 'checkbox',
+        '#title' => t('Enable Disqus comments'),
+        '#default_value' => isset($node->disqus['status']) ? $node->disqus['status'] : TRUE,
       ),
     );
   }
@@ -426,6 +434,57 @@ function disqus_footer($main = 0, $options = NULL) {
         $settings['language'] = $language->language;
       }
 
+      // Check if we are to provide Single Sign-On access.
+      if (variable_get('disqus_sso', FALSE)) {
+        $data = array();
+
+        // Inject the user data if it's available.
+        if ($user->uid > 0) {
+          $data['id'] = $user->uid;
+          $data['username'] = $user->name;
+          $data['email'] = $user->mail;
+          $data['url'] = url('user/' . $user->uid, array('absolute' => TRUE));
+
+          // Load the user's avatar.
+          $user_picture_default = variable_get('user_picture_default', '');
+          if (isset($user->picture) && !empty($user->picture)) {
+            $data['avatar'] = url($user->picture, array('absolute' => TRUE));
+          }
+          elseif (!empty($user_picture_default)) {
+            $data['avatar'] = url($user_picture_default, array('absolute' => TRUE));
+          }
+        }
+
+        // Give Disqus information about the site.
+        $settings['sso'] = array(
+          'name' => variable_get('site_name', t('Drupal')),
+          // The login window must be closed once the user logs in.
+          'url' => url('user/login', array('query' => array('destination' => 'disqus/closewindow'))),
+          // The logout link must redirect back to the original page.
+          'logout' => url('logout', array('query' => array('destination' => $_GET['q']))),
+          'width' => 800,
+          'height' => 600,
+        );
+        if ($logo = theme_get_setting('logo')) {
+          $settings['sso']['button'] = $logo;
+        }
+        else {
+          $settings['sso']['button'] = url('misc/druplicon.png', array('absolute' => TRUE));
+        }
+        if ($favicon = theme_get_setting('favicon')) {
+          $settings['sso']['icon'] = $favicon;
+        }
+
+        // Encode the data to be sent off to Disqus.
+        $message = base64_encode(json_encode($data));
+        $timestamp = time();
+        $hmac = hash_hmac('sha1', "$message $timestamp", variable_get('disqus_secretkey', ''));
+
+        // Stick the authentication requirements and data in the settings.
+        $settings['remote_auth_s3'] = "$message $hmac $timestamp";
+        $settings['api_key'] = variable_get('disqus_publickey', '');
+      }
+
       // Add the JavaScript.
       drupal_add_js(array(
         'disqus' => $settings,
-- 
1.7.2.1

