From 9ef62a475aec9bba333bee7f82ea39087e16ae0a Mon Sep 17 00:00:00 2001
From: Pandaiolo <aurelien@arimaska.net>
Date: Sun, 21 Sep 2014 23:04:21 +0200
Subject: [PATCH] Compliance with loopback 2.x models declaration

---
 docs.json                              |   1 +
 lib/index.js                           |  25 ++-
 lib/models/application-credential.js   | 120 +++++-------
 lib/models/application-credential.json |  25 +++
 lib/models/user-credential.js          |  77 ++++++++
 lib/models/user-credential.json        |  42 ++++
 lib/models/user-identity.js            | 345 +++++++++++----------------------
 lib/models/user-identity.json          |  43 ++++
 lib/passport-configurator.js           |   9 +-
 test/model.user-credential.test.js     |  88 +++++++++
 test/model.user-identity.test.js       |  83 +-------
 11 files changed, 463 insertions(+), 395 deletions(-)
 create mode 100644 lib/models/application-credential.json
 create mode 100644 lib/models/user-credential.js
 create mode 100644 lib/models/user-credential.json
 create mode 100644 lib/models/user-identity.json
 create mode 100644 test/model.user-credential.test.js

diff --git a/docs.json b/docs.json
index da47e54..2d91ca2 100644
--- a/docs.json
+++ b/docs.json
@@ -2,6 +2,7 @@
   "title": "LoopBack Passport Integration",
   "content": [
     "lib/models/user-identity.js",
+    "lib/models/user-credential.js",
     "lib/models/application-credential.js",
     "lib/passport-configurator.js"
   ]
diff --git a/lib/index.js b/lib/index.js
index d6d95a2..8a08b1b 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,10 +1,25 @@
-var uid = require('./models/user-identity');
-exports.UserIdentity = uid.UserIdentity;
-exports.UserCredential = uid.UserCredential;
-exports.ApplicationCredential = require('./models/application-credential');
+var loopback = require('loopback');
+var DataModel = loopback.PersistedModel || loopback.DataModel;
+
+function loadModel(jsonFile) {
+  var modelDefinition = require(jsonFile);
+  return DataModel.extend(modelDefinition.name,
+                          modelDefinition.properties,
+                          {
+                            relations: modelDefinition.relations
+                          });
+}
+
+var UserIdentityModel = loadModel('./models/user-identity.json');
+var UserCredentialModel = loadModel('./models/user-credential.json');
+var ApplicationCredentialModel = loadModel('./models/application-credential.json');
+
+exports.UserIdentity = require('./models/user-identity')(UserIdentityModel);
+exports.UserCredential = require('./models/user-credential')(UserCredentialModel);
+exports.ApplicationCredential = require('./models/application-credential')(ApplicationCredentialModel);
 
 exports.UserIdentity.autoAttach = 'db';
 exports.UserCredential.autoAttach = 'db';
 exports.ApplicationCredential.autoAttach = 'db';
 
-exports.PassportConfigurator = require('./passport-configurator');
\ No newline at end of file
+exports.PassportConfigurator = require('./passport-configurator');
diff --git a/lib/models/application-credential.js b/lib/models/application-credential.js
index 00e6245..d97bb36 100644
--- a/lib/models/application-credential.js
+++ b/lib/models/application-credential.js
@@ -1,29 +1,3 @@
-var loopback = require('loopback');
-var DataModel = loopback.PersistedModel || loopback.DataModel;
-var utils = require('./utils');
-
-/*!
- * Default ApplicationCredential properties.
- */
-var properties = {
-  provider: {type: String, required: true}, // facebook, google, twitter, linkedIn
-  authScheme: {type: String}, // oAuth, oAuth 2.0, OpenID, OpenID Connect
-  credentials: Object,
-  // appId: String, // To be injected by belongsTo relation
-  created: Date,
-  modified: Date
-};
-
-var options = {
-  relations: {
-    application: {
-      type: 'belongsTo',
-      model: 'Application',
-      foreignKey: 'appId'
-    }
-  }
-};
-
 /**
  * Credentials associated with the LoopBack client application, such as oAuth 2.0
  * client ID/secret, or SSL keys
@@ -31,7 +5,7 @@ var options = {
  * @param{String} provider: The auth provider name, such as facebook, google, twitter, linkedin
  * @param{String} authScheme: The auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect
  * @param{Object} credentials: Provider-specific credentials.  Actual properties depend on scheme being used:
- * 
+ *
  *   - openId: {returnURL: String, realm: String}
  *   - oAuth2: {clientID: String, clientSecret: String, callbackURL: String}
  *   - oAuth: {consumerKey: String, consumerSecret: String, callbackURL: String}
@@ -41,52 +15,54 @@ var options = {
  * @class
  * @inherits {DataModel}
  */
