Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public CentralLogoutController() {
public Result executeLogout(Http.Request request) {
if (ssoManager.isSsoEnabled()) {
try {
return logout(request).toCompletableFuture().get().withNewSession();
//return logout(request).toCompletableFuture().get().withNewSession();
// Customize: solve logout issue (https://github.com/datahub-project/datahub/issues/8369)
logout(request).toCompletableFuture().get();
} catch (Exception e) {
log.error(
"Caught exception while attempting to perform SSO logout! It's likely that SSO integration is mis-configured.",
Expand Down
2 changes: 2 additions & 0 deletions datahub-web-react/src/app/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AppProviders from '@app/AppProviders';
import { ProtectedRoutes } from '@app/ProtectedRoutes';
import { useTrackPageView } from '@app/analytics';
import { LogIn } from '@app/auth/LogIn';
import { AdminLogIn } from '@app/auth/AdminLogIn';
import { ResetCredentials } from '@app/auth/ResetCredentials';
import { SignUp } from '@app/auth/SignUp';
import { isLoggedInVar } from '@app/auth/checkAuthStatus';
Expand Down Expand Up @@ -35,6 +36,7 @@ export const Routes = (): JSX.Element => {

return (
<Switch>
<Route path={PageRoutes.ADMIN_LOG_IN} component={AdminLogIn} />
<Route path={PageRoutes.LOG_IN} component={LogIn} />
<Route path={PageRoutes.SIGN_UP} component={SignUp} />
<Route path={PageRoutes.RESET_CREDENTIALS} component={ResetCredentials} />
Expand Down
164 changes: 164 additions & 0 deletions datahub-web-react/src/app/auth/AdminLogIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import React, { useCallback, useState } from 'react';
import * as QueryString from 'query-string';
import { Input, Button, Form, message, Image, Divider } from 'antd';
import { UserOutlined, LockOutlined, LoginOutlined } from '@ant-design/icons';
import { useReactiveVar } from '@apollo/client';
import styled, { useTheme } from 'styled-components/macro';
import { Redirect, useLocation } from 'react-router';
import styles from './login.module.css';
import { Message } from '../shared/Message';
import { isLoggedInVar } from './checkAuthStatus';
import analytics, { EventType } from '../analytics';
import { useAppConfig } from '../useAppConfig';

type FormValues = {
username: string;
password: string;
};

const FormInput = styled(Input)`
&&& {
height: 32px;
font-size: 12px;
border: 1px solid #555555;
border-radius: 5px;
background-color: transparent;
color: white;
line-height: 1.5715;
}
> .ant-input {
color: white;
font-size: 14px;
background-color: transparent;
}
> .ant-input:hover {
color: white;
font-size: 14px;
background-color: transparent;
}
`;

const SsoDivider = styled(Divider)`
background-color: white;
`;

const SsoButton = styled(Button)`
&&& {
align-self: center;
display: flex;
justify-content: center;
align-items: center;
padding: 5.6px 11px;
gap: 4px;
}
`;

const LoginLogo = styled(LoginOutlined)`
padding-top: 7px;
`;

const SsoTextSpan = styled.span`
padding-top: 6px;
`;

export type AdminLogInProps = Record<string, never>;

export const AdminLogIn: React.VFC<AdminLogInProps> = () => {
const isLoggedIn = useReactiveVar(isLoggedInVar);
const location = useLocation();
const params = QueryString.parse(location.search);
const maybeRedirectError = params.error_msg;

const themeConfig = useTheme();
const [loading, setLoading] = useState(false);

const { refreshContext } = useAppConfig();

const handleLogin = useCallback(
(values: FormValues) => {
setLoading(true);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: values.username, password: values.password }),
};
fetch('/logIn', requestOptions)
.then(async (response) => {
if (!response.ok) {
const data = await response.json();
const error = (data && data.message) || response.status;
return Promise.reject(error);
}
isLoggedInVar(true);
refreshContext();
analytics.event({ type: EventType.LogInEvent });
return Promise.resolve();
})
.catch((_) => {
message.error(`Failed to log in! An unexpected error occurred.`);
})
.finally(() => setLoading(false));
},
[refreshContext],
);

if (isLoggedIn) {
const maybeRedirectUri = params.redirect_uri;
return <Redirect to={(maybeRedirectUri && decodeURIComponent(maybeRedirectUri as string)) || '/'} />;
}

return (
<div className={styles.login_page}>
{maybeRedirectError && maybeRedirectError.length > 0 && (
<Message type="error" content={maybeRedirectError} />
)}
<div className={styles.login_box}>
<div className={styles.login_logo_box}>
<Image wrapperClassName={styles.logo_image} src={themeConfig.assets?.logoUrl} preview={false} />
</div>
<div className={styles.login_form_box}>
{loading && <Message type="loading" content="Logging in..." />}
<Form onFinish={handleLogin} layout="vertical">
<Form.Item
name="username"
// eslint-disable-next-line jsx-a11y/label-has-associated-control
label={<label style={{ color: 'white' }}>Username</label>}
>
<FormInput prefix={<UserOutlined />} data-testid="username" />
</Form.Item>
<Form.Item
name="password"
// eslint-disable-next-line jsx-a11y/label-has-associated-control
label={<label style={{ color: 'white' }}>Password</label>}
>
<FormInput prefix={<LockOutlined />} type="password" data-testid="password" />
</Form.Item>
<Form.Item style={{ marginBottom: '0px' }} shouldUpdate>
{({ getFieldsValue }) => {
const { username, password } = getFieldsValue();
const formIsComplete = !!username && !!password;
return (
<Button
type="primary"
block
htmlType="submit"
className={styles.login_button}
disabled={!formIsComplete}
>
Sign In
</Button>
);
}}
</Form.Item>
</Form>
<SsoDivider />
<SsoButton type="primary" href="/sso" block htmlType="submit" className={styles.sso_button}>
<LoginLogo />
<SsoTextSpan>Sign in with Kakao Okta</SsoTextSpan>
<span />
</SsoButton>
</div>
</div>
</div>
);
};
6 changes: 3 additions & 3 deletions datahub-web-react/src/app/auth/LogIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const LogIn: React.VFC<LogInProps> = () => {
</div>
<div className={styles.login_form_box}>
{loading && <Message type="loading" content="Logging in..." />}
<Form onFinish={handleLogin} layout="vertical">
{/*<Form onFinish={handleLogin} layout="vertical">
<Form.Item
name="username"
// eslint-disable-next-line jsx-a11y/label-has-associated-control
Expand Down Expand Up @@ -153,10 +153,10 @@ export const LogIn: React.VFC<LogInProps> = () => {
}}
</Form.Item>
</Form>
<SsoDivider />
<SsoDivider /> */}
<SsoButton type="primary" href="/sso" block htmlType="submit" className={styles.sso_button}>
<LoginLogo />
<SsoTextSpan>Sign in with SSO</SsoTextSpan>
<SsoTextSpan>Sign in with Kakao Okta</SsoTextSpan>
<span />
</SsoButton>
</div>
Expand Down
1 change: 1 addition & 0 deletions datahub-web-react/src/conf/Global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum PageRoutes {
AUTHENTICATE = '/authenticate',
SIGN_UP = '/signup',
LOG_IN = '/login',
ADMIN_LOG_IN = '/login/admin',
RESET_CREDENTIALS = '/reset',
SEARCH_RESULTS = '/search/:type?',
SEARCH = '/search',
Expand Down
Loading