Skip to content

Commit fe64fc5

Browse files
Adding JWT Authentication Functionality
stopping point added tests for action loginJwt Added some more tests for the actions class JWT Token Authentication - Fixes apache#1468
1 parent 6db0708 commit fe64fc5

17 files changed

+892
-40
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,6 @@ coverage
4949
# IDEs
5050
.idea/
5151
.vscode
52+
/docker/formatted.key
53+
/docker/test_private_key.pem
54+
/docker/test_public_key.pem
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
2+
// use this file except in compliance with the License. You may obtain a copy of
3+
// the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
// License for the specific language governing permissions and limitations under
11+
// the License.
12+
13+
import FauxtonAPI from "../../../core/api";
14+
import FauxtonJwt from "../fauxtonjwt";
15+
import Api from '../api';
16+
import {loginJwt, login} from "../actions";
17+
import utils from "../../../../test/mocha/testUtils";
18+
import sinon, {stub} from "sinon";
19+
20+
const {restore} = utils;
21+
22+
describe('Auth -- Actions', () => {
23+
24+
describe('loginJwt', () => {
25+
26+
const authenticatedResponse = {
27+
"ok": true,
28+
"userCtx": {
29+
"name": "tester",
30+
"roles": [
31+
"manage-account",
32+
"view-profile",
33+
"_admin"
34+
]
35+
},
36+
"info": {
37+
"authentication_handlers": [
38+
"cookie",
39+
"jwt",
40+
"default"
41+
],
42+
"authenticated": "jwt"
43+
}
44+
};
45+
46+
const jwtNotSetupResponse = {
47+
"ok": true,
48+
"userCtx": {
49+
"name": null,
50+
"roles": []
51+
},
52+
"info": {
53+
"authentication_handlers": [
54+
"cookie",
55+
"default",
56+
]
57+
}
58+
};
59+
60+
const unathenticatedResponse = {
61+
"ok": true,
62+
"userCtx": {
63+
"name": null,
64+
"roles": []
65+
},
66+
"info": {
67+
"authentication_handlers": [
68+
"cookie",
69+
"default",
70+
"jwt"
71+
]
72+
}
73+
};
74+
75+
let loginStub;
76+
let loginJwtStub;
77+
let deleteJwtCookieStub;
78+
let addNotificationStub;
79+
let navigateStub;
80+
81+
beforeEach(() => {
82+
loginJwtStub = stub(Api, "loginJwt");
83+
loginStub = stub(Api, "login");
84+
deleteJwtCookieStub = stub(FauxtonJwt, "deleteJwtCookie");
85+
addNotificationStub = stub(FauxtonAPI, "addNotification");
86+
navigateStub = stub(FauxtonAPI, "navigate");
87+
});
88+
89+
afterEach(() => {
90+
restore(loginJwtStub);
91+
restore(loginStub);
92+
restore(addNotificationStub);
93+
restore(deleteJwtCookieStub);
94+
restore(navigateStub);
95+
});
96+
97+
it('loginJwt logs in if userCtx present', async () => {
98+
loginJwtStub.returns(Promise.resolve(authenticatedResponse));
99+
100+
const mockToken = "mockToken";
101+
102+
await loginJwt(mockToken);
103+
104+
expect(loginJwtStub.calledOnce).toBeTruthy();
105+
expect(loginStub.notCalled).toBeTruthy();
106+
expect(addNotificationStub.calledOnce).toBeTruthy();
107+
expect(navigateStub.calledOnce).toBeTruthy();
108+
sinon.assert.calledWithExactly(
109+
navigateStub,
110+
'/');
111+
});
112+
113+
it('loginJwt is not called if token is empty', async () => {
114+
loginJwtStub.returns(Promise.resolve(authenticatedResponse));
115+
116+
const mockToken = "";
117+
118+
await loginJwt(mockToken);
119+
120+
expect(loginJwtStub.notCalled).toBeTruthy();
121+
expect(loginStub.notCalled).toBeTruthy();
122+
expect(addNotificationStub.calledOnce).toBeTruthy();
123+
expect(navigateStub.notCalled).toBeTruthy();
124+
});
125+
126+
it('loginJwt does not navigate if jwt auth is not enabled', async () => {
127+
loginJwtStub.returns(Promise.resolve(jwtNotSetupResponse));
128+
129+
const mockToken = "mockToken";
130+
131+
await loginJwt(mockToken);
132+
133+
expect(loginJwtStub.calledOnce).toBeTruthy();
134+
expect(loginStub.notCalled).toBeTruthy();
135+
expect(deleteJwtCookieStub.calledOnce).toBeTruthy();
136+
expect(addNotificationStub.calledOnce).toBeTruthy();
137+
expect(navigateStub.notCalled).toBeTruthy();
138+
});
139+
140+
it('loginJwt does not navigate if jwt auth is not successful', async () => {
141+
loginJwtStub.returns(Promise.resolve(unathenticatedResponse));
142+
143+
const mockToken = "mockToken";
144+
145+
await loginJwt(mockToken);
146+
147+
expect(loginJwtStub.calledOnce).toBeTruthy();
148+
expect(loginStub.notCalled).toBeTruthy();
149+
expect(deleteJwtCookieStub.calledOnce).toBeTruthy();
150+
expect(addNotificationStub.calledOnce).toBeTruthy();
151+
expect(navigateStub.notCalled).toBeTruthy();
152+
});
153+
});
154+
155+
describe('login', () => {
156+
157+
const authenticatedResponse = {
158+
"ok": true,
159+
"userCtx": {
160+
"name": "tester",
161+
"roles": [
162+
"_admin"
163+
]
164+
},
165+
"info": {
166+
"authentication_handlers": [
167+
"cookie",
168+
"default"
169+
],
170+
"authenticated": "cookie"
171+
}
172+
};
173+
174+
let loginStub;
175+
let loginJwtStub;
176+
let addNotificationStub;
177+
let navigateStub;
178+
179+
beforeEach(() => {
180+
loginJwtStub = stub(Api, "loginJwt");
181+
loginStub = stub(Api, "login");
182+
addNotificationStub = stub(FauxtonAPI, "addNotification");
183+
navigateStub = stub(FauxtonAPI, "navigate");
184+
});
185+
186+
afterEach(() => {
187+
restore(loginJwtStub);
188+
restore(loginStub);
189+
restore(addNotificationStub);
190+
restore(navigateStub);
191+
});
192+
193+
it('login logs in if there is no error', async () => {
194+
loginStub.returns(Promise.resolve(authenticatedResponse));
195+
196+
const mockUser = "mockUser";
197+
const mockPassword = "mockPassword";
198+
199+
await login(mockUser, mockPassword);
200+
201+
expect(loginJwtStub.notCalled).toBeTruthy();
202+
expect(loginStub.calledOnce).toBeTruthy();
203+
expect(addNotificationStub.calledOnce).toBeTruthy();
204+
expect(navigateStub.calledOnce).toBeTruthy();
205+
sinon.assert.calledWithExactly(
206+
navigateStub,
207+
'/');
208+
});
209+
210+
it('login does not log in if username is blank', async () => {
211+
loginStub.returns(Promise.resolve(authenticatedResponse));
212+
213+
const mockUser = "";
214+
const mockPassword = "mockPassword";
215+
216+
await login(mockUser, mockPassword);
217+
218+
expect(loginJwtStub.notCalled).toBeTruthy();
219+
expect(loginStub.notCalled).toBeTruthy();
220+
expect(addNotificationStub.calledOnce).toBeTruthy();
221+
expect(navigateStub.notCalled).toBeTruthy();
222+
});
223+
224+
it('login does not log in if password is blank', async () => {
225+
loginStub.returns(Promise.resolve(authenticatedResponse));
226+
227+
const mockUser = "mockUser";
228+
const mockPassword = "";
229+
230+
await login(mockUser, mockPassword);
231+
232+
expect(loginJwtStub.notCalled).toBeTruthy();
233+
expect(loginStub.notCalled).toBeTruthy();
234+
expect(addNotificationStub.calledOnce).toBeTruthy();
235+
expect(navigateStub.notCalled).toBeTruthy();
236+
});
237+
});
238+
});

