Skip to content

Commit

Permalink
[Enhancement #431] Link to auth service from user administration and …
Browse files Browse the repository at this point in the history
…user profile.
  • Loading branch information
ledsoft committed Nov 6, 2023
1 parent 3bed4c5 commit 0428777
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ REACT_APP_DEPLOYMENT_NAME=
REACT_APP_AUTHENTICATION=
REACT_APP_AUTH_SERVER_URL=
REACT_APP_AUTH_CLIENT_ID=
REACT_APP_AUTH_SERVER_MANAGEMENT=
REACT_APP_AUTH_SERVER_USER_PROFILE=
4 changes: 3 additions & 1 deletion public/config.js.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ window.__config__ = {
SHOW_PUBLIC_VIEW_ON_UNAUTHORIZED: '${SHOW_PUBLIC_VIEW_ON_UNAUTHORIZED}',
AUTHENTICATION: '${AUTHENTICATION}',
AUTH_SERVER_URL: '${AUTH_SERVER_URL}',
AUTH_CLIENT_ID: '${AUTH_CLIENT_ID}'
AUTH_CLIENT_ID: '${AUTH_CLIENT_ID}',
AUTH_SERVER_MANAGEMENT: '${AUTH_SERVER_MANAGEMENT}',
AUTH_SERVER_USER_PROFILE: '${AUTH_SERVER_USER_PROFILE}'
}
15 changes: 15 additions & 0 deletions src/component/administration/user/Users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import { useI18n } from "../../hook/useI18n";
import PromiseTrackingMask from "../../misc/PromiseTrackingMask";
import { trackPromise } from "react-promise-tracker";
import IfInternalAuth from "../../misc/oidc/IfInternalAuth";
import { isUsingOidcAuth } from "../../../util/OidcUtils";
import IfOidcAuth from "../../misc/oidc/IfOidcAuth";
import { getEnv } from "../../../util/Constants";
import ConfigParam from "../../../util/ConfigParam";
import OutgoingLink from "../../misc/OutgoingLink";

const Users: React.FC = () => {
const { i18n } = useI18n();
Expand Down Expand Up @@ -88,13 +93,23 @@ const Users: React.FC = () => {
onSubmit={onUserRoleSubmit}
onCancel={() => setEditedUser(EMPTY_USER)}
/>
<IfOidcAuth>
<p id="oidc-notice" className="italics">
<OutgoingLink
iri={getEnv(ConfigParam.AUTH_SERVER_MANAGEMENT_URL, "")}
label={i18n("administration.users.oidc")}
showLink={true}
/>
</p>
</IfOidcAuth>
<UsersTable
users={users}
currentUser={currentUser}
disable={onDisableUser}
enable={onEnableUser}
unlock={(user) => setUserToUnlock(user)}
changeRole={(user) => setEditedUser(user)}
readOnly={isUsingOidcAuth()}
/>
</PanelWithActions>
</>
Expand Down
27 changes: 15 additions & 12 deletions src/component/administration/user/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import classNames from "classnames";
interface UsersTableProps extends UserActions {
users: User[];
currentUser: User;
readOnly?: boolean;
}

const UsersTable: React.FC<UsersTableProps> = (props) => {
const { users, currentUser, disable, enable, unlock, changeRole } = props;
const { users, currentUser, disable, enable, unlock, changeRole, readOnly } =
props;
const { i18n } = useI18n();
const data = React.useMemo(() => users, [users]);
const columns: Column<User>[] = React.useMemo(
Expand Down Expand Up @@ -77,20 +79,21 @@ const UsersTable: React.FC<UsersTableProps> = (props) => {
disableFilters: true,
disableSortBy: true,
// @ts-ignore
Cell: ({ row }) => (
<UserActionsButtons
user={row.original}
currentUser={currentUser}
disable={disable}
enable={enable}
unlock={unlock}
changeRole={changeRole}
/>
),
Cell: ({ row }) =>
!readOnly && (
<UserActionsButtons
user={row.original}
currentUser={currentUser}
disable={disable}
enable={enable}
unlock={unlock}
changeRole={changeRole}
/>
),
className: "align-middle table-row-actions",
},
],
[i18n, disable, enable, unlock, changeRole, currentUser]
[i18n, disable, enable, unlock, changeRole, currentUser, readOnly]
);
const filterTypes = React.useMemo(() => ({ text: textContainsFilter }), []);
const tableInstance = useTable<User>(
Expand Down
18 changes: 18 additions & 0 deletions src/component/administration/user/__tests__/Users.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as UserActions from "../../../../action/AsyncUserActions";
import UsersTable from "../UsersTable";
import { mockUseI18n } from "../../../../__tests__/environment/IntlUtil";
import * as Redux from "react-redux";
import * as OidcUtils from "../../../../util/OidcUtils";
import * as Constats from "../../../../util/Constants";

jest.mock("react-redux", () => ({
...jest.requireActual("react-redux"),
Expand Down Expand Up @@ -61,6 +63,22 @@ describe("Users", () => {
});
});

it("renders users table read only when using OIDC authentication", () => {
jest.spyOn(OidcUtils, "isUsingOidcAuth").mockReturnValue(true);
jest.spyOn(UserActions, "loadUsers");
const wrapper = render();
expect(wrapper.find(UsersTable).prop("readOnly")).toBeTruthy();
});

it("renders link to auth service administration when using OIDC authentication", () => {
const link = "http://localhost/services/auth";
jest.spyOn(Constats, "getEnv").mockReturnValue(link);
jest.spyOn(OidcUtils, "isUsingOidcAuth").mockReturnValue(true);
jest.spyOn(UserActions, "loadUsers");
const wrapper = render();
expect(wrapper.exists("#oidc-notice")).toBeTruthy();
});

describe("user unlocking", () => {
it("opens unlock user dialog and passes selected user to it on unlock click", () => {
const wrapper = render();
Expand Down
5 changes: 1 addition & 4 deletions src/component/misc/oidc/IfInternalAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import React from "react";
import { isUsingOidcAuth } from "../../../util/OidcUtils";

const IfInternalAuth: React.FC = ({ children }) => {
if (isUsingOidcAuth()) {
return null;
}
return <>{children}</>;
return isUsingOidcAuth() ? null : <>{children}</>;
};

export default IfInternalAuth;
8 changes: 8 additions & 0 deletions src/component/misc/oidc/IfOidcAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import { isUsingOidcAuth } from "../../../util/OidcUtils";

const IfOidcAuth: React.FC = ({ children }) => {
return isUsingOidcAuth() ? <>{children}</> : null;
};

export default IfOidcAuth;
13 changes: 13 additions & 0 deletions src/component/profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import { Card, CardBody } from "reactstrap";
import WindowTitle from "../misc/WindowTitle";
import UserRoles from "../administration/user/UserRoles";
import IfInternalAuth from "../misc/oidc/IfInternalAuth";
import { getEnv } from "../../util/Constants";
import ConfigParam from "../../util/ConfigParam";
import IfOidcAuth from "../misc/oidc/IfOidcAuth";
import OutgoingLink from "../misc/OutgoingLink";

interface ProfileProps extends HasI18n {
user: User;
Expand Down Expand Up @@ -108,6 +112,15 @@ export class Profile extends React.Component<ProfileProps, ProfileState> {
/>
<Card id="panel-profile">
<CardBody>
<IfOidcAuth>
<p id="oidc-notice" className="italics">
<OutgoingLink
iri={getEnv(ConfigParam.AUTH_SERVER_USER_PROFILE_URL, "")}
label={i18n("administration.users.oidc")}
showLink={true}
/>
</p>
</IfOidcAuth>
{!this.state.edit ? (
<ProfileView user={user} />
) : (
Expand Down
20 changes: 20 additions & 0 deletions src/component/profile/__tests__/Profile.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import Generator from "../../../__tests__/environment/Generator";
import { intlFunctions } from "../../../__tests__/environment/IntlUtil";
import ProfileEditForm from "../ProfileEditForm";
import HeaderWithActions from "../../misc/HeaderWithActions";
import * as OidcUtils from "../../../util/OidcUtils";
import * as Constats from "../../../util/Constants";

describe("Profile", () => {
let updateProfile: (user: User) => Promise<AsyncAction>;
Expand Down Expand Up @@ -47,4 +49,22 @@ describe("Profile", () => {
expect(actionButtons.length).toEqual(1);
expect(wrapper.find(ProfileEditForm).length).toEqual(1);
});

it("does not render edit buttons when using OIDC authentication", () => {
jest.spyOn(OidcUtils, "isUsingOidcAuth").mockReturnValue(true);
const wrapper = mountWithIntl(
<Profile updateProfile={updateProfile} user={user} {...intlFunctions()} />
);
expect(wrapper.exists(ProfileActionButtons)).toBeFalsy();
});

it("renders link to user profile in auth service when using OIDC authentication", () => {
const link = "http://localhost/services/auth/profile";
jest.spyOn(Constats, "getEnv").mockReturnValue(link);
jest.spyOn(OidcUtils, "isUsingOidcAuth").mockReturnValue(true);
const wrapper = mountWithIntl(
<Profile updateProfile={updateProfile} user={user} {...intlFunctions()} />
);
expect(wrapper.exists("#oidc-notice")).toBeTruthy();
});
});
2 changes: 2 additions & 0 deletions src/i18n/cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ const cs = {
'Uživatel "{name}" úspěšně vytvořen.',
"administration.users.you": "Toto je Váš účet",
"administration.users.types.admin": "Tento uživatel je administrátor",
"administration.users.oidc":
"Pro správu uživatelů je využívána externí autentizační služba.",
"administration.maintenance.title": "Správa systému",
"administration.maintenance.invalidateCaches": "Vyprázdnit cache",
"administration.maintenance.invalidateCaches.tooltip":
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ const en = {
'User "{name}" successfully created.',
"administration.users.you": "This is you",
"administration.users.types.admin": "This user is an administrator",
"administration.users.oidc":
"An external authentication service is used to management users.",
"administration.maintenance.title": "Maintenance",
"administration.maintenance.invalidateCaches": "Invalidate caches",
"administration.maintenance.invalidateCaches.tooltip":
Expand Down
2 changes: 2 additions & 0 deletions src/util/ConfigParam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const ConfigParam = {
SHOW_PUBLIC_VIEW_ON_UNAUTHORIZED: "SHOW_PUBLIC_VIEW_ON_UNAUTHORIZED",
MOCK_REST_API: "MOCK_REST_API",
AUTH_TYPE: "AUTHENTICATION",
AUTH_SERVER_MANAGEMENT_URL: "AUTH_SERVER_MANAGEMENT",
AUTH_SERVER_USER_PROFILE_URL: "AUTH_SERVER_USER_PROFILE",
};

export default ConfigParam;

0 comments on commit 0428777

Please sign in to comment.