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