001package com.box.sdk;
002
003import com.eclipsesource.json.Json;
004import com.eclipsesource.json.JsonObject;
005import java.io.UnsupportedEncodingException;
006import java.net.MalformedURLException;
007import java.net.URL;
008import java.net.URLEncoder;
009
010/**
011 * Represents an authenticated transactional connection to the Box API.
012 *
013 * <p>This class handles everything for transactional API that isn't already handled by
014 * BoxAPIConnection.
015 */
016public class BoxTransactionalAPIConnection extends BoxAPIConnection {
017
018  private static final String SUBJECT_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
019  private static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
020
021  /**
022   * Constructs a new BoxTransactionalAPIConnection that authenticates with an access token.
023   *
024   * @param accessToken a transactional auth access token.
025   */
026  public BoxTransactionalAPIConnection(String accessToken) {
027    super(accessToken);
028    super.setAutoRefresh(false);
029  }
030
031  /**
032   * Request a scoped transactional token.
033   *
034   * @param accessToken application access token.
035   * @param scope scope of transactional token.
036   * @return a BoxAPIConnection which can be used to perform transactional requests.
037   */
038  public static BoxAPIConnection getTransactionConnection(String accessToken, String scope) {
039    return BoxTransactionalAPIConnection.getTransactionConnection(accessToken, scope, null);
040  }
041
042  /**
043   * Request a scoped transactional token for a particular resource.
044   *
045   * @param accessToken application access token.
046   * @param scope scope of transactional token.
047   * @param resource resource transactional token has access to.
048   * @return a BoxAPIConnection which can be used to perform transactional requests.
049   */
050  public static BoxAPIConnection getTransactionConnection(
051      String accessToken, String scope, String resource) {
052    BoxAPIConnection apiConnection = new BoxAPIConnection(accessToken);
053
054    URL url;
055    try {
056      url = new URL(apiConnection.getTokenURL());
057    } catch (MalformedURLException e) {
058      assert false : "An invalid token URL indicates a bug in the SDK.";
059      throw new RuntimeException("An invalid token URL indicates a bug in the SDK.", e);
060    }
061
062    String urlParameters;
063    try {
064      urlParameters =
065          String.format(
066              "grant_type=%s&subject_token=%s&subject_token_type=%s&scope=%s",
067              GRANT_TYPE,
068              URLEncoder.encode(accessToken, "UTF-8"),
069              SUBJECT_TOKEN_TYPE,
070              URLEncoder.encode(scope, "UTF-8"));
071
072      if (resource != null) {
073        urlParameters += "&resource=" + URLEncoder.encode(resource, "UTF-8");
074      }
075    } catch (UnsupportedEncodingException e) {
076      throw new BoxAPIException(
077          "An error occurred while attempting to encode url parameters for a transactional token request");
078    }
079
080    // authentication uses form url encoded params but response is JSON
081    BoxAPIRequest request = new BoxAPIRequest(apiConnection, url, "POST");
082    request.shouldAuthenticate(false);
083    request.setBody(urlParameters);
084
085    try (BoxJSONResponse response = (BoxJSONResponse) request.send()) {
086      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
087
088      final String fileToken = responseJSON.get("access_token").asString();
089      BoxTransactionalAPIConnection transactionConnection =
090          new BoxTransactionalAPIConnection(fileToken);
091      transactionConnection.setExpires(responseJSON.get("expires_in").asLong() * 1000);
092
093      return transactionConnection;
094    }
095  }
096
097  /**
098   * Disabling the non-Box Developer Edition authenticate method.
099   *
100   * @param authCode an auth code obtained from the first half of the OAuth process.
101   * @throws UnsupportedOperationException Box Transactional API does not support authentication
102   *     with an auth code
103   */
104  @Override
105  public void authenticate(String authCode) {
106    throw new UnsupportedOperationException(
107        "BoxTransactionalAPIConnection does not support the authenticate method.");
108  }
109
110  /**
111   * BoxTransactionalAPIConnection can never refresh.
112   *
113   * @return false always.
114   */
115  @Override
116  public boolean canRefresh() {
117    return false;
118  }
119
120  /**
121   * Auto refresh is not available for transactional auth.
122   *
123   * @param autoRefresh true to enable auto token refresh; otherwise false.
124   * @throws UnsupportedOperationException Box Transactional API tokens can not be refreshed
125   */
126  @Override
127  public void setAutoRefresh(boolean autoRefresh) {
128    throw new UnsupportedOperationException(
129        "BoxTransactionalAPIConnection does not support token refreshing, "
130            + "access tokens can be generated in the developer console.");
131  }
132
133  /**
134   * Transactional auth does not support token refreshes.
135   *
136   * @throws UnsupportedOperationException Box Transactional API tokens can not be refreshed
137   */
138  @Override
139  public void refresh() {
140    throw new UnsupportedOperationException(
141        "BoxTransactionalAPIConnection does not support token refreshing, "
142            + "access tokens can be generated in the developer console.");
143  }
144}