55package cloud .katta .protocols .s3 ;
66
77import ch .cyberduck .core .Credentials ;
8- import ch .cyberduck .core .DefaultIOExceptionMappingService ;
98import ch .cyberduck .core .Host ;
109import ch .cyberduck .core .LoginCallback ;
1110import ch .cyberduck .core .OAuthTokens ;
1211import ch .cyberduck .core .exception .BackgroundException ;
1312import ch .cyberduck .core .exception .LoginCanceledException ;
1413import ch .cyberduck .core .exception .LoginFailureException ;
15- import ch .cyberduck .core .http .DefaultHttpResponseExceptionMappingService ;
1614import ch .cyberduck .core .oauth .OAuth2RequestInterceptor ;
17- import ch .cyberduck .core .oauth .OAuthExceptionMappingService ;
1815import ch .cyberduck .core .preferences .HostPreferences ;
1916import ch .cyberduck .core .preferences .PreferencesReader ;
2017
21- import org .apache .commons .lang3 .StringUtils ;
2218import org .apache .http .client .HttpClient ;
2319import org .apache .logging .log4j .LogManager ;
2420import org .apache .logging .log4j .Logger ;
2521
26- import java .io .IOException ;
27- import java .util .ArrayList ;
2822import java .util .Arrays ;
2923import java .util .List ;
3024
25+ import cloud .katta .client .ApiException ;
26+ import cloud .katta .client .api .StorageResourceApi ;
27+ import cloud .katta .client .model .AccessTokenResponse ;
28+ import cloud .katta .protocols .hub .HubSession ;
29+ import cloud .katta .protocols .hub .exceptions .HubExceptionMappingService ;
3130import com .auth0 .jwt .JWT ;
3231import com .auth0 .jwt .exceptions .JWTDecodeException ;
3332import com .auth0 .jwt .interfaces .DecodedJWT ;
34- import com .google .api .client .auth .oauth2 .TokenRequest ;
35- import com .google .api .client .auth .oauth2 .TokenResponse ;
36- import com .google .api .client .auth .oauth2 .TokenResponseException ;
37- import com .google .api .client .http .GenericUrl ;
38- import com .google .api .client .http .HttpResponseException ;
39- import com .google .api .client .http .apache .v2 .ApacheHttpTransport ;
40- import com .google .api .client .json .gson .GsonFactory ;
41-
42- import static cloud .katta .protocols .s3 .S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE ;
4333
4434/**
4535 * Exchange OIDC token to scoped token using OAuth 2.0 Token Exchange. Used for S3-STS in Katta.
4636 */
4737public class TokenExchangeRequestInterceptor extends OAuth2RequestInterceptor {
4838 private static final Logger log = LogManager .getLogger (TokenExchangeRequestInterceptor .class );
4939
50- // https://datatracker.ietf.org/doc/html/rfc8693#name-request
51- public static final String OAUTH_GRANT_TYPE_TOKEN_EXCHANGE = "urn:ietf:params:oauth:grant-type:token-exchange" ;
52- public static final String OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_CLIENT_ID = "client_id" ;
53- public static final String OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_CLIENT_SECRET = "client_secret" ;
54- public static final String OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_SUBJECT_TOKEN = "subject_token" ;
55- public static final String OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_SUBJECT_TOKEN_TYPE = "subject_token_type" ;
56- public static final String OAUTH_TOKEN_TYPE_ACCESS_TOKEN = "urn:ietf:params:oauth:token-type:access_token" ;
57- // https://openid.net/specs/openid-connect-core-1_0.html
40+ /**
41+ * The party to which the ID Token was issued
42+ * <a href="https://openid.net/specs/openid-connect-core-1_0.html">...</a>
43+ */
5844 public static final String OIDC_AUTHORIZED_PARTY = "azp" ;
5945
60-
6146 private final Host bookmark ;
62- private final HttpClient client ;
6347
6448 public TokenExchangeRequestInterceptor (final HttpClient client , final Host bookmark , final LoginCallback prompt ) throws LoginCanceledException {
6549 super (client , bookmark , prompt );
6650 this .bookmark = bookmark ;
67- this .client = client ;
6851 }
6952
7053 @ Override
@@ -82,49 +65,26 @@ public OAuthTokens refresh(final OAuthTokens previous) throws BackgroundExceptio
8265 *
8366 * @param previous Input tokens retrieved to exchange at the token endpoint
8467 * @return New tokens
85- * @see S3AssumeRoleProtocol#OAUTH_TOKENEXCHANGE_CLIENT_ID
86- * @see S3AssumeRoleProtocol#OAUTH_TOKENEXCHANGE_ADDITIONAL_SCOPES
68+ * @see S3AssumeRoleProtocol#OAUTH_TOKENEXCHANGE_VAULT
69+ * @see S3AssumeRoleProtocol#OAUTH_TOKENEXCHANGE_BASEPATH
8770 */
8871 public OAuthTokens exchange (final OAuthTokens previous ) throws BackgroundException {
8972 log .info ("Exchange tokens {} for {}" , previous , bookmark );
90- final TokenRequest request = new TokenRequest (
91- new ApacheHttpTransport (client ),
92- new GsonFactory (),
93- new GenericUrl (bookmark .getProtocol ().getOAuthTokenUrl ()),
94- OAUTH_GRANT_TYPE_TOKEN_EXCHANGE
95- );
96- request .set (OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_CLIENT_ID , bookmark .getProtocol ().getOAuthClientId ());
9773 final PreferencesReader preferences = new HostPreferences (bookmark );
98- if (!StringUtils .isEmpty (preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_CLIENT_ID ))) {
99- request .set (OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_CLIENT_ID , preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_CLIENT_ID ));
100- request .set (OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_CLIENT_SECRET , preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_CLIENT_SECRET ));
101- }
102- request .set (OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_SUBJECT_TOKEN , previous .getAccessToken ());
103- request .set (OAUTH_GRANT_TYPE_TOKEN_EXCHANGE_SUBJECT_TOKEN_TYPE , OAUTH_TOKEN_TYPE_ACCESS_TOKEN );
104- final ArrayList <String > scopes = new ArrayList <>(bookmark .getProtocol ().getOAuthScopes ());
105- if (!StringUtils .isEmpty (preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_ADDITIONAL_SCOPES ))) {
106- scopes .addAll (Arrays .asList (preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_ADDITIONAL_SCOPES ).split (" " )));
107- }
108- request .setScopes (scopes );
109- log .debug ("Token exchange request {} for {}" , request , bookmark );
74+ final HubSession hub = bookmark .getProtocol ().getFeature (HubSession .class );
75+ log .debug ("Exchange token with hub {}" , hub );
76+ final StorageResourceApi api = new StorageResourceApi (hub .getClient ());
11077 try {
111- final TokenResponse tokenExchangeResponse = request . execute ( );
78+ AccessTokenResponse tokenExchangeResponse = api . apiStorageS3TokenPost ( preferences . getProperty ( S3AssumeRoleProtocol . OAUTH_TOKENEXCHANGE_VAULT ) );
11279 // N.B. token exchange with Id token does not work!
11380 final OAuthTokens tokens = new OAuthTokens (tokenExchangeResponse .getAccessToken (),
11481 tokenExchangeResponse .getRefreshToken (),
115- System .currentTimeMillis () + tokenExchangeResponse .getExpiresInSeconds () * 1000 );
82+ System .currentTimeMillis () + tokenExchangeResponse .getExpiresIn () * 1000 );
11683 log .debug ("Received exchanged token {} for {}" , tokens , bookmark );
11784 return tokens ;
11885 }
119- catch (TokenResponseException e ) {
120- throw new OAuthExceptionMappingService ().map (e );
121- }
122- catch (HttpResponseException e ) {
123- throw new DefaultHttpResponseExceptionMappingService ().map (new org .apache .http .client
124- .HttpResponseException (e .getStatusCode (), e .getStatusMessage ()));
125- }
126- catch (IOException e ) {
127- throw new DefaultIOExceptionMappingService ().map (e );
86+ catch (ApiException e ) {
87+ throw new HubExceptionMappingService ().map (e );
12888 }
12989 }
13090
@@ -133,12 +93,6 @@ public Credentials validate() throws BackgroundException {
13393 final Credentials credentials = super .validate ();
13494 final OAuthTokens tokens = credentials .getOauth ();
13595 final String accessToken = tokens .getAccessToken ();
136- final PreferencesReader preferences = new HostPreferences (bookmark );
137- final String tokenExchangeClientId = preferences .getProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_CLIENT_ID );
138- if (StringUtils .isEmpty (tokenExchangeClientId )) {
139- log .warn ("Found {} empty, although {} is set to {} - misconfiguration?" , S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE_CLIENT_ID , OAUTH_TOKENEXCHANGE , preferences .getBoolean (OAUTH_TOKENEXCHANGE ));
140- return credentials ;
141- }
14296 try {
14397 final DecodedJWT jwt = JWT .decode (accessToken );
14498
0 commit comments