github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/pages/auth/login.tsx (about)

     1  import React, {useState} from "react";
     2  import Row from "react-bootstrap/Row";
     3  import Card from "react-bootstrap/Card";
     4  import Form from "react-bootstrap/Form";
     5  import Col from "react-bootstrap/Col";
     6  import Button from "react-bootstrap/Button";
     7  import {auth, AuthenticationError, setup, SETUP_STATE_INITIALIZED} from "../../lib/api";
     8  import {AlertError} from "../../lib/components/controls"
     9  import {useRouter} from "../../lib/hooks/router";
    10  import {useAPI} from "../../lib/hooks/api";
    11  
    12  interface LoginConfig {
    13      login_url: string;
    14      login_failed_message?: string;
    15      fallback_login_url?: string;
    16      fallback_login_label?: string;
    17      login_cookie_names: string[];
    18      logout_url: string;
    19  }
    20  
    21  const LoginForm = ({loginConfig}: {loginConfig: LoginConfig}) => {
    22      const router = useRouter();
    23      const [loginError, setLoginError] = useState(null);
    24      const { next } = router.query;
    25  
    26      return (
    27          <Row>
    28              <Col md={{offset: 4, span: 4}}>
    29                  <Card className="login-widget">
    30                      <Card.Header>Login</Card.Header>
    31                      <Card.Body>
    32                          <Form onSubmit={async (e) => {
    33                              e.preventDefault()
    34                              try {
    35                                  await auth.login(e.target.username.value, e.target.password.value)
    36                                  setLoginError(null);
    37                                  router.push(next ? next : '/');
    38                              } catch(err) {
    39                                  if (err instanceof AuthenticationError && err.status === 401) {
    40                                      const contents = {__html: `${loginConfig.login_failed_message}` ||
    41                                          "Credentials don't match."};
    42                                      setLoginError(<span dangerouslySetInnerHTML={contents}/>);
    43                                  }
    44                              }
    45                          }}>
    46                              <Form.Group controlId="username" className="mb-3">
    47                                  <Form.Control type="text" placeholder={"Access Key ID"} autoFocus/>
    48                              </Form.Group>
    49  
    50                              <Form.Group controlId="password" className="mb-3">
    51                                  <Form.Control type="password" placeholder={"Secret Access Key"}/>
    52                              </Form.Group>
    53  
    54                              {(!!loginError) && <AlertError error={loginError}/>}
    55  
    56                              <Button variant="primary" type="submit">Login</Button>
    57                          </Form>
    58                          <div className={"mt-2 mb-1"}>
    59                              { loginConfig.fallback_login_url ?
    60                                  <Button variant="link" className="text-secondary mt-2" onClick={async ()=> {
    61                                      loginConfig.login_cookie_names?.forEach(
    62                                          cookie => {
    63                                              document.cookie = `${cookie}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
    64                                          }
    65                                      );
    66                                      window.location = loginConfig.fallback_login_url;
    67                                  }}>{loginConfig.fallback_login_label || 'Try another way to login'}</Button>
    68                                  : ""
    69                              }
    70                          </div>
    71                      </Card.Body>
    72                  </Card>
    73              </Col>
    74          </Row>
    75      )
    76  }
    77  
    78  
    79  const LoginPage = () => {
    80      const router = useRouter();
    81      const { response, error, loading } = useAPI(() => setup.getState());
    82      if (loading) {
    83          return null;
    84      }
    85  
    86      // if we are not initialized, or we are not done with comm prefs, redirect to 'setup' page
    87      if (!error && response && (response.state !== SETUP_STATE_INITIALIZED || response.comm_prefs_missing === true)) {
    88          router.push({pathname: '/setup', query: router.query})
    89          return null;
    90      }
    91      const loginConfig = response?.login_config;
    92      if (router.query.redirected)  {
    93          if(!error && loginConfig?.login_url) {
    94              window.location = loginConfig.login_url;
    95              return null;
    96          }
    97          delete router.query.redirected;
    98  
    99          router.push({pathname: '/auth/login', query: router.query})
   100      }
   101      return (
   102          <LoginForm loginConfig={loginConfig}/>
   103      );
   104  };
   105  
   106  export default LoginPage;