Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions web/client/actions/__tests__/login-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ describe('login actions', () => {
it('default with provider', () => {
let page;
const PROVIDER = "google";
openIDLogin({provider: PROVIDER}, (p) => {page = p;} )();
openIDLogin({provider: PROVIDER, loginRedirectHash: false}, (p) => {page = p;} )();
const geostore = ConfigUtils.getConfigProp("geoStoreUrl");
expect(page).toEqual(`${geostore}openid/${PROVIDER}/login`);
});
it('custom URL', () => {
let page;
const PROVIDER = "google";
const TEST_URL = "/test/path";
openIDLogin({provider: PROVIDER, url: TEST_URL}, (p) => {page = p;} )();
openIDLogin({provider: PROVIDER, url: TEST_URL, loginRedirectHash: false}, (p) => {page = p;} )();
expect(page).toEqual(TEST_URL);
});
});
Expand Down
8 changes: 7 additions & 1 deletion web/client/actions/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@
import ConfigUtils from '../utils/ConfigUtils';

import { setControlProperty } from './controls';
import { logoutWithReload, resetError } from './security';
import { logoutWithReload, resetError, LOGIN_REDIRECT_KEY } from './security';
import AuthenticationAPI from '../api/GeoStoreDAO';

/**
* Thunk with side effects to trigger set the proper temp cookie and redirect to openID login provider URL.
* @param {object} entry the provider entry to use for login
* @param {string} entry.provider the name of the provider configured (e.g. google, keycloak, ...)
* @param {string} entry.url URL of the entry to use to login. If not passed, `<geostore-base-path>/openid/<provider>/login`.
* @param {boolean} [entry.loginRedirectHash=true] if true, the hash of the current page is stored in sessionStorage to redirect after login. Notice: (this has been introduced for tests, where it should be set to false, to prevent the loginSuccess o fail)
* @param {function} goToPage redirect function, useful to mock for testing.
* @returns {function} the think to execute. It doesn't dispatch any action, but sets a cookie to remember the authProvider used.
* @memberof actions.login
*/
export function openIDLogin(entry, goToPage = (page) => {window.location.href = page; }) {
return () => {
if (entry.loginRedirectHash ?? true) {
alert("You are being redirected to the login page. Please wait...");

Check warning on line 28 in web/client/actions/login.js

View workflow job for this annotation

GitHub Actions / test-front-end

Unexpected alert

Check warning on line 28 in web/client/actions/login.js

View workflow job for this annotation

GitHub Actions / test-front-end

Unexpected alert
debugger;

Check warning on line 29 in web/client/actions/login.js

View workflow job for this annotation

GitHub Actions / test-front-end

Unexpected 'debugger' statement

Check warning on line 29 in web/client/actions/login.js

View workflow job for this annotation

GitHub Actions / test-front-end

Unexpected 'debugger' statement
sessionStorage.setItem(LOGIN_REDIRECT_KEY, window.location.hash); // store the hash to redirect after login
}
goToPage(entry?.url ?? `${ ConfigUtils.getConfigProp("geoStoreUrl")}openid/${entry?.provider}/login`);
};
}
Expand Down
27 changes: 26 additions & 1 deletion web/client/actions/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Here you can change the API to use for AuthenticationAPI
*/
import AuthenticationAPI from '../api/GeoStoreDAO';
import { push } from 'connected-react-router';

import {setCredentials, getToken, getRefreshToken} from '../utils/SecurityUtils';
import {encodeUTF8} from '../utils/EncodeUtils';
Expand All @@ -34,8 +35,21 @@ export const SET_CREDENTIALS = 'SECURITY:SET_CREDENTIALS';
export const CLEAR_SECURITY = 'SECURITY:CLEAR_SECURITY';
export const SET_PROTECTED_SERVICES = 'SECURITY:SET_PROTECTED_SERVICES';
export const REFRESH_SECURITY_LAYERS = 'SECURITY:REFRESH_SECURITY_LAYERS';

export const LOGIN_REDIRECT_KEY = 'loginRedirectHash'; // key used to store the redirect hash in sessionStorage
/**
* Action dispatched when the user successfully logs in.
* Note: It will also redirect to the hash stored in sessionStorage, if available. This because in case of external login (e.g. OpenID Connect),
* the login is done in a different page, and the redirect url as hash is not managed by the authentication API.
* @param {object} userDetails the user details returned by the authentication API
* @param {string} username the username.
* @param {string} password the password.
* @param {string} authProvider the auth provider used for authentication.
* @returns {object|function} the action to dispatch on successful login.
* If a redirect hash is stored in sessionStorage, will return a function, becoming a thunk. It will redirect to that hash after dispatch
*/
export function loginSuccess(userDetails, username, password, authProvider) {
return {
const loginAction = {
type: LOGIN_SUCCESS,
userDetails: userDetails,
// set here for compatibility reasons
Expand All @@ -45,6 +59,17 @@ export function loginSuccess(userDetails, username, password, authProvider) {
password: password,
authProvider: authProvider
};
const hash = sessionStorage.getItem(LOGIN_REDIRECT_KEY);
if (hash && hash !== window.location.hash) {
sessionStorage.removeItem(LOGIN_REDIRECT_KEY);
// creating the thunk only in this case preserves
// the original action for testing purposes
return (dispatch) => {
dispatch(loginAction);
dispatch(push(hash.split('#')[1]));
};
}
return loginAction;
}

export function loginFail(e) {
Expand Down
4 changes: 2 additions & 2 deletions web/client/plugins/__tests__/Login-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe('Login Plugin', () => {
goToPage: () => {}
};
expect.spyOn(spyOn, 'goToPage');
ConfigUtils.setConfigProp("authenticationProviders", [{type: "openID", provider: "oidc", goToPage: spyOn.goToPage}]); // goToPage is normally empty, but can be used to mock the redirect in tests
ConfigUtils.setConfigProp("authenticationProviders", [{type: "openID", provider: "oidc", loginRedirectHash: false, goToPage: spyOn.goToPage}]); // goToPage is normally empty, but can be used to mock the redirect in tests

const { Plugin } = getPluginForTest(Login, {});
const { Plugin: OmniBarPlugin } = getPluginForTest(OmniBar, {}, { LoginPlugin: Login });
Expand All @@ -198,7 +198,7 @@ describe('Login Plugin', () => {
expect(spyOn.goToPage.calls[0].arguments[0]).toEqual(`/rest/geostore/openid/oidc/login`);
});
it('openID with userInfo configured', () => {
ConfigUtils.setConfigProp("authenticationProviders", [{type: "openID", provider: "google", showAccountInfo: true}]);
ConfigUtils.setConfigProp("authenticationProviders", [{type: "openID", provider: "google", loginRedirectHash: false, showAccountInfo: true}]);
const storeState = stateMocker(toggleControl('LoginForm', 'enabled'), loginSuccess({ User: { name: "Test", access_token: "some-token" }, authProvider: "google"}) );
const { Plugin } = getPluginForTest(Login, storeState);
const { Plugin: OmniBarPlugin } = getPluginForTest(OmniBar, storeState, { LoginPlugin: Login });
Expand Down
2 changes: 1 addition & 1 deletion web/client/utils/__tests__/KeycloakUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('KeycloakUtils', () => {
});
});
it('keycloak login', (done) => {
const provider = {...PROVIDER, goToPage: () => {}};
const provider = {...PROVIDER, loginRedirectHash: false, goToPage: () => {}};
getKeycloakClient(provider).then((kc) => {
const epic = monitorKeycloak(provider);
const initSpy = expect.spyOn(kc, "init").andCallThrough();
Expand Down