From 7adf105ad920a12d8b0cc762ffe64d82c4ccb23b Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 27 Sep 2023 15:57:19 -0400 Subject: [PATCH 01/20] feat(jvmid): restyle warning when JVM ID cannot be computed --- src/app/Topology/Shared/utils.tsx | 117 +++++++++++++++++++++++++----- 1 file changed, 100 insertions(+), 17 deletions(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 77e823f31..909d496da 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -17,11 +17,18 @@ import { TopologyFilters } from '@app/Shared/Redux/Filters/TopologyFilterSlice'; import { NodeType, EnvironmentNode, TargetNode } from '@app/Shared/Services/api.types'; import { DEFAULT_EMPTY_UNIVERSE, isTargetNode } from '@app/Shared/Services/api.utils'; -import { Button, Text, TextVariants } from '@patternfly/react-core'; -import { GraphElement, NodeStatus } from '@patternfly/react-topology'; +import { Button, Text, TextVariants , + DescriptionListTermHelpText, + DescriptionListTermHelpTextButton, + Popover, + TextContent, + TextList, + TextListItem, +} from '@patternfly/react-core'; +import { NodeStatus } from '@patternfly/react-topology'; import * as React from 'react'; import { WarningResolverAsCredModal, WarningResolverAsLink } from '../Actions/WarningResolver'; -import { ListElement, StatusExtra } from './types'; +import { GraphElement, ListElement, StatusExtra } from './types'; export const TOPOLOGY_GRAPH_ID = 'cryostat-target-topology-graph'; @@ -34,6 +41,66 @@ export const nodeTypeToAbbr = (type: NodeType): string => { return (type.replace(/[^A-Z]/g, '') || type.toUpperCase()).slice(0, 4); }; +const JmxAuthDescription: React.FC<{}> = () => { + return ( + + + JVM applications may be configured to require clients (such as Cryostat) to pass an authentication challenge + before establishing a connection. + + + Check your JVM application's deployment configuration for system properties such as: + + + + com.sun.management.jmxremote.authenticate + + + com.sun.management.jmxremote.password.file + + + com.sun.management.jmxremote.login.config + + + + ); +}; + +const JmxSslDescription: React.FC<{}> = () => { + return ( + + + JVM applications may be configured to present an SSL certificate for incoing JMX connections. Clients (such as + Cryostat) should be configured to trust these certificates so that the origin and authenticity of the connection + data can be verified. + + + Check your JVM application's deployment configuration for system properties such as: + + + + javax.net.ssl.keyStore + + + javax.net.ssl.keyStorePassword + + + com.sun.management.jmxremote.ssl.need.client.auth + + + javax.net.ssl.trustStore + + + javax.net.ssl.trustStorePassword + + + com.sun.management.jmxremote.registry.ssl + + + + ); +}; + export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeStatus?, StatusExtra?] => { if (isTargetNode(node)) { return node.target.jvmId @@ -44,23 +111,39 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt title: 'Failed to compute JVM ID', description: ( <> - - If target has JMX Authentication enabled, add the credential to Cryostat keyring. - - - If the target has SSL enabled over JMX, add its certificate to Cryostat truststore. - + + ), callForAction: [ - - - , - - Add certificates - , + + If the target has{' '} + + }> + JMX Authentication + + {' '} + enabled,{' '} + + + . + + , + + If the target has{' '} + + }> + JMX over SSL + + {' '} + enabled,{' '} + + add its certificate + + . + , ], }, ]; From bdffc7d99c32626663737d2011c4c16d5b3b192e Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 27 Sep 2023 15:57:56 -0400 Subject: [PATCH 02/20] compute -> generate --- src/app/Topology/Entity/EntityDetails.tsx | 4 ++-- src/app/Topology/Shared/utils.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/Topology/Entity/EntityDetails.tsx b/src/app/Topology/Entity/EntityDetails.tsx index fb84f404e..df8cb89bb 100644 --- a/src/app/Topology/Entity/EntityDetails.tsx +++ b/src/app/Topology/Entity/EntityDetails.tsx @@ -191,7 +191,7 @@ export const TargetDetails: React.FC<{ <> JVM ID {!serviceRef.jvmId && ( - + )} @@ -201,7 +201,7 @@ export const TargetDetails: React.FC<{ <> JVM ID {!serviceRef.jvmId && ( - + )} diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 909d496da..c7e8da428 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -108,7 +108,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt : [ NodeStatus.warning, { - title: 'Failed to compute JVM ID', + title: 'Failed to generate JVM ID', description: ( <> From 1fafa3990adf5e67d13fd1cf8295208ca0bc706c Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 27 Sep 2023 16:10:55 -0400 Subject: [PATCH 03/20] add helper text hover popovers on Security view cards --- .../Credentials/StoreCredentials.tsx | 17 +++++++++++++++-- src/app/SecurityPanel/ImportCertificate.tsx | 19 ++++++++++++++++--- src/app/SecurityPanel/SecurityPanel.tsx | 3 ++- src/app/SecurityPanel/types.ts | 3 ++- src/app/Topology/Shared/utils.tsx | 4 ++-- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx index 8d360978c..fcd6b6410 100644 --- a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx @@ -31,13 +31,15 @@ import { DropdownToggleCheckbox, EmptyState, EmptyStateIcon, + Icon, Text, Title, Toolbar, ToolbarContent, ToolbarItem, + Tooltip, } from '@patternfly/react-core'; -import { SearchIcon } from '@patternfly/react-icons'; +import { OutlinedQuestionCircleIcon, SearchIcon } from '@patternfly/react-icons'; import { ExpandableRowContent, TableComposable, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; import * as React from 'react'; import { Link } from 'react-router-dom'; @@ -45,6 +47,7 @@ import { forkJoin } from 'rxjs'; import { SecurityCard } from '../types'; import { CreateCredentialModal } from './CreateCredentialModal'; import { MatchedTargetsTable } from './MatchedTargetsTable'; +import { JmxAuthDescription } from '@app/Topology/Shared/utils'; export const includesCredential = (credentials: StoredCredential[], credential: StoredCredential): boolean => { return credentials.some((cred) => cred.id === credential.id); @@ -516,7 +519,17 @@ export const CheckBoxActions: React.FC = ({ }; export const StoreCredentialsCard: SecurityCard = { - title: 'Store Credentials', + key: 'credentials', + title: ( + + Store Credentials{' '} + }> + + + + + + ), description: ( Credentials that Cryostat uses to connect to Cryostat agents or target JVMs over JMX are stored here. These are diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index f608a40fa..084bb7a1d 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -14,10 +14,12 @@ * limitations under the License. */ -import { Button } from '@patternfly/react-core'; +import { Button, Icon, Text, Tooltip } from '@patternfly/react-core'; import * as React from 'react'; import { CertificateUploadModal } from './CertificateUploadModal'; import { SecurityCard } from './types'; +import { JmxSslDescription } from '@app/Topology/Shared/utils'; +import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; export const CertificateImport: React.FC = () => { const [showModal, setShowModal] = React.useState(false); @@ -37,7 +39,18 @@ export const CertificateImport: React.FC = () => { }; export const ImportCertificate: SecurityCard = { - title: 'Import SSL Certificates', - description: 'The Cryostat server must be restarted in order to reload the certificate store.', + key: 'ssl', + title: ( + + Import SSL Certificates{' '} + }> + + + + + + ), + description: + 'Add SSL certificates to the Cryostat server truststore. The Cryostat server must be restarted in order to reload the certificate store.', content: CertificateImport, }; diff --git a/src/app/SecurityPanel/SecurityPanel.tsx b/src/app/SecurityPanel/SecurityPanel.tsx index 877979960..a8766a7c3 100644 --- a/src/app/SecurityPanel/SecurityPanel.tsx +++ b/src/app/SecurityPanel/SecurityPanel.tsx @@ -23,6 +23,7 @@ export interface SecurityPanelProps {} export const SecurityPanel: React.FC = (_) => { const securityCards = [ImportCertificate, StoreCredentialsCard].map((c) => ({ + key: c.key, title: c.title, description: c.description, element: React.createElement(c.content, null), @@ -31,7 +32,7 @@ export const SecurityPanel: React.FC = (_) => { return ( {securityCards.map((s) => ( - + {s.title} {s.description} diff --git a/src/app/SecurityPanel/types.ts b/src/app/SecurityPanel/types.ts index 2a83da277..53c03bb10 100644 --- a/src/app/SecurityPanel/types.ts +++ b/src/app/SecurityPanel/types.ts @@ -15,7 +15,8 @@ */ export interface SecurityCard { - title: string; + key: string; + title: JSX.Element | string; description: JSX.Element | string; content: React.FC; } diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index c7e8da428..0a0bdc614 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -41,7 +41,7 @@ export const nodeTypeToAbbr = (type: NodeType): string => { return (type.replace(/[^A-Z]/g, '') || type.toUpperCase()).slice(0, 4); }; -const JmxAuthDescription: React.FC<{}> = () => { +export const JmxAuthDescription: React.FC<{}> = () => { return ( @@ -66,7 +66,7 @@ const JmxAuthDescription: React.FC<{}> = () => { ); }; -const JmxSslDescription: React.FC<{}> = () => { +export const JmxSslDescription: React.FC<{}> = () => { return ( From a7b85fe302f9c6ee18dfa0573b625cc752fd8132 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 27 Sep 2023 16:13:35 -0400 Subject: [PATCH 04/20] typo --- src/app/Topology/Shared/utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 0a0bdc614..cac0d7d93 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -70,7 +70,7 @@ export const JmxSslDescription: React.FC<{}> = () => { return ( - JVM applications may be configured to present an SSL certificate for incoing JMX connections. Clients (such as + JVM applications may be configured to present an SSL certificate for incoming JMX connections. Clients (such as Cryostat) should be configured to trust these certificates so that the origin and authenticity of the connection data can be verified. From 7df574609b4e079a409ecdc9fc8a18e1dfe87ec2 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 29 Sep 2023 11:50:11 -0400 Subject: [PATCH 05/20] rephrasing --- src/app/Topology/Shared/utils.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index cac0d7d93..14302e5bd 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -111,8 +111,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt title: 'Failed to generate JVM ID', description: ( <> - - + Check the target authentication settings: ), callForAction: [ @@ -140,7 +139,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt {' '} enabled,{' '} - add its certificate + add the SSL certificate . , From 70fd94ae0ef798e868e3761d528c220bd7cf1cdb Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 29 Sep 2023 11:50:23 -0400 Subject: [PATCH 06/20] add tooltip titles in Security view --- .../SecurityPanel/Credentials/StoreCredentials.tsx | 11 ++++++++++- src/app/SecurityPanel/ImportCertificate.tsx | 12 ++++++++++-- src/app/Topology/Shared/utils.tsx | 10 ++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx index fcd6b6410..587f3570f 100644 --- a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx @@ -33,6 +33,7 @@ import { EmptyStateIcon, Icon, Text, + TextVariants, Title, Toolbar, ToolbarContent, @@ -523,7 +524,15 @@ export const StoreCredentialsCard: SecurityCard = { title: ( Store Credentials{' '} - }> + + JMX Authentication + + } + > diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index 084bb7a1d..2d5cafb94 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Button, Icon, Text, Tooltip } from '@patternfly/react-core'; +import { Button, Icon, Text, TextVariants, Tooltip } from '@patternfly/react-core'; import * as React from 'react'; import { CertificateUploadModal } from './CertificateUploadModal'; import { SecurityCard } from './types'; @@ -43,7 +43,15 @@ export const ImportCertificate: SecurityCard = { title: ( Import SSL Certificates{' '} - }> + + JMX over SSL + + } + > diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 14302e5bd..75035410b 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -41,9 +41,14 @@ export const nodeTypeToAbbr = (type: NodeType): string => { return (type.replace(/[^A-Z]/g, '') || type.toUpperCase()).slice(0, 4); }; -export const JmxAuthDescription: React.FC<{}> = () => { +export type DescriptionProps = { + children?: React.ReactNode; +}; + +export const JmxAuthDescription: React.FC> = ({ children }) => { return ( + {children} JVM applications may be configured to require clients (such as Cryostat) to pass an authentication challenge before establishing a connection. @@ -66,9 +71,10 @@ export const JmxAuthDescription: React.FC<{}> = () => { ); }; -export const JmxSslDescription: React.FC<{}> = () => { +export const JmxSslDescription: React.FC> = ({ children }) => { return ( + {children} JVM applications may be configured to present an SSL certificate for incoming JMX connections. Clients (such as Cryostat) should be configured to trust these certificates so that the origin and authenticity of the connection From 65274199e72fa89fef3558cb51ffc1caef7a3c5e Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 29 Sep 2023 11:52:38 -0400 Subject: [PATCH 07/20] reword --- src/app/Topology/Shared/utils.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 75035410b..4969a32ea 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -50,11 +50,11 @@ export const JmxAuthDescription: React.FC {children} - JVM applications may be configured to require clients (such as Cryostat) to pass an authentication challenge - before establishing a connection. + JVM applications may be configured to require clients, such as Cryostat, to pass a challenge based + authentication before establishing a connection. - Check your JVM application's deployment configuration for system properties such as: + Check the deployment configuration of your JVM application for system properties such as: @@ -76,12 +76,12 @@ export const JmxSslDescription: React.FC {children} - JVM applications may be configured to present an SSL certificate for incoming JMX connections. Clients (such as - Cryostat) should be configured to trust these certificates so that the origin and authenticity of the connection + JVM applications can be configured to present an SSL certificate for incoming JMX connections. Clients, such as + Cryostat, should be configured to trust these certificates so that the origin and authenticity of the connection data can be verified. - Check your JVM application's deployment configuration for system properties such as: + Check the deployment configuration of your JVM application for system properties such as: From 91fbe307be0e1b4876ec3d212c30cc91087c3ac7 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 29 Sep 2023 15:25:19 -0400 Subject: [PATCH 08/20] refactor cleanup --- .../Credentials/StoreCredentials.tsx | 2 +- src/app/SecurityPanel/ImportCertificate.tsx | 4 +- .../Shared/Components/JmxAuthDescription.tsx | 29 +++++++ .../Shared/Components/JmxSslDescription.tsx | 39 +++++++++ src/app/Shared/Components/types.ts | 4 + src/app/Topology/Shared/utils.tsx | 80 ++----------------- 6 files changed, 83 insertions(+), 75 deletions(-) create mode 100644 src/app/Shared/Components/JmxAuthDescription.tsx create mode 100644 src/app/Shared/Components/JmxSslDescription.tsx diff --git a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx index 587f3570f..3eaca9a08 100644 --- a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx @@ -15,6 +15,7 @@ */ import { DeleteWarningModal } from '@app/Modal/DeleteWarningModal'; import { DeleteOrDisableWarningType } from '@app/Modal/types'; +import { JmxAuthDescription } from '@app/Shared/Components/JmxAuthDescription'; import { LoadingView } from '@app/Shared/Components/LoadingView'; import { StoredCredential, NotificationCategory } from '@app/Shared/Services/api.types'; import { ServiceContext } from '@app/Shared/Services/Services'; @@ -48,7 +49,6 @@ import { forkJoin } from 'rxjs'; import { SecurityCard } from '../types'; import { CreateCredentialModal } from './CreateCredentialModal'; import { MatchedTargetsTable } from './MatchedTargetsTable'; -import { JmxAuthDescription } from '@app/Topology/Shared/utils'; export const includesCredential = (credentials: StoredCredential[], credential: StoredCredential): boolean => { return credentials.some((cred) => cred.id === credential.id); diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index 2d5cafb94..c1cebcac8 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ +import { JmxSslDescription } from '@app/Shared/Components/JmxSslDescription'; import { Button, Icon, Text, TextVariants, Tooltip } from '@patternfly/react-core'; +import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import * as React from 'react'; import { CertificateUploadModal } from './CertificateUploadModal'; import { SecurityCard } from './types'; -import { JmxSslDescription } from '@app/Topology/Shared/utils'; -import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; export const CertificateImport: React.FC = () => { const [showModal, setShowModal] = React.useState(false); diff --git a/src/app/Shared/Components/JmxAuthDescription.tsx b/src/app/Shared/Components/JmxAuthDescription.tsx new file mode 100644 index 000000000..2ab475af9 --- /dev/null +++ b/src/app/Shared/Components/JmxAuthDescription.tsx @@ -0,0 +1,29 @@ +import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; +import * as React from 'react'; +import { DescriptionProps } from './types'; + +export const JmxAuthDescription: React.FC> = ({ children }) => { + return ( + + {children} + + JVM applications may be configured to require clients, such as Cryostat, to pass a challenge based + authentication before establishing a connection. + + + Check the deployment configuration of your JVM application for system properties such as: + + + + com.sun.management.jmxremote.authenticate + + + com.sun.management.jmxremote.password.file + + + com.sun.management.jmxremote.login.config + + + + ); +}; diff --git a/src/app/Shared/Components/JmxSslDescription.tsx b/src/app/Shared/Components/JmxSslDescription.tsx new file mode 100644 index 000000000..571f8a2ac --- /dev/null +++ b/src/app/Shared/Components/JmxSslDescription.tsx @@ -0,0 +1,39 @@ +import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; +import * as React from 'react'; +import { DescriptionProps } from './types'; + +export const JmxSslDescription: React.FC> = ({ children }) => { + return ( + + {children} + + JVM applications can be configured to present an SSL certificate for incoming JMX connections. Clients, such as + Cryostat, should be configured to trust these certificates so that the origin and authenticity of the connection + data can be verified. + + + Check the deployment configuration of your JVM application for system properties such as: + + + + javax.net.ssl.keyStore + + + javax.net.ssl.keyStorePassword + + + com.sun.management.jmxremote.ssl.need.client.auth + + + javax.net.ssl.trustStore + + + javax.net.ssl.trustStorePassword + + + com.sun.management.jmxremote.registry.ssl + + + + ); +}; diff --git a/src/app/Shared/Components/types.ts b/src/app/Shared/Components/types.ts index 98052db17..149e9df74 100644 --- a/src/app/Shared/Components/types.ts +++ b/src/app/Shared/Components/types.ts @@ -20,3 +20,7 @@ export interface LoadingProps { spinnerAriaLabel?: string; // Accessible label for the spinner to describe what is loading isLoading: boolean; } + +export type DescriptionProps = { + children?: React.ReactNode; +}; diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 4969a32ea..4fee3bbd6 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -14,16 +14,18 @@ * limitations under the License. */ +import { JmxAuthDescription } from '@app/Shared/Components/JmxAuthDescription'; +import { JmxSslDescription } from '@app/Shared/Components/JmxSslDescription'; import { TopologyFilters } from '@app/Shared/Redux/Filters/TopologyFilterSlice'; import { NodeType, EnvironmentNode, TargetNode } from '@app/Shared/Services/api.types'; import { DEFAULT_EMPTY_UNIVERSE, isTargetNode } from '@app/Shared/Services/api.utils'; -import { Button, Text, TextVariants , +import { + Button, + Text, + TextVariants, DescriptionListTermHelpText, DescriptionListTermHelpTextButton, Popover, - TextContent, - TextList, - TextListItem, } from '@patternfly/react-core'; import { NodeStatus } from '@patternfly/react-topology'; import * as React from 'react'; @@ -41,72 +43,6 @@ export const nodeTypeToAbbr = (type: NodeType): string => { return (type.replace(/[^A-Z]/g, '') || type.toUpperCase()).slice(0, 4); }; -export type DescriptionProps = { - children?: React.ReactNode; -}; - -export const JmxAuthDescription: React.FC> = ({ children }) => { - return ( - - {children} - - JVM applications may be configured to require clients, such as Cryostat, to pass a challenge based - authentication before establishing a connection. - - - Check the deployment configuration of your JVM application for system properties such as: - - - - com.sun.management.jmxremote.authenticate - - - com.sun.management.jmxremote.password.file - - - com.sun.management.jmxremote.login.config - - - - ); -}; - -export const JmxSslDescription: React.FC> = ({ children }) => { - return ( - - {children} - - JVM applications can be configured to present an SSL certificate for incoming JMX connections. Clients, such as - Cryostat, should be configured to trust these certificates so that the origin and authenticity of the connection - data can be verified. - - - Check the deployment configuration of your JVM application for system properties such as: - - - - javax.net.ssl.keyStore - - - javax.net.ssl.keyStorePassword - - - com.sun.management.jmxremote.ssl.need.client.auth - - - javax.net.ssl.trustStore - - - javax.net.ssl.trustStorePassword - - - com.sun.management.jmxremote.registry.ssl - - - - ); -}; - export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeStatus?, StatusExtra?] => { if (isTargetNode(node)) { return node.target.jvmId @@ -121,7 +57,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt ), callForAction: [ - + If the target has{' '} }> @@ -136,7 +72,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt . , - + If the target has{' '} }> From 96f0c9b8d38d6b71ec821ef149aef79833f2ab25 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 29 Sep 2023 15:36:24 -0400 Subject: [PATCH 09/20] add license headers --- src/app/Shared/Components/JmxAuthDescription.tsx | 15 +++++++++++++++ src/app/Shared/Components/JmxSslDescription.tsx | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/app/Shared/Components/JmxAuthDescription.tsx b/src/app/Shared/Components/JmxAuthDescription.tsx index 2ab475af9..99bd8d1c6 100644 --- a/src/app/Shared/Components/JmxAuthDescription.tsx +++ b/src/app/Shared/Components/JmxAuthDescription.tsx @@ -1,3 +1,18 @@ +/* + * Copyright The Cryostat Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; import * as React from 'react'; import { DescriptionProps } from './types'; diff --git a/src/app/Shared/Components/JmxSslDescription.tsx b/src/app/Shared/Components/JmxSslDescription.tsx index 571f8a2ac..8fb138ae9 100644 --- a/src/app/Shared/Components/JmxSslDescription.tsx +++ b/src/app/Shared/Components/JmxSslDescription.tsx @@ -1,3 +1,18 @@ +/* + * Copyright The Cryostat Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; import * as React from 'react'; import { DescriptionProps } from './types'; From d7b823bd0377d3e7d7e7c7b54cd37f5c6e94ab39 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 5 Oct 2023 11:49:28 -0400 Subject: [PATCH 10/20] restyle text, add line break --- .../Credentials/StoreCredentials.tsx | 17 ++++++++++------- src/app/SecurityPanel/ImportCertificate.tsx | 12 +++++++++--- src/app/SecurityPanel/SecurityPanel.tsx | 2 +- src/app/SecurityPanel/types.ts | 4 ++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx index 3eaca9a08..198b25933 100644 --- a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx @@ -34,6 +34,7 @@ import { EmptyStateIcon, Icon, Text, + TextContent, TextVariants, Title, Toolbar, @@ -540,13 +541,15 @@ export const StoreCredentialsCard: SecurityCard = { ), description: ( - - Credentials that Cryostat uses to connect to Cryostat agents or target JVMs over JMX are stored here. These are - stored in encrypted storage managed by the Cryostat backend. These credentials may be used for manually managing - recordings and event templates on target JVMs, as well as for Automated Rules which run in the background and open - unattended target connections. Any locally-stored client credentials held by your browser session are not - displayed here. See Settings to configure locally-stored credentials. - + + + Credentials that Cryostat uses to connect to Cryostat agents or target JVMs over JMX are stored here. These are + stored in encrypted storage managed by the Cryostat backend. These credentials may be used for manually managing + recordings and event templates on target JVMs, as well as for Automated Rules which run in the background and + open unattended target connections. Any locally-stored client credentials held by your browser session are not + displayed here. See Settings to configure locally-stored credentials. + + ), content: StoreCredentials, }; diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index c1cebcac8..ee7cf3242 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -15,7 +15,7 @@ */ import { JmxSslDescription } from '@app/Shared/Components/JmxSslDescription'; -import { Button, Icon, Text, TextVariants, Tooltip } from '@patternfly/react-core'; +import { Button, Icon, Text, TextContent, TextVariants, Tooltip } from '@patternfly/react-core'; import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import * as React from 'react'; import { CertificateUploadModal } from './CertificateUploadModal'; @@ -58,7 +58,13 @@ export const ImportCertificate: SecurityCard = { ), - description: - 'Add SSL certificates to the Cryostat server truststore. The Cryostat server must be restarted in order to reload the certificate store.', + description: ( + + Add SSL certificates to the Cryostat server truststore. + + The Cryostat server must be restarted in order to reload the certificate store. + + + ), content: CertificateImport, }; diff --git a/src/app/SecurityPanel/SecurityPanel.tsx b/src/app/SecurityPanel/SecurityPanel.tsx index a8766a7c3..80644ce30 100644 --- a/src/app/SecurityPanel/SecurityPanel.tsx +++ b/src/app/SecurityPanel/SecurityPanel.tsx @@ -35,7 +35,7 @@ export const SecurityPanel: React.FC = (_) => { {s.title} - {s.description} + {s.description} {s.element} diff --git a/src/app/SecurityPanel/types.ts b/src/app/SecurityPanel/types.ts index 53c03bb10..195ab40ec 100644 --- a/src/app/SecurityPanel/types.ts +++ b/src/app/SecurityPanel/types.ts @@ -16,7 +16,7 @@ export interface SecurityCard { key: string; - title: JSX.Element | string; - description: JSX.Element | string; + title: JSX.Element; + description: JSX.Element; content: React.FC; } From 882a3218b91cb2fdb36bece83c963055f5cef838 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 5 Oct 2023 11:50:33 -0400 Subject: [PATCH 11/20] rephrase --- src/app/Topology/Entity/EntityDetails.tsx | 4 ++-- src/app/Topology/Shared/utils.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/Topology/Entity/EntityDetails.tsx b/src/app/Topology/Entity/EntityDetails.tsx index df8cb89bb..eaf4aff3a 100644 --- a/src/app/Topology/Entity/EntityDetails.tsx +++ b/src/app/Topology/Entity/EntityDetails.tsx @@ -191,7 +191,7 @@ export const TargetDetails: React.FC<{ <> JVM ID {!serviceRef.jvmId && ( - + )} @@ -201,7 +201,7 @@ export const TargetDetails: React.FC<{ <> JVM ID {!serviceRef.jvmId && ( - + )} diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index 4fee3bbd6..b4a7c5c8c 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -50,7 +50,7 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt : [ NodeStatus.warning, { - title: 'Failed to generate JVM ID', + title: 'Failed to generate the JVM identifier', description: ( <> Check the target authentication settings: From 3db652a39731f44a306490d4a3d9e5cfb49fbc5f Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 5 Oct 2023 11:52:40 -0400 Subject: [PATCH 12/20] rephrase --- src/app/Topology/Shared/utils.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index b4a7c5c8c..a2acdaa0c 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -58,13 +58,13 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt ), callForAction: [ - If the target has{' '} + If{' '} }> JMX Authentication {' '} - enabled,{' '} + is enabled,{' '} + + ); +}; + export const StoreCredentialsCard: SecurityCard = { key: 'credentials', title: ( - Store Credentials{' '} - - JMX Authentication - - } - > - - - - + Store Credentials ), description: ( diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index e47abf29c..6c9cbc9f2 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -38,24 +38,35 @@ export const CertificateImport: React.FC = () => { ); }; +const CertificateTooltip: React.FC<{}> = () => { + const [visible, setVisible] = React.useState(false); + + return ( + + JMX over SSL + + } + > + + + ); +}; + export const ImportCertificate: SecurityCard = { key: 'ssl', title: ( - Import SSL Certificates{' '} - - JMX over SSL - - } - > - - - - + Import SSL Certificates ), description: ( From e07c58944416f5da45b20a7fbbad3e9d959db2ab Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 12 Oct 2023 11:05:20 -0400 Subject: [PATCH 18/20] replace tooltips with popovers --- .../Credentials/StoreCredentials.tsx | 32 ++++-------------- src/app/SecurityPanel/ImportCertificate.tsx | 33 ++++--------------- 2 files changed, 14 insertions(+), 51 deletions(-) diff --git a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx index ade583f1b..395b88d7e 100644 --- a/src/app/SecurityPanel/Credentials/StoreCredentials.tsx +++ b/src/app/SecurityPanel/Credentials/StoreCredentials.tsx @@ -33,6 +33,7 @@ import { EmptyState, EmptyStateIcon, Icon, + Popover, Text, TextContent, TextVariants, @@ -520,35 +521,16 @@ export const CheckBoxActions: React.FC = ({ ); }; -const CredentialsTooltip: React.FC<{}> = () => { - const [visible, setVisible] = React.useState(false); - - return ( - - JMX Authentication - - } - > - - - ); -}; - export const StoreCredentialsCard: SecurityCard = { key: 'credentials', title: ( - Store Credentials + Store Credentials + }> + + ), description: ( diff --git a/src/app/SecurityPanel/ImportCertificate.tsx b/src/app/SecurityPanel/ImportCertificate.tsx index 6c9cbc9f2..9dfa6b996 100644 --- a/src/app/SecurityPanel/ImportCertificate.tsx +++ b/src/app/SecurityPanel/ImportCertificate.tsx @@ -15,7 +15,7 @@ */ import { JmxSslDescription } from '@app/Shared/Components/JmxSslDescription'; -import { Button, Icon, Text, TextContent, TextVariants, Tooltip } from '@patternfly/react-core'; +import { Button, Icon, Popover, Text, TextContent, TextVariants, Tooltip } from '@patternfly/react-core'; import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; import * as React from 'react'; import { CertificateUploadModal } from './CertificateUploadModal'; @@ -38,35 +38,16 @@ export const CertificateImport: React.FC = () => { ); }; -const CertificateTooltip: React.FC<{}> = () => { - const [visible, setVisible] = React.useState(false); - - return ( - - JMX over SSL - - } - > - - - ); -}; - export const ImportCertificate: SecurityCard = { key: 'ssl', title: ( - Import SSL Certificates + Import SSL Certificates + }> + + ), description: ( From 4642e617f4b57432ef8f6b2ac0712cb454b3976f Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 12 Oct 2023 11:10:35 -0400 Subject: [PATCH 19/20] reword --- src/app/Topology/Shared/utils.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/Topology/Shared/utils.tsx b/src/app/Topology/Shared/utils.tsx index a2acdaa0c..fa5699cc1 100644 --- a/src/app/Topology/Shared/utils.tsx +++ b/src/app/Topology/Shared/utils.tsx @@ -76,10 +76,10 @@ export const getStatusTargetNode = (node: TargetNode | EnvironmentNode): [NodeSt If{' '} }> - JMX over SSL + SSL is enabled {' '} - is enabled,{' '} + for JMX,{' '} add the SSL certificate From 27c2cbc950bb3f0a6e479e64c6d15a120e727e2f Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Thu, 12 Oct 2023 11:14:08 -0400 Subject: [PATCH 20/20] rephrase --- src/app/Shared/Components/FileUploads.tsx | 2 +- src/test/Agent/AgentProbeTemplates.test.tsx | 2 +- src/test/Events/EventTemplates.test.tsx | 2 +- src/test/Recordings/ArchivedRecordingsTable.test.tsx | 8 ++++---- src/test/Rules/Rules.test.tsx | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/Shared/Components/FileUploads.tsx b/src/app/Shared/Components/FileUploads.tsx index 4510f7174..1e782d347 100644 --- a/src/app/Shared/Components/FileUploads.tsx +++ b/src/app/Shared/Components/FileUploads.tsx @@ -276,7 +276,7 @@ export const MultiFileUpload: React.FC = ({ > } - titleText={titleText || 'Drag and drop files here'} + titleText={titleText || 'Drag a file here'} titleTextSeparator={titleTextSeparator || 'or'} infoText={infoText || `Accepted file types: ${displayAccepts.join(', ')}`} /> diff --git a/src/test/Agent/AgentProbeTemplates.test.tsx b/src/test/Agent/AgentProbeTemplates.test.tsx index 0bda3d66d..d7c92e027 100644 --- a/src/test/Agent/AgentProbeTemplates.test.tsx +++ b/src/test/Agent/AgentProbeTemplates.test.tsx @@ -154,7 +154,7 @@ describe('', () => { expect(modalTitle).toBeInTheDocument(); expect(modalTitle).toBeVisible(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); diff --git a/src/test/Events/EventTemplates.test.tsx b/src/test/Events/EventTemplates.test.tsx index a9bade5cf..feff35c8a 100644 --- a/src/test/Events/EventTemplates.test.tsx +++ b/src/test/Events/EventTemplates.test.tsx @@ -263,7 +263,7 @@ describe('', () => { expect(modalTitle).toBeInTheDocument(); expect(modalTitle).toBeVisible(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); diff --git a/src/test/Recordings/ArchivedRecordingsTable.test.tsx b/src/test/Recordings/ArchivedRecordingsTable.test.tsx index f81ae47d2..f4111cdc8 100644 --- a/src/test/Recordings/ArchivedRecordingsTable.test.tsx +++ b/src/test/Recordings/ArchivedRecordingsTable.test.tsx @@ -460,7 +460,7 @@ describe('', () => { expect(fileLabel).toBeInTheDocument(); expect(fileLabel).toBeInTheDocument(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); @@ -520,7 +520,7 @@ describe('', () => { expect(fileLabel).toBeInTheDocument(); expect(fileLabel).toBeInTheDocument(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); @@ -608,7 +608,7 @@ describe('', () => { expect(fileLabel).toBeInTheDocument(); expect(fileLabel).toBeInTheDocument(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); @@ -692,7 +692,7 @@ describe('', () => { expect(fileLabel).toBeInTheDocument(); expect(fileLabel).toBeInTheDocument(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); diff --git a/src/test/Rules/Rules.test.tsx b/src/test/Rules/Rules.test.tsx index d3246ea25..70c389603 100644 --- a/src/test/Rules/Rules.test.tsx +++ b/src/test/Rules/Rules.test.tsx @@ -146,7 +146,7 @@ describe('', () => { expect(modalTitle).toBeInTheDocument(); expect(modalTitle).toBeVisible(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible(); }); @@ -264,7 +264,7 @@ describe('', () => { expect(modalTitle).toBeInTheDocument(); expect(modalTitle).toBeVisible(); - const dropZoneText = within(modal).getByText('Drag and drop files here'); + const dropZoneText = within(modal).getByText('Drag a file here'); expect(dropZoneText).toBeInTheDocument(); expect(dropZoneText).toBeVisible();