Skip to content

Commit 1a3e4e1

Browse files
committed
Merge remote-tracking branch 'origin/main' into davidkna-sap_pnpm
* origin/main: feat: Add `getIasToken()` and `getIasDestination()` convenience functions (#6431)
2 parents b5f1651 + 9102f18 commit 1a3e4e1

18 files changed

Lines changed: 930 additions & 742 deletions

.changeset/empty-dryers-boil.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sap-cloud-sdk/connectivity': minor
3+
---
4+
5+
[New Functionality] Add `getIasDestination()` convenience function to build IAS-backed destinations.
6+
This function aims to offer more convenience for obtaining IAS-backed destinations outside SAP BTP-environments.

.changeset/stupid-files-create.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sap-cloud-sdk/connectivity': minor
3+
---
4+
5+
[New Functionality] Add `getIasToken()` convenience function to fetch IAS token.
6+
This function aims to offer more convenience for obtaining IAS tokens outside SAP BTP-environments.

.changeset/wild-kids-poke.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sap-cloud-sdk/connectivity': minor
3+
---
4+
5+
[Compatibility Note] IAS tokens are now cached via `@sap/xssec`.
6+
`@sap/xssec` uses an LRU cache limited to 100 items, previously this cache was unbound.

eslint.config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,25 @@ module.exports = defineConfig([
9595
rules: {
9696
'jsdoc/require-description-complete-sentence': 'off'
9797
}
98+
},
99+
{
100+
// avoid circular imports via destination barrel
101+
files: [
102+
'packages/connectivity/src/scp-cf/token-accessor.ts'
103+
],
104+
rules: {
105+
'import/no-internal-modules': [
106+
'error',
107+
{
108+
allow: [
109+
'@sap-cloud-sdk/**/internal',
110+
'@sap-cloud-sdk/**/internal.js',
111+
'**/destination/build-ias-destination',
112+
'**/destination/ias-types',
113+
'**/destination/destination-service-types'
114+
]
115+
}
116+
]
117+
}
98118
}
99119
]);

