feat(ui): enforce username from credentials if auth is enabled

This commit is contained in:
Łukasz Mierzwa
2020-02-22 15:50:01 +00:00
parent e08c442e39
commit 541b1ef519
6 changed files with 128 additions and 48 deletions
+15 -5
View File
@@ -172,6 +172,20 @@ const AlertAck = observer(
return;
}
let author =
alertStore.settings.values.silenceForm.author !== ""
? alertStore.settings.values.silenceForm.author
: silenceFormStore.data.author !== ""
? toJS(silenceFormStore.data.author)
: toJS(alertStore.settings.values.alertAcknowledgement.author);
if (alertStore.info.authentication.enabled) {
silenceFormStore.data.author = toJS(
alertStore.info.authentication.username
);
author = alertStore.info.authentication.username;
}
const alertmanagers = Object.entries(group.alertmanagerCount)
.filter(([amName, alertCount]) => alertCount > 0)
.map(([amName, _]) => amName);
@@ -187,11 +201,7 @@ const AlertAck = observer(
toJS(group),
toJS(clusterMembers),
toJS(alertStore.settings.values.alertAcknowledgement.durationSeconds),
alertStore.settings.values.silenceForm.author !== ""
? alertStore.settings.values.silenceForm.author
: silenceFormStore.data.author !== ""
? toJS(silenceFormStore.data.author)
: toJS(alertStore.settings.values.alertAcknowledgement.author),
author,
toJS(alertStore.settings.values.alertAcknowledgement.commentPrefix)
);
this.submitState.pushSilence(clusterName, pendingSilence);
+21
View File
@@ -189,6 +189,27 @@ describe("<AlertAck />", () => {
});
});
it("uses author from authentication info when auth is enabled", () => {
alertStore.info.authentication.enabled = true;
alertStore.info.authentication.username = "auth@example.com";
alertStore.settings.values.silenceForm.author = "john@example.com";
alertStore.settings.values.alertAcknowledgement.durationSeconds = 222;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.commentPrefix = "FOO:";
MountAndClick();
expect(JSON.parse(fetch.mock.calls[0][1].body)).toEqual({
comment:
"FOO: This alert was acknowledged using karma on Tue Feb 01 2000 00:00:00 GMT+0000",
createdBy: "auth@example.com",
endsAt: "2000-02-01T00:03:42.000Z",
matchers: [
{ isRegex: false, name: "alertname", value: "Fake Alert" },
{ isRegex: true, name: "foo", value: "(bar|baz)" }
],
startsAt: "2000-02-01T00:00:00.000Z"
});
});
it("uses author from alertStore if present", () => {
alertStore.settings.values.silenceForm.author = "john@example.com";
alertStore.settings.values.alertAcknowledgement.durationSeconds = 222;
@@ -0,0 +1,59 @@
import React from "react";
import PropTypes from "prop-types";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
import { AlertStore } from "Stores/AlertStore";
const IconInput = ({
type,
autoComplete,
icon,
placeholder,
value,
onChange,
...extra
}) => (
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text">
<FontAwesomeIcon icon={icon} />
</span>
</div>
<input
type={type}
className="form-control"
placeholder={placeholder}
value={value}
required
autoComplete={autoComplete}
onChange={onChange}
{...extra}
/>
</div>
);
IconInput.propTypes = {
type: PropTypes.string.isRequired,
autoComplete: PropTypes.string.isRequired,
icon: FontAwesomeIcon.propTypes.icon.isRequired,
placeholder: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
onChange: PropTypes.func
};
const AuthenticatedAuthorInput = ({ alertStore }) => (
<IconInput
type="text"
autoComplete="email"
placeholder="Author"
icon={faUser}
value={alertStore.info.authentication.username}
readOnly={true}
/>
);
AuthenticatedAuthorInput.propTypes = {
alertStore: PropTypes.instanceOf(AlertStore).isRequired
};
export { IconInput, AuthenticatedAuthorInput };
+18 -42
View File
@@ -21,40 +21,7 @@ import { AlertManagerInput } from "./AlertManagerInput";
import { SilenceMatch } from "./SilenceMatch";
import { DateTimeSelect } from "./DateTimeSelect";
import { PayloadPreview } from "./PayloadPreview";
const IconInput = ({
type,
autoComplete,
icon,
placeholder,
value,
onChange
}) => (
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text">
<FontAwesomeIcon icon={icon} />
</span>
</div>
<input
type={type}
className="form-control"
placeholder={placeholder}
value={value}
required
autoComplete={autoComplete}
onChange={onChange}
/>
</div>
);
IconInput.propTypes = {
type: PropTypes.string.isRequired,
autoComplete: PropTypes.string.isRequired,
icon: FontAwesomeIcon.propTypes.icon.isRequired,
placeholder: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
};
import { IconInput, AuthenticatedAuthorInput } from "./AuthorInput";
const SilenceForm = observer(
class SilenceForm extends Component {
@@ -111,6 +78,10 @@ const SilenceForm = observer(
silenceFormStore.data.author =
settingsStore.silenceFormConfig.config.author;
}
if (alertStore.info.authentication.enabled) {
silenceFormStore.data.author = alertStore.info.authentication.username;
}
});
addMore = action(event => {
@@ -177,14 +148,19 @@ const SilenceForm = observer(
</button>
</TooltipWrapper>
<DateTimeSelect silenceFormStore={silenceFormStore} />
<IconInput
type="text"
autoComplete="email"
placeholder="Author"
icon={faUser}
value={silenceFormStore.data.author}
onChange={this.onAuthorChange}
/>
{alertStore.info.authentication.enabled ? (
<AuthenticatedAuthorInput alertStore={alertStore} />
) : (
<IconInput
type="text"
autoComplete="email"
placeholder="Author"
icon={faUser}
value={silenceFormStore.data.author}
onChange={this.onAuthorChange}
/>
)}
<IconInput
type="text"
autoComplete="on"
@@ -127,6 +127,16 @@ describe("<SilenceForm /> preview", () => {
});
describe("<SilenceForm /> inputs", () => {
it("author is read-only when info.authentication.enabled is true", () => {
alertStore.info.authentication.enabled = true;
alertStore.info.authentication.username = "auth@example.com";
const tree = MountedSilenceForm();
const input = tree.find("input[placeholder='Author']");
expect(input.props().readOnly).toBe(true);
expect(input.props().value).toBe("auth@example.com");
expect(silenceFormStore.data.author).toBe("auth@example.com");
});
it("default author value comes from Settings store", () => {
settingsStore.silenceFormConfig.config.author = "foo@example.com";
const tree = MountedSilenceForm();
+5 -1
View File
@@ -215,6 +215,10 @@ class AlertStore {
info = observable(
{
authentication: {
enabled: false,
username: ""
},
totalAlerts: 0,
version: "unknown",
upgradeNeeded: false,
@@ -418,7 +422,7 @@ class AlertStore {
this.info.upgradeNeeded = true;
}
// update extra root level keys that are stored under 'info'
for (const key of ["totalAlerts", "version"]) {
for (const key of ["totalAlerts", "version", "authentication"]) {
if (this.info[key] !== result[key]) {
this.info[key] = result[key];
}