Permalink
Browse files

Initial Commit

  • Loading branch information...
1 parent 76fa5e4 commit 806c384d15b29d8ad559530fb26173538cee8794 Steve King committed Feb 16, 2013
Showing with 555 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +4 −0 .npmignore
  3. +23 −0 package.json
  4. +41 −0 src/accesstokengenerator.js
  5. +128 −0 src/authenticator.js
  6. +43 −0 src/endpointresolver.js
  7. +246 −0 src/index.js
  8. +24 −0 src/user.js
  9. +1 −0 test/.googleauth
  10. +11 −0 test/example.js
  11. +21 −0 test/test-middleware.js
  12. +10 −0 test/test.js
View
@@ -0,0 +1,3 @@
+.idea/*
+*.iml
+node_modules/*
View
@@ -0,0 +1,4 @@
+.idea/*
+*.iml
+.git*
+node_modules/*
View
@@ -0,0 +1,23 @@
+{
+ "name": "gauth",
+ "version": "0.0.1",
+ "description": "Middleware component to authenticate users through their Google account",
+ "author": "Steve King <steve@mydev.co>",
+ "contributors": [ { "name": "Steve King", "email": "steve@mydev.co" } ],
+ "keywords": ["authentication", "oauth", "google", "express", "connect", "middleware"],
+ "repository": "git://github.com/steveukx/gauth",
+ "main":"./src/index.js",
+ "engines": { "node": ">= 0.8.0" },
+ "dependencies":{
+ "promise-lite": "",
+ "subscribable": "",
+ "xhrequest": ""
+ },
+ "devDependencies": {
+ "express": "3.1.0",
+ "unit-test": ""
+ },
+ "scripts": {
+ "test": "node test/test.js"
+ }
+}
@@ -0,0 +1,41 @@
+/**
+ * @exports AccessTokenGenerator
+ */
+(function () {
+
+ "use strict";
+
+ /**
+ * The AccessTokenGenerator requires an end point URL that requests can be sent to and returns a promise interface
+ * that will be resolved with the access token or rejected should any errors take place.
+ *
+ * @name AccessTokenGenerator
+ * @constructor
+ */
+ function AccessTokenGenerator(endPointUrl) {
+ var promise = new (require('promise-lite').Promise);
+ var query = '?' + require('querystring').stringify({
+ "openid.ns": 'http://specs.openid.net/auth/2.0',
+ "openid.mode": "associate",
+ "openid.assoc_type": "HMAC-SHA1",
+ "openid.session_type": "no-encryption"
+ });
+
+ require('xhrequest')(endPointUrl + query, {
+ success: function (data) {
+ promise.resolve(AccessTokenGenerator.getResultFromServerResponse(data.toString('utf8')));
+ },
+ error: function () {
+ promise.reject(new Error("Unable to fetch an access token"));
+ }
+ });
+ return promise;
+ }
+
+ AccessTokenGenerator.getResultFromServerResponse = function (data) {
+ return data.match(/assoc_handle\:(.+)/)[1];
+ };
+
+ module.exports = AccessTokenGenerator;
+
+}());
View
@@ -0,0 +1,128 @@
+/**
+ * @exports Authenticator
+ */
+(function () {
+
+ "use strict";
+
+ /**
+ *
+ * @name Authenticator
+ * @constructor
+ */
+ function Authenticator(endPointUrl, assocHandle, baseUrl) {
+ this._assocHandle = assocHandle;
+ this._endPointUrl = endPointUrl;
+ this._baseUrl = baseUrl;
+ this._realm = (function(url) { return url.protocol + '//' + url.host + '/'; }(require('url').parse(baseUrl)));
+ }
+
+ /**
+ * @type {String} The base url is the absolute URL to the root of the authenticated content (eg: http://domain.com/usercontent/)
+ */
+ Authenticator.prototype._baseUrl = "";
+
+ /**
+ * @type {String} The realm is the trusted domain that the user must agree to authenticating with, derived from the host of the base url (eg: http://domain.com/)
+ */
+ Authenticator.prototype._realm = "";
+
+ /**
+ * Sets the base url to be used in this authenticator, and will as a result also set the realm to match the base url.
+ * @param {String} baseUrl
+ * @return {Authenticator}
+ */
+ Authenticator.prototype.setBaseUrl = function(baseUrl) {
+ if(baseUrl != this._baseUrl) {
+ this._baseUrl = baseUrl;
+ this._realm = (function(url) { return url.protocol + '//' + url.host + '/'; }(require('url').parse(baseUrl)));
+ }
+ return this;
+ };
+
+ /**
+ * Gets the URL that should be used to authenticate a user with a terminal URL of the supplied backTo path.
+ *
+ * @param {String} backTo
+ * @return {string}
+ */
+ Authenticator.prototype.getLogInUrl = function(backTo) {
+ var params = this._getLoginParameters();
+ params['openid.return_to'] += '?next=' + backTo;
+
+ return this._endPointUrl + '?' + require('querystring').stringify(params);
+ };
+
+ /**
+ * Applies properties to the supplied object that will include email request parameters
+ * @param {Object} params
+ */
+ Authenticator.prototype._mergeEmailRequest = function(params) {
+ params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
+ params['openid.ax.mode'] = 'fetch_request';
+ params['openid.ax.required'] = 'email,firstname,lastname';
+
+ params['openid.ax.type.email'] = 'http://schema.openid.net/contact/email';
+ params['openid.ax.type.firstname'] = 'http://axschema.org/namePerson/first';
+ params['openid.ax.type.lastname'] = 'http://axschema.org/namePerson/last';
+ };
+
+ /**
+ * Gets the URL parameters used for associating a user's google account with this application
+ * @return {Object}
+ */
+ Authenticator.prototype._getLoginParameters = function() {
+ var params = this._getParameters();
+
+ params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
+ params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
+ params['openid.return_to'] = this._baseUrl + '/responder';
+ params['openid.realm'] = this._realm;
+ params['openid.assoc_handle'] = '';
+ params['openid.mode'] = 'checkid_setup';
+ this._mergeEmailRequest(params);
+
+ return params;
+ };
+
+ Authenticator.prototype._getIdentityResponseParameters = function() {
+ var params = this._getParameters();
+
+ params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
+ params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
+ params['openid.return_to'] = this._baseUrl + '/responder';
+ params['openid.realm'] = this._realm;
+ params['openid.assoc_handle'] = '';
+ params['openid.mode'] = 'checkid_setup';
+ this._mergeEmailRequest(params);
+
+ return params;
+ };
+
+ /**
+ * Gets the URL parameters used for cancelling the association of the google account with this application
+ * @return {Object}
+ */
+ Authenticator.prototype._getCancelParameters = function() {
+ return {
+ 'openid.ns': 'http://specs.openid.net/auth/2.0',
+ 'openid.mode': 'cancel'
+ };
+ };
+
+ /**
+ * Gets default parameters for all requests
+ * @return {Object}
+ */
+ Authenticator.prototype._getParameters = function() {
+ return {
+ 'openid.ns': 'http://specs.openid.net/auth/2.0',
+ 'openid.assoc_handle': this._assocHandle
+ };
+ };
+
+
+
+ module.exports = Authenticator;
+
+}());
View
@@ -0,0 +1,43 @@
+/**
+ * @exports EndPointResolver
+ */
+(function () {
+
+ "use strict";
+
+ /**
+ * Sends a request to the supplied discovery URL and parses the response for the URL that subsequent requests should
+ * be sent. The result of calling the EndPointResolver is a promise interface that will be resolved with the end point
+ * url or rejected if any errors took place.
+ *
+ * @param {String} discoveryUrl
+ *
+ * @name EndPointResolver
+ * @constructor
+ */
+ function EndPointResolver(discoveryUrl) {
+ var promise = new (require('promise-lite').Promise);
+ require('xhrequest')(discoveryUrl, {
+ success: function(data) {
+ promise.resolve(EndPointResolver.getResultFromServerResponse(data.toString('utf8')));
+ },
+ error: function() {
+ promise.reject(new Error("Unable to connect to end point discovery URL"));
+ }
+ });
+ return promise;
+ }
+
+ /**
+ * Given the response data from the discovery resource, retrieves the URI for making all further requests bound to.
+ *
+ * @param {String} data
+ * @return {String}
+ */
+ EndPointResolver.getResultFromServerResponse = function(data) {
+ return data.match(/<URI>(.+)<\/URI>/i)[1];
+ };
+
+ module.exports = EndPointResolver;
+
+}());
Oops, something went wrong.

0 comments on commit 806c384

Please sign in to comment.