Fix login and logout flow for MCS (#185)
fixes: https://github.com/minio/mcs/issues/184 There was a bug in Safari in related to the browser not setting the session token correctly in localstorage, this was because we were using window.location.href for redirect instead of history.push after login, the redirect execution was faster was faster that the promise function getting the response after the login request and it seems to be that Safari will kill all current request of a window when the page is getting redirected. Test this: Try to sign-in using Safari browser (latest version is recommended)
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
import storage from "local-storage-fallback";
|
||||
import request from "superagent";
|
||||
import get from "lodash/get";
|
||||
import { clearSession } from "../utils";
|
||||
|
||||
export class API {
|
||||
invoke(method: string, url: string, data?: object) {
|
||||
@@ -28,8 +29,11 @@ export class API {
|
||||
.catch((err) => {
|
||||
// if we get unauthorized, kick out the user
|
||||
if (err.status === 401) {
|
||||
storage.removeItem("token");
|
||||
window.location.href = "/";
|
||||
clearSession();
|
||||
// Refresh the whole page to ensure cache is clear
|
||||
// and we dont end on an infinite loop
|
||||
window.location.href = "/login";
|
||||
return;
|
||||
}
|
||||
return this.onError(err);
|
||||
});
|
||||
@@ -48,7 +52,8 @@ export class API {
|
||||
|
||||
return Promise.reject(throwMessage);
|
||||
} else {
|
||||
return Promise.reject("Unknown error");
|
||||
clearSession();
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import storage from "local-storage-fallback";
|
||||
|
||||
export const units = [
|
||||
"B",
|
||||
"KiB",
|
||||
@@ -50,6 +52,20 @@ export const setCookie = (name: string, val: string) => {
|
||||
name + "=" + value + "; expires=" + date.toUTCString() + "; path=/";
|
||||
};
|
||||
|
||||
export const deleteCookie = (name: string) => {
|
||||
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
|
||||
};
|
||||
|
||||
export const setSession = (token: string) => {
|
||||
setCookie("token", token);
|
||||
storage.setItem("token", token);
|
||||
};
|
||||
|
||||
export const clearSession = () => {
|
||||
storage.removeItem("token");
|
||||
deleteCookie("token");
|
||||
};
|
||||
|
||||
// timeFromdate gets time string from date input
|
||||
export const timeFromDate = (d: Date) => {
|
||||
let h = d.getHours() < 10 ? `0${d.getHours()}` : `${d.getHours()}`;
|
||||
|
||||
@@ -68,6 +68,7 @@ import ListTenants from "./Tenants/ListTenants/ListTenants";
|
||||
import { ISessionResponse } from "./types";
|
||||
import { saveSessionResponse } from "./actions";
|
||||
import TenantDetails from "./Tenants/TenantDetails/TenantDetails";
|
||||
import { clearSession } from "../../common/utils";
|
||||
|
||||
function Copyright() {
|
||||
return (
|
||||
@@ -206,9 +207,12 @@ const Console = ({
|
||||
.then((res) => {
|
||||
saveSessionResponse(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
storage.removeItem("token");
|
||||
history.push("/");
|
||||
.catch(() => {
|
||||
// if server returns 401 for /api/v1/session call invoke function will internally call clearSession()
|
||||
// and redirecto to window.location.href = "/"; and this code will be not reached
|
||||
// in case that not happen we clear session here and redirect as well
|
||||
clearSession();
|
||||
window.location.href = "/login";
|
||||
});
|
||||
}, [saveSessionResponse]);
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
UsersIcon,
|
||||
WarpIcon,
|
||||
} from "../../../icons";
|
||||
import { clearSession } from "../../../common/utils";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -156,9 +157,9 @@ const Menu = ({ userLoggedIn, classes, pages }: IMenuProps) => {
|
||||
|
||||
const logout = () => {
|
||||
const deleteSession = () => {
|
||||
storage.removeItem("token");
|
||||
clearSession();
|
||||
userLoggedIn(false);
|
||||
history.push("/");
|
||||
history.push("/login");
|
||||
};
|
||||
api
|
||||
.invoke("POST", `/api/v1/logout`)
|
||||
|
||||
@@ -28,7 +28,8 @@ import { SystemState } from "../../types";
|
||||
import { userLoggedIn } from "../../actions";
|
||||
import api from "../../common/api";
|
||||
import { ILoginDetails, loginStrategyType } from "./types";
|
||||
import { setCookie } from "../../common/utils";
|
||||
import { setSession } from "../../common/utils";
|
||||
import history from "../../history";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -120,13 +121,13 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
|
||||
});
|
||||
|
||||
const loginStrategyEndpoints: LoginStrategyRoutes = {
|
||||
"form": "/api/v1/login",
|
||||
form: "/api/v1/login",
|
||||
"service-account": "/api/v1/login/mkube",
|
||||
}
|
||||
};
|
||||
const loginStrategyPayload: LoginStrategyPayload = {
|
||||
"form": { accessKey, secretKey },
|
||||
form: { accessKey, secretKey },
|
||||
"service-account": { jwt },
|
||||
}
|
||||
};
|
||||
|
||||
const fetchConfiguration = () => {
|
||||
setLoading(true);
|
||||
@@ -147,15 +148,15 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
|
||||
const formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
request
|
||||
.post(loginStrategyEndpoints[loginStrategy.loginStrategy] || "/api/v1/login")
|
||||
.post(
|
||||
loginStrategyEndpoints[loginStrategy.loginStrategy] || "/api/v1/login"
|
||||
)
|
||||
.send(loginStrategyPayload[loginStrategy.loginStrategy])
|
||||
.then((res: any) => {
|
||||
const bodyResponse = res.body;
|
||||
if (bodyResponse.sessionId) {
|
||||
// store the jwt token
|
||||
setCookie("token", bodyResponse.sessionId);
|
||||
storage.setItem("token", bodyResponse.sessionId);
|
||||
//return res.body.sessionId;
|
||||
setSession(bodyResponse.sessionId);
|
||||
} else if (bodyResponse.error) {
|
||||
// throw will be moved to catch block once bad login returns 403
|
||||
throw bodyResponse.error;
|
||||
@@ -164,9 +165,7 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
|
||||
.then(() => {
|
||||
// We set the state in redux
|
||||
userLoggedIn(true);
|
||||
// There is a browser cache issue if we change the policy associated to an account and then logout and history.push("/") after login
|
||||
// therefore after login we need to use window.location redirect
|
||||
window.location.href = "/";
|
||||
history.push("/");
|
||||
})
|
||||
.catch((err) => {
|
||||
setError(err.message);
|
||||
|
||||
Reference in New Issue
Block a user