001package com.box.sdk;
002
003import static com.box.sdk.http.ContentType.APPLICATION_FORM_URLENCODED;
004
005import com.eclipsesource.json.Json;
006import com.eclipsesource.json.JsonObject;
007import java.net.URL;
008
009/**
010 * Creates and manages Client Credentials Grant API connection.
011 */
012public final class BoxCCGAPIConnection extends BoxAPIConnection {
013
014    static final String ENTERPRISE_SUBJECT_TYPE = "enterprise";
015    static final String USER_SUBJECT_TYPE = "user";
016    private String subjectType;
017    private String subjectId;
018
019    // Hiding constructor
020    private BoxCCGAPIConnection(String accessToken) {
021        super(accessToken);
022    }
023
024    // Hiding constructor
025    private BoxCCGAPIConnection(String clientID, String clientSecret, String accessToken, String refreshToken) {
026        super(clientID, clientSecret, accessToken, refreshToken);
027    }
028
029    // Hiding constructor
030    private BoxCCGAPIConnection(String clientID, String clientSecret, String authCode) {
031        super(clientID, clientSecret, authCode);
032    }
033
034    // Hiding constructor
035    private BoxCCGAPIConnection(String clientID, String clientSecret) {
036        super(clientID, clientSecret);
037    }
038
039    // Hiding constructor
040    private BoxCCGAPIConnection(BoxConfig boxConfig) {
041        super(boxConfig);
042    }
043
044    /**
045     * Creates connection that authenticates as a Service Account
046     *
047     * @param clientId     the client ID to use when getting the access token.
048     * @param clientSecret the client secret to use when getting the access token.
049     * @param enterpriseId the enterprise ID to use when getting the access token.
050     * @return Client Credentials Grant API connection.
051     */
052    public static BoxCCGAPIConnection applicationServiceAccountConnection(
053        String clientId, String clientSecret, String enterpriseId
054    ) {
055        BoxCCGAPIConnection api = new BoxCCGAPIConnection(clientId, clientSecret);
056        api.subjectType = ENTERPRISE_SUBJECT_TYPE;
057        api.subjectId = enterpriseId;
058        return api;
059    }
060
061    /**
062     * Creates connection that authenticates as a User
063     *
064     * @param clientId     the client ID to use when getting the access token.
065     * @param clientSecret the client secret to use when getting the access token.
066     * @param userId       the user ID to use when getting the access token.
067     * @return Client Credentials Grant API connection.
068     */
069    public static BoxCCGAPIConnection userConnection(String clientId, String clientSecret, String userId) {
070        BoxCCGAPIConnection api = new BoxCCGAPIConnection(clientId, clientSecret);
071        api.subjectType = USER_SUBJECT_TYPE;
072        api.subjectId = userId;
073        return api;
074    }
075
076    /**
077     * Restores a BoxAPIConnection from a saved state.
078     *
079     * @param clientID     the client ID to use with the connection.
080     * @param clientSecret the client secret to use with the connection.
081     * @param state        the saved state that was created with {@link #save}.
082     * @return a restored API connection.
083     * @see #save
084     */
085    public static BoxCCGAPIConnection restore(String clientID, String clientSecret, String state) {
086        BoxCCGAPIConnection api = new BoxCCGAPIConnection(clientID, clientSecret);
087        api.restore(state);
088        return api;
089    }
090
091    @Override
092    protected BoxAPIRequest createTokenRequest(URL url) {
093        String urlParameters = String.format(
094            "grant_type=client_credentials&client_id=%s&client_secret=%s&box_subject_type=%s&box_subject_id=%s",
095            this.getClientID(), this.getClientSecret(), this.subjectType, this.subjectId);
096        BoxAPIRequest request = new BoxAPIRequest(this, url, "POST");
097        request.shouldAuthenticate(false);
098        request.setBody(urlParameters);
099        request.addHeader("Content-Type", APPLICATION_FORM_URLENCODED);
100        return request;
101    }
102
103    @Override
104    protected void extractTokens(JsonObject jsonObject) {
105        this.setAccessToken(jsonObject.get("access_token").asString());
106        this.setLastRefresh(System.currentTimeMillis());
107        this.setExpires(jsonObject.get("expires_in").asLong() * 1000);
108    }
109
110    @Override
111    public boolean canRefresh() {
112        return true;
113    }
114
115    public boolean isUserConnection() {
116        return subjectType.equals(USER_SUBJECT_TYPE);
117    }
118
119    @Override
120    public String save() {
121        JsonObject state = new JsonObject()
122            .add("accessToken", this.getAccessToken())
123            .add("lastRefresh", this.getLastRefresh())
124            .add("expires", this.getExpires())
125            .add("userAgent", this.getUserAgent())
126            .add("tokenURL", this.getTokenURL())
127            .add("baseURL", this.getBaseURL())
128            .add("baseUploadURL", this.getBaseUploadURL())
129            .add("autoRefresh", this.getAutoRefresh())
130            .add("maxRetryAttempts", this.getMaxRetryAttempts())
131            .add("subjectType", this.subjectType)
132            .add("subjectId", this.subjectId);
133        return state.toString();
134    }
135
136    @Override
137    public void restore(String state) {
138        JsonObject json = Json.parse(state).asObject();
139        String accessToken = json.get("accessToken").asString();
140        long lastRefresh = json.get("lastRefresh").asLong();
141        long expires = json.get("expires").asLong();
142        String userAgent = json.get("userAgent").asString();
143        String tokenURL = json.get("tokenURL").asString();
144        String baseURL = json.get("baseURL").asString();
145        String baseUploadURL = json.get("baseUploadURL").asString();
146        boolean autoRefresh = json.get("autoRefresh").asBoolean();
147        String subjectType = json.get("subjectType").asString();
148        String subjectId = json.get("subjectId").asString();
149
150        int maxRetryAttempts = -1;
151        if (json.names().contains("maxRetryAttempts")) {
152            maxRetryAttempts = json.get("maxRetryAttempts").asInt();
153        }
154
155        this.setAccessToken(accessToken);
156        setLastRefresh(lastRefresh);
157        setExpires(expires);
158        setUserAgent(userAgent);
159        setTokenURL(tokenURL);
160        setBaseURL(baseURL);
161        setBaseUploadURL(baseUploadURL);
162        setAutoRefresh(autoRefresh);
163        setMaxRetryAttempts(maxRetryAttempts);
164        this.subjectType = subjectType;
165        this.subjectId = subjectId;
166
167    }
168}