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.
 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 
 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
 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
 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.
 is carried over from Drupal for each logged-in user.
 
 
+
 Pros and cons
 Pros and cons
 -------------
 -------------
 
 
 * Pros
 * 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
     * 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 
     * The Drupal instance authorizes the Meteor applications in advance 
     * A Drupal instance can authorize multiple Meteor applications
     * A Drupal instance can authorize multiple Meteor applications
     * Supports Drupal 8 instances
     * Supports Drupal 8 instances
 * Cons
 * 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
     * 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
     * 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 
     * 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({
 Package.describe({
   name: 'fgm:drupal-sso',
   name: 'fgm:drupal-sso',
   version: '0.0.1',
   version: '0.0.1',
-  summary: 'A transparent authentication package for Drupal',
+  summary: 'A transparent authentication package for Drupal 8',
   // git: '',
   // git: '',
   documentation: 'README.md'
   documentation: 'README.md'
 });
 });
 
 
 Package.onUse(function(api) {
 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');
   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) {
 Package.onTest(function(api) {
@@ -35,6 +22,3 @@ Package.onTest(function(api) {
   api.use('fgm:drupal-sso');
   api.use('fgm:drupal-sso');
   api.addFiles('drupal-sso-tests.js');
   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!
 // Write your package code here!
+