Browse Source

First acceptable-looking part: SSO initialization.

Frederic G. MARAND 8 years ago
parent
commit
79862964d0
7 changed files with 183 additions and 28 deletions
  1. 9 0
      .jshintrc
  2. 27 6
      README.md
  3. 0 0
      client/sso.js
  4. 88 0
      lib/startup.js
  5. 6 22
      package.js
  6. 52 0
      server/sso.js
  7. 1 0
      sso.js

+ 9 - 0
.jshintrc

@@ -0,0 +1,9 @@
+//.jshintrc
+{
+  "globals" : {
+
+
+    // A fictive global just added for the last comma.
+    "xyzzy": false
+  }
+}

+ 27 - 6
README.md

@@ -4,8 +4,29 @@ Drupal SSO
 The Drupal SSO package provides transparent authentication integration with a Drupal instance.
  
 
-What does this mean ?
----------------------
+Usage
+-----
+
+* Add the package to the application: `meteor add fgm:drupal-sso`
+* Add and enable the Meteor module to your Drupal server
+    * Obtain an application token from the module for your Meteor app
+* Configure a `drupal-sso` section in your `settings.json`, like:
+
+        {
+        'drupal-sso': {
+          "site": "http://example.com",
+          "appToken": "the application token you got from the Meteor module"
+          }
+        }
+* In the app startup, initialize a SSO instance: `SSO = new DrupalSSO();`
+* Once this is done, your application can use the SSO methods, passive and reactive data sources:
+    * Reactive: `userId()`, `userName()`,  `userRoles()`
+    * Passive: `state.sessionName`, `state.anonymousName`, `state.online`
+* You may delay until initialization by the Drupal server has completed by waiting on `SSO.state.online` until it is no longer `undefined`.    
+
+
+What exactly does this provide ?
+--------------------------------
 
 Unlike Meteor, Drupal relies by default on cookie-based authentication. This 
 package makes use of the Drupal session cookie to authenticate the user with the
@@ -14,19 +35,19 @@ Drupal instance having created the cookie.
 It enables adding Meteor pages to a Drupal site without having to care for authentication, which
 is carried over from Drupal for each logged-in user.
 
+
 Pros and cons
 -------------
 
 * Pros
-    * Unlike OAuth-based users Meteor packages, users never see any authentication 
-      request from the backend Drupal instance
+    * Unlike OAuth-based users Meteor packages, users never see any authentication request from the backend Drupal instance, making the whole process transparent
     * The user experience is seamless authentication-wise: users can link from a Drupal page to a Meteor page and vice-versa and their credentials track them
+    * Logging out of Drupal automatically logs the user out of Meteor too
     * The Drupal instance authorizes the Meteor applications in advance 
     * A Drupal instance can authorize multiple Meteor applications
     * Supports Drupal 8 instances
 * Cons
-    * This is a one-off, _ad hoc_ mechanism, not a standards-based approach like
-      OAuth
+    * This is a one-off, _ad hoc_ mechanism, not a standards-based approach like OAuth
     * This package does not (currently) provide integration with the Meteor accounts API
     * The authentication targets a single Drupal instance for a given application, preventing integration with multiple backends, as a NOC-type dashboard applciation might need
     * Does not support Drupal 7, BackdropCMS, nor earlier Drupal versions 

+ 0 - 0
client/sso.js


+ 88 - 0
lib/startup.js

@@ -0,0 +1,88 @@
+/**
+ * The SSO constructor.
+ *
+ * Notice that the returned sso instance has asynchronous behavior: its state
+ * component will only be initialized once the server callback has returned,
+ * which will almost always be some milliseconds after the instance itself is
+ * returned: check sso.state.online to ensure the connection attempts is done:
+ * - undefined -> not yet
+ * -> false -> failed, values are defaults,
+ * -> true -> succeeded,valuers are those provided by the server.
+ *
+ * @param {string} document_cookies
+ * @returns {DrupalSSO}
+ * @constructor
+ */
+DrupalSSO = function (document_cookies) {
+  // Called without `new`: call with it.
+  if (!(this instanceof DrupalSSO)) {
+    return new DrupalSSO(document_cookies);
+  }
+
+  // Work around "this" interpretation in local scope methods.
+  var that = this;
+
+  this.settings = {
+    client: {}
+  };
+
+  this.state = {
+    anonymousName: 'anome',
+    cookieName: 'SESS___4___8__12__16__20__24__28__32',
+    // Online is only set once the initialization has completed.
+    online: undefined
+  };
+
+  var user = {
+    uid: 0,
+    name: 'undefined name',
+    roles: ['anonymous user']
+  };
+
+  var userDep = new Tracker.Dependency();
+
+  this.getUserId = function () {
+    userDep.depend();
+    return user.uid;
+  };
+
+  this.getUserName = function () {
+    userDep.depend();
+    return user.name;
+  };
+
+  this.getUserRoles = function () {
+    userDep.depend();
+    return user.roles;
+  };
+
+  /**
+   * Parse a cookie blob for value of the relevant session cookie.
+   *
+   * @param {string} cookieBlob
+   * @returns {undefined}
+   */
+  this.getSessionCookie = function (cookieBlob) {
+    cookieBlob = '; ' + cookieBlob;
+
+    var cookieName = that.state.cookieName;
+    var cookieValue = undefined;
+    var cookies = cookieBlob.split('; ' + cookieName + "=");
+
+    if (cookies.length == 2) {
+      cookieValue = cookies.pop().split(';').shift();
+    }
+
+    return cookieValue;
+  }
+
+  // Constructor body.
+  _.extend(that.settings.client, Meteor.settings.public);
+
+  Meteor.call('drupal-sso.initState', function (err, res) {
+    if (err) {
+      throw new Meteor.Error('init-state', err);
+    }
+    _.extend(that.state, res);
+  });
+};

