Andreas Knecht avatar Andreas Knecht committed 2faa2e4

Requests to JIRA as a crowd server are working. Just need to pass results into passport properly now.

Comments (0)

Files changed (13)

+.DS_Store
+node_modules
+.idea
+(The MIT License)
+
+Copyright (c) 2012 Andreas Knecht
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# Passport-Local
+
+[Passport](http://passportjs.org/) strategy for authenticating with a username
+and password.
+
+This module lets you authenticate using a username and password in your Node.js
+applications.  By plugging into Passport, local authentication can be easily and
+unobtrusively integrated into any application or framework that supports
+[Connect](http://www.senchalabs.org/connect/)-style middleware, including
+[Express](http://expressjs.com/).
+
+## Installation
+
+    $ npm install passport-local
+
+## Usage
+
+#### Configure Strategy
+
+The local authentication strategy authenticates users using a username and
+password.  The strategy requires a `verify` callback, which accepts these
+credentials and calls `done` providing a user.
+
+    passport.use(new LocalStrategy(
+      function(username, password, done) {
+        User.findOne({ username: username }, function (err, user) {
+          if (err) { return done(err); }
+          if (!user) { return done(null, false); }
+          if (!user.verifyPassword(password)) { return done(null, false); }
+          return done(null, user);
+        });
+      }
+    ));
+
+#### Authenticate Requests
+
+Use `passport.authenticate()`, specifying the `'local'` strategy, to
+authenticate requests.
+
+For example, as route middleware in an [Express](http://expressjs.com/)
+application:
+
+    app.post('/login', 
+      passport.authenticate('local', { failureRedirect: '/login' }),
+      function(req, res) {
+        res.redirect('/');
+      });
+
+## Examples
+
+For a complete, working example, refer to the [login example](https://github.com/jaredhanson/passport-local/tree/master/examples/login).
+
+## Tests
+
+    $ npm install --dev
+    $ make test
+
+[![Build Status](https://secure.travis-ci.org/jaredhanson/passport-local.png)](http://travis-ci.org/jaredhanson/passport-local)
+
+## Credits
+
+  - [Jared Hanson](http://github.com/jaredhanson)
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2012 Andreas Knecht
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

examples/login/app.js

+var express = require('express'),
+    http = require('http'),
+    passport = require('passport'),
+    flash = require('connect-flash'),
+    AtlassianCrowdStrategy = require('passport-atlassian-crowd').Strategy;
+
+
+var users = [
+    { id:1, username:'bob', password:'secret', email:'bob@example.com' }
+    ,
+    { id:2, username:'joe', password:'birthday', email:'joe@example.com' }
+];
+
+function findById(id, fn) {
+    var idx = id - 1;
+    if (users[idx]) {
+        fn(null, users[idx]);
+    } else {
+        fn(new Error('User ' + id + ' does not exist'));
+    }
+}
+
+function findByUsername(username, fn) {
+    for (var i = 0, len = users.length; i < len; i++) {
+        var user = users[i];
+        if (user.username === username) {
+            return fn(null, user);
+        }
+    }
+    return fn(null, null);
+}
+
+
+// Passport session setup.
+//   To support persistent login sessions, Passport needs to be able to
+//   serialize users into and deserialize users out of the session.  Typically,
+//   this will be as simple as storing the user ID when serializing, and finding
+//   the user by ID when deserializing.
+passport.serializeUser(function (user, done) {
+    done(null, user.id);
+});
+
+passport.deserializeUser(function (id, done) {
+    findById(id, function (err, user) {
+        done(err, user);
+    });
+});
+
+
+// Use the AtlassianCrowdStrategy within Passport.
+//   Strategies in passport require a `verify` function, which accept
+//   credentials (in this case, a username and password), and invoke a callback
+//   with a user object.  In the real world, this would query a database;
+//   however, in this example we are using a baked-in set of users.
+passport.use(new AtlassianCrowdStrategy({
+        crowdServer:"http://localhost:2990/jira",
+        crowdApplication:"nodejs",
+        crowdApplicationPassword:"password"
+    },
+    function (username, password, done) {
+        // asynchronous verification, for effect...
+        process.nextTick(function () {
+
+            // Find the user by username.  If there is no user with the given
+            // username, or the password is not correct, set the user to `false` to
+            // indicate failure and set a flash message.  Otherwise, return the
+            // authenticated `user`.
+            findByUsername(username, function (err, user) {
+                if (err) {
+                    return done(err);
+                }
+                if (!user) {
+                    return done(null, false, { message:'Unknown user ' + username });
+                }
+                if (user.password != password) {
+                    return done(null, false, { message:'Invalid password' });
+                }
+                return done(null, user);
+            })
+        });
+    }
+));
+
+
+var app = express();
+
+// configure Express
+app.configure(function () {
+    app.set('port', process.env.PORT || 4000);
+    app.set('views', __dirname + '/views');
+    app.set('view engine', 'ejs');
+    app.engine('ejs', require('ejs-locals'));
+    app.use(express.logger());
+    app.use(express.cookieParser());
+    app.use(express.bodyParser());
+    app.use(express.methodOverride());
+    app.use(express.session({ secret:'sssh!' }));
+    app.use(flash());
+    // Initialize Passport!  Also use passport.session() middleware, to support
+    // persistent login sessions (recommended).
+    app.use(passport.initialize());
+    app.use(passport.session());
+    app.use(app.router);
+    app.use(express.static(__dirname + '/../../public'));
+});
+
+
+app.get('/', function (req, res) {
+    res.render('index', { user:req.user });
+});
+
+app.get('/account', ensureAuthenticated, function (req, res) {
+    res.render('account', { user:req.user });
+});
+
+app.get('/login', function (req, res) {
+    res.render('login', { user:req.user, message:req.flash('error') });
+});
+
+// POST /login
+//   Use passport.authenticate() as route middleware to authenticate the
+//   request.  If authentication fails, the user will be redirected back to the
+//   login page.  Otherwise, the primary route function function will be called,
+//   which, in this example, will redirect the user to the home page.
+//
+//   curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login
+app.post('/login',
+    passport.authenticate('atlassian-crowd', { failureRedirect:'/login', failureFlash:true }),
+    function (req, res) {
+        res.redirect('/');
+    });
+
+// POST /login
+//   This is an alternative implementation that uses a custom callback to
+//   acheive the same functionality.
+/*
+ app.post('/login', function(req, res, next) {
+ passport.authenticate('local', function(err, user, info) {
+ if (err) { return next(err) }
+ if (!user) {
+ req.flash('error', info.message);
+ return res.redirect('/login')
+ }
+ req.logIn(user, function(err) {
+ if (err) { return next(err); }
+ return res.redirect('/users/' + user.username);
+ });
+ })(req, res, next);
+ });
+ */
+
+app.get('/logout', function (req, res) {
+    req.logout();
+    res.redirect('/');
+});
+
+http.createServer(app).listen(app.get('port'), function () {
+    console.log("Express server listening on port " + app.get('port'));
+});
+
+
+// Simple route middleware to ensure user is authenticated.
+//   Use this route middleware on any resource that needs to be protected.  If
+//   the request is authenticated (typically via a persistent login session),
+//   the request will proceed.  Otherwise, the user will be redirected to the
+//   login page.
+function ensureAuthenticated(req, res, next) {
+    if (req.isAuthenticated()) {
+        return next();
+    }
+    res.redirect('/login')
+}

examples/login/package.json

+{
+  "name": "passport-atlassian-crowd-examples-login",
+  "version": "0.0.0",
+  "dependencies": {
+    "express": "3.x.x",
+    "connect-flash": "0.1.x",
+    "ejs": ">= 0.0.0",
+    "ejs-locals": ">= 0.0.0",
+    "passport": ">= 0.0.0",
+    "passport-atlassian-crowd": ">= 0.0.0"
+  }
+}

examples/login/views/account.ejs

+<% layout('layout') -%>
+<p>Username: <%= user.username %></p>
+<p>Email: <%= user.email %></p>
+

examples/login/views/index.ejs

+<% layout('layout') -%>
+<% if (!user) { %>
+	<h2>Welcome! Please log in.</h2>
+<% } else { %>
+	<h2>Hello, <%= user.username %>.</h2>
+<% } %>

examples/login/views/layout.ejs

+<!DOCTYPE html>
+<html>
+	<head>
+		<title>Passport-Local Example</title>
+	</head>
+	<body>
+		<% if (!user) { %>
+			<p>
+			<a href="/">Home</a> | 
+			<a href="/login">Log In</a>
+			</p>
+		<% } else { %>
+			<p>
+			<a href="/">Home</a> | 
+			<a href="/account">Account</a> | 
+			<a href="/logout">Log Out</a>
+			</p>
+		<% } %>
+		<%- body %>
+	</body>
+</html>

examples/login/views/login.ejs

+<% layout('layout') -%>
+<% if (message) { %>
+<p><%= message %></p>
+<% } %>
+<form action="/login" method="post">
+	<div>
+	<label>Username:</label>
+	<input type="text" name="username"/><br/>
+	</div>
+	<div>
+	<label>Password:</label>
+	<input type="password" name="password"/>
+	</div>
+	<div>
+	<input type="submit" value="Submit"/>
+	</div>
+</form>
+<p><small>Hint - bob:secret</small></p>

lib/passport-atlassian-crowd/errors/badrequesterror.js

+/**
+ * `BadRequestError` error.
+ *
+ * @api public
+ */
+function BadRequestError(message) {
+  Error.call(this);
+  Error.captureStackTrace(this, arguments.callee);
+  this.name = 'BadRequestError';
+  this.message = message || null;
+}
+
+/**
+ * Inherit from `Error`.
+ */
+BadRequestError.prototype.__proto__ = Error.prototype;
+
+
+/**
+ * Expose `BadRequestError`.
+ */
+module.exports = BadRequestError;

lib/passport-atlassian-crowd/index.js

+/**
+ * Module dependencies.
+ */
+var Strategy = require('./strategy')
+  , BadRequestError = require('./errors/badrequesterror');
+
+
+/**
+ * Framework version.
+ */
+require('pkginfo')(module, 'version');
+
+/**
+ * Expose constructors.
+ */
+exports.Strategy = Strategy;
+
+exports.BadRequestError = BadRequestError;

lib/passport-atlassian-crowd/strategy.js

+/**
+ * Module dependencies.
+ */
+var passport = require('passport'),
+    https = require('https'),
+    http = require('http'),
+    URL = require('url'),
+    util = require('util'),
+    BadRequestError = require('./errors/badrequesterror');
+
+
+/**
+ * `Strategy` constructor.
+ *
+ * The local authentication strategy authenticates requests based on the
+ * credentials submitted through an HTML-based login form.
+ *
+ * Applications must supply a `verify` callback which accepts `username` and
+ * `password` credentials, and then calls the `done` callback supplying a
+ * `user`, which should be set to `false` if the credentials are not valid.
+ * If an exception occured, `err` should be set.
+ *
+ * Optionally, `options` can be used to change the fields in which the
+ * credentials are found.
+ *
+ * Options:
+ *   - `usernameField`  field name where the username is found, defaults to _username_
+ *   - `passwordField`  field name where the password is found, defaults to _password_
+ *   - `passReqToCallback`  when `true`, `req` is the first argument to the verify callback (default: `false`)
+ *
+ * Examples:
+ *
+ *     passport.use(new LocalStrategy(
+ *       function(username, password, done) {
+ *         User.findOne({ username: username, password: password }, function (err, user) {
+ *           done(err, user);
+ *         });
+ *       }
+ *     ));
+ *
+ * @param {Object} options
+ * @param {Function} verify
+ * @api public
+ */
+function Strategy(options, verify) {
+    if (typeof options == 'function') {
+        verify = options;
+        options = {};
+    }
+    if (!verify) throw new Error('atlassian-crowd authentication strategy requires a verify function');
+
+    if (!options.crowdServer) {
+        throw new Error("atlassian-crowd strategy requires a crowd server url");
+    }
+
+    this._crowdServer = option.crowdServer;
+    this._crowdApplication = option.crowdApplication;
+    this._crowdApplicationPassword = option.crowdApplication;
+
+    this._usernameField = options.usernameField || 'username';
+    this._passwordField = options.passwordField || 'password';
+
+    passport.Strategy.call(this);
+    this.name = 'atlassian-crowd';
+    this._verify = verify;
+    this._passReqToCallback = options.passReqToCallback;
+}
+
+/**
+ * Inherit from `passport.Strategy`.
+ */
+util.inherits(Strategy, passport.Strategy);
+
+/**
+ * Authenticate request based on the contents of a form submission.
+ *
+ * @param {Object} req
+ * @api protected
+ */
+Strategy.prototype.authenticate = function (req, options) {
+    options = options || {};
+    var username = lookup(req.body, this._usernameField) || lookup(req.query, this._usernameField);
+    var password = lookup(req.body, this._passwordField) || lookup(req.query, this._passwordField);
+
+    if (!username || !password) {
+        return this.fail(new BadRequestError(options.badRequestMessage || 'Missing credentials'));
+    }
+
+    var self = this;
+
+
+    var http_library = https;
+    var parsedUrl = URL.parse(this._crowdServer, true);
+    if (parsedUrl.protocol == "https:" && !parsedUrl.port) {
+        parsedUrl.port = 443;
+    }
+
+    // As this is OAUth2, we *assume* https unless told explicitly otherwise.
+    if (parsedUrl.protocol != "https:") {
+        http_library = http;
+    }
+
+    var postData = JSON.stringify({
+        "value":password
+    });
+
+    var crowdRequest = http_library.request({
+        host:parsedUrl.hostname,
+        port:parsedUrl.port,
+        path:parsedUrl.pathname + "/authentication?username=" + username,
+        method:"POST",
+        headers:{
+            "Content-Type":"application/json",
+            "Content-Length":postData.length
+        }
+    }, function (res) {
+        console.log(res);
+    });
+    crowdRequest.write(postData);
+    crowdRequest.end();
+//
+//    function verified(err, user, info) {
+//        if (err) {
+//            return self.error(err);
+//        }
+//        if (!user) {
+//            return self.fail(info);
+//        }
+//        self.success(user, info);
+//    }
+//
+//    if (self._passReqToCallback) {
+//        this._verify(req, username, password, verified);
+//    } else {
+//        this._verify(username, password, verified);
+//    }
+//
+//    function lookup(obj, field) {
+//        if (!obj) {
+//            return null;
+//        }
+//        var chain = field.split(']').join('').split('[');
+//        for (var i = 0, len = chain.length; i < len; i++) {
+//            var prop = obj[chain[i]];
+//            if (typeof(prop) === 'undefined') {
+//                return null;
+//            }
+//            if (typeof(prop) !== 'object') {
+//                return prop;
+//            }
+//            obj = prop;
+//        }
+//        return null;
+//    }
+};
+
+
+/**
+ * Expose `Strategy`.
+ */
+module.exports = Strategy;
+{
+  "name": "passport-atlassian-crowd",
+  "version": "0.0.1",
+  "description": "Password authentication strategy using Atlassian Crowd for Passport",
+  "author": { "name": "Andreas Knecht", "email": "knecht.andreas@gmail.com"},
+  "repository": {
+    "type": "git",
+    "url": "https://bitbucket.org/knecht_andreas/passport-atlassian-crowd"
+  },
+  "main": "./lib/passport-atlassian-crowd",
+  "dependencies": {
+    "pkginfo": "0.2.x",
+    "passport": "~0.1.1"
+  },
+  "engines": { "node": ">= 0.4.0" },
+  "licenses": [ {
+    "type": "MIT",
+    "url": "http://www.opensource.org/licenses/MIT" 
+  } ],
+  "keywords": ["passport", "atlassian", "crowd", "auth", "authn", "authentication"]
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.