argo-cd

Форк
0
151 строка · 7.5 Кб
1
import {FormField, NotificationType} from 'argo-ui';
2
import * as PropTypes from 'prop-types';
3
import * as React from 'react';
4
import {Form, Text} from 'react-form';
5
import {RouteComponentProps} from 'react-router';
6

7
import {AppContext} from '../../shared/context';
8
import {AuthSettings} from '../../shared/models';
9
import {services} from '../../shared/services';
10
import {getPKCERedirectURI, pkceLogin} from './utils';
11

12
require('./login.scss');
13

14
export interface LoginForm {
15
    username: string;
16
    password: string;
17
}
18

19
interface State {
20
    authSettings: AuthSettings;
21
    loginError: string;
22
    loginInProgress: boolean;
23
    returnUrl: string;
24
    hasSsoLoginError: boolean;
25
}
26

27
export class Login extends React.Component<RouteComponentProps<{}>, State> {
28
    public static contextTypes = {
29
        apis: PropTypes.object
30
    };
31

32
    public static getDerivedStateFromProps(props: RouteComponentProps<{}>): Partial<State> {
33
        const search = new URLSearchParams(props.history.location.search);
34
        const returnUrl = search.get('return_url') || '';
35
        const hasSsoLoginError = search.get('has_sso_error') === 'true';
36
        return {hasSsoLoginError, returnUrl};
37
    }
38

39
    constructor(props: RouteComponentProps<{}>) {
40
        super(props);
41
        this.state = {authSettings: null, loginError: null, returnUrl: null, hasSsoLoginError: false, loginInProgress: false};
42
    }
43

44
    public async componentDidMount() {
45
        this.setState({
46
            authSettings: await services.authService.settings()
47
        });
48
    }
49

50
    public render() {
51
        const authSettings = this.state.authSettings;
52
        const ssoConfigured = authSettings && ((authSettings.dexConfig && (authSettings.dexConfig.connectors || []).length > 0) || authSettings.oidcConfig);
53
        return (
54
            <div className='login'>
55
                <div className='login__content show-for-medium'>
56
                    <div className='login__text'>Let's get stuff deployed!</div>
57
                    <div className='argo__logo' />
58
                </div>
59
                <div className='login__box'>
60
                    <div className='login__logo width-control'>
61
                        <img className='logo-image' src='assets/images/argo_o.svg' alt='argo' />
62
                    </div>
63
                    {ssoConfigured && (
64
                        <div className='login__box_saml width-control'>
65
                            <a
66
                                {...(authSettings?.oidcConfig?.enablePKCEAuthentication
67
                                    ? {
68
                                          onClick: async () => {
69
                                              pkceLogin(authSettings.oidcConfig, getPKCERedirectURI().toString()).catch(err => {
70
                                                  this.appContext.apis.notifications.show({
71
                                                      type: NotificationType.Error,
72
                                                      content: err?.message || JSON.stringify(err)
73
                                                  });
74
                                              });
75
                                          }
76
                                      }
77
                                    : {href: `auth/login?return_url=${encodeURIComponent(this.state.returnUrl)}`})}>
78
                                <button className='argo-button argo-button--base argo-button--full-width argo-button--xlg'>
79
                                    {(authSettings.oidcConfig && <span>Log in via {authSettings.oidcConfig.name}</span>) ||
80
                                        (authSettings.dexConfig.connectors.length === 1 && <span>Log in via {authSettings.dexConfig.connectors[0].name}</span>) || (
81
                                            <span>SSO Login</span>
82
                                        )}
83
                                </button>
84
                            </a>
85
                            {this.state.hasSsoLoginError && <div className='argo-form-row__error-msg'>Login failed.</div>}
86
                            {authSettings && !authSettings.userLoginsDisabled && (
87
                                <div className='login__saml-separator'>
88
                                    <span>or</span>
89
                                </div>
90
                            )}
91
                        </div>
92
                    )}
93
                    {authSettings && !authSettings.userLoginsDisabled && (
94
                        <Form
95
                            onSubmit={(params: LoginForm) => this.login(params.username, params.password, this.state.returnUrl)}
96
                            validateError={(params: LoginForm) => ({
97
                                username: !params.username && 'Username is required',
98
                                password: !params.password && 'Password is required'
99
                            })}>
100
                            {formApi => (
101
                                <form role='form' className='width-control' onSubmit={formApi.submitForm}>
102
                                    <div className='argo-form-row'>
103
                                        <FormField formApi={formApi} label='Username' field='username' component={Text} componentProps={{autoCapitalize: 'none'}} />
104
                                    </div>
105
                                    <div className='argo-form-row'>
106
                                        <FormField formApi={formApi} label='Password' field='password' component={Text} componentProps={{type: 'password'}} />
107
                                        {this.state.loginError && <div className='argo-form-row__error-msg'>{this.state.loginError}</div>}
108
                                    </div>
109
                                    <div className='login__form-row'>
110
                                        <button disabled={this.state.loginInProgress} className='argo-button argo-button--full-width argo-button--xlg' type='submit'>
111
                                            Sign In
112
                                        </button>
113
                                    </div>
114
                                </form>
115
                            )}
116
                        </Form>
117
                    )}
118
                    {authSettings && authSettings.userLoginsDisabled && !ssoConfigured && (
119
                        <div className='argo-form-row__error-msg'>Login is disabled. Please contact your system administrator.</div>
120
                    )}
121
                    <div className='login__footer'>
122
                        <a href='https://argoproj.io' target='_blank'>
123
                            <img className='logo-image' src='assets/images/argologo.svg' alt='argo' />
124
                        </a>
125
                    </div>
126
                </div>
127
            </div>
128
        );
129
    }
130

131
    private async login(username: string, password: string, returnURL: string) {
132
        try {
133
            this.setState({loginError: '', loginInProgress: true});
134
            this.appContext.apis.navigation.goto('.', {sso_error: null});
135
            await services.users.login(username, password);
136
            this.setState({loginInProgress: false});
137
            if (returnURL) {
138
                const url = new URL(returnURL);
139
                this.appContext.apis.navigation.goto(url.pathname + url.search);
140
            } else {
141
                this.appContext.apis.navigation.goto('/applications');
142
            }
143
        } catch (e) {
144
            this.setState({loginError: e.response.body.error, loginInProgress: false});
145
        }
146
    }
147

148
    private get appContext(): AppContext {
149
        return this.context as AppContext;
150
    }
151
}
152

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.