Overdrivr / micro-ci

Continuous Integration for embedded platforms
0 stars 0 forks source link

Test middleware that moves access token from passport session to authorization header #98

Open Overdrivr opened 8 years ago

Overdrivr commented 8 years ago

This middleware is located in ./server/server.js, registered right after passport.session(). It was added by f2e71a606fb6aea8e97aa70faa52cebb533c722b

To test it, it is necessary to inject manually a fake access token in a request, inside req.passport.user.accessToken

Initially wrote the following test but it doesn't work, the injected data is removed before it reaches the middleware to test.

var request = require('supertest'),
    async   = require('async'),
    assert  = require('chai').assert,
    clear   = require('clear-require'),
    payload = require('./github-repos-getall-payload.json');

describe('Session', function() {

    var app   = {};
    var clientToken = '';
    var nock = require('nock');

    // Create a test user for authenticated requests
    before(function(done) {
      clear('../../server/server');
      app = require('../../server/server');

      async.waterfall([
        function(callback) {
          app.models.Client.create({
            email: 'foo@bar.com',
            password: 'dummy',
            provider: 'github',
            providerId: 1
          }, function(err, client) {
            if (err) return callback(err);
            if (!client) return callback(Error('Could not create client.'));
            callback(null, client);
          });
        },
        function(client, callback) {
          client.createAccessToken(1209600, function(err, token) {
            if (err) return callback(err);
            if (!token) return callback(new Error('token could not be created'));
            clientToken = token.id;
            callback();
          });
        }
      ], function(err, result) {
        if (err) return done(err);
        done();
      }
    );
  });

  after(function(done)
  {
    if(nock.pendingMocks().length >  0) //Make sure no pending mocks are available. Else it could influence the next test
      return done(new Error("Pending mocks in nock :"+ nock.pendingMocks()))
    nock.cleanAll();
    done();
  });

  it('Should not be able to make an authenticated request without session data',
  function(done) {
    request(app)
      .get('/api/Repositories/me/github')
      .expect(401, done);
  });

  it('Should be able to make an authenticated request with session data',
  function(done) {
    var nockGithub = nock('https://api.github.com/')
      .get('/user/repos')
      .query({access_token: clientToken})
      .reply(200, payload);

    var req = request(app).get('/api/Repositories/me/github');

    req.session= {
          passport: {
            user: {
              userId: 1,
              accessToken: clientToken
            }
          }
        };
      }
      req.expect(200, function(err, res){
        if (err) return done(err);
        done();
      });
  });
});

Opened a question on SO, because I don't know for now how to test that.

Overdrivr commented 8 years ago

A potential solution:

  1. nock endpoints that passport will try to call during passport's authentication transaction
  2. Call passport.authenticate, faking the temporary token exchange transaction
  3. At this point, passport receives a fake oauth token in return, and creates a session
  4. use some npm module (supertest-session ?) to keep this session alive between api calls
  5. Call api/repositories/me/github (with api.github.com also nocked). It should return a fake list of repositories, validating the middleware

Also, if nocking external oauth provider endpoints works, then it means we could test the entire oauth flow in unit tests, which would be great. To investigate

Overdrivr commented 8 years ago

A quick idea for a simpler solution:

  1. Use passport-local as unique strategy for this test. We are trying to bypass external providers anyway
  2. Login to the server to have passport generate a session, calling auth/login endpoint
  3. Use supertest-session to maintain session data for a second api call, on api/Repositories/me/github
  4. Done

This has the advantage to validate everything from passport authenticating the user to the acl system, through the middleware we want to test in this ticket