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