Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge pull request from GHSA-pr2g-j78h-84cr
* Fix access control issues with users

* Fix access control issues with packs

* Fix access control issues with software

* Changes suggested by Martin

* All users can access the global schedule

* Restrict access to activities

* Add explicit test for team admin escalation vuln

* All global users should be able to read all software

* Handbook editor pass - Security - GitHub Security (#5108)

* Update security.md

All edits are recorded by line:

395 replaced “open-source” with “open source”
411 replaced “open-source” with “open source”
439 added “the” before “comment”; replaced “repositories,” with “repositories”
445 deleted “being” before “located”
458 added “and” after “PR”
489 replaced “on” with “in”
493 replaced “open-source” with “open source”; Replaced “privileges,” with “privileges”

* Update security.md

line 479

* Update security.md

added (static analysis tools used to identify problems in code) to line 479

* Fix UI

* Fix UI

* revert api v1 to latest in documentation (#5149)

* revert api v1 to latest in documentation

* Update fleetctl doc page

Co-authored-by: Noah Talerman <noahtal@umich.edu>

* Add team admin team policy automation; fix e2e

* Update to company page of the handbook (#5164)

Updated "Why do we use a wireframe-first approach?" section of company.md

* removed extra data on smaller screens (#5154)

* Update for team automations; e2e

* Jira Integration: Cypress e2e tests only (#5055)

* Update company.md (#5170)

This is to update the formatting under "empathy" and to fix the spelling of "help text."
This was done as per @mikermcneil .
This is related to ##4941 and #4902

* fix update updated_at for aggregated_stats (#5112)

Update the updated_at column when using ON DUPLICATE UPDATE so that
the counts_updated_at is up to date

* basic sql formatting in code ie whitespace around operators

* Fix e2e test

* Fix tests in server/authz

Co-authored-by: gillespi314 <73313222+gillespi314@users.noreply.github.com>
Co-authored-by: Desmi-Dizney <99777687+Desmi-Dizney@users.noreply.github.com>
Co-authored-by: Michal Nicpon <39177923+michalnicp@users.noreply.github.com>
Co-authored-by: Noah Talerman <noahtal@umich.edu>
Co-authored-by: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com>
Co-authored-by: Martavis Parker <47053705+martavis@users.noreply.github.com>
Co-authored-by: RachelElysia <71795832+RachelElysia@users.noreply.github.com>
  • Loading branch information
8 people committed Apr 18, 2022
1 parent 2ee4a52 commit da171d3
Show file tree
Hide file tree
Showing 31 changed files with 1,339 additions and 352 deletions.
1 change: 1 addition & 0 deletions changes/activities-rbac
@@ -0,0 +1 @@
* Restrict non-global user from access to activities
3 changes: 3 additions & 0 deletions changes/issue-GHSA-pr2g-j78h-84cr
@@ -0,0 +1,3 @@
* Fix access control issues with "user" endpoints.
* Fix access control issues with "pack" endpoints.
* Fix access control issues with "software" endpoints.
36 changes: 8 additions & 28 deletions cypress/integration/free/maintainer.spec.ts
Expand Up @@ -189,31 +189,7 @@ describe(
describe("Manage software page", () => {
beforeEach(() => cy.visit("/software/manage"));
it("should restrict global maintainer from 'Manage automations' button", () => {
it("hides manages software automations when all teams selected", () => {
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.getAttached(".Select").within(() => {
cy.findByText(/all teams/i).should("exist");
});
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.findByRole("button", {
name: /manage automations/i,
}).should("not.exist");
});
});
});
it("hides manage automations button when all teams not selected", () => {
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.getAttached(".Select").within(() => {
cy.getAttached(".Select-control").click();
cy.getAttached(".Select-menu-outer").within(() => {
cy.findByText(/apples/i).should("exist");
});
cy.findByRole("button", {
name: /manage automations/i,
}).should("not.exist");
});
});
});
cy.findByText(/manage automations/).should("not.exist");
});
});
describe("Query pages", () => {
Expand Down Expand Up @@ -274,9 +250,13 @@ describe(
cy.loginWithCySession("mary@organization.com", "user123#");
cy.visit("/policies/manage");
});
it("allows maintainer to manage automations", () => {
cy.findByRole("button", { name: /manage automations/i }).click();
cy.findByRole("button", { name: /cancel/i }).click();
it("hides manage automations from maintainer", () => {
cy.getAttached(".button-wrap").within(() => {
cy.findByRole("button", { name: /add a policy/i }).should("exist");
cy.findByRole("button", { name: /manage automations/i }).should(
"not.exist"
);
});
});
it("allows maintainer to add a policy", () => {
cy.findByRole("button", { name: /add a policy/i }).click();
Expand Down
6 changes: 2 additions & 4 deletions cypress/integration/free/observer.spec.ts
Expand Up @@ -209,12 +209,10 @@ describe("Free tier - Observer user", () => {
cy.visit("/policies/manage");
});
it("hides manage automations button", () => {
cy.findByRole("button", { name: /manage automations/i }).should(
"not.exist"
);
cy.findByText(/manage automations/i).should("not.exist");
});
it("hides add a policy button", () => {
cy.findByRole("button", { name: /add a policy/i }).should("not.exist");
cy.findByText(/add a policy/).should("not.exist");
});
it("hides run, edit, or delete a policy", () => {
cy.getAttached("tbody").within(() => {
Expand Down
21 changes: 21 additions & 0 deletions cypress/integration/premium/admin.spec.ts
Expand Up @@ -564,6 +564,27 @@ describe("Premium tier - Global Admin user", () => {
});
cy.findByText(/successfully updated policy automations/i).should("exist");
});
it("allows global admin to automate a team policy", () => {
cy.visit("/policies/manage");
cy.getAttached(".Select-control").within(() => {
cy.findByText(/all teams/i).click();
});
cy.getAttached(".Select-menu")
.contains(/apples/i)
.click();
cy.getAttached(".button-wrap")
.findByRole("button", { name: /manage automations/i })
.click();
cy.getAttached(".manage-automations-modal").within(() => {
cy.getAttached(".fleet-slider").click();
cy.getAttached(".fleet-checkbox__input").check({ force: true });
cy.getAttached("#webhook-url")
.clear()
.type("https://example.com/global_admin");
cy.findByText(/save/i).click();
});
cy.findByText(/successfully updated policy automations/i).should("exist");
});
it("allows global admin to delete a team policy", () => {
cy.visit("/policies/manage");
cy.getAttached(".Select-control").within(() => {
Expand Down
35 changes: 4 additions & 31 deletions cypress/integration/premium/maintainer.spec.ts
Expand Up @@ -201,32 +201,8 @@ describe("Premium tier - Maintainer user", () => {
});
describe("Manage software page", () => {
beforeEach(() => cy.visit("/software/manage"));
it("should restrict global maintainer from 'Manage automations' button", () => {
it("hides manages software automations when all teams selected", () => {
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.getAttached(".Select").within(() => {
cy.findByText(/all teams/i).should("exist");
});
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.findByRole("button", {
name: /manage automations/i,
}).should("not.exist");
});
});
});
it("hides manage automations button when all teams not selected", () => {
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.getAttached(".Select").within(() => {
cy.getAttached(".Select-control").click();
cy.getAttached(".Select-menu-outer").within(() => {
cy.findByText(/apples/i).should("exist");
});
cy.findByRole("button", {
name: /manage automations/i,
}).should("not.exist");
});
});
});
it("hides 'Manage automations' button from global maintainer", () => {
cy.findByText(/manage automations/i).should("not.exist");
});
});
describe("Query pages", () => {
Expand All @@ -250,11 +226,8 @@ describe("Premium tier - Maintainer user", () => {
});
describe("Manage policies page", () => {
beforeEach(() => cy.visit("/policies/manage"));
it("allows global maintainer to click 'Manage automations' button", () => {
cy.getAttached(".button-wrap")
.findByRole("button", { name: /manage automations/i })
.click();
cy.findByRole("button", { name: /cancel/i }).click();
it("hides manage automations button", () => {
cy.findByText(/manage hosts/i).should("not.exist");
});
it("allows global maintainer to add a new policy", () => {
cy.getAttached(".button-wrap")
Expand Down
13 changes: 2 additions & 11 deletions cypress/integration/premium/team_admin.spec.ts
Expand Up @@ -192,10 +192,7 @@ describe("Premium tier - Team Admin user", () => {
});
describe("Manage software page", () => {
beforeEach(() => cy.visit("/software/manage"));
it("hides manage automations button since all teams not selected", () => {
cy.getAttached(".manage-software-page__header-wrap").within(() => {
cy.findByText(/apples/i).should("exist");
});
it("hides manage automations button", () => {
cy.findByText(/manage automations/i).should("not.exist");
});
});
Expand Down Expand Up @@ -283,12 +280,6 @@ describe("Premium tier - Team Admin user", () => {
});
describe("Manage policies page", () => {
beforeEach(() => cy.visit("/policies/manage"));
it("hides manage automations button when all teams not selected", () => {
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
cy.findByText(/apples/i).should("exist");
});
cy.findByText(/manage automations/i).should("not.exist");
});
it("allows team admin to add a new policy", () => {
cy.getAttached(".button-wrap")
.findByRole("button", { name: /add a policy/i })
Expand Down Expand Up @@ -358,7 +349,7 @@ describe("Premium tier - Team Admin user", () => {
cy.findByText(/apples/i).should("exist");
});
it("displays the team admin controls", () => {
cy.findByRole("button", { name: /add member/i }).click();
cy.findByRole("button", { name: /create user/i }).click();
cy.findByRole("button", { name: /cancel/i }).click();
cy.findByRole("button", { name: /add hosts/i }).click();
cy.findByRole("button", { name: /done/i }).click();
Expand Down
4 changes: 2 additions & 2 deletions cypress/integration/premium/team_maintainer_observer.spec.ts
Expand Up @@ -276,8 +276,8 @@ describe("Premium tier - Team observer/maintainer user", () => {
cy.findByText(/apples/i).click();
cy.findByText(/oranges/i).click();

// On maintaining team, should see the "Manage automations" button
cy.findByText(/manage automations/i).should("exist");
// On maintaining team, should not see the "Manage automations" button
cy.findByText(/manage automations/i).should("not.exist");
// On maintaining team, should see "add a policy" and "save" a policy
cy.findByText(/add a policy/i).click();

Expand Down
12 changes: 10 additions & 2 deletions frontend/pages/Homepage/cards/Software/Software.tsx
@@ -1,7 +1,8 @@
import React, { useState } from "react";
import React, { useContext, useState } from "react";
import { useQuery } from "react-query";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";

import { AppContext } from "context/app";
import paths from "router/paths";
import configAPI from "services/entities/config";
import softwareAPI, { ISoftwareResponse } from "services/entities/software";
Expand Down Expand Up @@ -39,6 +40,10 @@ const Software = ({
const [pageIndex, setPageIndex] = useState<number>(0);
const [isSoftwareEnabled, setIsSoftwareEnabled] = useState<boolean>();

const { availableTeams, currentTeam, isOnGlobalTeam } = useContext(
AppContext
);

const { data: config } = useQuery(["config"], configAPI.loadAll, {
onSuccess: (data) => {
setIsSoftwareEnabled(data?.host_settings?.enable_software_inventory);
Expand Down Expand Up @@ -71,8 +76,11 @@ const Software = ({
teamId: currentTeamId,
}),
{
enabled:
isOnGlobalTeam ||
!!availableTeams?.find((t) => t.id === currentTeam?.id),
keepPreviousData: true,
staleTime: 30000, // TODO: Discuss a reasonable staleTime given that counts are only updated infrequently?
staleTime: 30000, // stale time can be adjusted if fresher data is desired based on software inventory interval
onSuccess: (data) => {
setShowSoftwareUI(true);
if (isSoftwareEnabled && data.software?.length !== 0) {
Expand Down
Expand Up @@ -51,9 +51,13 @@ const MembersPage = ({
const teamId = parseInt(team_id, 10);

const { renderFlash } = useContext(NotificationContext);
const { config, isGlobalAdmin, currentUser, isPremiumTier } = useContext(
AppContext
);
const {
config,
currentUser,
isGlobalAdmin,
isPremiumTier,
isTeamAdmin,
} = useContext(AppContext);

const smtpConfigured = config?.smtp_settings.configured || false;
const canUseSso = config?.sso_settings.enable_sso || false;
Expand Down Expand Up @@ -137,14 +141,7 @@ const MembersPage = ({
const toggleCreateMemberModal = useCallback(() => {
setShowCreateUserModal(!showCreateUserModal);
setShowAddMemberModal(false);
currentUser ? setUserEditing(currentUser) : setUserEditing(undefined);
}, [
showCreateUserModal,
currentUser,
setShowCreateUserModal,
setUserEditing,
setShowAddMemberModal,
]);
}, [showCreateUserModal, setShowCreateUserModal, setShowAddMemberModal]);

// FUNCTIONS

Expand All @@ -153,7 +150,10 @@ const MembersPage = ({
teamsAPI
.removeMembers(teamId, removedUsers)
.then(() => {
renderFlash("success", `Successfully removed ${userEditing?.name}`);
renderFlash(
"success",
`Successfully removed ${userEditing?.name || "member"}`
);
// If user removes self from team, redirect to home
if (currentUser && currentUser.id === removedUsers.users[0].id) {
window.location.href = "/";
Expand All @@ -178,12 +178,15 @@ const MembersPage = ({
(newMembers: INewMembersBody) => {
teamsAPI
.addMembers(teamId, newMembers)
.then(() =>
.then(() => {
const count = newMembers.users.length;
renderFlash(
"success",
`${newMembers.users.length} members successfully added to ${currentTeam?.name}.`
)
)
`${count} ${
count === 1 ? "member" : "members"
} successfully added to ${currentTeam?.name}.`
);
})
.catch(() =>
renderFlash("error", "Could not add members. Please try again.")
)
Expand Down Expand Up @@ -288,7 +291,10 @@ const MembersPage = ({
usersAPI
.update(userEditing.id, updatedAttrs)
.then(() => {
renderFlash("success", `Successfully edited ${userName}.`);
renderFlash(
"success",
`Successfully edited ${userName || "member"}.`
);

if (
currentUser &&
Expand Down Expand Up @@ -317,7 +323,7 @@ const MembersPage = ({
} else {
renderFlash(
"error",
`Could not edit ${userName}. Please try again.`
`Could not edit ${userName || "member"}. Please try again.`
);
}
});
Expand Down Expand Up @@ -349,13 +355,24 @@ const MembersPage = ({
Expecting to see new team members listed here? Try again in a
few seconds as the system catches up.
</p>
<Button
variant="brand"
className={`${noMembersClass}__create-button`}
onClick={toggleAddUserModal}
>
Add member
</Button>
{isGlobalAdmin && (
<Button
variant="brand"
className={`${noMembersClass}__create-button`}
onClick={toggleAddUserModal}
>
Add member
</Button>
)}
{isTeamAdmin && (
<Button
variant="brand"
className={`${noMembersClass}__create-button`}
onClick={toggleCreateMemberModal}
>
Create user
</Button>
)}
</>
) : (
<>
Expand Down Expand Up @@ -396,8 +413,10 @@ const MembersPage = ({
isLoading={isLoadingMembers}
defaultSortHeader={"name"}
defaultSortDirection={"asc"}
onActionButtonClick={toggleAddUserModal}
actionButtonText={"Add member"}
onActionButtonClick={
isGlobalAdmin ? toggleAddUserModal : toggleCreateMemberModal
}
actionButtonText={isGlobalAdmin ? "Add member" : "Create user"}
actionButtonVariant={"brand"}
hideActionButton={memberIds.length === 0 && searchString === ""}
onQueryChange={({ searchQuery }) => setSearchString(searchQuery)}
Expand All @@ -424,7 +443,7 @@ const MembersPage = ({
onSubmit={onEditMemberSubmit}
defaultName={userEditing?.name}
defaultEmail={userEditing?.email}
defaultGlobalRole={userEditing?.global_role}
defaultGlobalRole={userEditing?.global_role || null}
defaultTeamRole={userEditing?.role}
defaultTeams={userEditing?.teams}
availableTeams={teams || []}
Expand Down
Expand Up @@ -121,7 +121,7 @@ const UserForm = ({
});

const [isGlobalUser, setIsGlobalUser] = useState<boolean>(
defaultGlobalRole !== null
!!defaultGlobalRole
);

useEffect(() => {
Expand Down
Expand Up @@ -138,6 +138,7 @@ const ManagePolicyPage = ({

const canAddOrRemovePolicy =
isGlobalAdmin || isGlobalMaintainer || isTeamMaintainer || isTeamAdmin;
const canManageAutomations = isGlobalAdmin || isTeamAdmin;

const { isLoading: isLoadingWebhooks, refetch: refetchWebhooks } = useQuery<
IConfig | ILoadTeamResponse,
Expand Down Expand Up @@ -364,7 +365,7 @@ const ManagePolicyPage = ({
</div>
</div>
<div className={`${baseClass} button-wrap`}>
{canAddOrRemovePolicy &&
{canManageAutomations &&
!isLoadingWebhooks &&
!isLoadingGlobalPolicies && (
<Button
Expand Down

0 comments on commit da171d3

Please sign in to comment.