packages/connectivity/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export {
1717
retrieveJwt,
1818
jwtBearerToken,
1919
serviceToken,
20+
getIasToken,
21+
getIasDestination,
2022
isHttpDestination,
2123
assertHttpDestination,
2224
DestinationSelectionStrategies,
@@ -63,7 +65,9 @@ export type {
6365
IasOptionsBase,
6466
IasOptionsBusinessUser,
6567
IasOptionsTechnicalUser,
66-
IasResource
68+
IasResource,
69+
IasTokenOptions,
70+
IasTokenResult
6771
} from './scp-cf';
6872

6973
export type {
Lines changed: 1 addition & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { createLogger } from '@sap-cloud-sdk/util';
2-
import {
3-
clientCredentialsTokenCache,
4-
getIasCacheKey
5-
} from './client-credentials-token-cache';
2+
import { clientCredentialsTokenCache } from './client-credentials-token-cache';
63

74
const oneHourInSeconds = 60 * 60;
85

@@ -90,217 +87,4 @@ describe('ClientCredentialsTokenCache', () => {
9087
'Cannot create cache key for client credentials token cache. The given client ID is undefined.'
9188
);
9289
});
93-
94-
describe('IAS resource parameter support', () => {
95-
const validToken = {
96-
access_token: '1234567890',
97-
token_type: 'Bearer',
98-
expires_in: oneHourInSeconds * 3,
99-
jti: '',
100-
scope: ''
101-
};
102-
const iasTokenCacheData = {
103-
iasInstance: 'subscriber-tenant',
104-
clientId: 'clientid',
105-
resource: { name: 'my-app' }
106-
};
107-
108-
beforeEach(() => {
109-
clientCredentialsTokenCache.clear();
110-
});
111-
112-
it('should cache and retrieve token with resource name', () => {
113-
clientCredentialsTokenCache.cacheIasToken(iasTokenCacheData, validToken);
114-
115-
const cached = clientCredentialsTokenCache.getTokenIas(iasTokenCacheData);
116-
117-
expect(cached).toEqual(validToken);
118-
});
119-
120-
it('should cache and retrieve token with resource clientId', () => {
121-
const resource = { providerClientId: 'resource-client-123' };
122-
123-
clientCredentialsTokenCache.cacheIasToken(
124-
{
125-
...iasTokenCacheData,
126-
resource
127-
},
128-
validToken
129-
);
130-
131-
const cached = clientCredentialsTokenCache.getTokenIas({
132-
...iasTokenCacheData,
133-
resource
134-
});
135-
136-
expect(cached).toEqual(validToken);
137-
});
138-
139-
it('should cache and retrieve token with resource clientId and tenantId', () => {
140-
const resource = {
141-
providerClientId: 'resource-client-123',
142-
providerTenantId: 'tenant-456'
143-
};
144-
145-
clientCredentialsTokenCache.cacheIasToken(
146-
{
147-
...iasTokenCacheData,
148-
resource
149-
},
150-
validToken
151-
);
152-
153-
const cached = clientCredentialsTokenCache.getTokenIas({
154-
...iasTokenCacheData,
155-
resource
156-
});
157-
158-
expect(cached).toEqual(validToken);
159-
});
160-
161-
it('should isolate cache by resource name', () => {
162-
const resource1 = { name: 'app-1' };
163-
const resource2 = { name: 'app-2' };
164-
165-
clientCredentialsTokenCache.cacheIasToken(
166-
{
167-
...iasTokenCacheData,
168-
resource: resource1
169-
},
170-
validToken
171-
);
172-
173-
const cached1 = clientCredentialsTokenCache.getTokenIas({
174-
...iasTokenCacheData,
175-
resource: resource1
176-
});
177-
const cached2 = clientCredentialsTokenCache.getTokenIas({
178-
...iasTokenCacheData,
179-
resource: resource2
180-
});
181-
182-
expect(cached1).toEqual(validToken);
183-
expect(cached2).toBeUndefined();
184-
});
185-
186-
it('should isolate cache by resource providerClientId', () => {
187-
const resource1 = { providerClientId: 'client-1' };
188-
const resource2 = { providerClientId: 'client-2' };
189-
190-
clientCredentialsTokenCache.cacheIasToken(
191-
{
192-
...iasTokenCacheData,
193-
resource: resource1
194-
},
195-
validToken
196-
);
197-
198-
const cached1 = clientCredentialsTokenCache.getTokenIas({
199-
...iasTokenCacheData,
200-
resource: resource1
201-
});
202-
const cached2 = clientCredentialsTokenCache.getTokenIas({
203-
...iasTokenCacheData,
204-
resource: resource2
205-
});
206-
207-
expect(cached1).toEqual(validToken);
208-
expect(cached2).toBeUndefined();
209-
});
210-
211-
it('should generate correct cache key with resource name', () => {
212-
const key = getIasCacheKey({
213-
iasInstance: 'tenant-123',
214-
clientId: 'client-id',
215-
resource: { name: 'my-app' }
216-
});
217-
expect(key).toBe('tenant-123::client-id:name=my-app');
218-
});
219-
220-
it('should generate correct cache key with resource clientId only', () => {
221-
const key = getIasCacheKey({
222-
iasInstance: 'tenant-123',
223-
clientId: 'client-id',
224-
resource: {
225-
providerClientId: 'resource-client-123'
226-
}
227-
});
228-
expect(key).toBe(
229-
'tenant-123::client-id:provider-clientId=resource-client-123'
230-
);
231-
});
232-
233-
it('should generate correct cache key with resource clientId and tenantId', () => {
234-
const key = getIasCacheKey({
235-
iasInstance: 'tenant-123',
236-
clientId: 'client-id',
237-
resource: {
238-
providerClientId: 'resource-client-123',
239-
providerTenantId: 'tenant-456'
240-
}
241-
});
242-
expect(key).toBe(
243-
'tenant-123::client-id:provider-clientId=resource-client-123:provider-tenantId=tenant-456'
244-
);
245-
});
246-
247-
it('should generate cache key without resource when not provided', () => {
248-
const key = getIasCacheKey({
249-
iasInstance: 'tenant-123',
250-
clientId: 'client-id'
251-
});
252-
expect(key).toBe('tenant-123::client-id');
253-
});
254-
255-
it('should isolate cache by appTid', () => {
256-
clientCredentialsTokenCache.cacheIasToken(
257-
{
258-
...iasTokenCacheData,
259-
appTid: 'tenant-123'
260-
},
261-
validToken
262-
);
263-
264-
const cached1 = clientCredentialsTokenCache.getTokenIas({
265-
...iasTokenCacheData,
266-
appTid: 'tenant-123'
267-
});
268-
const cached2 = clientCredentialsTokenCache.getTokenIas({
269-
...iasTokenCacheData,
270-
appTid: 'tenant-456'
271-
});
272-
const cached3 = clientCredentialsTokenCache.getTokenIas({
273-
...iasTokenCacheData
274-
// No appTid
275-
});
276-
277-
expect(cached1).toEqual(validToken);
278-
expect(cached2).toBeUndefined();
279-
expect(cached3).toBeUndefined();
280-
});
281-
282-
it('should generate correct cache key with appTid', () => {
283-
const key = getIasCacheKey({
284-
iasInstance: 'tenant-123',
285-
clientId: 'client-id',
286-
appTid: 'app-tenant-456'
287-
});
288-
expect(key).toBe('tenant-123:app-tenant-456:client-id');
289-
});
290-
291-
it('should generate cache key with double colon when appTid is undefined', () => {
292-
const key1 = getIasCacheKey({
293-
iasInstance: 'tenant-123',
294-
clientId: 'client-id',
295-
appTid: undefined
296-
});
297-
const key2 = getIasCacheKey({
298-
iasInstance: 'tenant-123',
299-
clientId: 'client-id'
300-
});
301-
// Both should produce the same key with double colon
302-
expect(key1).toBe('tenant-123::client-id');
303-
expect(key2).toBe('tenant-123::client-id');
304-
});
305-
});
30690
});

0 commit comments

Comments
 (0)