-var ApplicationCredential = DataModel.extend('ApplicationCredential', properties, options);
-module.exports = ApplicationCredential;
+module.exports = function(ApplicationCredential) {
+  var utils = require('./utils');
 
-/**
- * Link a third-party application credential with the LoopBack application.
- * @param {String} appId The LoopBack application iID.
- * @param {String} provider The third party provider name.
- * @param {String} authScheme The authentication scheme.
- * @param {Object} credentials Credentials for the given scheme.
- * @callback {Function} cb The callback function.
- * @param {Error|String} err The error object or string.
- * @param {Object} user The user object.
- * @param {Object} [info] The auth info object.
- * 
- * -  identity: UserIdentity object
- * -  accessToken: AccessToken object 
- */
-ApplicationCredential.link = function (appId, provider, authScheme, credentials, cb) {
-  var appCredentialModel = utils.getModel(this, ApplicationCredential);
-  appCredentialModel.findOne({where: {
-    appId: appId,
-    provider: provider
-  }}, function (err, extCredential) {
-    if (err) {
-      return cb(err);
-    }
+  /**
+   * Link a third-party application credential with the LoopBack application.
+   * @param {String} appId The LoopBack application iID.
+   * @param {String} provider The third party provider name.
+   * @param {String} authScheme The authentication scheme.
+   * @param {Object} credentials Credentials for the given scheme.
+   * @callback {Function} cb The callback function.
+   * @param {Error|String} err The error object or string.
+   * @param {Object} user The user object.
+   * @param {Object} [info] The auth info object.
+   *
+   * -  identity: UserIdentity object
+   * -  accessToken: AccessToken object
+   */
+  ApplicationCredential.link = function (appId, provider, authScheme, credentials, cb) {
+    var appCredentialModel = utils.getModel(this, ApplicationCredential);
+    appCredentialModel.findOne({where: {
+      appId: appId,
+      provider: provider
+    }}, function (err, extCredential) {
+      if (err) {
+        return cb(err);
+      }
 
-    var date = new Date();
-    if (extCredential) {
-      // Find the app for the given extCredential
-      extCredential.credentials = credentials;
-      return extCredential.updateAttributes({
-        credentials: credentials, modified: date}, cb);
-    }
+      var date = new Date();
+      if (extCredential) {
+        // Find the app for the given extCredential
+        extCredential.credentials = credentials;
+        return extCredential.updateAttributes({
+          credentials: credentials, modified: date}, cb);
+      }
 
-    // Create the linked account
-    appCredentialModel.create({
-      provider: provider,
-      authScheme: authScheme,
-      credentials: credentials,
-      appId: appId,
-      created: date,
-      modified: date
-    }, function (err, i) {
-      cb(err, i);
-    });
+      // Create the linked account
+      appCredentialModel.create({
+        provider: provider,
+        authScheme: authScheme,
+        credentials: credentials,
+        appId: appId,
+        created: date,
+        modified: date
+      }, function (err, i) {
+        cb(err, i);
+      });
 
-  });
-}
+    });
+  }
+  return ApplicationCredential;
+};
diff --git a/lib/models/application-credential.json b/lib/models/application-credential.json
new file mode 100644
index 0000000..09dcac2
--- /dev/null
+++ b/lib/models/application-credential.json
@@ -0,0 +1,25 @@
+{
+  "name": "ApplicationCredential",
+  "base": "PersistedModel",
+  "properties": {
+    "provider": {
+      "type": "String",
+      "required": true,
+      "comments": "Facebook, google, twitter, linkedIn"
+    },
+    "authScheme": {
+      "type": "String",
+      "comments": "oAuth, oAuth 2.0, OpenID, OpenID Connect"
+    },
+    "credentials": "Object",
+    "created": "Date",
+    "modified": "Date"
+  },
+  "relations": {
+    "application": {
+      "type": "belongsTo",
+      "model": "Application",
+      "foreignKey": "appId"
+    }
+  }
+}
diff --git a/lib/models/user-credential.js b/lib/models/user-credential.js
new file mode 100644
index 0000000..7dac07d
--- /dev/null
+++ b/lib/models/user-credential.js
@@ -0,0 +1,77 @@
+/**
+ * Tracks third-party logins and profiles.
+ *
+ * @param {String} provider   Auth provider name, such as facebook, google, twitter, linkedin.
+ * @param {String} authScheme Auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect.
+ * @param {String} externalId Provider specific user ID.
+ * @param {Object} profile User profile, see http://passportjs.org/guide/profile.
+ * @param {Object} credentials Credentials.  Actual properties depend on the auth scheme being used:
+ *
+ * - oAuth: token, tokenSecret
+ * - oAuth 2.0: accessToken, refreshToken
+ * - OpenID: openId
+ * - OpenID: Connect: accessToken, refreshToken, profile
+ * @param {*} userId The LoopBack user ID.
+ * @param {Date} created The created date
+ * @param {Date} modified The last modified date
+ *
+ * @class
+ * @inherits {DataModel}
+ */
+module.exports = function(UserCredential) {
+  var utils = require('./utils');
+
+  /**
+   * Link a third party account to a LoopBack user
+   * @param {String} provider The provider name
+   * @param {String} authScheme The authentication scheme
+   * @param {Object} profile The profile
+   * @param {Object} credentials The credentials
+   * @param {Object} [options] The options
+   * @callback {Function} cb The callback function
+   * @param {Error|String} err The error object or string
+   * @param {Object} [credential] The user credential object
+   */
+  UserCredential.link = function (userId, provider, authScheme, profile,
+                                  credentials, options, cb) {
+    options = options || {};
+    if(typeof options === 'function' && cb === undefined) {
+      cb = options;
+      options = {};
+    }
+    var userCredentialModel = utils.getModel(this, UserCredential);
+    userCredentialModel.findOne({where: {
+      userId: userId,
+      provider: provider,
+      externalId: profile.id
+    }}, function (err, extCredential) {
+      if (err) {
+        return cb(err);
+      }
+
+      var date = new Date();
+      if (extCredential) {
+        // Find the user for the given extCredential
+        extCredential.credentials = credentials;
+        return extCredential.updateAttributes({profile: profile,
+          credentials: credentials, modified: date}, cb);
+      }
+
+      // Create the linked account
+      userCredentialModel.create({
+        provider: provider,
+        externalId: profile.id,
+        authScheme: authScheme,
+        profile: profile,
+        credentials: credentials,
+        userId: userId,
+        created: date,
+        modified: date
+      }, function (err, i) {
+        cb(err, i);
+      });
+
+    });
+  }
+  return UserCredential;
+};
diff --git a/lib/models/user-credential.json b/lib/models/user-credential.json
new file mode 100644
index 0000000..c2d05cb
--- /dev/null
+++ b/lib/models/user-credential.json
@@ -0,0 +1,42 @@
+{
+  "name": "UserCredential",
+  "base": "PersistedModel",
+  "properties": {
+    "provider": {
+      "type": "String",
+      "comments": "facebook, google, twitter, linkedin"
+    },
+    "authScheme": {
+      "type": "String",
+      "comments": "oAuth, oAuth 2.0, OpenID, OpenID Connect"
+    },
+    "externalId": {
+      "type": "String",
+      "comments": "The provider specific id"
+    },
+    "profile": {
+      "type": "Object"
+    },
+    "credentials": {
+      "type": "Object"
+    },
+    "created": "Date",
+    "modified": "Date"
+  },
+  "acls": [{
+    "principalType": "ROLE",
+    "principalId": "$everyone",
+    "permission": "DENY"
+  }, {
+    "principalType": "ROLE",
+    "principalId": "$owner",
+    "permission": "ALLOW"
+  }],
+  "relations": {
+    "user": {
+      "type": "belongsTo",
+      "model": "User",
+      "foreignKey": "userId"
+    }
+  }
+}
diff --git a/lib/models/user-identity.js b/lib/models/user-identity.js
index 3bd18b0..0ae12c2 100644
--- a/lib/models/user-identity.js
+++ b/lib/models/user-identity.js
@@ -1,55 +1,12 @@
-var loopback = require('loopback');
-var DataModel = loopback.PersistedModel || loopback.DataModel;
-var Role = loopback.Role;
-var ACL = loopback.ACL;
-var utils = require('./utils');
-
-/*!
- * Default UserIdentity properties.
- */
-
-var properties = {
-  provider: {type: String}, // facebook, google, twitter, linkedin
-  authScheme: {type: String}, // oAuth, oAuth 2.0, OpenID, OpenID Connect
-  externalId: {type: String}, // The provider specific id
-  profile: {type: Object},
-  credentials: {type: Object},
-  // userId: {type: String}, // Allow LoopBack to inject it based on the relation
-  created: Date,
-  modified: Date
-};
-
-var options = {
-  acls: [
-    {
-      principalType: ACL.ROLE,
-      principalId: Role.EVERYONE,
-      permission: ACL.DENY
-    },
-    {
-      principalType: ACL.ROLE,
-      principalId: Role.OWNER,
-      permission: ACL.ALLOW
-    }
-  ],
-  relations: {
-    user: {
-      type: 'belongsTo',
-      model: 'User',
-      foreignKey: 'userId'
-    }
-  }
-};
-
 /**
  * Tracks third-party logins and profiles.
  *
- * @param {String} provider Auth provider name, such as facebook, google, twitter, linkedin.
+ * @param {String} provider   Auth provider name, such as facebook, google, twitter, linkedin.
  * @param {String} authScheme Auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect.
  * @param {String} externalId Provider specific user ID.
  * @param {Object} profile User profile, see http://passportjs.org/guide/profile.
  * @param {Object} credentials Credentials.  Actual properties depend on the auth scheme being used:
- * 
+ *
  * - oAuth: token, tokenSecret
  * - oAuth 2.0: accessToken, refreshToken
  * - OpenID: openId
@@ -61,84 +18,121 @@ var options = {
  * @class
  * @inherits {DataModel}
  */
