Skip to content

Commit 96e1e9e

Browse files
committed
[MTV-1794] Update provider vCenter validation
Signed-off-by: Jeff Puzzo <[email protected]>
1 parent c2811e2 commit 96e1e9e

File tree

6 files changed

+22
-44
lines changed

6 files changed

+22
-44
lines changed

packages/forklift-console-plugin/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
"jsonpath": "^1.1.1",
4242
"jsrsasign": "11.1.0",
4343
"luxon": "^3.5.0",
44-
"node-forge": "^1",
4544
"react": "17.0.2",
4645
"react-dom": "17.0.2",
4746
"react-i18next": "^11.14.3",

packages/forklift-console-plugin/src/modules/Providers/utils/validators/provider/providerValidator.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function providerValidator(
2727
validationError = ovirtProviderValidator(provider);
2828
break;
2929
case 'vsphere':
30-
validationError = vsphereProviderValidator(provider, subType, secret?.data?.cacert);
30+
validationError = vsphereProviderValidator(provider, subType, secret);
3131
break;
3232
case 'ova':
3333
validationError = ovaProviderValidator(provider);

packages/forklift-console-plugin/src/modules/Providers/utils/validators/provider/vsphere/validateVCenterURL.ts

+9-29
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,9 @@
1-
import { pki } from 'node-forge';
1+
import { IoK8sApiCoreV1Secret } from '@kubev2v/types';
22

33
import { safeBase64Decode } from '../../../helpers';
44
import { validateIpv4, validateURL, ValidationMsg } from '../../common';
55

6-
export const urlMatchesCertFqdn = (urlHostname: string, caCert: string): boolean => {
7-
try {
8-
const decodedCaCert = safeBase64Decode(caCert);
9-
const cert = pki.certificateFromPem(decodedCaCert);
10-
const dnsAltName = cert.extensions
11-
.find((ext) => ext.name === 'subjectAltName')
12-
?.altNames.find((altName) => altName.type === 2)?.value;
13-
const commonName = cert.subject.attributes.find((attr) => attr.name === 'commonName')?.value;
14-
15-
return urlHostname === (dnsAltName || commonName);
16-
} catch (e) {
17-
console.error('Unable to parse certificate object from PEM.');
18-
}
19-
20-
return false;
21-
};
22-
23-
export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg => {
6+
export const validateVCenterURL = (url: string, secret?: IoK8sApiCoreV1Secret): ValidationMsg => {
247
// For a newly opened form where the field is not set yet, set the validation type to default.
258
if (url === undefined) {
269
return {
@@ -38,6 +21,8 @@ export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg
3821
const isValidURL = validateURL(trimmedUrl);
3922
const urlObject = getUrlObject(url);
4023
const urlHostname = urlObject?.hostname;
24+
const insecureSkipVerify = secret?.data?.insecureSkipVerify;
25+
const isSecure = !insecureSkipVerify || safeBase64Decode(insecureSkipVerify) === 'false';
4126

4227
if (trimmedUrl === '') {
4328
return {
@@ -53,18 +38,13 @@ export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg
5338
};
5439
}
5540

56-
if (urlObject?.protocol === 'https:') {
57-
if (validateIpv4(urlHostname)) {
58-
return {
59-
type: 'error',
60-
msg: 'Invalid URL. The URL must be a fully qualified domain name (FQDN).',
61-
};
62-
}
41+
if (isSecure) {
42+
const isValidIpAddress = validateIpv4(urlHostname);
6343

64-
if (caCert && !urlMatchesCertFqdn(urlHostname, caCert)) {
44+
if (isValidIpAddress) {
6545
return {
66-
type: 'error',
67-
msg: 'Invalid URL. The URL must be a fully qualified domain name (FQDN) and match the FQDN in the certificate you uploaded.',
46+
type: 'warning',
47+
msg: 'The URL is not a fully qualified domain name (FQDN). If the certificate does not match the URL, the connection might fail.',
6848
};
6949
}
7050
}

packages/forklift-console-plugin/src/modules/Providers/utils/validators/provider/vsphere/vsphereProviderValidator.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { V1beta1Provider } from '@kubev2v/types';
2+
import { IoK8sApiCoreV1Secret } from '@kubev2v/types';
23

34
import { validateK8sName, validateURL, ValidationMsg } from '../../common';
45
import { SecretSubType } from '../secretValidator';
@@ -9,7 +10,7 @@ import { validateVDDKImage } from './validateVDDKImage';
910
export function vsphereProviderValidator(
1011
provider: V1beta1Provider,
1112
subType?: SecretSubType,
12-
caCert?: string,
13+
secret?: IoK8sApiCoreV1Secret,
1314
): ValidationMsg {
1415
const name = provider?.metadata?.name;
1516
const url = provider?.spec?.url || '';
@@ -23,9 +24,7 @@ export function vsphereProviderValidator(
2324
}
2425

2526
if (
26-
subType === 'vcenter' && caCert
27-
? validateVCenterURL(url, caCert).type === 'error'
28-
: !validateURL(url)
27+
subType === 'vcenter' ? validateVCenterURL(url, secret).type === 'error' : !validateURL(url)
2928
) {
3029
return { type: 'error', msg: 'invalid URL' };
3130
}

packages/forklift-console-plugin/src/modules/Providers/views/create/components/EditProvider.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const EditProvider: React.FC<ProvidersCreateFormProps> = ({
7373
<>
7474
<VCenterProviderCreateForm
7575
provider={newProvider}
76-
caCert={newSecret.data.cacert}
76+
secret={newSecret}
7777
onChange={onNewProviderChange}
7878
/>
7979

packages/forklift-console-plugin/src/modules/Providers/views/create/components/VCenterProviderCreateForm.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ import {
88
import { useForkliftTranslation } from 'src/utils/i18n';
99

1010
import { FormGroupWithHelpText } from '@kubev2v/common';
11-
import { V1beta1Provider } from '@kubev2v/types';
11+
import { IoK8sApiCoreV1Secret, V1beta1Provider } from '@kubev2v/types';
1212
import { Alert, Checkbox, Form, Popover, Radio, TextInput } from '@patternfly/react-core';
1313
import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon';
1414

1515
export interface VCenterProviderCreateFormProps {
1616
provider: V1beta1Provider;
17-
caCert: string;
17+
secret: IoK8sApiCoreV1Secret;
1818
onChange: (newValue: V1beta1Provider) => void;
1919
}
2020

2121
export const VCenterProviderCreateForm: React.FC<VCenterProviderCreateFormProps> = ({
2222
provider,
23-
caCert,
23+
secret,
2424
onChange,
2525
}) => {
2626
const { t } = useForkliftTranslation();
@@ -33,7 +33,7 @@ export const VCenterProviderCreateForm: React.FC<VCenterProviderCreateFormProps>
3333

3434
const initialState = {
3535
validation: {
36-
url: validateVCenterURL(url, caCert),
36+
url: validateVCenterURL(url, secret),
3737
vddkInitImage: validateVDDKImage(vddkInitImage),
3838
},
3939
};
@@ -42,9 +42,9 @@ export const VCenterProviderCreateForm: React.FC<VCenterProviderCreateFormProps>
4242
useEffect(() => {
4343
dispatch({
4444
type: 'SET_FIELD_VALIDATED',
45-
payload: { field: 'url', validationState: validateVCenterURL(url, caCert) },
45+
payload: { field: 'url', validationState: validateVCenterURL(url, secret) },
4646
});
47-
}, [caCert]);
47+
}, [secret]);
4848

4949
const reducer = (state, action) => {
5050
switch (action.type) {
@@ -127,14 +127,14 @@ export const VCenterProviderCreateForm: React.FC<VCenterProviderCreateFormProps>
127127

128128
if (id === 'url') {
129129
// Validate URL - VCenter of ESXi
130-
const validationState = validateVCenterURL(trimmedValue, caCert);
130+
const validationState = validateVCenterURL(trimmedValue, secret);
131131

132132
dispatch({ type: 'SET_FIELD_VALIDATED', payload: { field: 'url', validationState } });
133133

134134
onChange({ ...provider, spec: { ...provider.spec, url: trimmedValue } });
135135
}
136136
},
137-
[provider, caCert],
137+
[provider, secret],
138138
);
139139

140140
const onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void = (event) => {

0 commit comments

Comments
 (0)