Object Storage Service (OSS) SDK for Android provides the Security Token Service (STS) authentication mode, self-signed mode, and signed URLs to ensure the data security of mobile devices.

Background information

When you use the STS authentication mode or self-signed mode, make sure that the callback function that you implement can return the security token and signature. If you must obtain the token and signature from the app server by sending a request in the callback function, we recommend that you call the synchronous API operations included in the network library. The callback function runs in the child thread of the request generated by the SDK and does not block the main thread.

STS authentication mode

Note To use the STS authentication mode, you must first activate Alibaba Cloud Resource Access Management (RAM).

You can use Alibaba Cloud STS to authorize temporary access to OSS. STS is a web service that provides temporary access tokens for users. You can use STS to grant temporary access credentials that have a custom validity period and custom permissions to a third-party application or a RAM user that is managed by you. For more information about STS, see What is STS?

STS provides the following benefits:

  • You need to only generate an access token and send the access token to a third-party application. You do not need to expose your AccessKey pair to the third-party application. You can specify the access permissions and the validity period of the token.
  • The token automatically expires after the validity period. Therefore, you do not need to manually revoke the access permissions of a token.
Note For more information about how to configure STS, see Use temporary credentials provided by STS to access OSS. You can call the AssumeRole operation or use STS SDKs for various programming languages to obtain temporary access credentials. The temporary access credentials consist of an AccessKey pair and a security token. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. The unit of the validity period of temporary access credentials is seconds. The minimum validity period of temporary access credentials is 900 seconds. The maximum validity period of temporary access credentials is the maximum session duration specified for the current role. For more information, see Specify the maximum session duration for a RAM role.

To access OSS by using temporary access credentials provided by STS, perform the following operations:

  1. Obtain temporary access credentials.

    The temporary access credentials consist of an AccessKey pair and a security token. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. The minimum validity period of temporary access credentials is 900 seconds. The maximum validity period of temporary access credentials is the maximum session duration specified for the current role. For more information, see Specify the maximum session duration for a RAM role.

    You can use one of the following methods to obtain temporary access credentials:

  2. Use temporary access credentials to initialize the SDK
    String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    
    OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider("StsToken.AccessKeyId", "StsToken.SecretKeyId", "StsToken.SecurityToken");
    
    OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider);                  

    When you initialize the SDK by using temporary access credentials, take note of the validity period of an STS token.

    The following code provides an example on how to determine the validity period of an STS token:
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date date = sdf.parse("<StsToken.Expiration>");
    long expiration = date.getTime() / 1000;
    // The STS token is about to expire within less than five minutes. 
    if (DateUtil.getFixedSkewedTimeMillis() / 1000 > expiration - 5 * 60) {
        oss.updateCredentialProvider(new OSSStsTokenCredentialProvider("StsToken.AccessKeyId", "StsToken.SecretKeyId", "StsToken.SecurityToken"));
    }
    • Manually update the STS token

      When the STS token is about to expire, you can create another OSSClient instance or update CredentialProvider by running the following command:

      oss.updateCredentialProvider(new OSSStsTokenCredentialProvider("StsToken.AccessKeyId", "StsToken.SecretKeyId", "StsToken.SecurityToken"));                   
    • Automatically update the STS token

      If you want the SDK to automatically update the STS token, you must implement callback in your app. The app uses the callback to obtain a federation token (STS token) and returns the token to the SDK. The SDK uses the STS token to generate signatures. When the STS token needs to be updated, the SDK calls the callback to obtain a new token.

      String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
      
      OSSCredentialProvider credentialProvider = new OSSFederationCredentialProvider() {
      
          @Override
          public OSSFederationToken getFederationToken() {
          // Obtain a federation token, construct the token, and then return the token as an OSSFederationToken object. If no federation token is obtained, null is returned. 
      
              OSSFederationToken token;
              // Obtain a federation token from your server. 
              return token;
          }
      };
      
      OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider);                    
      Note If you obtain all fields required to generate a token in other ways, you can also return these fields by using the callback. In this case, you must manually update the token, and then reconfigure OSSCredentialProvider of the OSSClient instance.

      If the URL of the server from which you request a token is http://localhost:8080/distribute-token.json, the following data is returned:

      {
          "StatusCode": 200,
          "AccessKeyId":"STS.iA645eTOXEqP3cg3****",
          "AccessKeySecret":"rV3VQrpFQ4BsyHSAvi5NVLpPIVffDJv4LojU****",
          "Expiration":"2015-11-03T09:52:59Z",
          "SecurityToken":"CAES7QIIARKAAZPlqaN9ILiQZPS+JDkS/GSZN45RLx4YS/p3OgaUC+oJl3XSlbJ7StKpQ****"}                    

      The following code provides an example on how to implement OSSFederationCredentialProvider:

      OSSCredentialProvider credetialProvider = new OSSFederationCredentialProvider() {
          @Override
          public OSSFederationToken getFederationToken() {
              try {
                  URL stsUrl = new URL("http://localhost:8080/distribute-token.json");
                  HttpURLConnection conn = (HttpURLConnection) stsUrl.openConnection();
                  InputStream input = conn.getInputStream();
                  String jsonText = IOUtils.readStreamAsString(input, OSSConstants.DEFAULT_CHARSET_NAME);
                  JSONObject jsonObjs = new JSONObject(jsonText);
                  String ak = jsonObjs.getString("AccessKeyId");
                  String sk = jsonObjs.getString("AccessKeySecret");
                  String token = jsonObjs.getString("SecurityToken");
                  String expiration = jsonObjs.getString("Expiration");
                  return new OSSFederationToken(ak, sk, token, expiration);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return null;
          }
      };                    

Self-signed mode

You can perform the following operations to save the AccessKey ID and AccessKey secret to your own server and then sign the client information on your server:
  1. Obtain the string-to-sign from the client and send the string to your own server.
    1. Use the signContent method of OSSCustomSignerCredentialProvider provided by Object Storage Service (OSS) SDK for Android to obtain the string-to-sign when you create the request.
    2. Send the string-to-sign to your own server.
  2. Sign the string on your own server and return the signed string to the client.
    1. Use the specified signature algorithm to sign the string. For more information about the signature algorithm, see Include signatures in the Authorization header.

      The signature algorithm is in the following format: signature = "OSS " + AccessKeyId + ":" + base64(hmac-sha1(AccessKeySecret, content)), in which content is the string that is concatenated based on the request parameters.

    2. Return the signed string to the client.

      For example, the URL of the server is http://localhost:8080/sign. You can send the content to the server to generate a signature. Then, the server returns the signature to the client. The following sample code provides an example:

      String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
      
      OSSCredentialProvider credentialProvider = new OSSCustomSignerCredentialProvider() {
          @Override
          public String signContent(String content) {
              URL stsUrl = new URL("http://localhost:8080/sign?content=" + content);
              HttpURLConnection conn = (HttpURLConnection) stsUrl.openConnection();
              InputStream input = conn.getInputStream();
              String jsonText = IOUtils.readStreamAsString(input, OSSConstants.DEFAULT_CHARSET_NAME);
              JSONObject jsonObjs = new JSONObject(jsonText);
              String signature = jsonObjs.getString("signature");
              return signature;
          }
      };
      OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider);
  3. Send the signed string on the client to the OSS server for authentication.
