Skip to content

Commit d6839d1

Browse files
authored
Merge pull request #1 from dvaldivia/jwt-form
JWT Form
2 parents 65ec350 + e8f2f34 commit d6839d1

File tree

6 files changed

+191
-145
lines changed

6 files changed

+191
-145
lines changed

models/login_details.go

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

portal-ui/src/screens/LoginPage/LoginPage.tsx

Lines changed: 170 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

17-
import React from "react";
17+
import React, { useEffect, useState } from "react";
1818
import request from "superagent";
1919
import storage from "local-storage-fallback";
2020
import { connect, ConnectedProps } from "react-redux";
@@ -26,9 +26,8 @@ import { CircularProgress, Paper } from "@material-ui/core";
2626
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
2727
import { SystemState } from "../../types";
2828
import { userLoggedIn } from "../../actions";
29-
import history from "../../history";
3029
import api from "../../common/api";
31-
import { ILoginDetails } from "./types";
30+
import { ILoginDetails, loginStrategyType } from "./types";
3231
import { setCookie } from "../../common/utils";
3332

3433
const styles = (theme: Theme) =>
@@ -109,42 +108,36 @@ interface ILoginState {
109108
loginStrategy: ILoginDetails;
110109
}
111110

112-
class Login extends React.Component<ILoginProps, ILoginState> {
113-
state: ILoginState = {
114-
accessKey: "",
115-
secretKey: "",
116-
error: "",
117-
loading: false,
118-
loginStrategy: {
119-
loginStrategy: "",
120-
redirect: "",
121-
},
122-
};
111+
const Login = ({ classes, userLoggedIn }: ILoginProps) => {
112+
const [accessKey, setAccessKey] = useState<string>("");
113+
const [jwt, setJwt] = useState<string>("");
114+
const [secretKey, setSecretKey] = useState<string>("");
115+
const [error, setError] = useState<string>("");
116+
const [loading, setLoading] = useState<boolean>(false);
117+
const [loginStrategy, setLoginStrategy] = useState<ILoginDetails>({
118+
loginStrategy: loginStrategyType.unknown,
119+
redirect: "",
120+
});
123121

124-
fetchConfiguration() {
125-
this.setState({ loading: true }, () => {
126-
api
127-
.invoke("GET", "/api/v1/login")
128-
.then((loginDetails: ILoginDetails) => {
129-
this.setState({
130-
loading: false,
131-
});
132-
this.setState({
133-
loading: false,
134-
loginStrategy: loginDetails,
135-
error: "",
136-
});
137-
})
138-
.catch((err: any) => {
139-
this.setState({ loading: false, error: err });
140-
});
141-
});
142-
}
122+
const fetchConfiguration = () => {
123+
setLoading(true);
124+
125+
api
126+
.invoke("GET", "/api/v1/login")
127+
.then((loginDetails: ILoginDetails) => {
128+
setLoading(false);
129+
setLoginStrategy(loginDetails);
130+
setError("");
131+
})
132+
.catch((err: any) => {
133+
setLoading(false);
134+
setError(err);
135+
});
136+
};
143137

144-
formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
138+
const formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
145139
e.preventDefault();
146140
const url = "/api/v1/login";
147-
const { accessKey, secretKey } = this.state;
148141

149142
request
150143
.post(url)
@@ -164,134 +157,173 @@ class Login extends React.Component<ILoginProps, ILoginState> {
164157
})
165158
.then(() => {
166159
// We set the state in redux
167-
this.props.userLoggedIn(true);
160+
userLoggedIn(true);
168161
// There is a browser cache issue if we change the policy associated to an account and then logout and history.push("/") after login
169162
// therefore after login we need to use window.location redirect
170163
window.location.href = "/";
171164
})
172165
.catch((err) => {
173-
this.setState({ error: `${err}` });
166+
setError(err);
174167
});
175168
};
176169

