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