3

What is the equivalent of express/connect app.use in Mojito?

I would like to use middleware defined in a third party Node JS module and in an express/connect app, this is done by using the app.use function; based on the Mojito docs (http://developer.yahoo.com/cocktails/mojito/docs/topics/mojito_extensions.html#middleware), this can be configured through the application.json file, but I wasn't able to successfully do this yet.

Here are the steps taken so far.

- for the PassportJS module, the passport.initialize middleware is required; in an Express/Connect app, this configuration would be done as follows:
app.configure(function() {
 ...
 app.use(passport.initialize());
 ...
});
- in Mojito, I added the following to the application.json file:
        "middleware": [
            "./node_modules/passport/lib/passport/middleware/initialize.js"
        ]
however when submitting any request to the application, the browser is waiting for the localhost forever, without any response.

- when removing the above middleware setting form application.json, the app responds to browser requests right away, but of course the application logic is not correct, because the required middleware was not executed.


Any ideas on how to solve this?

  • Tags:
  • m
by
  • BL
  • Sep 15, 2012
31 Replies
  • Hi BL,

    You can require the 'passport' module in the middleware and then invoke 'initialize()'.

    example application.json

    [
        {
            "settings": [ "master" ],
            "middleware": [
              "./middleware/initialize_passport.js"
            ],
            "specs": {
              "passportExample": {
               "type": "passportMojit"
             }
          }
      }
    ]

    /middleware/initialize_passport.js

    module.exports = function (req, res, next) {
      var passport = require('passport');
      passport.initialize();
      // do something
      next();
    };

    Unfortunately, I haven't tried using passport for authentication or OAuth authorization. Express works at a lower level than Mojito, so I'm not sure how easy it would be to take the Passport examples and apply them to Mojito.

    I did find the following passport examples (you may have seen them already):

    - https://github.com/jaredhanson/passport-local/tree/master/examples
    - https://gist.github.com/1712931
    - https://github.com/JanVanRyswyck/node-examples/tree/master/passport

    Let me know how far you get. I'll see if I can help you or find someone who can. 

    ~Joe


    1
  • Thanks Joe for your response! I've tried what you suggested, but it didn't seem to do what was expected.

    I'm wondering if this has to do the way the initialize middleware is written. If you look into the PassportJS module, I believe in index.js (lines 103-107) the initialize property of Passport is set to a function that returns the initialize() function (from the middleware folder of the passport module) and the function is bound to the current instance of Passport... not sure if I'm interpreting the code correctly though.

    Any other ideas? It would be great if someone in your team could spend some time playing around with this to get a basic example going. I am assuming similar problems might arise when trying to use other third party modules that require configuration in the app.use style.

    Thank you!
    1
  • Hi BL,

    Sorry, I tried adapting the login example (https://github.com/jaredhanson/passport-local/blob/master/examples/login/app.js) for Mojito but didn't have much luck. I have requested help from other fellow Yahoos, so hopefully one of them can help you.

    ~Joe
    1
  • Thanks for the update Joe, looking forward for a solution!
    1
  • Any news Joe?
    1
  • Hi,
    I had the same issue. I just sent a pull request for solving this kind of problem.

    Take a look here https://github.com/yahoo/mojito/pull/661
    1
  • Hi,

    I just sent a pull request that fixes this issue. Anyway you can set your middleware on the options object.

    var options.appConfig = {
    middleware: [
    'middleware-passport-init',
    'middleware-passport-session'
    ]
    };

    But those middlewares need to be on the root folder. With my fix, you can set a folder to hold all middlewares. For example:

    var options.midDir = 'middleware';

    For more information take a look here: https://github.com/yahoo/mojito/pull/661



    QUOTE(BL @ 26 Sep 2012 5:09 PM)
    Any news Joe?
    1
  • Thanks Rodrigo! I will look into your suggestion.
    1
  • Hi Rodrigo, what do you have in your middleware-passport-init.js file?

    1
  • Hi,

    Just two lines of code:

    var passport = require('passport');
    module.exports = passport.initialize();




    QUOTE(BL @ 25 Oct 2012 10:03 AM)
    Hi Rodrigo, what do you have in your middleware-passport-init.js file?

    1
  • Thanks Rodrgio, how about the middleware-passport-session.js file? For the module.exports = passport.session(); statement how do you get access to the same passport instance that was defined in the middleware-passport-init.js file?
    1
  • Hi,

    I'm not sure if you really need it. Just do the same like this:
     
    var passport = require('passport');
    module.exports = passport.session();

    You also need to export express.session() before all those middlewares. The last one, called middleware-passport-session has the logic to work with the facebook API just like the example from passportjs.org.

    Give me some time and I will publish a working version on my github.




    QUOTE(BL @ 26 Oct 2012 11:25 AM)
    Thanks Rodrgio, how about the middleware-passport-session.js file? For the module.exports = passport.session(); statement how do you get access to the same passport instance that was defined in the middleware-passport-init.js file?
    1
  • Sorry. I was wrong in the last reply.. "the last one" I meant is another middleware I've created called middleware-passport-facebook and not "middleware-passport-session". So my config looks like the code below:

    var options.appConfig = { 
    middleware: [
    'middleware-passport-init',
    'middleware-passport-session',

      'middleware-passport-facebook', // this file contains the callbacks
    ]
    };



    1
  • Sorry for jumping onto this thread; it offers the best clues I was able to find, but I remain clueless.

    What happens to the exports defined in the middleware files?

    Having set it up as you suggest, the only trace of passport I could find is stashed inside action context passed to action methods, such as: {{{ index: function(ac) { console.log(ac.cookie.req._passport); }}}

    I understand the idea of middleware is to be completely transparent, but I still need a handle to passport somewhere I can set it up and add a strategy, and so forth. And then, how do I check whether it is in the logged-in state or not when I am inside an action? I do need to redirect to /login if it is in the wrong state, right?

    1
  • How about this:

    export NODE_PATH="/usr/local/lib/node_modules/mojito/node_modules" (or where you have mojito installed). You can persist this by including it in your .bashrc file and source it afterward.

    Then all you have to do is declare:

    var passport = require('passport');

    where you want to use and call the variable password. YOu can check that passport is installed and it works for example by: console.log(passport;

    1
  • Setting NODE_PATH to $HOME/lib/node_modules/mojito/node_modules and then linking

    $HOME/lib/node_modules/mojito/node_modules/passport -> $HOME/lib/node_modules/passport

    did help in the loading of passport through the middleware config as described above (my node is installed in $HOME; both mojito and passport are installed using nom install -g, so setting NODE_PATH to node_modules and symlinking passport therein did the job).

    The next hurdle: While I was bumbling around trying to load passport, the init action has been removed from mojito controllers and now I can't find a way to hook passport into the controller object (or action context). I see Caridy's comment about the _app property on the server object, but I can't find it. None of the objects stored as app property in the depths of the action context has it, and this code

    var app = Mojito.createServer();

    inside server.js does not get called. It looks like server.js is not used anywhere in the server loop (I have verified that by running stat on it)

    It would be nice to hear from somebody who could give a recipe for setting up session management under mojito. Session management can be hideously complex; there are solutions for it (possport is one); I just can't figure out how to hook one up with mojito (or wrap one around it).

    2
  • Ops, sorry @GeneS, I forgot to mention that you can boot your app by doing $ node server.js instead of $ mojito start, they should be equivalent, except for the ability to pass the custom context using --context environment:development', in which case you can pass{environment: "device"}as the default configuration for context inserver.js` as well.

    In any case, we plan to consolidate all these different ways to boot the app.

    Hopefully that will get you unblock in the meantime.

    1
  • Btw, you can always create a mojito middleware, similar to those we ship by default, and add them into the list of middleware to get them plug thru app.use under the hood, in that middleware, you can get req.app as well.

    1
  • Definitely the smoothest way to go by hooking into the mojito middleware using the setting as per Rodrigo Nicola. The key is linking letting mojito load your middleware, by calling your passport insertion code mojito-my-middleware.js then you don't need app.use. You can check the passport code to see what you should be doing.

    When that is correctly done, you get a User object on the HTTP Request. so Mojits become as simple as:
    req = ac.http.getRequest();
    userInfo = ac.req.user;

    Hope that's not too cryptic.

    1
  • Hi All,

    First off, thank you for taking the time to read this post.

    I too am trying to get Passportjs (with sessions stored in redis) to work with mojito. I am currently stuck on how to include "express.session" before all of the other passport related functions.

    I placed the following code in a middleware file that I called "express-redis-session.js":

    var redis = require("redis").createClient();
    var express = require('express');
    var RedisStore = require('connect-redis')(express);
    
     module.exports =  function () {
                    return express.session({
                      secret: "my secret",
                      store: new RedisStore({ host: 'localhost', port: 6379, client: redis }),
                                  cookie: { secure: false, maxAge:86400000 }
            });};
    

    The middleware in application.js file looks like the following:

    "./middleware/express-redis-session.js",
              "./middleware/passport-init.js",
              "./middleware/passport-session.js",
              "./middleware/passport-local-callbacks.js"
    

    In my package.json file I have the following dependencies:

    "dependencies": {
            "mojito": "0.5.x",
            "passport": ">= 0.0.0",
            "passport-local": ">= 0.0.0",
            "redis": ">= 0.0.0",
            "connect-redis": ">= 0.0.0"
        },
    

    The problem I am hitting is that the runtime does not recognize the "require(express)" statement. If I try to include express in my node_modules (version 2.5.10) and add it to my dependencies list, the program just hangs after I load the first page.

    What is the proper way to use req.app to accomplish loading up the express.session with redis?

    Thanks again for your time and help.

    1
  • @Jay, it will be difficult to spot the issue without a very small reproducible code. If you can provide a basic example, I can try to help you.

    1
  • Jay,

    I think I have now understood enough, if not to answer your question, at least to help us ask better questions (thanks to Caridy, Ronald, and everybody here -- although not completely unblocked, I am making progress).

    First off, a couple general observations.

    1. If you require something and it is not found, make sure the module you are requiring is in your NODE_PATH. That much we've figured out in the top part of this thread.

    2. Since the magic of middleware insertion has not been properly explained, it may be helpful to understand that module.exports in each of the middleware files listed in application.json defines the function that will be called during each request. For each middleware, this request callback function will have this signature:

    
    module.exports = function (request, response, next) {
      ...
      next();
    };
    
    

    Here you can see how different layers of middleware are chained. If you want to break the chain, just don't call the next middleware in the stack. Their stacking order is determined by the order they appear in application.json

    Now, if you want to do any initialisation or set context for a middleware request callback just once, you can do it in each middleware file outside the callback function that gets assigned to module.exports. Anything you write there will be executed when mojito builds its middleware chain on start-up.

    That's how much I've understood so far. I believe you don't want to set up your own express because express is already part of mojito and you can access it through the request object in your middleware callback that runs once for each request. Setting up a new instance of express would make no sense. Same applies to connect. But passport is not there, so you do need to set it up during start-up the way Rodrigo has shown above:

    
    var passport = require('passport');
    module.exports = passport.initialize();
    
    

    The magic not visible here is that the call to passport.initialize() returns a properly formed middleware callback. So, if you want to further modify your passport by, for example, adding a strategy, you do:

    
    var passport = require('passport');
    var LocalStrategy = require("passport-local").Strategy;
    
    passport.use(new LocalStrategy(
      function(username, password, done) {
        ...
      }
    ));
    
    module.exports = passport.initialize();
    
    

    What I still do not understand is how does one go about augmenting the already instantiated objects like express and connect outside the middleware callbacks, i.e., at the start-up stage (if one needs to).

    I understood Caridy as saying that you can apply all required customisations on the app object returned by Mojito.createServer() in server.js, instead of running mojito start, in which case the reference to the app object never gets exposed outside the middleware callbacks.

    The call to createServer() returns a fully configured app object with middleware set up and chained in. I haven't explored this option yet because it did not work in the previous version of mojito I had installed. I just verified that it works now (mojito@0.5.5).

    1
  • Just to clear all doubts, here is a demo:

    https://github.com/caridy/mojito-demos/tree/master/passport

    hope that helps, I added some comments here and there to try to explain the flow. Feel free to drop any question here.

    1
  • Thanks Caridy and GeneS,

    Both of your explanations really helped. I mocked up a quick and dirty login to demonstrate how to use basic sessions with passportjs and mojito.

    You can find the code here:

    http://github.com/jayppc/mojito-demos/tree/master/passport

    I may work on throwing together a redis example. I actually moved on to evaluate other frameworks, but I appreciated the response and wanted to help out in case others are confused.

    Please note that in "mojits/login/controller.server.js" the basic passport.authentication function was not redirecting properly so I wrote it out in a probably unnecessary way.

    Thanks again for your help. It is really appreciated.

    Does the Mojito team have planned integrating easier session support out of the box?

    Also, when the Manhattan service is up, what will be the recommended storage engine? It doesn't seem like YQL would be appropriate in many cases.

    1
  • @Jay, I'm glad you get something working. As for the other questions:

    • No, we plan to keep the core very small, and people can provide archetypes and extensions to augment the functionalities, but we don't have plans to have have session support out of the box, in fact, at Yahoo! scale we don't use session.
    • I don't have any info or timeline about manhattan for the public, but it does provide multiple storage engines at the moment, including mobstor/hadoop, redis, etc. YQL is not a storage engine at scale.
    1
  • @caridy,

    Thanks again for your insight. In regards to not using sessions, is that because your implementation uses encrypted cookies to store the traditional session data (user roles/rights), or does it mean that your requirements are more "R" than full on CRUD.?

    I am experimenting with using redis (with frequent persisting) as the "session store" and also just general cache, so all front end instances would have access to the same data store. I see how scaling could be more difficult with the central repository of session data, opposed to delegating it to the client. I have read some mix reactions to encrypted cookies and wanted to see what your take on it was.

    Great Job, on Mojito, by the way. I like the ideas behind it. I hope it gathers a bigger community following.

    2
  • All right, making some progress here. Thanks to Jay's monumental efforts, I have working passport sessions. But I could make them work only by making my mojits consult with the passport object and redirect to /login. That is not the proper use of middleware, I don't think.

    When I try to redirect in the middleware, like this:

    if (req.isAuthenticated()) {
      next();
    }
    else {
      res.redirect('/login');
    }
    

    I get a redirect loop, and I don't know how to break it.

    Ideally, I would like to use connect-ensure-login, but I do not understand how to plug it in correctly. It works by inserting an additional argument in all action methods requiring authentication, like so:

    app.get('/account',
      ensureLoggedIn('/login'),
      function(req, res) {
        res.send('Hello ' + req.user.username);
      }
    );
    

    Is there a way to map app.get() and app.post() to Mojito controller actions that would allow such insertion?

    1
  • GeneS, You get into the infinite loop because your middleware is redirecting you to a page that is not whitelisted from the redirect routine. If you redirect to /login, your middleware will be executed again for that page, and the user will still not be logged, so, you either whitelist that url, or mark the url with something to identify it later on.

    In express, the whitelist process is simple, just add the authentication middleware to those urls that requires it, but in mojito that is not possible, and all requests will be processed thru all enabled middleware. We are going to change that in 0.6.x where we plan to bring express as a first class citizen in mojito, but in the meantime, you will have to deal with that at the middleware level.

    1
  • Caridy, I get the impression that when I receive the request object in middleware as an argument of its eported function, the header has already been sent to the browser and it's already too late to redirect -- is that so? One of the symptoms is:

    http.js:578
        throw new Error("Can't render headers after they are sent to the client.")
    

    Is there an alternative exit from a middleware function besides calling next()? I mean, something that would cancel the current rendering queue and allow me to start another? If I simply return without calling next(), the response is left in an incomplete state.

    An alternative rendering path could be equivalent to a redirect, for the purposes of design.

    For now, I can use this solution (a version of passport-session.js middleware in Jay's example):

    module.exports = function (req, res, next) {
      // we want to take control of the middleware so we can
      // initialize and also attach passport into req object
      passport_session(req, res, function (err) {
        if (err) {
          return next(err);
        }
    
        if (!req.isAuthenticated() && !req.url.match(/login/)) { // whitelist /login
          res.send('Please <a href="/login">log in</a>');
        }
        else {
          // returning control back to mojito flow
          next();
        }
      });
    };
    

    I guess I can render the login page as raw html here, instead of using a login mojit. But asking the user to follow a link to it is not too bad either. I just wonder if those are all my options at the moment.

    1
  • GeneS, middlewares are executed at the top of the chain before mojito dispatcher kicks in. Your custom middleware will be executed before any mojito middleware, so, unless you're sending something to the client, it should not fail to send those headers.

    That being said, I remember some issues in express with POST requests and redirect. If this request happens to be a POST, then you will have to do something like this to force express to do a full redirect and discard the post:

    req.method = 'get';
    res.redirect('/login');
    

    otherwise express will do an internal redirect.

    1
  • It works now, thanks!

    I would have never imagined that you needed to alter the request object to change the composition of the response.

    It works with POST as well, to the extent I could test it.

    0

Recent Posts

in Yahoo! Mojito