fig

Signed URLs

You can generate a signed URL and provide the URL to a visitor for temporary access. When you generate a signed URL, you can specify the validity period of the URL to limit the period of time during which the visitor can access the object.

Important If you use the following code to generate a signed URL that contains the plus sign (+), you may fail to access OSS by using the URL. In this case, you must replace the plus sign (+) in the URL with %2B.

The following code provides an example on how to generate a signed URL and use the signed URL to upload and download objects.

Generate a signed URL and use the signed URL to upload an object

  1. Generate a signed URL
    // Specify the bucket name. Example: examplebucket. 
    String bucketName = "examplebucket";
    // Specify the full path of the source object. The full path of the object cannot contain the bucket name. Example: exampleobject.txt. 
    String objectKey = "exampleobject.txt";
    // Specify Content-Type. 
    String contentType = "application/octet-stream";
    String url = null;
    try {
        // Generate a signed URL used to upload the object. 
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey);
        // Set the validity period of the signed URL to 30 minutes. 
        request.setExpiration(30*60);
        request.setContentType(contentType);    
        request.setMethod(HttpMethod.PUT);
        url = mOss.presignConstrainedObjectURL(request);
        Log.d("url", url);
    } catch (ClientException e) {
        e.printStackTrace();
    }
  2. Upload an object by using the signed URL
    // Enter the generated signed URL. 
    String url = "";
    // Specify the full path of the local file. 
    String localFile = "/storage/emulated/0/oss/examplefile";
    // Specify Content-Type. 
    String contentType = "application/octet-stream";
    // Upload the object by using the signed URL. 
    OkHttpClient client = new OkHttpClient();
    Request putRequest = new Request.Builder()
            .url(url)
            .put(RequestBody.create(MediaType.parse(contentType), new File(localFile)))
            .build();
    client.newCall(putRequest).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.d("response", response.body().string());
        }
    });

Generate a signed URL and use the signed URL to download an object

  1. Generate a signed URL
    // Specify the bucket name. Example: examplebucket. 
    String bucketName = "examplebucket";
    // Specify the full path of the source object. The full path of the object cannot contain the bucket name. Example: exampleobject.txt. 
    String objectKey = "exampleobject.txt";
    String url = null;
    try {
        // Generate a signed URL used to download the object. 
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey);
        // Set the validity period of the signed URL to 30 minutes. 
        request.setExpiration(30*60);
        request.setMethod(HttpMethod.GET);
        url = mOss.presignConstrainedObjectURL(request);
        Log.d("url", url);
    } catch (ClientException e) {
        e.printStackTrace();
    }
  2. Download an object by using the signed URL
    // Enter the generated signed URL. 
    String url = "";
    OkHttpClient client = new OkHttpClient();
    // Use the signed URL to download the object. 
    Request getRequest = new Request.Builder()
            .url(url)
            .get()
            .build();
    client.newCall(getRequest).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.code() == 203 || response.code() >= 300) {
                Log.d("download", "fail");
                Log.d("download", response.body().string());
                return;
            }
            // The specified part of the object is downloaded. 
            InputStream inputStream = response.body().byteStream();
    
            byte[] buffer = new byte[2048];
            int len;
    
            while ((len = inputStream.read(buffer)) != -1) {
                // Process the downloaded data. For example, display the image or perform a write operation on the object. 
            }
        }
    });