Как я могу проверить контроллер входа в Sails.js v1.0 с включенной защитой CSRF (с помощью mocha, supertest)? - PullRequest
0 голосов
/ 24 августа 2018

У меня есть почти новое приложение Sails.js 1.0.2, и я могу войти как с браузером, так и с почтальоном.Тем не менее, я не могу заставить этот процесс работать в моем тестовом прогоне.

Приведенный ниже тест должен привести к успешному входу в систему, когда возвращается cookie с новым идентификатором сеанса.Если я изменю конфигурацию безопасности, чтобы отключить CSRF-защиту , она работает отлично.Но при включенной защите запрос запрещен (403).Единственная существенная разница между тем, что я посылаю в Postman, заключается в том, что mocha запускает приложение на другом порту (Postman отправляет на localhost:1337, переменная express 'res говорит: PUT /api/v1/entrance/login HTTP/1.1 Host: 127.0.0.1:56002

мне не хватает?

Вот тестовый файл:

/**
 * /test/integration/controllers/entrance/login.test.js
 */

'use strict';

const supertest = require('supertest');  // also tried supertest-session

describe('Entrance controllers', () => {

  describe('/api/v1/entrance/login', () => {

    before(() => {
      return supertest(sails.hooks.http.app)
      .get('/login')
      .then(res => {
        const reTokenCapture = /_csrf:\s*unescape\('([^']+)'\)/;
        const found = reTokenCapture.exec(res.text);
        this._csrf = sails.config.security.csrf ? found[1] : '';
        this.url = '/api/v1/entrance/login';
      });
    });

    it('should return a session cookie in response headers', () => {
      return supertest(sails.hooks.http.app)
      .put(this.url)
      .set('x-csrf-token', this._csrf)
      .send({
        emailAddress: 'admin@example.com',
        password: 'abc123',
        // _csrf: this._csrf,  // I tried this too; no luck
      })
      .expect(200)  // if sails.config.security.csrf is enabled, status is 403
      .then(res => {
        // console.log('res:', res);  // this shows the correct header
        res.headers['set-cookie'].should.be.an('array');
        const hasSid = res.headers['set-cookie'].map(cookie => {
          const reSid = /^sails\.sid=[^;]+;\sPath=\/;(?:\sExpires=[^;]+GMT;)?\sHttpOnly$/;
          return reSid.test(cookie);
        });
        hasSid.should.include.members([true]);
      });
    });

  });

});

Я использую узел v8.11.3, паруса v1.0.2, mocha v5.2.0, супертест v3.1.0, chai v4.1.2

К вашему сведению, вот запрос Почтальона, который работал нормально (токен CSRF был скопирован вручную предыдущим запросом Почтальона на GET /login):

PUT /api/v1/entrance/login HTTP/1.1
Host: localhost:1337
x-csrf-token: mjWXQTa2-RFEHu78Tr-JGJwhWeryKGRJI4S8
Cache-Control: no-cache
Postman-Token: e3d920fe-6178-4642-80e4-8005b477fd98

{"emailAddress": "admin@example.com", "password":"abc123"}

1 Ответ

0 голосов
/ 24 августа 2018

Понял!Я думал, что должен был получить идентификатор сеанса из заголовка set-cookie после входа в систему. Вместо этого я должен захватить как токен CSRF, так и идентификатор сеанса, когда он все еще вышел из системы, затем отправить электронную почту и пароль, а затем использовать токени ID в последующих запросах.Я упустил эту деталь в Postman, потому что не заметил cookie, который сохранялся между запросами.

Вот исправленный тестовый файл (теперь работает с включенной защитой CSRF) :

/**
 * /test/integration/controllers/entrance/login.test.js
 */

'use strict';

const supertest = require('supertest');  // also tried

describe('Entrance controllers', () => {

  describe('/api/v1/entrance/login', () => {

    before(() => {
      this._url = '/api/v1/entrance/login';

      return supertest(sails.hooks.http.app).get('/login')
      .then(getRes => {
        const reTokenCapture = /_csrf:\s*unescape\('([^']+)'\)/;
        const foundToken = reTokenCapture.exec(getRes.text);
        this._csrf = sails.config.security.csrf ? foundToken[1] : '';
        this._cookie = getRes.headers['set-cookie'].join('; ');
      });

    });

    it('should accept the session ID & CSRF token procured by GET /login', () => {
      return supertest(sails.hooks.http.app)
      .put(this._url)
      .set('Cookie', this._cookie)
      .set('X-CSRF-Token', this._csrf)
      .send({
        emailAddress: 'admin@example.com',
        password: 'abc123',
      })
      .expect(200);
    });

    it('should reject requests without a CSRF token', () => {
      return supertest(sails.hooks.http.app)
      .put(this._url)
      .set('Cookie', this._cookie)
      .expect(403);
    });

    it('should reject requests without a session cookie', () => {
      return supertest(sails.hooks.http.app)
      .put(this._url)
      .set('Cookie', '')
      .set('x-csrf-token', this._csrf)
      .expect(403);
    });

    it('should reject requests with invalid tokens', () => {
      return supertest(sails.hooks.http.app)
      .put(this._url)
      .set('Cookie', 'sails.sid=foo; Path=/; HttpOnly')
      .set('X-CSRF-Token', 'foo')
      .send({
        emailAddress: 'admin@example.com',
        password: 'abc123',
      })
      .expect(403);
    });

    it('should reject requests with invalid credentionals', () => {
      return supertest(sails.hooks.http.app)
      .put(this._url)
      .set('Cookie', this._cookie)
      .set('X-CSRF-Token', this._csrf)
      .send({
        emailAddress: 'user@example.com',
        password: 'password'
      })
      .expect(401);
    });

    it('should reject get requests', () => {
      return supertest(sails.hooks.http.app)
      .get(this._url)
      .set('Cookie', this._cookie)
      .set('X-CSRF-Token', this._csrf)
      .send({
        emailAddress: 'admin@example.com',
        password: 'abc123',
      })
      .expect(404);
    });

    it('should reject post requests', () => {
      return supertest(sails.hooks.http.app)
      .post(this._url)
      .set('Cookie', this._cookie)
      .set('X-CSRF-Token', this._csrf)
      .send({
        emailAddress: 'admin@example.com',
        password: 'abc123',
      })
      .expect(404);
    });

  });

});
...