Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit eff8697

Browse files
committedMar 12, 2025·
[MTV-1794] Update provider vCenter validation
Signed-off-by: Jeff Puzzo <[email protected]>
1 parent c16eb10 commit eff8697

File tree

5 files changed

+28
-22
lines changed

5 files changed

+28
-22
lines changed
 

‎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

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { pki } from 'node-forge';
22

3+
import { IoK8sApiCoreV1Secret } from '@kubev2v/types';
4+
35
import { safeBase64Decode } from '../../../helpers';
46
import { validateIpv4, validateURL, ValidationMsg } from '../../common';
57

@@ -12,15 +14,15 @@ export const urlMatchesCertFqdn = (urlHostname: string, caCert: string): boolean
1214
?.altNames.find((altName) => altName.type === 2)?.value;
1315
const commonName = cert.subject.attributes.find((attr) => attr.name === 'commonName')?.value;
1416

15-
return urlHostname === (dnsAltName || commonName);
17+
return urlHostname === commonName || urlHostname === dnsAltName;
1618
} catch (e) {
1719
console.error('Unable to parse certificate object from PEM.');
1820
}
1921

2022
return false;
2123
};
2224

23-
export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg => {
25+
export const validateVCenterURL = (url: string, secret?: IoK8sApiCoreV1Secret): ValidationMsg => {
2426
// For a newly opened form where the field is not set yet, set the validation type to default.
2527
if (url === undefined) {
2628
return {
@@ -38,6 +40,8 @@ export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg
3840
const isValidURL = validateURL(trimmedUrl);
3941
const urlObject = getUrlObject(url);
4042
const urlHostname = urlObject?.hostname;
43+
const insecureSkipVerify = secret?.data?.insecureSkipVerify;
44+
const isSecure = !insecureSkipVerify || safeBase64Decode(insecureSkipVerify) === 'false';
4145

4246
if (trimmedUrl === '') {
4347
return {
@@ -53,18 +57,21 @@ export const validateVCenterURL = (url: string, caCert?: string): ValidationMsg
5357
};
5458
}
5559

56-
if (urlObject?.protocol === 'https:') {
57-
if (validateIpv4(urlHostname)) {
60+
if (isSecure) {
61+
const caCert = secret?.data?.cacert;
62+
const isValidIpAddress = validateIpv4(urlHostname);
63+
64+
if (!isValidIpAddress && caCert && !urlMatchesCertFqdn(urlHostname, caCert)) {
5865
return {
5966
type: 'error',
60-
msg: 'Invalid URL. The URL must be a fully qualified domain name (FQDN).',
67+
msg: 'Invalid URL. The URL must be a fully qualified domain name (FQDN) and match the FQDN in the certificate you uploaded.',
6168
};
6269
}
6370

64-
if (caCert && !urlMatchesCertFqdn(urlHostname, caCert)) {
71+
if (isValidIpAddress) {
6572
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.',
73+
type: 'warning',
74+
msg: 'The URL is not a fully qualified domain name (FQDN). If the certificate does not match the URL, the connection might fail.',
6875
};
6976
}
7077
}

‎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)
Please sign in to comment.