Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

Commit

Permalink
Read localAuthEnabled config from backend (#44)
Browse files Browse the repository at this point in the history
* teleport/Login.jsx
  - Login.jsx retrieves and sets isLocalAuthEnabled flag
* teleport/config.js
  - add a localAuthEnabled prop to cfg.auth, defaulted to true
  - add a getter for localAuthEnabled 
* shared/FormLogin.jsx
  - receive isLocalAuthEnabled as prop
  - renders input and login elements based on isLocalAuthEnabled flag
  - update old story format
  - created snapshot testing based on story for testing render
  • Loading branch information
Lisa Kim authored Mar 9, 2020
1 parent 3346274 commit 83f8c89
Show file tree
Hide file tree
Showing 7 changed files with 1,828 additions and 126 deletions.
103 changes: 54 additions & 49 deletions packages/shared/components/FormLogin/FormLogin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function LoginForm(props) {
onLogin,
onLoginWithSso,
authProviders,
isLocalAuthEnabled = true,
} = props;

const [pass, setPass] = React.useState('');
Expand Down Expand Up @@ -66,59 +67,63 @@ export default function LoginForm(props) {
{title}
</Text>
{isFailed && <Alerts.Danger> {message} </Alerts.Danger>}
<FieldInput
rule={requiredField('Username is required')}
label="Username"
autoFocus
value={user}
onChange={e => setUser(e.target.value)}
placeholder="User name"
/>
<FieldInput
rule={requiredField('Password is required')}
label="Password"
value={pass}
onChange={e => setPass(e.target.value)}
type="password"
placeholder="Password"
/>
{otpEnabled && (
<Flex flexDirection="row">
{isLocalAuthEnabled && (
<>
<FieldInput
label="Two factor token"
rule={requiredToken}
autoComplete="off"
width="200px"
value={token}
onChange={e => setToken(e.target.value)}
placeholder="123 456"
rule={requiredField('Username is required')}
label="Username"
autoFocus
value={user}
onChange={e => setUser(e.target.value)}
placeholder="User name"
/>
<ButtonLink
<FieldInput
rule={requiredField('Password is required')}
label="Password"
value={pass}
onChange={e => setPass(e.target.value)}
type="password"
placeholder="Password"
/>
{otpEnabled && (
<Flex flexDirection="row">
<FieldInput
label="Two factor token"
rule={requiredToken}
autoComplete="off"
width="200px"
value={token}
onChange={e => setToken(e.target.value)}
placeholder="123 456"
/>
<ButtonLink
width="100%"
kind="secondary"
target="_blank"
size="small"
href="https://support.google.com/accounts/answer/1066447?co=GENIE.Platform%3DiOS&hl=en&oco=0"
rel="noreferrer"
>
Download Google Authenticator
</ButtonLink>
</Flex>
)}
<ButtonPrimary
width="100%"
kind="secondary"
target="_blank"
size="small"
href="https://support.google.com/accounts/answer/1066447?co=GENIE.Platform%3DiOS&hl=en&oco=0"
rel="noreferrer"
my="3"
type="submit"
size="large"
onClick={e => onLoginClick(e, validator)}
disabled={isProcessing}
>
Download Google Authenticator
</ButtonLink>
</Flex>
)}
<ButtonPrimary
width="100%"
my="3"
type="submit"
size="large"
onClick={e => onLoginClick(e, validator)}
disabled={isProcessing}
>
LOGIN
</ButtonPrimary>
{isProcessing && u2fEnabled && (
<Text typography="paragraph2" width="100%" textAlign="center">
Insert your U2F key and press the button on the key
</Text>
LOGIN
</ButtonPrimary>
{isProcessing && u2fEnabled && (
<Text typography="paragraph2" width="100%" textAlign="center">
Insert your U2F key and press the button on the key
</Text>
)}
</>
)}
</Box>
{ssoEnabled && (
Expand Down
181 changes: 107 additions & 74 deletions packages/shared/components/FormLogin/FormLogin.story.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ limitations under the License.
*/

import React from 'react';
import { storiesOf } from '@storybook/react';
import FormLogin from './FormLogin';
import { AuthProviderTypeEnum } from './../../services/enums';

Expand All @@ -26,76 +25,110 @@ const defaultProps = {
cb() {},
};

storiesOf('Shared/FormLogin', module)
.add('with user name and password', () => {
return (
<FormLogin
title="Custom Title"
authProviders={[]}
auth2faType="otp"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
/>
);
})
.add('with server errors', () => {
const attempt = {
...defaultProps.attempt,
isFailed: true,
message:
'invalid credentials with looooooooooooooooooooooooooooooooong text',
};

return (
<FormLogin
title="Welcome!"
authProviders={[]}
auth2faType="off"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={attempt}
/>
);
})
.add('with social', () => {
const ssoProvider = [
{ name: 'github', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'google', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'bitbucket', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'unknown', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'microsoft', type: AuthProviderTypeEnum.OIDC, url: '' },
];

return (
<FormLogin
title="Welcome!"
authProviders={ssoProvider}
auth2faType="off"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
/>
);
})
.add('with U2F USB KEY', () => {
const attempt = {
...defaultProps.attempt,
isProcessing: true,
};

return (
<FormLogin
title="Welcome!"
authProviders={[]}
auth2faType="u2f"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={attempt}
/>
);
});
export default {
title: 'Shared/FormLogin',
};

export const Basic = () => (
<FormLogin
title="Custom Title"
authProviders={[]}
auth2faType="otp"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
/>
);

export const ServerError = () => {
const attempt = {
...defaultProps.attempt,
isFailed: true,
message:
'invalid credentials with looooooooooooooooooooooooooooooooong text',
};

return (
<FormLogin
title="Welcome!"
authProviders={[]}
auth2faType="off"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={attempt}
/>
);
};

export const SSOProviders = () => {
const ssoProvider = [
{ name: 'github', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'google', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'bitbucket', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'unknown', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'microsoft', type: AuthProviderTypeEnum.OIDC, url: '' },
];

return (
<FormLogin
title="Welcome!"
authProviders={ssoProvider}
auth2faType="off"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
/>
);
};

export const Universal2ndFactor = () => {
const attempt = {
...defaultProps.attempt,
isProcessing: true,
};

return (
<FormLogin
title="Welcome!"
authProviders={[]}
auth2faType="u2f"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={attempt}
/>
);
};

export const LocalAuthDisabled = () => {
const ssoProvider = [
{ name: 'github', type: AuthProviderTypeEnum.OIDC, url: '' },
{ name: 'google', type: AuthProviderTypeEnum.OIDC, url: '' },
];

return (
<FormLogin
title="Welcome!"
authProviders={ssoProvider}
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
isLocalAuthEnabled={false}
/>
);
};

export const LocalAuthDisabledNoSSO = () => (
<FormLogin
title="Welcome!"
onLoginWithSso={defaultProps.cb}
onLoginWithU2f={defaultProps.cb}
onLogin={defaultProps.cb}
attempt={defaultProps.attempt}
isLocalAuthEnabled={false}
/>
);
56 changes: 56 additions & 0 deletions packages/shared/components/FormLogin/FormLogin.story.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright 2020 Gravitational, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';
import {
Basic,
ServerError,
SSOProviders,
Universal2ndFactor,
LocalAuthDisabled,
LocalAuthDisabledNoSSO,
} from './FormLogin.story';
import { render } from 'design/utils/testing';

test('auth2faType: otp rendering', () => {
const { container } = render(<Basic />);
expect(container.firstChild).toMatchSnapshot();
});

test('server error rendering', () => {
const { container } = render(<ServerError />);
expect(container.firstChild).toMatchSnapshot();
});

test('sso providers rendering', () => {
const { container } = render(<SSOProviders />);
expect(container.firstChild).toMatchSnapshot();
});

test('auth2faType: u2f rendering', () => {
const { container } = render(<Universal2ndFactor />);
expect(container.firstChild).toMatchSnapshot();
});

test('nonrendering of user/pass/otp/login elements w/ local auth disabled', () => {
const { container } = render(<LocalAuthDisabled />);
expect(container.firstChild).toMatchSnapshot();
});

test('nonrendering of SSO providers w/ local auth disabled and no providers', () => {
const { container } = render(<LocalAuthDisabledNoSSO />);
expect(container.firstChild).toMatchSnapshot();
});
Loading

0 comments on commit 83f8c89

Please sign in to comment.