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

Usage notes

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

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:

    • Method 1:

      You can call the AssumeRole operation to obtain temporary access credentials.

    • Method 2:

      You can use STS SDKs to obtain temporary access credentials. For more information, see STS SDK overview.

  2. Use temporary access credentials to initialize OSS SDK for iOS.
    id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"];
    client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
    Note To use OSSAuthCredentialProvider to initialize OSS SDK for iOS, see Initialization.

    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:

    NSDateFormatter * fm = [NSDateFormatter new];
    fm.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    [fm setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
    NSDate *expirationDate = [fm dateFromString:@"<StsToken.Expiration>"];
    NSTimeInterval interval = [expirationDate timeIntervalSinceDate:[NSDate date]];
    // The STS token is about to expire within less than five minutes. 
    if (interval < 5 * 60) {
        id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"];
        client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
    }
    • Manually update the STS token

      When the STS token is about to expire, you can create a new OSSClient instance or update CredentialProvider by using the following method:

      id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"];
      client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
    • 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.

      id<OSSCredentialProvider> credential = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * {
          // Obtain a FederationToken and return it as an OSSFederationToken object. 
          // If the FederationToken is not obtained, nil is returned. 
            OSSFederationToken * token;
          // Obtain a FederationToken from your server. 
          ...
          return token;
      }];
      client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
      Note If you obtain all fields required to generate an STS token in other ways, you can directly return the token in 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:

      id<OSSCredentialProvider> credential2 = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * {
          // Create a request to access your service server. 
          NSURL * url = [NSURL URLWithString:@"http://localhost:8080/distribute-token.json"];
          // Use a request to set the parameters required by your server. 
          NSURLRequest * request = [NSURLRequest requestWithURL:url];
          OSSTaskCompletionSource * tcs = [OSSTaskCompletionSource taskCompletionSource];
          NSURLSession * session = [NSURLSession sharedSession];
          // Send the request. 
          NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request
                                                      completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                          if (error) {
                                                              [tcs setError:error];
                                                              return;
                                                          }
                                                          [tcs setResult:data];
                                                      }];
          [sessionTask resume];
          // Wait until the response to the request is returned. 
          [tcs.task waitUntilFinished];
          // Parse the returned results. 
          if (tcs.task.error) {
              NSLog(@"get token error: %@", tcs.task.error);
              return nil;
          } else {
              // The returned data is in the JSON format. Parse the data to obtain the values of the fields of the token. 
              NSDictionary * object = [NSJSONSerialization JSONObjectWithData:tcs.task.result
                                                                      options:kNilOptions
                                                                        error:nil];
              OSSFederationToken * token = [OSSFederationToken new];
              token.tAccessKey = [object objectForKey:@"AccessKeyId"];
              token.tSecretKey = [object objectForKey:@"AccessKeySecret"];
              token.tToken = [object objectForKey:@"SecurityToken"];
              token.expirationTimeInGMTFormat = [object objectForKey:@"Expiration"];
              NSLog(@"get token: %@", token);
              return token;
          }
      }];

Self-signed mode

You can perform the following operations to save the AccessKey ID and AccessKey secret to your own server and sign the client information on your server. Perform the following steps:
  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 OSS SDK for iOS 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. Sample code:

      id<OSSCredentialProvider> credential = [[OSSCustomSignerCredentialProvider alloc] initWithImplementedSigner:^NSString *(NSString *contentToSign, NSError *__autoreleasing *error) {
          // Use the specified signature algorithm to sign a string, concatenate your AccessKey ID to the signed string, and then return the final string. 
          // Send the signed string to your own server and return the signature. 
          // If the string fails to be signed, the server returns nil with an error message. 
      NSString *signature = [OSSUtil calBase64Sha1WithData:contentToSign withSecret:@"<your accessKeySecret>"]; // In this example, the string is signed on the client by using the tool provided by OSS SDK for iOS. We recommend that you sign the string on your business server. 
          if (signature != nil) {
              *error = nil;
          } else {
              *error = [NSError errorWithDomain:@"<your domain>" code:-1001 userInfo:@"<your error info>"];
              return nil;
          }
          return [NSString stringWithFormat:@"OSS %@:%@", @"<your accessKeyId>", signature];
      }];
      
      client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
                  
    2. Return the signed string to the client.
  3. Send the signed string on the client to the OSS server for authentication.

Signed URLs

You can use signed URLs to upload and download objects.

Use a signed URL to upload an object

  1. Generate a signed URL used to upload the object.
    // Specify the name of the bucket. 
    NSString *bucketName = @"examplebucket";
    // Specify the name of the object. 
    NSString *objectKey = @"exampleobject.txt";
    NSURL *file = [NSURL fileURLWithPath:@"<filePath>"];
    NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey];
    __block NSString *urlString;
    // Generate a signed URL with a specified validity period for uploading the object. In this example, the validity period of the URL is 30 minutes. 
    OSSTask *task = [client presignConstrainURLWithBucketName:bucketName
                                                withObjectKey:objectKey
                                                   httpMethod:@"PUT"
                                       withExpirationInterval:30 * 60
                                               withParameters:@{}
                                                  contentType:contentType
                                                   contentMd5:nil];
    [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
        if (task.error) {
            NSLog(@"presign error: %@", task.error);
        } else {
            urlString = task.result;
            NSLog(@"url: %@", urlString);
        }
        return nil;
    }];
  2. Use the signed URL to upload the object.
    // Upload the object by using the signed URL. 
    NSURL * url = [NSURL URLWithString:urlString];
    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"PUT";
    request.allHTTPHeaderFields = @{OSSHttpHeaderContentType: contentType};
    NSURLSession * session = [NSURLSession sharedSession];
    NSURLSessionTask * sessionTask = [session uploadTaskWithRequest:request
                                                           fromFile:file
                                                  completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"upload error: %@", error);
            return;
        } else if (((NSHTTPURLResponse*)response).statusCode == 203 ||
                   ((NSHTTPURLResponse*)response).statusCode >= 300) {
            NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"upload error: %@", body);
            return;
        }
        NSLog(@"upload success");
    }];
    [sessionTask resume];

Use a signed URL to download an object

  1. Generate a signed URL used to download the object.
    // Specify the name of the bucket. 
    NSString *bucketName = @"examplebucket";
    // Specify the name of the object. 
    NSString *objectKey = @"exampleobject.txt";
    __block NSString *urlString;
    // Generate a signed URL with a specified validity period for downloading the object. In this example, the validity period of the URL is 30 minutes. 
    OSSTask *task = [client presignConstrainURLWithBucketName:bucketName
                                                withObjectKey:objectKey
                                                   httpMethod:@"GET"
                                       withExpirationInterval:30 * 60
                                               withParameters:@{}];
    [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
        if (task.error) {
            NSLog(@"presign error: %@", task.error);
        } else {
            urlString = task.result;
            NSLog(@"url: %@", urlString);
        }
        return nil;
    }];
  2. Use the signed URL to download the object.
    // Use the signed URL to download the object. 
    NSURL * url = [NSURL URLWithString:urlString];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    NSURLSession * session = [NSURLSession sharedSession];
    NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"download error: %@", error);
            return;
        } else if (((NSHTTPURLResponse*)response).statusCode == 203 ||
                   ((NSHTTPURLResponse*)response).statusCode >= 300) {
            NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"download error: %@", body);
            return;
        }
        NSLog(@"download success");
    }];
    [sessionTask resume];