@@ -33,7 +33,7 @@ import {
3333 addProxyConfigurationInternet ,
3434 proxyStrategy
3535} from './http-proxy-util' ;
36- import { setForwardedAuthTokenIfNeeded } from './forward-auth-token' ;
36+ import { addForwardedAuthTokenIfNeeded } from './forward-auth-token' ;
3737import type { SubscriberToken } from './get-subscriber-token' ;
3838import type { Destination } from './destination-service-types' ;
3939import type { AuthAndExchangeTokens } from './destination-service' ;
@@ -89,80 +89,63 @@ export class DestinationFromServiceRetriever {
8989 public static async getDestinationFromDestinationService (
9090 options : DestinationFetchOptions
9191 ) : Promise < Destination | null > {
92- // TODO: This is currently always skipped for tokens issued by XSUAA
93- // in the XSUAA case no exchange takes place
94- if ( shouldExchangeToken ( options ) && options . jwt ) {
95- // Exchange the IAS token to a XSUAA token using the destination service credentials
96- options . jwt = await jwtBearerToken ( options . jwt , 'destination' ) ;
92+ // Exchange the IAS token to a XSUAA token using the destination service credentials
93+ if ( shouldExchangeToken ( options ) ) {
94+ options . jwt = await jwtBearerToken ( options . jwt ! , 'destination' ) ;
9795 }
9896
99- const subscriberToken = await getSubscriberToken ( options ) ;
100- const providerToken = await getProviderServiceToken ( options ) ;
101-
102- const da = new DestinationFromServiceRetriever (
97+ // Create retriever with subscriber and provider tokens
98+ const retriever = new DestinationFromServiceRetriever (
10399 options ,
104- subscriberToken ,
105- providerToken
100+ await getSubscriberToken ( options ) ,
101+ await getProviderServiceToken ( options )
106102 ) ;
107103
108- const destinationResult =
109- await da . searchDestinationWithSelectionStrategyAndCache ( ) ;
110- if ( ! destinationResult ) {
104+ // Search destination with selection strategy and cache
105+ const destinationSearchResult =
106+ await retriever . searchDestinationWithSelectionStrategyAndCache ( ) ;
107+
108+ // Immediately return null if no destination found
109+ if ( ! destinationSearchResult ) {
111110 return null ;
112111 }
113112
114- let { destination } = destinationResult ;
115-
116- setForwardedAuthTokenIfNeeded ( destination , options . jwt ) ;
117-
118- if ( destinationResult . fromCache ) {
119- return da . addProxyConfiguration ( destination ) ;
120- }
113+ const { origin, fromCache } = destinationSearchResult ;
114+ let { destination } = destinationSearchResult ;
121115
122- if ( ! destination . forwardAuthToken ) {
123- if (
124- destination . authentication === 'OAuth2UserTokenExchange' ||
125- destination . authentication === 'OAuth2JWTBearer' ||
126- destination . authentication === 'SAMLAssertion' ||
127- ( destination . authentication === 'OAuth2SAMLBearerAssertion' &&
128- ! da . usesSystemUser ( destination ) )
129- ) {
130- destination =
131- await da . fetchDestinationWithUserExchangeFlows ( destinationResult ) ;
132- }
116+ if ( ! fromCache ) {
117+ /* Destination NOT from cache */
133118
134- if ( destination . authentication === 'PrincipalPropagation' ) {
135- if ( ! this . isUserJwt ( da . subscriberToken ) ) {
136- DestinationFromServiceRetriever . throwUserTokenMissing ( destination ) ;
137- }
138- }
119+ // Fetch and add auth token if needed.
120+ // Needed means `forwardAuthToken` is `false`
121+ // AND authentication is one of the supported types
122+ destination = await retriever . fetchAndAddAuthTokenIfNeeded (
123+ destination ,
124+ origin
125+ ) ;
139126
140- if (
141- destination . authentication === 'OAuth2Password' ||
142- destination . authentication === 'ClientCertificateAuthentication' ||
143- destination . authentication === 'OAuth2ClientCredentials' ||
144- da . usesSystemUser ( destination )
145- ) {
146- destination =
147- await da . fetchDestinationWithNonUserExchangeFlows ( destinationResult ) ;
148- }
127+ // Add trust store configuration if needed.
128+ // Needed means `TrustStoreLocation` is defined
129+ destination = await retriever . addTrustStoreConfigurationIfNeeded (
130+ destination ,
131+ origin
132+ ) ;
149133
150- if ( destination . authentication === 'OAuth2RefreshToken' ) {
151- destination =
152- await da . fetchDestinationWithRefreshTokenFlow ( destinationResult ) ;
153- }
134+ // Cache the destination
135+ await retriever . cacheDestination ( destination , origin ) ;
154136 }
155137
156- const withTrustStore = await da . addTrustStoreConfiguration (
157- destination ,
158- destinationResult . origin
159- ) ;
160- await da . updateDestinationCache ( withTrustStore , destinationResult . origin ) ;
138+ // Add auth token based on the given `options.jwt` if needed
139+ // Needed means `forwardAuthToken` is `true`
140+ destination = addForwardedAuthTokenIfNeeded ( destination , options . jwt ) ;
141+
142+ // Add proxy configuration based on the proxy strategy
143+ destination = await retriever . addProxyConfiguration ( destination ) ;
161144
162- return da . addProxyConfiguration ( withTrustStore ) ;
145+ return destination ;
163146 }
164147
165- private static throwUserTokenMissing ( destination ) {
148+ private static throwUserTokenMissing ( destination : Destination ) {
166149 throw Error (
167150 `No user token (JWT) has been provided. This is strictly necessary for '${ destination . authentication } '.`
168151 ) ;
@@ -247,9 +230,9 @@ export class DestinationFromServiceRetriever {
247230 }
248231
249232 private async getAuthTokenForOAuth2ClientCredentials (
250- destinationResult : DestinationSearchResult
233+ destination : Destination ,
234+ origin : DestinationOrigin
251235 ) : Promise < AuthAndExchangeTokens > {
252- const { destination, origin } = destinationResult ;
253236 // This covers the x-tenant case https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/resource
254237 const exchangeTenant = this . getExchangeTenant ( destination ) ;
255238 const authHeaderJwt =
@@ -285,9 +268,9 @@ Possible alternatives for such technical user authentication are BasicAuthentica
285268 }
286269
287270 private async getAuthTokenForOAuth2UserBasedTokenExchanges (
288- destinationResult : DestinationSearchResult
271+ destination : Destination ,
272+ origin : DestinationOrigin
289273 ) : Promise < AuthAndExchangeTokens > {
290- const { destination, origin } = destinationResult ;
291274 const { destinationName } = this . options ;
292275 if ( ! DestinationFromServiceRetriever . isUserJwt ( this . subscriberToken ) ) {
293276 throw DestinationFromServiceRetriever . throwUserTokenMissing ( destination ) ;
@@ -341,9 +324,9 @@ Possible alternatives for such technical user authentication are BasicAuthentica
341324 }
342325
343326 private async getAuthTokenForOAuth2RefreshToken (
344- destinationResult : DestinationSearchResult
327+ destination : Destination ,
328+ origin : DestinationOrigin
345329 ) : Promise < AuthAndExchangeTokens > {
346- const { destination, origin } = destinationResult ;
347330 const { refreshToken } = this . options ;
348331 if ( ! refreshToken ) {
349332 throw Error (
@@ -361,14 +344,18 @@ Possible alternatives for such technical user authentication are BasicAuthentica
361344 * @internal
362345 * This method calls the 'find destination by name' endpoint of the destination service using a client credentials grant.
363346 * For the find by name endpoint, the destination service will take care of OAuth flows and include the token in the destination.
364- * @param destinationResult - Result of the getDestinations call for which the exchange flow is triggered.
347+ * @param destination - The destination for which the token should be fetched.
348+ * @param origin - The origin of the destination, either 'subscriber' or 'provider'.
365349 * @returns Destination containing the auth token.
366350 */
367351 private async fetchDestinationWithNonUserExchangeFlows (
368- destinationResult : DestinationSearchResult
352+ destination : Destination ,
353+ origin : DestinationOrigin
369354 ) : Promise < Destination > {
370- const token =
371- await this . getAuthTokenForOAuth2ClientCredentials ( destinationResult ) ;
355+ const token = await this . getAuthTokenForOAuth2ClientCredentials (
356+ destination ,
357+ origin
358+ ) ;
372359
373360 return fetchDestinationWithTokenRetrieval (
374361 getDestinationServiceCredentials ( ) . uri ,
@@ -378,12 +365,13 @@ Possible alternatives for such technical user authentication are BasicAuthentica
378365 }
379366
380367 private async fetchDestinationWithUserExchangeFlows (
381- destinationResult : DestinationSearchResult
368+ destination : Destination ,
369+ origin : DestinationOrigin
382370 ) : Promise < Destination > {
383- const token =
384- await this . getAuthTokenForOAuth2UserBasedTokenExchanges (
385- destinationResult
386- ) ;
371+ const token = await this . getAuthTokenForOAuth2UserBasedTokenExchanges (
372+ destination ,
373+ origin
374+ ) ;
387375
388376 return fetchDestinationWithTokenRetrieval (
389377 getDestinationServiceCredentials ( ) . uri ,
@@ -393,10 +381,13 @@ Possible alternatives for such technical user authentication are BasicAuthentica
393381 }
394382
395383 private async fetchDestinationWithRefreshTokenFlow (
396- destinationResult : DestinationSearchResult
384+ destination : Destination ,
385+ origin : DestinationOrigin
397386 ) : Promise < Destination > {
398- const token =
399- await this . getAuthTokenForOAuth2RefreshToken ( destinationResult ) ;
387+ const token = await this . getAuthTokenForOAuth2RefreshToken (
388+ destination ,
389+ origin
390+ ) ;
400391
401392 return fetchDestinationWithTokenRetrieval (
402393 getDestinationServiceCredentials ( ) . uri ,
@@ -405,6 +396,47 @@ Possible alternatives for such technical user authentication are BasicAuthentica
405396 ) ;
406397 }
407398
399+ private async fetchAndAddAuthTokenIfNeeded (
400+ destination : Destination ,
401+ origin : DestinationOrigin
402+ ) : Promise < Destination > {
403+ const { forwardAuthToken, authentication } = destination ;
404+ if ( forwardAuthToken ) {
405+ return destination ;
406+ }
407+
408+ if (
409+ authentication === 'OAuth2UserTokenExchange' ||
410+ authentication === 'OAuth2JWTBearer' ||
411+ authentication === 'SAMLAssertion' ||
412+ ( authentication === 'OAuth2SAMLBearerAssertion' &&
413+ ! this . usesSystemUser ( destination ) )
414+ ) {
415+ return this . fetchDestinationWithUserExchangeFlows ( destination , origin ) ;
416+ }
417+
418+ if (
419+ authentication === 'OAuth2Password' ||
420+ authentication === 'ClientCertificateAuthentication' ||
421+ authentication === 'OAuth2ClientCredentials' ||
422+ this . usesSystemUser ( destination )
423+ ) {
424+ return this . fetchDestinationWithNonUserExchangeFlows ( destination , origin ) ;
425+ }
426+
427+ if ( authentication === 'OAuth2RefreshToken' ) {
428+ return this . fetchDestinationWithRefreshTokenFlow ( destination , origin ) ;
429+ }
430+
431+ if ( authentication === 'PrincipalPropagation' ) {
432+ if ( ! DestinationFromServiceRetriever . isUserJwt ( this . subscriberToken ) ) {
433+ DestinationFromServiceRetriever . throwUserTokenMissing ( destination ) ;
434+ }
435+ }
436+
437+ return destination ;
438+ }
439+
408440 private async addProxyConfiguration (
409441 destination : Destination
410442 ) : Promise < Destination > {
@@ -429,10 +461,10 @@ Possible alternatives for such technical user authentication are BasicAuthentica
429461 }
430462 }
431463
432- private async updateDestinationCache (
464+ private async cacheDestination (
433465 destination : Destination ,
434466 destinationOrigin : DestinationOrigin
435- ) {
467+ ) : Promise < void > {
436468 if ( ! this . options . useCache ) {
437469 return ;
438470 }
@@ -577,11 +609,11 @@ Possible alternatives for such technical user authentication are BasicAuthentica
577609 ) ;
578610 }
579611
580- private async addTrustStoreConfiguration (
612+ private async addTrustStoreConfigurationIfNeeded (
581613 destination : Destination ,
582614 origin : DestinationOrigin
583615 ) : Promise < Destination > {
584- const originalProperties = destination . originalProperties ;
616+ const { originalProperties } = destination ;
585617 const trustStoreLocation =
586618 originalProperties ?. TrustStoreLocation ||
587619 originalProperties ?. destinationConfiguration ?. TrustStoreLocation ;
@@ -593,7 +625,10 @@ Possible alternatives for such technical user authentication are BasicAuthentica
593625 : this . subscriberToken ! . serviceJwt ! . encoded ,
594626 trustStoreLocation
595627 ) ;
596- destination . trustStoreCertificate = trustStoreCertificate ;
628+ return {
629+ ...destination ,
630+ trustStoreCertificate
631+ } ;
597632 }
598633 return destination ;
599634 }
0 commit comments