app/addons/auth/__tests__/api.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import FauxtonJwt from "../fauxtonjwt";
2+
import Helpers from "../../../helpers";
3+
import utils from "../../../../test/mocha/testUtils";
4+
import sinon, {stub} from "sinon";
5+
import {loginJwt, logout} from "../api";
6+
import * as ajax from "../../../core/ajax";
7+
8+
const {restore} = utils;
9+
10+
jest.mock("../../../core/ajax");
11+
12+
describe('Api -- Actions', () => {
13+
14+
const sessionUrl = "http://testurl/_session";
15+
16+
describe('loginJwt', () => {
17+
18+
let setJwtCookieStub;
19+
let deleteJwtCookieStub;
20+
let getServerUrlStub;
21+
22+
beforeEach(() => {
23+
setJwtCookieStub = stub(FauxtonJwt, "setJwtCookie");
24+
deleteJwtCookieStub = stub(FauxtonJwt, "deleteJwtCookie");
25+
getServerUrlStub = stub(Helpers, "getServerUrl");
26+
ajax.get.mockReturnValue(Promise.resolve({}));
27+
ajax.deleteFormEncoded.mockReturnValue(Promise.resolve({}));
28+
});
29+
30+
afterEach(() => {
31+
restore(setJwtCookieStub);
32+
restore(deleteJwtCookieStub);
33+
restore(getServerUrlStub);
34+
});
35+
36+
it('loginJwt sets jwt auth as token and calls _session endpoint using global get method', async () => {
37+
const mockToken = "mockToken";
38+
getServerUrlStub.returns(sessionUrl);
39+
await loginJwt(mockToken);
40+
expect(setJwtCookieStub.calledOnce).toBeTruthy();
41+
expect(getServerUrlStub.calledOnce).toBeTruthy();
42+
sinon.assert.calledWithExactly(
43+
setJwtCookieStub,
44+
mockToken);
45+
sinon.assert.calledWithExactly(
46+
getServerUrlStub,
47+
'/_session');
48+
});
49+
50+
51+
it('logout deletes cookie from browser and calls global delete _session endpoint', async () => {
52+
getServerUrlStub.returns(sessionUrl);
53+
await logout();
54+
expect(deleteJwtCookieStub.calledOnce).toBeTruthy();
55+
expect(getServerUrlStub.calledOnce).toBeTruthy();
56+
sinon.assert.calledWithExactly(
57+
getServerUrlStub,
58+
'/_session');
59+
});
60+
});
61+
});

