login-required.test.js 8.3 KB

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