remove roles, as a simplification
This commit is contained in:
parent
0c630f0f93
commit
6935b63706
@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"jwt_secret":"esp8266-react",
|
"jwt_secret":"esp8266-react",
|
||||||
"roles": ["admin", "guest"],
|
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"username": "admin",
|
"username": "admin",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"role": "admin"
|
"admin": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"username": "guest",
|
"username": "guest",
|
||||||
"password": "guest",
|
"password": "guest",
|
||||||
"role": "guest"
|
"admin": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
import { ValidatorForm } from 'react-material-ui-form-validator';
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
@ -13,14 +13,16 @@ import TableCell from '@material-ui/core/TableCell';
|
|||||||
import TableFooter from '@material-ui/core/TableFooter';
|
import TableFooter from '@material-ui/core/TableFooter';
|
||||||
import TableHead from '@material-ui/core/TableHead';
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
import TableRow from '@material-ui/core/TableRow';
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import Chip from '@material-ui/core/Chip';
|
|
||||||
|
|
||||||
import EditIcon from '@material-ui/icons/Edit';
|
import EditIcon from '@material-ui/icons/Edit';
|
||||||
import DeleteIcon from '@material-ui/icons/Delete';
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import CheckIcon from '@material-ui/icons/Check';
|
||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
|
||||||
import SectionContent from '../components/SectionContent';
|
import SectionContent from '../components/SectionContent';
|
||||||
import UserForm from './UserForm';
|
import UserForm from './UserForm';
|
||||||
|
import { withAuthenticationContext } from '../authentication/Context';
|
||||||
|
|
||||||
const styles = theme => ({
|
const styles = theme => ({
|
||||||
loadingSettings: {
|
loadingSettings: {
|
||||||
@ -30,26 +32,15 @@ const styles = theme => ({
|
|||||||
margin: theme.spacing.unit * 4,
|
margin: theme.spacing.unit * 4,
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
},
|
},
|
||||||
switchControl: {
|
|
||||||
width: "100%",
|
|
||||||
marginTop: theme.spacing.unit * 2,
|
|
||||||
marginBottom: theme.spacing.unit
|
|
||||||
},
|
|
||||||
textField: {
|
|
||||||
width: "100%"
|
|
||||||
},
|
|
||||||
button: {
|
button: {
|
||||||
marginRight: theme.spacing.unit * 2,
|
marginRight: theme.spacing.unit * 2,
|
||||||
marginTop: theme.spacing.unit * 2,
|
marginTop: theme.spacing.unit * 2,
|
||||||
},
|
},
|
||||||
chip: {
|
|
||||||
margin: theme.spacing.unit,
|
|
||||||
},
|
|
||||||
table: {
|
table: {
|
||||||
'& td, & th': { padding: theme.spacing.unit }
|
'& td, & th': { padding: theme.spacing.unit }
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
color: theme.palette.text.secondary,
|
whiteSpace: "nowrap"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,7 +67,7 @@ class ManageUsersForm extends React.Component {
|
|||||||
user: {
|
user: {
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
roles: []
|
admin: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -85,8 +76,8 @@ class ManageUsersForm extends React.Component {
|
|||||||
return !this.props.userData.users.find(u => u.username === username);
|
return !this.props.userData.users.find(u => u.username === username);
|
||||||
}
|
}
|
||||||
|
|
||||||
usersValid = username => {
|
noAdminConfigured = () => {
|
||||||
return !!this.props.userData.users.find(u => u.roles.includes("admin"));
|
return !this.props.userData.users.find(u => u.admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
startEditingUser = user => {
|
startEditingUser = user => {
|
||||||
@ -102,10 +93,6 @@ class ManageUsersForm extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedUsers(users) {
|
|
||||||
return users.sort(compareUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
doneEditingUser = () => {
|
doneEditingUser = () => {
|
||||||
const { user } = this.state;
|
const { user } = this.state;
|
||||||
const { userData } = this.props;
|
const { userData } = this.props;
|
||||||
@ -120,17 +107,29 @@ class ManageUsersForm extends React.Component {
|
|||||||
|
|
||||||
handleUserValueChange = name => event => {
|
handleUserValueChange = name => event => {
|
||||||
const { user } = this.state;
|
const { user } = this.state;
|
||||||
if (user) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
user: {
|
user: {
|
||||||
...user, [name]: event.target.value
|
...user, [name]: event.target.value
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleUserCheckboxChange = name => event => {
|
||||||
|
const { user } = this.state;
|
||||||
|
this.setState({
|
||||||
|
user: {
|
||||||
|
...user, [name]: event.target.checked
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit = () => {
|
||||||
|
this.props.onSubmit();
|
||||||
|
this.props.authenticationContex.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { classes, userData, userDataFetched, errorMessage, onSubmit, onReset, handleValueChange } = this.props;
|
const { classes, userData, userDataFetched, errorMessage, onReset } = this.props;
|
||||||
const { user, creating } = this.state;
|
const { user, creating } = this.state;
|
||||||
return (
|
return (
|
||||||
<SectionContent title="Manage Users">
|
<SectionContent title="Manage Users">
|
||||||
@ -148,33 +147,31 @@ class ManageUsersForm extends React.Component {
|
|||||||
<UserForm
|
<UserForm
|
||||||
user={user}
|
user={user}
|
||||||
creating={creating}
|
creating={creating}
|
||||||
roles={userData.roles}
|
|
||||||
onDoneEditing={this.doneEditingUser}
|
onDoneEditing={this.doneEditingUser}
|
||||||
onCancelEditing={this.cancelEditingUser}
|
onCancelEditing={this.cancelEditingUser}
|
||||||
handleValueChange={this.handleUserValueChange}
|
handleValueChange={this.handleUserValueChange}
|
||||||
|
handleCheckboxChange={this.handleUserCheckboxChange}
|
||||||
uniqueUsername={this.uniqueUsername}
|
uniqueUsername={this.uniqueUsername}
|
||||||
/>
|
/>
|
||||||
:
|
:
|
||||||
<ValidatorForm onSubmit={onSubmit}>
|
<ValidatorForm onSubmit={this.onSubmit}>
|
||||||
<Table className={classes.table}>
|
<Table className={classes.table}>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Username</TableCell>
|
<TableCell>Username</TableCell>
|
||||||
<TableCell align="center">Role(s)</TableCell>
|
<TableCell align="center">Admin?</TableCell>
|
||||||
<TableCell align="center">Action</TableCell>
|
<TableCell align="center">Action</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{this.sortedUsers(userData.users).map(user => (
|
{userData.users.sort(compareUsers).map(user => (
|
||||||
<TableRow key={user.username}>
|
<TableRow key={user.username}>
|
||||||
<TableCell component="th" scope="row">
|
<TableCell component="th" scope="row">
|
||||||
{user.username}
|
{user.username}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{
|
{
|
||||||
user.roles.map(role => (
|
user.admin ? <CheckIcon /> : <CloseIcon />
|
||||||
<Chip label={role} className={classes.chip} />
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
@ -192,7 +189,7 @@ class ManageUsersForm extends React.Component {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={2}>
|
<TableCell colSpan={2}>
|
||||||
{
|
{
|
||||||
!this.usersValid() &&
|
this.noAdminConfigured() &&
|
||||||
<Typography variant="body1" color="error">
|
<Typography variant="body1" color="error">
|
||||||
You must have at least one admin user configured.
|
You must have at least one admin user configured.
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -206,7 +203,7 @@ class ManageUsersForm extends React.Component {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableFooter>
|
</TableFooter>
|
||||||
</Table>
|
</Table>
|
||||||
<Button variant="contained" color="primary" className={classes.button} type="submit">
|
<Button variant="contained" color="primary" className={classes.button} type="submit" disabled={this.noAdminConfigured()}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
|
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
|
||||||
@ -230,6 +227,7 @@ class ManageUsersForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ManageUsersForm.propTypes = {
|
ManageUsersForm.propTypes = {
|
||||||
|
authenticationContex: PropTypes.object.isRequired,
|
||||||
classes: PropTypes.object.isRequired,
|
classes: PropTypes.object.isRequired,
|
||||||
userData: PropTypes.object,
|
userData: PropTypes.object,
|
||||||
userDataFetched: PropTypes.bool.isRequired,
|
userDataFetched: PropTypes.bool.isRequired,
|
||||||
@ -240,4 +238,4 @@ ManageUsersForm.propTypes = {
|
|||||||
handleValueChange: PropTypes.func.isRequired
|
handleValueChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withStyles(styles)(ManageUsersForm);
|
export default withAuthenticationContext(withStyles(styles)(ManageUsersForm));
|
||||||
|
@ -7,12 +7,9 @@ import Button from '@material-ui/core/Button';
|
|||||||
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
||||||
import PasswordValidator from '../components/PasswordValidator';
|
import PasswordValidator from '../components/PasswordValidator';
|
||||||
|
|
||||||
import Input from '@material-ui/core/Input';
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import InputLabel from '@material-ui/core/InputLabel';
|
import Switch from '@material-ui/core/Switch';
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
import FormGroup from '@material-ui/core/FormGroup';
|
||||||
import FormControl from '@material-ui/core/FormControl';
|
|
||||||
import Select from '@material-ui/core/Select';
|
|
||||||
import Chip from '@material-ui/core/Chip';
|
|
||||||
|
|
||||||
const styles = theme => ({
|
const styles = theme => ({
|
||||||
textField: {
|
textField: {
|
||||||
@ -41,7 +38,7 @@ class UserForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { classes, user, roles, creating, handleValueChange, onDoneEditing, onCancelEditing } = this.props;
|
const { classes, user, creating, handleValueChange, handleCheckboxChange, onDoneEditing, onCancelEditing } = this.props;
|
||||||
return (
|
return (
|
||||||
<ValidatorForm onSubmit={onDoneEditing}>
|
<ValidatorForm onSubmit={onDoneEditing}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
@ -62,31 +59,15 @@ class UserForm extends React.Component {
|
|||||||
label="Password"
|
label="Password"
|
||||||
className={classes.textField}
|
className={classes.textField}
|
||||||
value={user.password}
|
value={user.password}
|
||||||
onChange={handleValueChange('password')}
|
onChange={handleCheckboxChange('password')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<FormControl className={classes.textField}>
|
<FormGroup>
|
||||||
<InputLabel htmlFor="roles">Roles</InputLabel>
|
<FormControlLabel
|
||||||
<Select
|
control={<Switch checked={user.admin} onChange={handleCheckboxChange('admin')} id="admin" />}
|
||||||
multiple
|
label="Admin?"
|
||||||
value={user.roles}
|
/>
|
||||||
onChange={handleValueChange('roles')}
|
</FormGroup>
|
||||||
input={<Input id="roles" />}
|
|
||||||
renderValue={selected => (
|
|
||||||
<div className={classes.chips}>
|
|
||||||
{selected.map(value => (
|
|
||||||
<Chip key={value} label={value} className={classes.chip} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{roles.map(name => (
|
|
||||||
<MenuItem key={name} value={name}>
|
|
||||||
{name}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
<Button variant="contained" color="primary" className={classes.button} type="submit">
|
<Button variant="contained" color="primary" className={classes.button} type="submit">
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@ -102,11 +83,11 @@ UserForm.propTypes = {
|
|||||||
classes: PropTypes.object.isRequired,
|
classes: PropTypes.object.isRequired,
|
||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
creating: PropTypes.bool.isRequired,
|
creating: PropTypes.bool.isRequired,
|
||||||
roles: PropTypes.array.isRequired,
|
|
||||||
onDoneEditing: PropTypes.func.isRequired,
|
onDoneEditing: PropTypes.func.isRequired,
|
||||||
onCancelEditing: PropTypes.func.isRequired,
|
onCancelEditing: PropTypes.func.isRequired,
|
||||||
uniqueUsername: PropTypes.func.isRequired,
|
uniqueUsername: PropTypes.func.isRequired,
|
||||||
handleValueChange: PropTypes.func.isRequired
|
handleValueChange: PropTypes.func.isRequired,
|
||||||
|
handleCheckboxChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withStyles(styles)(UserForm);
|
export default withStyles(styles)(UserForm);
|
||||||
|
@ -7,26 +7,11 @@ void SecurityManager::readFromJsonObject(JsonObject& root) {
|
|||||||
// secret
|
// secret
|
||||||
_jwtSecret = root["jwt_secret"] | DEFAULT_JWT_SECRET;
|
_jwtSecret = root["jwt_secret"] | DEFAULT_JWT_SECRET;
|
||||||
|
|
||||||
// roles
|
|
||||||
_roles.clear();
|
|
||||||
if (root["roles"].is<JsonArray>()) {
|
|
||||||
JsonArray roles = root["roles"];
|
|
||||||
for (JsonVariant role : roles) {
|
|
||||||
_roles.push_back(role.as<String>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// users
|
// users
|
||||||
_users.clear();
|
_users.clear();
|
||||||
if (root["users"].is<JsonArray>()) {
|
if (root["users"].is<JsonArray>()) {
|
||||||
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
||||||
std::list<String> roles;
|
_users.push_back(User(user["username"], user["password"], user["admin"]));
|
||||||
if (user["roles"].is<JsonArray>()) {
|
|
||||||
for (JsonVariant role : user["roles"].as<JsonArray>()) {
|
|
||||||
roles.push_back(role.as<String>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_users.push_back(User(user["username"], user["password"], roles));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,22 +21,13 @@ void SecurityManager::writeToJsonObject(JsonObject& root) {
|
|||||||
// secret
|
// secret
|
||||||
root["jwt_secret"] = _jwtSecret;
|
root["jwt_secret"] = _jwtSecret;
|
||||||
|
|
||||||
// roles
|
|
||||||
JsonArray roles = root.createNestedArray("roles");
|
|
||||||
for (String _role : _roles) {
|
|
||||||
roles.add(_role);
|
|
||||||
}
|
|
||||||
|
|
||||||
// users
|
// users
|
||||||
JsonArray users = root.createNestedArray("users");
|
JsonArray users = root.createNestedArray("users");
|
||||||
for (User _user : _users) {
|
for (User _user : _users) {
|
||||||
JsonObject user = users.createNestedObject();
|
JsonObject user = users.createNestedObject();
|
||||||
user["username"] = _user.getUsername();
|
user["username"] = _user.getUsername();
|
||||||
user["password"] = _user.getPassword();
|
user["password"] = _user.getPassword();
|
||||||
JsonArray roles = user.createNestedArray("roles");
|
user["admin"] = _user.isAdmin();
|
||||||
for (String _role : _user.getRoles()){
|
|
||||||
roles.add(_role);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +76,7 @@ Authentication SecurityManager::authenticate(String username, String password) {
|
|||||||
|
|
||||||
inline void populateJWTPayload(JsonObject &payload, User *user) {
|
inline void populateJWTPayload(JsonObject &payload, User *user) {
|
||||||
payload["username"] = user->getUsername();
|
payload["username"] = user->getUsername();
|
||||||
JsonArray roles = payload.createNestedArray("roles");
|
payload["admin"] = user -> isAdmin();
|
||||||
for (String _role : user->getRoles()){
|
|
||||||
roles.add(_role);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) {
|
boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) {
|
||||||
|
@ -28,17 +28,17 @@ class User {
|
|||||||
private:
|
private:
|
||||||
String _username;
|
String _username;
|
||||||
String _password;
|
String _password;
|
||||||
std::list<String> _roles;
|
bool _admin;
|
||||||
public:
|
public:
|
||||||
User(String username, String password, std::list<String> roles): _username(username), _password(password), _roles(roles) {}
|
User(String username, String password, bool admin): _username(username), _password(password), _admin(admin) {}
|
||||||
String getUsername() {
|
String getUsername() {
|
||||||
return _username;
|
return _username;
|
||||||
}
|
}
|
||||||
String getPassword() {
|
String getPassword() {
|
||||||
return _password;
|
return _password;
|
||||||
}
|
}
|
||||||
std::list<String> getRoles() {
|
bool isAdmin() {
|
||||||
return _roles;
|
return _admin;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,7 +97,6 @@ class SecurityManager : public SettingsService {
|
|||||||
|
|
||||||
// access point settings
|
// access point settings
|
||||||
String _jwtSecret;
|
String _jwtSecret;
|
||||||
std::list<String> _roles;
|
|
||||||
std::list<User> _users;
|
std::list<User> _users;
|
||||||
|
|
||||||
// endpoint functions
|
// endpoint functions
|
||||||
|
Loading…
Reference in New Issue
Block a user