177-
componentDidMount(): void {
178-
this.fetchConfiguration();
179-
}
180-
181-
render() {
182-
const { error, accessKey, secretKey, loginStrategy } = this.state;
183-
const { classes } = this.props;
170+
useEffect(() => {
171+
fetchConfiguration();
172+
}, []);
184173

185-
let loginComponent = null;
174+
let loginComponent = null;
186175

187-
switch (loginStrategy.loginStrategy) {
188-
case "form": {
189-
loginComponent = (
190-
<React.Fragment>
191-
<Typography component="h1" variant="h6">
192-
Login
193-
</Typography>
194-
<form
195-
className={classes.form}
196-
noValidate
197-
onSubmit={this.formSubmit}
198-
>
199-
<Grid container spacing={2}>
200-
{error !== "" && (
201-
<Grid item xs={12}>
202-
<Typography
203-
component="p"
204-
variant="body1"
205-
className={classes.errorBlock}
206-
>
207-
{error}
208-
</Typography>
209-
</Grid>
210-
)}
176+
switch (loginStrategy.loginStrategy) {
177+
case loginStrategyType.form: {
178+
loginComponent = (
179+
<React.Fragment>
180+
<Typography component="h1" variant="h6">
181+
Login
182+
</Typography>
183+
<form className={classes.form} noValidate onSubmit={formSubmit}>
184+
<Grid container spacing={2}>
185+
{error !== "" && (
211186
<Grid item xs={12}>
212-
<TextField
213-
required
214-
fullWidth
215-
id="accessKey"
216-
value={accessKey}
217-
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
218-
this.setState({ accessKey: e.target.value })
219-
}
220-
label="Access Key"
221-
name="accessKey"
222-
autoComplete="username"
223-
/>
187+
<Typography
188+
component="p"
189+
variant="body1"
190+
className={classes.errorBlock}
191+
>
192+
{error}
193+
</Typography>
224194
</Grid>
195+
)}
196+
<Grid item xs={12}>
197+
<TextField
198+
required
199+
fullWidth
200+
id="accessKey"
201+
value={accessKey}
202+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
203+
setAccessKey(e.target.value)
204+
}
205+
label="Access Key"
206+
name="accessKey"
207+
autoComplete="username"
208+
/>
209+
</Grid>
210+
<Grid item xs={12}>
211+
<TextField
212+
required
213+
fullWidth
214+
value={secretKey}
215+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
216+
setSecretKey(e.target.value)
217+
}
218+
name="secretKey"
219+
label="Secret Key"
220+
type="password"
221+
id="secretKey"
222+
autoComplete="current-password"
223+
/>
224+
</Grid>
225+
</Grid>
226+
<Button
227+
type="submit"
228+
fullWidth
229+
variant="contained"
230+
color="primary"
231+
className={classes.submit}
232+
>
233+
Login
234+
</Button>
235+
</form>
236+
</React.Fragment>
237+
);
238+
break;
239+
}
240+
case loginStrategyType.redirect: {
241+
loginComponent = (
242+
<React.Fragment>
243+
<Typography component="h1" variant="h6">
244+
Login
245+
</Typography>
246+
<Button
247+
component={"a"}
248+
href={loginStrategy.redirect}
249+
type="submit"
250+
fullWidth
251+
variant="contained"
252+
color="primary"
253+
className={classes.submit}
254+
>
255+
Welcome
256+
</Button>
257+
</React.Fragment>
258+
);
259+
break;
260+
}
261+
case loginStrategyType.serviceAccount: {
262+
loginComponent = (
263+
<React.Fragment>
264+
<Typography component="h1" variant="h6">
265+
Login
266+
</Typography>
267+
<form className={classes.form} noValidate onSubmit={formSubmit}>
268+
<Grid container spacing={2}>
269+
{error !== "" && (
225270
<Grid item xs={12}>
226-
<TextField
227-
required
228-
fullWidth
229-
value={secretKey}
230-
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
231-
this.setState({ secretKey: e.target.value })
232-
}
233-
name="secretKey"
234-
label="Secret Key"
235-
type="password"
236-
id="secretKey"
237-
autoComplete="current-password"
238-
/>
271+
<Typography
272+
component="p"
273+
variant="body1"
274+
className={classes.errorBlock}
275+
>
276+
{error}
277+
</Typography>
239278
</Grid>
279+
)}
280+
<Grid item xs={12}>
281+
<TextField
282+
required
283+
fullWidth
284+
id="jwt"
285+
value={jwt}
286+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
287+
setJwt(e.target.value)
288+
}
289+
label="JWT"
290+
name="jwt"
291+
autoComplete="Service Account JWT Token"
292+
/>
240293
</Grid>
241-
<Button
242-
type="submit"
243-
fullWidth
244-
variant="contained"
245-
color="primary"
246-
className={classes.submit}
247-
>
248-
Login
249-
</Button>
250-
</form>
251-
</React.Fragment>
252-
);
253-
break;
254-
}
255-
case "redirect": {
256-
loginComponent = (
257-
<React.Fragment>
258-
<Typography component="h1" variant="h6">
259-
Login
260-
</Typography>
294+
</Grid>
261295
<Button
262-
component={"a"}
263-
href={loginStrategy.redirect}
264296
type="submit"
265297
fullWidth
266298
variant="contained"
267299
color="primary"
268300
className={classes.submit}
269301
>
270-
Welcome
302+
Login
271303
</Button>
272-
</React.Fragment>
273-
);
274-
break;
275-
}
276-
default:
277-
loginComponent = (
278-
<CircularProgress className={classes.loadingLoginStrategy} />
279-
);
304+
</form>
305+
</React.Fragment>
306+
);
307+
break;
280308
}
309+
default:
310+
loginComponent = (
311+
<CircularProgress className={classes.loadingLoginStrategy} />
312+
);
313+
}
281314

282-
return (
283-
<Paper className={classes.paper}>
284-
<Grid container className={classes.mainContainer}>
285-
<Grid item xs={7} className={classes.theOcean}>
286-
<div className={classes.oceanBg} />
287-
</Grid>
288-
<Grid item xs={5} className={classes.theLogin}>
289-
{loginComponent}
290-
</Grid>
315+
return (
316+
<Paper className={classes.paper}>
317+
<Grid container className={classes.mainContainer}>
318+
<Grid item xs={7} className={classes.theOcean}>
319+
<div className={classes.oceanBg} />
291320
</Grid>
292-
</Paper>
293-
);
294-
}
295-
}
321+
<Grid item xs={5} className={classes.theLogin}>
322+
{loginComponent}
323+
</Grid>
324+
</Grid>
325+
</Paper>
326+
);
327+
};
296328

297329
export default connector(withStyles(styles)(Login));

0 commit comments

Comments
 (0)