login-required.test.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /* eslint-disable arrow-body-style */
  2. const { getInstance } = require('../setup-crowi');
  3. describe('loginRequired', () => {
  4. let crowi;
  5. const fallbackMock = jest.fn().mockReturnValue('fallback');
  6. let loginRequiredStrictly;
  7. let loginRequired;
  8. let loginRequiredWithFallback;
  9. beforeEach(async(done) => {
  10. crowi = await getInstance();
  11. loginRequiredStrictly = require('@server/middlewares/login-required')(crowi);
  12. loginRequired = require('@server/middlewares/login-required')(crowi, true);
  13. loginRequiredWithFallback = require('@server/middlewares/login-required')(crowi, false, fallbackMock);
  14. done();
  15. });
  16. describe('not strict mode', () => {
  17. // setup req/res/next
  18. const req = {
  19. originalUrl: 'original url 1',
  20. session: {},
  21. };
  22. const res = {
  23. redirect: jest.fn().mockReturnValue('redirect'),
  24. };
  25. const next = jest.fn().mockReturnValue('next');
  26. test('pass guest user when aclService.isGuestAllowedToRead() returns true', () => {
  27. // prepare spy for AclService.isGuestAllowedToRead
  28. const isGuestAllowedToReadSpy = jest.spyOn(crowi.aclService, 'isGuestAllowedToRead')
  29. .mockImplementation(() => true);
  30. const result = loginRequired(req, res, next);
  31. expect(isGuestAllowedToReadSpy).toHaveBeenCalledTimes(1);
  32. expect(fallbackMock).not.toHaveBeenCalled();
  33. expect(next).toHaveBeenCalled();
  34. expect(res.redirect).not.toHaveBeenCalled();
  35. expect(result).toBe('next');
  36. });
  37. test('redirect to \'/login\' when aclService.isGuestAllowedToRead() returns false', () => {
  38. // prepare spy for AclService.isGuestAllowedToRead
  39. const isGuestAllowedToReadSpy = jest.spyOn(crowi.aclService, 'isGuestAllowedToRead')
  40. .mockImplementation(() => false);
  41. const result = loginRequired(req, res, next);
  42. expect(isGuestAllowedToReadSpy).toHaveBeenCalled();
  43. expect(fallbackMock).not.toHaveBeenCalled();
  44. expect(next).not.toHaveBeenCalled();
  45. expect(res.redirect).toHaveBeenCalledTimes(1);
  46. expect(res.redirect).toHaveBeenCalledWith('/login');
  47. expect(result).toBe('redirect');
  48. });
  49. test('pass anyone into sharedPage when aclService.isGuestAllowedToRead() returns false', () => {
  50. req.isSharedPage = true;
  51. // prepare spy for AclService.isGuestAllowedToRead
  52. const isGuestAllowedToReadSpy = jest.spyOn(crowi.aclService, 'isGuestAllowedToRead')
  53. .mockImplementation(() => false);
  54. const result = loginRequired(req, res, next);
  55. expect(isGuestAllowedToReadSpy).toHaveBeenCalled();
  56. expect(fallbackMock).not.toHaveBeenCalled();
  57. expect(next).toHaveBeenCalled();
  58. expect(res.redirect).not.toHaveBeenCalled();
  59. expect(result).toBe('next');
  60. });
  61. });
  62. describe('strict mode', () => {
  63. // setup req/res/next
  64. const req = {
  65. originalUrl: 'original url 1',
  66. session: null,
  67. };
  68. const res = {
  69. redirect: jest.fn().mockReturnValue('redirect'),
  70. sendStatus: jest.fn().mockReturnValue('sendStatus'),
  71. };
  72. const next = jest.fn().mockReturnValue('next');
  73. let isGuestAllowedToReadSpy;
  74. beforeEach(async(done) => {
  75. // reset session object
  76. req.session = {};
  77. // spy for AclService.isGuestAllowedToRead
  78. isGuestAllowedToReadSpy = jest.spyOn(crowi.aclService, 'isGuestAllowedToRead');
  79. done();
  80. });
  81. test('send status 403 when \'req.path\' starts with \'_api\'', () => {
  82. req.path = '/_api/someapi';
  83. const result = loginRequiredStrictly(req, res, next);
  84. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  85. expect(next).not.toHaveBeenCalled();
  86. expect(fallbackMock).not.toHaveBeenCalled();
  87. expect(res.redirect).not.toHaveBeenCalled();
  88. expect(res.sendStatus).toHaveBeenCalledTimes(1);
  89. expect(res.sendStatus).toHaveBeenCalledWith(403);
  90. expect(result).toBe('sendStatus');
  91. });
  92. test('redirect to \'/login\' when the user does not loggedin', () => {
  93. req.path = '/path/that/requires/loggedin';
  94. const result = loginRequiredStrictly(req, res, next);
  95. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  96. expect(next).not.toHaveBeenCalled();
  97. expect(fallbackMock).not.toHaveBeenCalled();
  98. expect(res.sendStatus).not.toHaveBeenCalled();
  99. expect(res.redirect).toHaveBeenCalledTimes(1);
  100. expect(res.redirect).toHaveBeenCalledWith('/login');
  101. expect(result).toBe('redirect');
  102. expect(req.session.redirectTo).toBe('original url 1');
  103. });
  104. test('pass user who logged in', () => {
  105. const User = crowi.model('User');
  106. req.user = {
  107. _id: 'user id',
  108. status: User.STATUS_ACTIVE,
  109. };
  110. const result = loginRequiredStrictly(req, res, next);
  111. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  112. expect(fallbackMock).not.toHaveBeenCalled();
  113. expect(res.sendStatus).not.toHaveBeenCalled();
  114. expect(res.redirect).not.toHaveBeenCalled();
  115. expect(next).toHaveBeenCalledTimes(1);
  116. expect(result).toBe('next');
  117. expect(req.session.redirectTo).toBe(undefined);
  118. });
  119. /* eslint-disable indent */
  120. test.each`
  121. userStatus | expectedPath
  122. ${1} | ${'/login/error/registered'}
  123. ${3} | ${'/login/error/suspended'}
  124. ${5} | ${'/login/invited'}
  125. `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
  126. req.user = {
  127. _id: 'user id',
  128. status: userStatus,
  129. };
  130. const result = loginRequiredStrictly(req, res, next);
  131. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  132. expect(next).not.toHaveBeenCalled();
  133. expect(fallbackMock).not.toHaveBeenCalled();
  134. expect(res.sendStatus).not.toHaveBeenCalled();
  135. expect(res.redirect).toHaveBeenCalledTimes(1);
  136. expect(res.redirect).toHaveBeenCalledWith(expectedPath);
  137. expect(result).toBe('redirect');
  138. expect(req.session.redirectTo).toBe(undefined);
  139. });
  140. /* eslint-disable indent */
  141. test('redirect to \'/login\' when user.status is \'STATUS_DELETED\'', () => {
  142. const User = crowi.model('User');
  143. req.path = '/path/that/requires/loggedin';
  144. req.user = {
  145. _id: 'user id',
  146. status: User.STATUS_DELETED,
  147. };
  148. const result = loginRequiredStrictly(req, res, next);
  149. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  150. expect(next).not.toHaveBeenCalled();
  151. expect(fallbackMock).not.toHaveBeenCalled();
  152. expect(res.sendStatus).not.toHaveBeenCalled();
  153. expect(res.redirect).toHaveBeenCalledTimes(1);
  154. expect(res.redirect).toHaveBeenCalledWith('/login');
  155. expect(result).toBe('redirect');
  156. expect(req.session.redirectTo).toBe('original url 1');
  157. });
  158. });
  159. describe('specified fallback', () => {
  160. // setup req/res/next
  161. const req = {
  162. originalUrl: 'original url 1',
  163. session: null,
  164. };
  165. const res = {
  166. redirect: jest.fn().mockReturnValue('redirect'),
  167. sendStatus: jest.fn().mockReturnValue('sendStatus'),
  168. };
  169. const next = jest.fn().mockReturnValue('next');
  170. let isGuestAllowedToReadSpy;
  171. beforeEach(async(done) => {
  172. // reset session object
  173. req.session = {};
  174. // spy for AclService.isGuestAllowedToRead
  175. isGuestAllowedToReadSpy = jest.spyOn(crowi.aclService, 'isGuestAllowedToRead');
  176. done();
  177. });
  178. test('invoke fallback when \'req.path\' starts with \'_api\'', () => {
  179. req.path = '/_api/someapi';
  180. const result = loginRequiredWithFallback(req, res, next);
  181. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  182. expect(next).not.toHaveBeenCalled();
  183. expect(res.redirect).not.toHaveBeenCalled();
  184. expect(res.sendStatus).not.toHaveBeenCalled();
  185. expect(fallbackMock).toHaveBeenCalledTimes(1);
  186. expect(fallbackMock).toHaveBeenCalledWith(req, res, next);
  187. expect(result).toBe('fallback');
  188. });
  189. test('invoke fallback when the user does not loggedin', () => {
  190. req.path = '/path/that/requires/loggedin';
  191. const result = loginRequiredWithFallback(req, res, next);
  192. expect(isGuestAllowedToReadSpy).not.toHaveBeenCalled();
  193. expect(next).not.toHaveBeenCalled();
  194. expect(res.sendStatus).not.toHaveBeenCalled();
  195. expect(res.redirect).not.toHaveBeenCalled();
  196. expect(fallbackMock).toHaveBeenCalledTimes(1);
  197. expect(fallbackMock).toHaveBeenCalledWith(req, res, next);
  198. expect(result).toBe('fallback');
  199. });
  200. });
  201. });