Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guest user #1246

Merged
merged 13 commits into from
Apr 2, 2019
Merged
10 changes: 10 additions & 0 deletions gsa/src/gmp/__tests__/gmpsettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ describe('GmpSettings tests', () => {
expect(settings.timeout).toBeUndefined();
expect(settings.timezone).toBeUndefined();
expect(settings.username).toBeUndefined();
expect(settings.guestUsername).toBeUndefined();
expect(settings.guestPassword).toBeUndefined();
expect(settings.disableLoginForm).toEqual(false);

expect(storage.setItem).toHaveBeenCalledTimes(1);
expect(storage.setItem).toHaveBeenCalledWith('loglevel', DEFAULT_LOG_LEVEL);
Expand All @@ -66,6 +69,9 @@ describe('GmpSettings tests', () => {
timeout: 30000,
timezone: 'cet',
username: 'foo',
guestUsername: 'guest',
guestPassword: 'pass',
disableLoginForm: true,
});

expect(settings.reloadinterval).toEqual(10);
Expand All @@ -80,6 +86,10 @@ describe('GmpSettings tests', () => {
expect(settings.username).toBeUndefined();
expect(settings.loglevel).toEqual('error');

expect(settings.guestUsername).toEqual('guest');
expect(settings.guestPassword).toEqual('pass');
expect(settings.disableLoginForm).toEqual(true);

expect(storage.setItem).toHaveBeenCalledTimes(1);
expect(storage.setItem).toHaveBeenCalledWith('loglevel', 'error');
});
Expand Down
6 changes: 6 additions & 0 deletions gsa/src/gmp/gmpsettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ const set = (storage, name, value) => {
class GmpSettings {
constructor(storage = global.localStorage, options = {}) {
const {
disableLoginForm = false,
loglevel = storage.loglevel,
manualurl = DEFAULT_MANUAL_URL,
protocol = global.location.protocol,
protocoldocurl = DEFAULT_PROTOCOLDOC_URL,
reloadinterval = DEFAULT_RELOAD_INTERVAL,
server = global.location.host,
timeout,
guestUsername,
guestPassword,
} = {...options};
this.storage = storage;

Expand All @@ -52,6 +55,9 @@ class GmpSettings {
this.reloadinterval = reloadinterval;
this.server = server;
this.timeout = timeout;
this.guestUsername = guestUsername;
this.guestPassword = guestPassword;
this.disableLoginForm = disableLoginForm;
}

set token(value) {
Expand Down
138 changes: 86 additions & 52 deletions gsa/src/web/pages/login/loginform.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ const Error = styled.p`
margin: 10px;
`;

const Wrapper = styled.div`
display: flex;
flex-direction: column;
border: 1px solid ${Theme.lightGray};
padding: 10px;
margin-bottom: 10px;
`;

class LoginForm extends React.Component {
constructor(props) {
super(props);
Expand Down Expand Up @@ -93,62 +101,85 @@ class LoginForm extends React.Component {
}

render() {
const {error} = this.props;
const {
error,
showGuestLogin = false,
showLogin = false,
bjoernricks marked this conversation as resolved.
Show resolved Hide resolved
onGuestLoginClick,
} = this.props;
const {username, password} = this.state;
const protocol_insecure = window.location.protocol !== 'https:';
return (
<React.Fragment>
{protocol_insecure && (
<Panel>
<Error>{_('Warning: Connection unencrypted')}</Error>
<p>
{_(
'The connection to this GSA is not encrypted, allowing ' +
'anyone listening to the traffic to steal your credentials.',
)}
</p>
<p>
{_(
'Please configure a TLS certificate for the HTTPS service ' +
'or ask your administrator to do so as soon as possible.',
)}
</p>
</Panel>
)}

<LoginPanel>
<ProductImage />
<Layout flex="column">
<FormGroup title={_('Username')} titleSize="4">
<TextField
name="username"
placeholder={_('e.g. johndoe')}
value={username}
autoFocus="autofocus"
tabIndex="1"
onChange={this.handleValueChange}
/>
</FormGroup>
<FormGroup title={_('Password')} titleSize="4">
<PasswordField
name="password"
grow="1"
placeholder={_('Password')}
value={password}
onKeyDown={this.handleKeyDown}
onChange={this.handleValueChange}
/>
</FormGroup>
<FormGroup size="4" offset="4">
<Button title={_('Login')} onClick={this.handleSubmit} />
</FormGroup>
</Layout>
</LoginPanel>

{isDefined(error) && (
<Panel>
<Error>{error}</Error>
</Panel>
<Wrapper>
{protocol_insecure && (
<Panel>
<Error>{_('Warning: Connection unencrypted')}</Error>
<p>
{_(
'The connection to this GSA is not encrypted, allowing ' +
'anyone listening to the traffic to steal your credentials.',
)}
</p>
<p>
{_(
'Please configure a TLS certificate for the HTTPS service ' +
'or ask your administrator to do so as soon as possible.',
)}
</p>
</Panel>
)}

<LoginPanel>
<ProductImage />

{showLogin && (
<Layout flex="column">
<FormGroup title={_('Username')} titleSize="4">
<TextField
name="username"
placeholder={_('e.g. johndoe')}
value={username}
autoFocus="autofocus"
tabIndex="1"
onChange={this.handleValueChange}
/>
</FormGroup>
<FormGroup title={_('Password')} titleSize="4">
<PasswordField
name="password"
grow="1"
placeholder={_('Password')}
value={password}
onKeyDown={this.handleKeyDown}
onChange={this.handleValueChange}
/>
</FormGroup>
<FormGroup size="4" offset="4">
<Button title={_('Login')} onClick={this.handleSubmit} />
</FormGroup>
</Layout>
)}
</LoginPanel>

{isDefined(error) && (
<Panel>
<Error>{error}</Error>
</Panel>
)}
</Wrapper>

{showGuestLogin && (
<Wrapper>
<LoginPanel>
<Layout align={['center', 'center']}>
<Button
title={_('Login as Guest')}
onClick={onGuestLoginClick}
/>
</Layout>
</LoginPanel>
</Wrapper>
)}
</React.Fragment>
);
Expand All @@ -157,6 +188,9 @@ class LoginForm extends React.Component {

LoginForm.propTypes = {
error: PropTypes.string,
showGuestLogin: PropTypes.bool,
showLogin: PropTypes.bool,
onGuestLoginClick: PropTypes.func,
onSubmit: PropTypes.func,
};

Expand Down
34 changes: 26 additions & 8 deletions gsa/src/web/pages/login/loginpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import _ from 'gmp/locale';

import logger from 'gmp/log';

import {isDefined} from 'gmp/utils/identity';
import {isEmpty} from 'gmp/utils/string';

import compose from 'web/utils/compose';
Expand Down Expand Up @@ -88,11 +89,6 @@ const MenuSpacer = styled.div`
z-index: ${Theme.Layers.menu};
`;

const Wrapper = styled.div`
border: 1px solid #ddd;
padding: 10px;
`;

class LoginPage extends React.Component {
constructor(props) {
super(props);
Expand All @@ -102,9 +98,19 @@ class LoginPage extends React.Component {
};

this.handleSubmit = this.handleSubmit.bind(this);
this.handleGuestLogin = this.handleGuestLogin.bind(this);
}

handleSubmit(username, password) {
this.login(username, password);
}

handleGuestLogin() {
const {gmp} = this.props;
this.login(gmp.settings.guestUsername, gmp.settings.guestPassword);
}

login(username, password) {
const {gmp} = this.props;

gmp.login(username, password).then(
Expand Down Expand Up @@ -143,6 +149,8 @@ class LoginPage extends React.Component {

render() {
const {error} = this.state;
const {gmp} = this.props;

let message;

if (error) {
Expand All @@ -153,15 +161,25 @@ class LoginPage extends React.Component {
}
}

const showGuestLogin =
isDefined(gmp.settings.guestUsername) &&
isDefined(gmp.settings.guestPassword);

const showLogin = !gmp.settings.disableLoginForm;

return (
<StyledLayout>
<LoginHeader />
<MenuSpacer />
<LoginLayout flex="column" className="login">
<GreenboneLogo />
<Wrapper>
<LoginForm error={message} onSubmit={this.handleSubmit} />
</Wrapper>
<LoginForm
error={message}
showGuestLogin={showGuestLogin}
showLogin={showLogin}
onGuestLoginClick={this.handleGuestLogin}
onSubmit={this.handleSubmit}
/>
</LoginLayout>
<Footer />
</StyledLayout>
Expand Down
9 changes: 9 additions & 0 deletions gsa/src/web/utils/testing.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ afterEach(cleanup);
const queryAllByName = (container, name) =>
queryAllByAttribute('name', container, name);

const queryByName = (container, name) => {
const els = queryAllByName(container, name);
bjoernricks marked this conversation as resolved.
Show resolved Hide resolved
if (!els.length) {
return null;
}
return els[0];
};

const getByName = (container, name) => {
const els = queryAllByName(container, name);
if (!els.length) {
Expand All @@ -70,6 +78,7 @@ export const render = ui => {
container,
element: hasValue(container) ? container.firstChild : undefined,
getByName: name => getByName(baseElement, name),
queryByName: name => queryByName(baseElement, name),
queryAllByName: name => queryAllByName(baseElement, name),
...other,
};
Expand Down