app/addons/auth/__tests__/components.test.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,38 @@ describe('Auth -- Components', () => {
2222

2323
describe('LoginForm', () => {
2424
let stub;
25+
let stubJwt;
2526

2627
beforeEach(() => {
2728
stub = sinon.stub(Actions, 'login');
29+
stubJwt = sinon.stub(Actions, 'loginJwt');
2830
});
2931

3032
afterEach(() => {
3133
Actions.login.restore();
34+
Actions.loginJwt.restore();
3235
});
3336

3437
it('should trigger login event when form submitted', () => {
3538
const loginForm = mount(<LoginForm/>);
39+
expect(loginForm.find('select#auth-method').prop('value')).toEqual('basic');
3640
loginForm.find('#login').simulate('submit');
3741
expect(stub.calledOnce).toBeTruthy();
42+
expect(stubJwt.notCalled).toBeTruthy();
3843
});
3944

40-
it('in case of nothing in state, should pass actual values to Actions.login()', () => {
45+
it('should change login type when dropdown option is chosen', () => {
46+
const loginForm = mount(<LoginForm/>);
47+
const dropdown = loginForm.find('select#auth-method');
48+
expect(loginForm.find('select').prop('value')).toEqual('basic');
49+
dropdown.simulate('change', {target: {value: 'token'}});
50+
expect(loginForm.find('select').prop('value')).toEqual('token');
51+
loginForm.find('#login').simulate('submit');
52+
expect(stub.notCalled).toBeTruthy();
53+
expect(stubJwt.calledOnce).toBeTruthy();
54+
});
55+
56+
it('in case of nothing in state, should pass actual basic auth values to Actions.login()', () => {
4157
const username = 'bob';
4258
const password = 'smith';
4359

@@ -55,6 +71,7 @@ describe('Auth -- Components', () => {
5571
expect(stub.args[0][1]).toBe(password);
5672
});
5773

74+
5875
});
5976

6077
describe('ChangePasswordForm', () => {

0 commit comments

Comments
 (0)