package com.tencent.cloud; import com.tencent.cloud.cos.util.Request; import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; public class CosStsClient { private static final int DEFAULT_DURATION_SECONDS = 1800; public static final String STS_DEFAULT_HOST = "sts.tencentcloudapi.com"; public static JSONObject getCredential(TreeMap<String, Object> config) throws IOException { TreeMap<String, Object> params = new TreeMap<String, Object>(); Parameters parameters = new Parameters(); parameters.parse(config); if(parameters.secretId == null) throw new IllegalArgumentException("secretId is null"); if(parameters.secretKey == null) throw new IllegalArgumentException("secretKey is null"); String policy = parameters.policy; if (policy != null) { params.put("Policy", policy); } else { params.put("Policy", getPolicy(parameters).toString()); } params.put("DurationSeconds", parameters.duration); params.put("Name", "cos-sts-java"); params.put("Action", "GetFederationToken"); params.put("Version", "2018-08-13"); String region = RegionCodeFilter.convert(parameters.region); params.put("Region", region); if(parameters.secretType != null) { params.put("SecretType", parameters.secretType); } String host = STS_DEFAULT_HOST; if (parameters.host != null) { host = parameters.host; } String path = "/"; String result = null; JSONObject jsonResult = null; try { result = Request.send(params, (String) parameters.secretId, parameters.secretKey, "POST", host, STS_DEFAULT_HOST, path); jsonResult = new JSONObject(result); JSONObject data = jsonResult.optJSONObject("Response"); if (data == null) { data = jsonResult; } long expiredTime = data.getLong("ExpiredTime"); data.put("startTime", expiredTime - parameters.duration); return downCompat(data); } catch (Exception e) { if (jsonResult != null) { JSONObject response = jsonResult.optJSONObject("Response"); if (response != null) { JSONObject error = response.optJSONObject("Error"); if (error != null) { String message = error.optString("Message"); String code = error.optString("Code"); if ("InvalidParameterValue".equals(code) && message != null && message.contains("Region")) { // Region is not recognized if (RegionCodeFilter.block(region)) { return getCredential(config); } } } } } throw new IOException("result = " + result, e); } } public static String getPolicy(List<Scope> scopes) { if(scopes == null || scopes.size() == 0)return null; STSPolicy stsPolicy = new STSPolicy(); stsPolicy.addScope(scopes); return stsPolicy.toString(); } // v2接口的key首字母小写,v3改成大写,此处做了向下兼容 private static JSONObject downCompat(JSONObject resultJson) { JSONObject dcJson = new JSONObject(); for (String key : resultJson.keySet()) { Object value = resultJson.get(key); if (value instanceof JSONObject) { dcJson.put(headerToLowerCase(key), downCompat((JSONObject) value)); } else { String newKey = "Token".equals(key) ? "sessionToken" : headerToLowerCase(key); dcJson.put(newKey, resultJson.get(key)); } } return dcJson; } private static String headerToLowerCase(String source) { return Character.toLowerCase(source.charAt(0)) + source.substring(1); } private static JSONObject getPolicy(Parameters parameters) { if(parameters.bucket == null) { throw new IllegalArgumentException("bucket == null"); } if(parameters.allowPrefixes == null) { throw new IllegalArgumentException("allowPrefixes == null"); } if(parameters.region == null) { throw new IllegalArgumentException("region == null"); } String bucket = parameters.bucket; String region = parameters.region; int lastSplit = bucket.lastIndexOf("-"); String appId = bucket.substring(lastSplit + 1); String[] allowPrefixes = parameters.allowPrefixes; List<String> resources = new ArrayList<String>(allowPrefixes.length); for (String prefix : allowPrefixes) { String p = prefix; if(!p.startsWith("/")) { p = "/" + p; } String resource = String.format("qcs::cos:%s:uid/%s:%s%s", region, appId, bucket, p); resources.add(resource); } JSONObject policy = new JSONObject(); policy.put("version", "2.0"); JSONArray statements = new JSONArray(); JSONObject statement = new JSONObject(); statement.put("effect", "allow"); statement.put("action", parameters.allowActions); statement.put("resource", resources.toArray(new String[0])); statements.put(statement); policy.put("statement", statements); return policy; } private static class Parameters{ String secretId; String secretKey; int duration = DEFAULT_DURATION_SECONDS; String bucket; String region; String[] allowPrefixes; String[] allowActions; String policy; Integer secretType; // option argument, only can choose 0 or 1, 0 for long certificate, 1 for short certificate String host; public void parse(Map<String, Object> config) { if(config == null) throw new NullPointerException("config == null"); for(Map.Entry<String, Object> entry : config.entrySet()) { String key = entry.getKey(); if("SecretId".equalsIgnoreCase(key)) { secretId = (String) entry.getValue(); }else if("SecretKey".equalsIgnoreCase(key)) { secretKey = (String) entry.getValue(); }else if("durationSeconds".equalsIgnoreCase(key)) { duration = (Integer) entry.getValue(); }else if("bucket".equalsIgnoreCase(key)) { bucket = (String) entry.getValue(); }else if("region".equalsIgnoreCase(key)) { region = (String) entry.getValue(); }else if("allowPrefix".equalsIgnoreCase(key)) { allowPrefixes = new String[] { (String) entry.getValue() }; }else if("allowPrefixes".equalsIgnoreCase(key)) { allowPrefixes = (String[]) entry.getValue(); }else if("policy".equalsIgnoreCase(key)) { policy = (String) entry.getValue(); }else if("allowActions".equalsIgnoreCase(key)) { allowActions = (String[]) entry.getValue(); }else if("secretType".equalsIgnoreCase(key)) { secretType = (Integer)entry.getValue(); }else if("host".equalsIgnoreCase(key)) { host = (String)entry.getValue(); } } } } }