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 /** 116 * Set this API connection to make API calls on behalf of another users, impersonating them. This 117 * functionality can only be used when using service connection, otherwise it will throw 118 * IllegalStateException 119 * 120 * @param userID the ID of the user to act as. 121 * @throws IllegalStateException when called on User connection 122 */ 123 @Override 124 public void asUser(String userID) { 125 if (isUserConnection()) { 126 throw new IllegalStateException("Cannot add As-User header to connection created for a user."); 127 } 128 super.asUser(userID); 129 } 130 131 /** 132 * Removes impersonation and returns connection to a service one. This undoes any previous calls to asUser(). 133 * 134 * @throws IllegalStateException when called on User connection 135 * @see #asUser 136 */ 137 @Override 138 public void asSelf() { 139 if (isUserConnection()) { 140 throw new IllegalStateException("Cannot remove As-User header from connection created for a user."); 141 } 142 super.asSelf(); 143 } 144 145 public boolean isUserConnection() { 146 return subjectType.equals(USER_SUBJECT_TYPE); 147 } 148 149 @Override 150 public String save() { 151 JsonObject state = new JsonObject() 152 .add("accessToken", this.getAccessToken()) 153 .add("lastRefresh", this.getLastRefresh()) 154 .add("expires", this.getExpires()) 155 .add("userAgent", this.getUserAgent()) 156 .add("tokenURL", this.getTokenURL()) 157 .add("baseURL", this.getBaseURL()) 158 .add("baseUploadURL", this.getBaseUploadURL()) 159 .add("autoRefresh", this.getAutoRefresh()) 160 .add("maxRetryAttempts", this.getMaxRetryAttempts()) 161 .add("subjectType", this.subjectType) 162 .add("subjectId", this.subjectId); 163 return state.toString(); 164 } 165 166 @Override 167 public void restore(String state) { 168 JsonObject json = Json.parse(state).asObject(); 169 String accessToken = json.get("accessToken").asString(); 170 long lastRefresh = json.get("lastRefresh").asLong(); 171 long expires = json.get("expires").asLong(); 172 String userAgent = json.get("userAgent").asString(); 173 String tokenURL = json.get("tokenURL").asString(); 174 String baseURL = json.get("baseURL").asString(); 175 String baseUploadURL = json.get("baseUploadURL").asString(); 176 boolean autoRefresh = json.get("autoRefresh").asBoolean(); 177 String subjectType = json.get("subjectType").asString(); 178 String subjectId = json.get("subjectId").asString(); 179 180 int maxRetryAttempts = -1; 181 if (json.names().contains("maxRetryAttempts")) { 182 maxRetryAttempts = json.get("maxRetryAttempts").asInt(); 183 } 184 185 this.setAccessToken(accessToken); 186 setLastRefresh(lastRefresh); 187 setExpires(expires); 188 setUserAgent(userAgent); 189 setTokenURL(tokenURL); 190 setBaseURL(baseURL); 191 setBaseUploadURL(baseUploadURL); 192 setAutoRefresh(autoRefresh); 193 setMaxRetryAttempts(maxRetryAttempts); 194 this.subjectType = subjectType; 195 this.subjectId = subjectId; 196 197 } 198}