+ 6 - 22
package.js

@@ -1,33 +1,20 @@
 Package.describe({
   name: 'fgm:drupal-sso',
   version: '0.0.1',
-  summary: 'A transparent authentication package for Drupal',
+  summary: 'A transparent authentication package for Drupal 8',
   // git: '',
   documentation: 'README.md'
 });
 
 Package.onUse(function(api) {
-  // If no version is specified for an 'api.use' dependency, use the one defined in Meteor 0.9.0.
   api.versionsFrom('1.1.0.3');
 
-  // Need to addFiles() for each file in the package.
-  api.addFiles('drupal-sso.js');
+  api.addFiles('lib/startup.js');
+  api.addFiles('client/sso.js', 'client');
+  api.addFiles('server/sso.js', 'server');
+  api.addFiles('sso.js');
 
-  // This is a reactive source exposing the user session information.
-  api.export('DrupalSession');
-  // This contains the server-only information for the Drupal instance:
-  // - The application token
-  api.export('DrupalServer', 'server');
-
-  //* @var "client", "server", "web.browser", or "web.cordova".
-  // var architecture
-  //   When not specified, component is available everywhere.
-
-  //* @var { weak: Boolean, unordered: Boolean }
-  // var options
-  //   both options default to false.
-
-  // api.use('packagename@version', architecture, options)
+  api.export('DrupalSSO');
 });
 
 Package.onTest(function(api) {
@@ -35,6 +22,3 @@ Package.onTest(function(api) {
   api.use('fgm:drupal-sso');
   api.addFiles('drupal-sso-tests.js');
 });
-
-// Npm.depends({ packageName: "version", ... });
-// Cordova.depends({ packageName: "version", packageName2: "http://packageName2.tar", ... });

+ 52 - 0
server/sso.js

@@ -0,0 +1,52 @@
+// Cause an error on startup if the Drupal server is unreachable.
+Meteor.startup(function () {
+  sso = new DrupalSSO();
+  if (!sso.state.online) {
+    throw new Meteor.Error('startup', "Could not reach the Drupal server.");
+  }
+});
+
+Meteor.methods({
+  /**
+   * Parse Meteor settings to initialize the SSO state from the server.
+   */
+  "drupal-sso.initState": function () {
+    var settings = Meteor.settings['drupal-sso'];
+    var site = settings.site;
+    var appToken = settings.appToken;
+
+    if (!settings) {
+      throw new Meteor.Error('invalid-settings', "Invalid settings: 'drupal-sso' key not found.");
+    }
+    if (!site) {
+      throw new Meteor.Error('invalid-settings', "Invalid settings: 'drupal-sso.site' key not found.");
+    }
+    if (!appToken) {
+      throw new Meteor.Error('invalid-settings', "Invalid settings: 'drupal-sso.appToken' key not found.");
+    }
+
+    var options = {
+      params: {
+        appToken: settings.appToken
+      }
+    };
+    try {
+      var ret = HTTP.get(site + "/meteor/siteInfo", options);
+      info = JSON.parse(ret.content);
+      info.online = true;
+    }
+    catch (err) {
+      info = {
+        cookieName: undefined,
+        anonymousName: undefined,
+        online: false
+      };
+      Meteor._debug("Error: ", err);
+    }
+    Meteor._debug("initState returning", info);
+    return info;
+  },
+
+  "drupal-sso.whoami": function () {
+  },
+});

+ 1 - 0
drupal-sso.js → sso.js

@@ -1 +1,2 @@
 // Write your package code here!
+