diff --git a/awx/api/generics.py b/awx/api/generics.py index 17d1bdd55e..d1bef1e837 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -97,7 +97,6 @@ class LoggedLoginView(auth_views.LoginView): current_user = UserSerializer(self.request.user) current_user = smart_str(JSONRenderer().render(current_user.data)) current_user = urllib.parse.quote('%s' % current_user, '') - ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None) ret.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid')) return ret diff --git a/awx/sso/views.py b/awx/sso/views.py index 67921b2fa4..00a392f5b3 100644 --- a/awx/sso/views.py +++ b/awx/sso/views.py @@ -45,7 +45,6 @@ class CompleteView(BaseRedirectView): current_user = UserSerializer(self.request.user) current_user = smart_str(JSONRenderer().render(current_user.data)) current_user = urllib.parse.quote('%s' % current_user, '') - response.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None) response.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid')) return response diff --git a/awx/ui/src/screens/Login/Login.js b/awx/ui/src/screens/Login/Login.js index e506eaf9b6..7b70e150d8 100644 --- a/awx/ui/src/screens/Login/Login.js +++ b/awx/ui/src/screens/Login/Login.js @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-no-useless-fragment */ -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useState, useEffect, useRef } from 'react'; import { Redirect, withRouter } from 'react-router-dom'; import { t } from '@lingui/macro'; @@ -28,11 +28,11 @@ import { UserCircleIcon, } from '@patternfly/react-icons'; import useRequest, { useDismissableError } from 'hooks/useRequest'; -import { AuthAPI, RootAPI } from 'api'; +import { AuthAPI, RootAPI, MeAPI } from 'api'; import AlertModal from 'components/AlertModal'; import ErrorDetail from 'components/ErrorDetail'; import { useSession } from 'contexts/Session'; -import { getCurrentUserId } from 'util/auth'; +import LoadingSpinner from 'components/LoadingSpinner'; import { SESSION_REDIRECT_URL, SESSION_USER_ID } from '../../constants'; const loginLogoSrc = 'static/media/logo-login.svg'; @@ -44,7 +44,8 @@ const Login = styled(PFLogin)` `; function AWXLogin({ alt, isAuthenticated }) { - const { authRedirectTo, isSessionExpired, setAuthRedirectTo } = useSession(); + const [userId, setUserId] = useState(null); + const { authRedirectTo, isSessionExpired } = useSession(); const isNewUser = useRef(true); const hasVerifiedUser = useRef(false); @@ -107,36 +108,45 @@ function AWXLogin({ alt, isAuthenticated }) { const { error: authError, dismissError: dismissAuthError } = useDismissableError(authenticationError); + const { isLoading: isUserIdLoading, request: fetchUserId } = useRequest( + useCallback(async () => { + if (isAuthenticated(document.cookie)) { + const { data } = await MeAPI.read(); + setUserId(data.results[0].id); + } + }, [isAuthenticated]) + ); + const handleSubmit = async (values) => { dismissAuthError(); await authenticate(values); - setAuthRedirectTo('/home'); + await fetchUserId(); }; - if (isCustomLoginInfoLoading) { - return null; - } + useEffect(() => { + fetchUserId(); + }, [fetchUserId]); - if (isAuthenticated(document.cookie) && !hasVerifiedUser.current) { - const currentUserId = getCurrentUserId(document.cookie); - const verifyIsNewUser = () => { - const previousUserId = JSON.parse( - window.localStorage.getItem(SESSION_USER_ID) - ); - if (previousUserId === null) { - return true; - } - return currentUserId.toString() !== previousUserId.toString(); - }; - isNewUser.current = verifyIsNewUser(); - hasVerifiedUser.current = true; - window.localStorage.setItem(SESSION_USER_ID, JSON.stringify(currentUserId)); - } + const setLocalStorageAndRedirect = useCallback(() => { + if (userId && !hasVerifiedUser.current) { + const verifyIsNewUser = () => { + const previousUserId = JSON.parse( + window.localStorage.getItem(SESSION_USER_ID) + ); + if (previousUserId === null) { + return true; + } + return userId.toString() !== previousUserId.toString(); + }; + isNewUser.current = verifyIsNewUser(); + hasVerifiedUser.current = true; + window.localStorage.setItem(SESSION_USER_ID, JSON.stringify(userId)); + } + }, [userId]); - if (isAuthenticated(document.cookie) && hasVerifiedUser.current) { - const redirect = isNewUser.current ? '/' : authRedirectTo; - return ; - } + useEffect(() => { + setLocalStorageAndRedirect(); + }, [userId, setLocalStorageAndRedirect]); let helperText; if (authError?.response?.status === 401) { @@ -162,6 +172,17 @@ function AWXLogin({ alt, isAuthenticated }) { window.sessionStorage.setItem(SESSION_REDIRECT_URL, authRedirectTo); }; + if (isCustomLoginInfoLoading) { + return null; + } + if (isUserIdLoading) { + return ; + } + if (userId && hasVerifiedUser.current) { + const redirect = isNewUser.current ? '/home' : authRedirectTo; + + return ; + } return ( ({ getCurrentUserId: jest.fn(), @@ -294,7 +296,7 @@ describe('', () => { }); test('render Redirect to / when already authenticated as a new user', async () => { - getCurrentUserId.mockReturnValue(1); + MeAPI.read.mockResolvedValue({ data: { results: [{ id: 1 }] } }); const history = createMemoryHistory({ initialEntries: ['/login'], }); @@ -316,17 +318,22 @@ describe('', () => { }, }); }); + expect(MeAPI.read).toHaveBeenCalled(); expect(window.localStorage.getItem).toHaveBeenCalledWith(SESSION_USER_ID); expect(window.localStorage.setItem).toHaveBeenCalledWith( SESSION_USER_ID, '1' ); await waitForElement(wrapper, 'Redirect', (el) => el.length === 1); - await waitForElement(wrapper, 'Redirect', (el) => el.props().to === '/'); + await waitForElement( + wrapper, + 'Redirect', + (el) => el.props().to === '/home' + ); }); test('render redirect to authRedirectTo when authenticated as a previous user', async () => { - getCurrentUserId.mockReturnValue(42); + MeAPI.read.mockResolvedValue({ data: { results: [{ id: 42 }] } }); const history = createMemoryHistory({ initialEntries: ['/login'], });