github.com/phrase/openapi@v0.0.0-20240514140800-49e8a106740e/openapi-generator/templates/java/libraries/okhttp-gson/auth/RetryingOAuth.mustache (about)

     1  {{#hasOAuthMethods}}
     2  package {{invokerPackage}}.auth;
     3  
     4  import {{invokerPackage}}.Pair;
     5  
     6  import okhttp3.Interceptor;
     7  import okhttp3.OkHttpClient;
     8  import okhttp3.Request;
     9  import okhttp3.Response;
    10  
    11  import org.apache.oltu.oauth2.client.OAuthClient;
    12  import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
    13  import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
    14  import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
    15  import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
    16  import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
    17  import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
    18  import org.apache.oltu.oauth2.common.message.types.GrantType;
    19  
    20  import java.io.IOException;
    21  import java.net.HttpURLConnection;
    22  import java.util.Map;
    23  import java.util.List;
    24  
    25  public class RetryingOAuth extends OAuth implements Interceptor {
    26      private OAuthClient oAuthClient;
    27  
    28      private TokenRequestBuilder tokenRequestBuilder;
    29  
    30      public RetryingOAuth(OkHttpClient client, TokenRequestBuilder tokenRequestBuilder) {
    31          this.oAuthClient = new OAuthClient(new OAuthOkHttpClient(client));
    32          this.tokenRequestBuilder = tokenRequestBuilder;
    33      }
    34  
    35      public RetryingOAuth(TokenRequestBuilder tokenRequestBuilder) {
    36          this(new OkHttpClient(), tokenRequestBuilder);
    37      }
    38  
    39      /**
    40      @param tokenUrl The token URL to be used for this OAuth2 flow.
    41          Applicable to the following OAuth2 flows: "password", "clientCredentials" and "authorizationCode".
    42          The value must be an absolute URL.
    43      @param clientId The OAuth2 client ID for the "clientCredentials" flow.
    44      @param clientSecret The OAuth2 client secret for the "clientCredentials" flow.
    45      */
    46      public RetryingOAuth(
    47              String tokenUrl,
    48              String clientId,
    49              OAuthFlow flow,
    50              String clientSecret,
    51              Map<String, String> parameters
    52      ) {
    53          this(OAuthClientRequest.tokenLocation(tokenUrl)
    54                  .setClientId(clientId)
    55                  .setClientSecret(clientSecret));
    56          setFlow(flow);
    57          if (parameters != null) {
    58              for (String paramName : parameters.keySet()) {
    59                  tokenRequestBuilder.setParameter(paramName, parameters.get(paramName));
    60              }
    61          }
    62      }
    63  
    64      public void setFlow(OAuthFlow flow) {
    65          switch(flow) {
    66              case accessCode:
    67                  tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
    68                  break;
    69              case implicit:
    70                  tokenRequestBuilder.setGrantType(GrantType.IMPLICIT);
    71                  break;
    72              case password:
    73                  tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
    74                  break;
    75              case application:
    76                  tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
    77                  break;
    78              default:
    79                  break;
    80          }
    81      }
    82  
    83      @Override
    84      public Response intercept(Chain chain) throws IOException {
    85          return retryingIntercept(chain, true);
    86      }
    87  
    88      private Response retryingIntercept(Chain chain, boolean updateTokenAndRetryOnAuthorizationFailure) throws IOException {
    89          Request request = chain.request();
    90  
    91          // If the request already has an authorization (e.g. Basic auth), proceed with the request as is
    92          if (request.header("Authorization") != null) {
    93              return chain.proceed(request);
    94          }
    95  
    96          // Get the token if it has not yet been acquired
    97          if (getAccessToken() == null) {
    98              updateAccessToken(null);
    99          }
   100  
   101          OAuthClientRequest oAuthRequest;
   102          if (getAccessToken() != null) {
   103              // Build the request
   104              Request.Builder requestBuilder = request.newBuilder();
   105  
   106              String requestAccessToken = getAccessToken();
   107              try {
   108                  oAuthRequest =
   109                          new OAuthBearerClientRequest(request.url().toString()).
   110                                  setAccessToken(requestAccessToken).
   111                                  buildHeaderMessage();
   112              } catch (OAuthSystemException e) {
   113                  throw new IOException(e);
   114              }
   115  
   116              Map<String, String> headers = oAuthRequest.getHeaders();
   117              for (String headerName : headers.keySet()) {
   118                  requestBuilder.addHeader(headerName, headers.get(headerName));
   119              }
   120              requestBuilder.url(oAuthRequest.getLocationUri());
   121  
   122              // Execute the request
   123              Response response = chain.proceed(requestBuilder.build());
   124  
   125              // 401/403 response codes most likely indicate an expired access token, unless it happens two times in a row
   126              if (
   127                      response != null &&
   128                              (   response.code() == HttpURLConnection.HTTP_UNAUTHORIZED ||
   129                                      response.code() == HttpURLConnection.HTTP_FORBIDDEN     ) &&
   130                              updateTokenAndRetryOnAuthorizationFailure
   131              ) {
   132                  try {
   133                      if (updateAccessToken(requestAccessToken)) {
   134                          response.body().close();
   135                          return retryingIntercept(chain, false);
   136                      }
   137                  } catch (Exception e) {
   138                      response.body().close();
   139                      throw e;
   140                  }
   141              }
   142              return response;
   143          }
   144          else {
   145              return chain.proceed(chain.request());
   146          }
   147      }
   148  
   149      /*
   150       * Returns true if the access token has been updated
   151       */
   152      public synchronized boolean updateAccessToken(String requestAccessToken) throws IOException {
   153          if (getAccessToken() == null || getAccessToken().equals(requestAccessToken)) {
   154              try {
   155                  OAuthJSONAccessTokenResponse accessTokenResponse =
   156                          oAuthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
   157                  if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
   158                      setAccessToken(accessTokenResponse.getAccessToken());
   159                      return !getAccessToken().equals(requestAccessToken);
   160                  }
   161              } catch (OAuthSystemException | OAuthProblemException e) {
   162                  throw new IOException(e);
   163              }
   164          }
   165  
   166          return false;
   167      }
   168  
   169      public TokenRequestBuilder getTokenRequestBuilder() {
   170          return tokenRequestBuilder;
   171      }
   172  
   173      public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) {
   174          this.tokenRequestBuilder = tokenRequestBuilder;
   175      }
   176  
   177      // Applying authorization to parameters is performed in the retryingIntercept method
   178      @Override
   179      public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams) {
   180          // No implementation necessary
   181      }
   182  }
   183  {{/hasOAuthMethods}}