-var UserIdentity = DataModel.extend('UserIdentity', properties, options);
+ module.exports = function(UserIdentity) {
+  var loopback = require('loopback');
+  var utils = require('./utils');
 
-/*!
- * Create an access token for the given user
- * @param {User} user The user instance
- * @param {Number} [ttl] The ttl in millisenconds
- * @callback {Function} cb The callback function
- * @param {Error|String} err The error object
-  * param {AccessToken} The access token
- */
-function createAccessToken(user, ttl, cb) {
-  if (arguments.length === 2 && typeof ttl === 'function') {
-    cb = ttl;
-    ttl = 0;
+  /*!
+   * Create an access token for the given user
+   * @param {User} user The user instance
+   * @param {Number} [ttl] The ttl in millisenconds
+   * @callback {Function} cb The callback function
+   * @param {Error|String} err The error object
+    * param {AccessToken} The access token
+   */
+  function createAccessToken(user, ttl, cb) {
+    if (arguments.length === 2 && typeof ttl === 'function') {
+      cb = ttl;
+      ttl = 0;
+    }
+    user.accessTokens.create({
+      ttl: Math.min(ttl || user.constructor.settings.ttl,
+        user.constructor.settings.maxTTL)
+    }, cb);
   }
-  user.accessTokens.create({
-    ttl: Math.min(ttl || user.constructor.settings.ttl,
-      user.constructor.settings.maxTTL)
-  }, cb);
-}
 
-function profileToUser(provider, profile) {
-// Let's create a user for that
-  var email = profile.emails && profile.emails[0] && profile.emails[0].value;
-  if (!email) {
-    // Fake an e-mail
-    email = (profile.username || profile.id) + '@loopback.'
-      + (profile.provider || provider) + '.com';
+  function profileToUser(provider, profile) {
+  // Let's create a user for that
+    var email = profile.emails && profile.emails[0] && profile.emails[0].value;
+    if (!email) {
+      // Fake an e-mail
+      email = (profile.username || profile.id) + '@loopback.' +
+              (profile.provider || provider) + '.com';
+    }
+    var username = provider + '.' + (profile.username || profile.id);
+    var password = utils.generateKey('password');
+    var userObj = {
+      username: username,
+      password: password,
+      email: email
+    };
+    return userObj;
   }
-  var username = provider + '.' + (profile.username || profile.id);
-  var password = utils.generateKey('password');
-  var userObj = {
-    username: username,
-    password: password,
-    email: email
-  };
-  return userObj;
-}
 
-/**
- * Log in with a third-party provider such as Facebook or Google.
- * 
- * @param {String} provider The provider name.
- * @param {String} authScheme The authentication scheme.
- * @param {Object} profile The profile.
- * @param {Object} credentials The credentials.
- * @param {Object} [options] The options.
- * @callback {Function} cb The callback function.
- * @param {Error|String} err The error object or string.
- * @param {Object} user The user object.
- * @param {Object} [info] The auth info object.
- * 
- * -  identity: UserIdentity object
- * -  accessToken: AccessToken object
- */
-UserIdentity.login = function (provider, authScheme, profile, credentials,
-                               options, cb) {
-  options = options || {};
-  if(typeof options === 'function' && cb === undefined) {
-    cb = options;
-    options = {};
-  }
-  var autoLogin = options.autoLogin || options.autoLogin === undefined;
-  var userIdentityModel = utils.getModel(this, UserIdentity);
-  userIdentityModel.findOne({where: {
-    provider: provider,
-    externalId: profile.id
-  }}, function (err, identity) {
-    if (err) {
-      return cb(err);
+  /**
+   * Log in with a third-party provider such as Facebook or Google.
+   *
+   * @param {String} provider The provider name.
+   * @param {String} authScheme The authentication scheme.
+   * @param {Object} profile The profile.
+   * @param {Object} credentials The credentials.
+   * @param {Object} [options] The options.
+   * @callback {Function} cb The callback function.
+   * @param {Error|String} err The error object or string.
+   * @param {Object} user The user object.
+   * @param {Object} [info] The auth info object.
+   *
+   * -  identity: UserIdentity object
+   * -  accessToken: AccessToken object
+   */
+  UserIdentity.login = function (provider, authScheme, profile, credentials,
+                                 options, cb) {
+    options = options || {};
+    if(typeof options === 'function' && cb === undefined) {
+      cb = options;
+      options = {};
     }
-    if (identity) {
-      identity.credentials = credentials;
-      return identity.updateAttributes({profile: profile,
-        credentials: credentials, modified: new Date()}, function (err, i) {
-        // Find the user for the given identity
-        return identity.user(function (err, user) {
-          // Create access token if the autoLogin flag is set to true
+    var autoLogin = options.autoLogin || options.autoLogin === undefined;
+    var userIdentityModel = utils.getModel(this, UserIdentity);
+    userIdentityModel.findOne({where: {
+      provider: provider,
+      externalId: profile.id
+    }}, function (err, identity) {
+      if (err) {
+        return cb(err);
+      }
+      if (identity) {
+        identity.credentials = credentials;
+        return identity.updateAttributes({profile: profile,
+          credentials: credentials, modified: new Date()}, function (err, i) {
+          // Find the user for the given identity
+          return identity.user(function (err, user) {
+            // Create access token if the autoLogin flag is set to true
+            if(!err && user && autoLogin) {
+              return createAccessToken(user, function(err, token) {
+                cb(err, user, identity, token);
+              });
+            }
+            cb(err, user, identity);
+          });
+        });
+      }
+      // Find the user model
+      var userModel = (userIdentityModel.relations.user &&
+                       userIdentityModel.relations.user.modelTo) ||
+                       loopback.getModelByType(loopback.User);
+      var userObj = (options.profileToUser || profileToUser)(provider, profile);
+      if (!userObj.email) {
+        return cb('email is missing from the user profile');
+      }
+      userModel.findOrCreate({where: {or: [
+        {username: userObj.username},
+        {email: userObj.email}
+      ]}}, userObj, function (err, user) {
+        if (err) {
+          return cb(err);
+        }
+        var date = new Date();
+        userIdentityModel.create({
+          provider: provider,
+          externalId: profile.id,
+          authScheme: authScheme,
+          profile: profile,
+          credentials: credentials,
+          userId: user.id,
+          created: date,
+          modified: date
+        }, function (err, identity) {
           if(!err && user && autoLogin) {
             return createAccessToken(user, function(err, token) {
               cb(err, user, identity, token);
@@ -147,120 +141,7 @@ UserIdentity.login = function (provider, authScheme, profile, credentials,
           cb(err, user, identity);
         });
       });
-    }
-    // Find the user model
-    var userModel = (userIdentityModel.relations.user
-      && userIdentityModel.relations.user.modelTo)
-      || loopback.getModelByType(loopback.User);
-    var userObj = (options.profileToUser || profileToUser)(provider, profile);
-    if (!userObj.email) {
-      return cb('email is missing from the user profile');
-    }
-    userModel.findOrCreate({where: {or: [
-      {username: userObj.username},
-      {email: userObj.email}
-    ]}}, userObj, function (err, user) {
-      if (err) {
-        return cb(err);
-      }
-      var date = new Date();
-      userIdentityModel.create({
-        provider: provider,
-        externalId: profile.id,
-        authScheme: authScheme,
-        profile: profile,
-        credentials: credentials,
-        userId: user.id,
-        created: date,
-        modified: date
-      }, function (err, identity) {
-        if(!err && user && autoLogin) {
-          return createAccessToken(user, function(err, token) {
-            cb(err, user, identity, token);
-          });
-        }
-        cb(err, user, identity);
-      });
-    });
-  });
-}
-
-/**
- * Tracks thrid-party credentials for linked accounts.
- *
- * @param {String} provider The auth provider name, such as facebook, google, twitter, linkedin
- * @param {String} authScheme The auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect
- * @param {String} externalId The provider-specific user ID.
- * @param {Object} profile The user profile, see http://passportjs.org/guide/profile
- * @param {Object} credentials Credentials.  Actual properties depend on the auth scheme being used:
- * 
- * - For oAuth: token, tokenSecret
- * - For oAuth 2.0: accessToken, refreshToken
- * - For OpenID: openId
- * - For OpenID: Connect: accessToken, refreshToken, profile
- * @param {*} userId: The LoopBack user ID.
- * @param {Date} created: The created date
- * @param {Date} modified: The last modified date
- *
- * @class
- * @inherits {DataModel}
- */
-var UserCredential = DataModel.extend('UserCredential', properties, options);
-
-/**
- * Link a third party account to a LoopBack user
- * @param {String} provider The provider name
- * @param {String} authScheme The authentication scheme
- * @param {Object} profile The profile
- * @param {Object} credentials The credentials
- * @param {Object} [options] The options
- * @callback {Function} cb The callback function
- * @param {Error|String} err The error object or string
- * @param {Object} [credential] The user credential object
- */
-UserCredential.link = function (userId, provider, authScheme, profile,
-                                credentials, options, cb) {
-  options = options || {};
-  if(typeof options === 'function' && cb === undefined) {
-    cb = options;
-    options = {};
-  }
-  var userCredentialModel = utils.getModel(this, UserCredential);
-  userCredentialModel.findOne({where: {
-    userId: userId,
-    provider: provider,
-    externalId: profile.id
-  }}, function (err, extCredential) {
-    if (err) {
-      return cb(err);
-    }
-
-    var date = new Date();
-    if (extCredential) {
-      // Find the user for the given extCredential
-      extCredential.credentials = credentials;
-      return extCredential.updateAttributes({profile: profile,
-        credentials: credentials, modified: date}, cb);
-    }
-
-    // Create the linked account
-    userCredentialModel.create({
-      provider: provider,
-      externalId: profile.id,
-      authScheme: authScheme,
-      profile: profile,
-      credentials: credentials,
-      userId: userId,
-      created: date,
-      modified: date
-    }, function (err, i) {
-      cb(err, i);
     });
-
-  });
-}
-
-module.exports = {
-  UserIdentity: UserIdentity,
-  UserCredential: UserCredential
+  };
+  return UserIdentity;
 };
diff --git a/lib/models/user-identity.json b/lib/models/user-identity.json
new file mode 100644
index 0000000..74b8c6d
--- /dev/null
+++ b/lib/models/user-identity.json
@@ -0,0 +1,43 @@
+{
+  "name": "UserIdentity",
+  "plural": "UserIdentities",
+  "base": "PersistedModel",
+  "properties": {
+    "provider": {
+      "type": "String",
+      "comments": "facebook, google, twitter, linkedin"
+    },
+    "authScheme": {
+      "type": "String",
+      "comments": "oAuth, oAuth 2.0, OpenID, OpenID Connect"
+    },
+    "externalId": {
+      "type": "String",
+      "comments": "The provider specific id"
+    },
+    "profile": {
+      "type": "Object"
+    },
+    "credentials": {
+      "type": "Object"
+    },
+    "created": "Date",
+    "modified": "Date"
+  },
+  "acls": [{
+    "principalType": "ROLE",
+    "principalId": "$everyone",
+    "permission": "DENY"
+  }, {
+    "principalType": "ROLE",
+    "principalId": "$owner",
+    "permission": "ALLOW"
+  }],
+  "relations": {
+    "user": {
+      "type": "belongsTo",
+      "model": "User",
+      "foreignKey": "userId"
+    }
+  }
+}
diff --git a/lib/passport-configurator.js b/lib/passport-configurator.js
index 9ca97bc..a6076bd 100644
--- a/lib/passport-configurator.js
+++ b/lib/passport-configurator.js
@@ -1,6 +1,5 @@
 var loopback = require('loopback');
 var passport = require('passport');
-var models = require('./models/user-identity');
 var _ = require('underscore');
 
 module.exports = PassportConfigurator;
@@ -30,9 +29,9 @@ function PassportConfigurator(app) {
 PassportConfigurator.prototype.setupModels = function (options) {
   options = options || {};
   // Set up relations
-  this.userModel = options.userModel || loopback.getModelByType(loopback.User);
-  this.userCredentialModel = options.userCredentialModel || loopback.getModelByType(models.UserCredential);
-  this.userIdentityModel = options.userIdentityModel || loopback.getModelByType(models.UserIdentity);
+  this.userModel = options.userModel || loopback.getModelByType(this.app.models.User);
+  this.userCredentialModel = options.userCredentialModel || loopback.getModelByType(this.app.models.UserCredential);
+  this.userIdentityModel = options.userIdentityModel || loopback.getModelByType(this.app.models.UserIdentity);
 
   if (!this.userModel.relations.identities) {
     this.userModel.hasMany(this.userIdentityModel, {as: 'identities'});
@@ -362,6 +361,7 @@ PassportConfigurator.prototype.configureProvider = function (name, options) {
               if (!!options.json) {
                 return res.json({'access_token': info.accessToken.id, userId: user.id});
               } else {
+                console.log('SIGNED COOKIES PASSPORT', req.signedCookies);
                 res.cookie('access_token', info.accessToken.id, { signed: req.signedCookies ? true : false,
                   maxAge: info.accessToken.ttl });
                 res.cookie('userId', user.id.toString(), { signed: req.signedCookies ? true : false,
@@ -375,6 +375,7 @@ PassportConfigurator.prototype.configureProvider = function (name, options) {
             if (!!options.json) {
               return res.json({'access_token': info.accessToken.id, userId: user.id});
             } else {
+              console.log('SIGNED COOKIES PASSPORT', req.signedCookies);
               res.cookie('access_token', info.accessToken.id, { signed: req.signedCookies ? true : false,
                 maxAge: info.accessToken.ttl });
               res.cookie('userId', user.id.toString(), { signed: req.signedCookies ? true : false,
diff --git a/test/model.user-credential.test.js b/test/model.user-credential.test.js
new file mode 100644
index 0000000..7b47187
--- /dev/null
+++ b/test/model.user-credential.test.js
@@ -0,0 +1,88 @@
+var m = require('./init');
+var loopback = require('loopback');
+var assert = require('assert');
+var UserCredential = m.UserCredential;
+var User = loopback.User;
+
+before(function (done) {
+  User.destroyAll(done);
+});
+
+describe('UserCredential', function () {
+  var userId = null;
+  before(function (done) {
+    var ds = loopback.createDataSource({
+      connector: 'memory'
+    });
+
+    UserCredential.attachTo(ds);
+    User.attachTo(ds);
+    UserCredential.belongsTo(User);
+
+    User.create({
+      username: 'facebook.abc',
+      email: 'uuu@facebook.com',
+      password: 'pass'
+    }, function (err, user) {
+      userId = user.id;
+      done(err);
+    });
+  });
+
+  it('supports linked 3rd party accounts', function (done) {
+    UserCredential.link(userId, 'facebook', 'oAuth 2.0',
+      {emails: [
+        {value: 'foo@bar.com'}
+      ], id: 'f123', username: 'xyz'
+      }, {accessToken: 'at1', refreshToken: 'rt1'}, function (err, cred) {
+        assert(!err, 'No error should be reported');
+
+        assert.equal(cred.externalId, 'f123');
+        assert.equal(cred.provider, 'facebook');
+        assert.equal(cred.authScheme, 'oAuth 2.0');
+        assert.deepEqual(cred.credentials, {accessToken: 'at1', refreshToken: 'rt1'});
+
+        assert.equal(userId, cred.userId);
+
+        // Follow the belongsTo relation
+        cred.user(function (err, user) {
+          assert(!err, 'No error should be reported');
+          assert.equal(user.username, 'facebook.abc');
+          assert.equal(user.email, 'uuu@facebook.com');
+          done();
+        });
+      });
+  });
+
+  it('supports linked 3rd party accounts if exists', function (done) {
+    UserCredential.create({
+      externalId: 'f456',
+      provider: 'facebook',
+      userId: userId,
+      credentials: {accessToken: 'at1', refreshToken: 'rt1'}
+    }, function (err, cred) {
+      UserCredential.link(userId, 'facebook', 'oAuth 2.0',
+        {emails: [
+          {value: 'abc1@facebook.com'}
+        ], id: 'f456', username: 'xyz'
+        }, {accessToken: 'at2', refreshToken: 'rt2'}, function (err, cred) {
+          assert(!err, 'No error should be reported');
+
+          assert.equal(cred.externalId, 'f456');
+          assert.equal(cred.provider, 'facebook');
+          assert.deepEqual(cred.credentials, {accessToken: 'at2', refreshToken: 'rt2'});
+
+          assert.equal(userId, cred.userId);
+
+          // Follow the belongsTo relation
+          cred.user(function (err, user) {
+            assert(!err, 'No error should be reported');
+            assert.equal(user.username, 'facebook.abc');
+            assert.equal(user.email, 'uuu@facebook.com');
+            done();
+          });
+        });
+    });
+  });
+
+});
diff --git a/test/model.user-identity.test.js b/test/model.user-identity.test.js
index d1634c4..f19b64c 100644
--- a/test/model.user-identity.test.js
+++ b/test/model.user-identity.test.js
@@ -2,7 +2,6 @@ var m = require('./init');
 var loopback = require('loopback');
 var assert = require('assert');
 var UserIdentity = m.UserIdentity;
-var UserCredential = m.UserCredential;
 var User = loopback.User;
 
 before(function (done) {
@@ -15,7 +14,7 @@ describe('UserIdentity', function () {
     var ds = loopback.createDataSource({
       connector: 'memory'
     });
-
+    
     UserIdentity.attachTo(ds);
     User.attachTo(ds);
     UserIdentity.belongsTo(User);
@@ -163,83 +162,3 @@ describe('UserIdentity', function () {
   });
 
 });
-
-describe('UserCredential', function () {
-  var userId = null;
-  before(function (done) {
-    var ds = loopback.createDataSource({
-      connector: 'memory'
-    });
-
-    UserCredential.attachTo(ds);
-    User.attachTo(ds);
-    UserCredential.belongsTo(User);
-
-    User.create({
-      username: 'facebook.abc',
-      email: 'uuu@facebook.com',
-      password: 'pass'
-    }, function (err, user) {
-      userId = user.id;
-      done(err);
-    });
-  });
-
-  it('supports linked 3rd party accounts', function (done) {
-    UserCredential.link(userId, 'facebook', 'oAuth 2.0',
-      {emails: [
-        {value: 'foo@bar.com'}
-      ], id: 'f123', username: 'xyz'
-      }, {accessToken: 'at1', refreshToken: 'rt1'}, function (err, cred) {
-        assert(!err, 'No error should be reported');
-
-        assert.equal(cred.externalId, 'f123');
-        assert.equal(cred.provider, 'facebook');
-        assert.equal(cred.authScheme, 'oAuth 2.0');
-        assert.deepEqual(cred.credentials, {accessToken: 'at1', refreshToken: 'rt1'});
-
-        assert.equal(userId, cred.userId);
-
-        // Follow the belongsTo relation
-        cred.user(function (err, user) {
-          assert(!err, 'No error should be reported');
-          assert.equal(user.username, 'facebook.abc');
-          assert.equal(user.email, 'uuu@facebook.com');
-          done();
-        });
-      });
-  });
-
-  it('supports linked 3rd party accounts if exists', function (done) {
-    UserCredential.create({
-      externalId: 'f456',
-      provider: 'facebook',
-      userId: userId,
-      credentials: {accessToken: 'at1', refreshToken: 'rt1'}
-    }, function (err, cred) {
-      UserCredential.link(userId, 'facebook', 'oAuth 2.0',
-        {emails: [
-          {value: 'abc1@facebook.com'}
-        ], id: 'f456', username: 'xyz'
-        }, {accessToken: 'at2', refreshToken: 'rt2'}, function (err, cred) {
-          assert(!err, 'No error should be reported');
-
-          assert.equal(cred.externalId, 'f456');
-          assert.equal(cred.provider, 'facebook');
-          assert.deepEqual(cred.credentials, {accessToken: 'at2', refreshToken: 'rt2'});
-
-          assert.equal(userId, cred.userId);
-
-          // Follow the belongsTo relation
-          cred.user(function (err, user) {
-            assert(!err, 'No error should be reported');
-            assert.equal(user.username, 'facebook.abc');
-            assert.equal(user.email, 'uuu@facebook.com');
-            done();
-          });
-        });
-    });
-  });
-
-});
-
