Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brave-coins-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sap-ux/btp-utils': patch
---

Update S4HC to validate hostname
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const mockDestinations = {
Type: 'HTTP',
Authentication: 'SAMLAssertion',
Description: 'Mock destination 2',
Host: 'https://mock.url.dest2.com',
Host: 'https://mock.s4hana.url.dest2.com',
ProxyType: 'Internet',
WebIDEUsage: 'odata_abap'
}
Expand Down
12 changes: 9 additions & 3 deletions packages/btp-utils/src/destination.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Validates whether the provided destination string contains 's4hana.' or 's4hanacloud.'.
*/
const s4hanaHostRegex = /s4hana\.|s4hanacloud\./i;

/**
* Support different Token Service URL Types
*/
Expand Down Expand Up @@ -238,16 +243,17 @@ export function getDisplayName(destination: Destination, displayUsername?: strin
}

/**
* Checks whether the provided destination is configured to point to an S/4 HANA system.
* Checks whether the provided destination is configured to point to an S/4 HANA Public Cloud system.
*
* @param destination destination info
* @returns boolean if the destination is configured for an SAP S/4HANA system
* @returns boolean if the destination is configured for an SAP S/4HANA public cloud system
*/
export function isS4HC(destination: Destination): boolean {
return Boolean(
destination.WebIDEUsage?.includes(WebIDEUsage.ODATA_ABAP) &&
destination.Authentication === Authentication.SAML_ASSERTION &&
destination.ProxyType === ProxyType.INTERNET
destination.ProxyType === ProxyType.INTERNET &&
s4hanaHostRegex.test(destination.Host.toLowerCase())
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/btp-utils/test/app-studio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe('App Studio', () => {
expect(!!actualDestinations[destination.Name]).toBe(destination.WebIDEEnabled === 'true');
});
// test host remains unchanged when no opts passed to api
expect(actualDestinations['S4HC'].Host).toBe('https://s4hc-example-api.sap.example');
expect(actualDestinations['S4HC'].Host).toBe('https://my41111-api.s4hana.ondemand.com');
});

test('nothing returned', async () => {
Expand All @@ -200,7 +200,7 @@ describe('App Studio', () => {
.get('/api/listDestinations')
.replyWithFile(200, join(__dirname, 'mockResponses/destinations.json'));
const destinationsWithOpts = await listDestinations({ stripS4HCApiHosts: true });
expect(destinationsWithOpts['S4HC'].Host).toBe('https://s4hc-example.sap.example');
expect(destinationsWithOpts['S4HC'].Host).toBe('https://my41111.s4hana.ondemand.com');
});
});

Expand Down
11 changes: 11 additions & 0 deletions packages/btp-utils/test/destination.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import destinations from './mockResponses/destinations.json';
const destination: Destination = destinations.find((destination) => destination.Name === 'NO_ADDITIONAL_PROPERTIES')!;
const S4HCDestination: Destination = destinations.find((destination) => destination.Name === 'S4HC')!;
const btpDestination: Destination = destinations.find((destination) => destination.Name === 'ABAP_ON_BTP')!;
const abapCloud: Destination = destinations.find(
(destination) => destination.Name === 'abap-cloud-my-abap-env-testorg-testspace'
)!;

describe('destination', () => {
describe('isAbapSystem', () => {
Expand Down Expand Up @@ -188,6 +191,9 @@ describe('destination', () => {
})
).toBe(true);
});
it('Authentication set to SamlAssertion, internet facing and contains the required hostname', () => {
expect(isS4HC({ ...S4HCDestination, Host: 'https://my41111-api.saps4hanacloud.cn' })).toBe(true);
});
it('Authentication set to SamlAssertion and is OnPremise', () => {
expect(
isS4HC({
Expand All @@ -196,6 +202,11 @@ describe('destination', () => {
})
).toBe(false);
});
it('Authentication set to SamlAssertion and is Internet and using ABAP Cloud host', () => {
expect(
isS4HC(abapCloud)
).toBe(false);
});
});

describe('Test if destination is odata abap, cloud or on prem', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/btp-utils/test/mockResponses/destinations.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@
"Description": "S4HC for ABAP Cloud Deployment",
"WebIDEEnabled": "true",
"WebIDEUsage": "odata_abap,dev_abap",
"Host": "https://s4hc-example-api.sap.example",
"Host": "https://my41111-api.s4hana.ondemand.com",
"HTML5.DynamicDestination": "true",
"audience": "https://s4hc-example.sap.example",
"audience": "https://s4hana-example.sap.example",
"authnContextClassRef": "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession"
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ builder:
configuration:
target:
destination: Dest2
url: https://mock.url.dest2.com
url: https://mock.s4hana.url.dest2.com
authenticationType: reentranceTicket # SAML support for vscode
app:
name: MY_UI5_ABAP_REPO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const mockDestinations = {
Type: 'HTTP',
Authentication: 'SAMLAssertion',
Description: 'Mock destination 2',
Host: 'https://mock.url.dest2.com',
Host: 'https://mock.s4hana.url.dest2.com',
ProxyType: 'Internet',
WebIDEUsage: 'odata_abap'
}
Expand Down
Loading