Linux 代码示例Linux code examples

重要

弃用2020年3月之前发布的 Microsoft Rights Management Service SDK 版本;必须将使用早期版本的应用程序更新为使用三月2020版。Versions of the Microsoft Rights Management Service SDK released prior to March 2020 are deprecated; applications using earlier versions must be updated to use the March 2020 release. 有关完整详细信息,请参阅弃用通知For full details, see the deprecation notice.

不会为 Microsoft Rights Management 服务 SDK 规划进一步的增强功能。No further enhancements are planned for the Microsoft Rights Management Service SDK. 我们强烈建议采用Microsoft Information PROTECTION SDK进行分类、标记和保护服务。We strongly recommend adoption of the Microsoft Information Protection SDK for classification, labeling, and protection services.

本主题向你介绍 Linux 版 RMS SDK 的重要方案和代码元素。This topic introduces you to important scenarios and code elements for the Linux version of the RMS SDK.

以下代码片段取自示例应用程序 rms_samplermsauth_sampleThe code snippets below are from the sample applications, rms_sample and rmsauth_sample. 相关详细信息,请参阅 GitHub 存储库中的示例For more information, see samples at the GitHub repository.

方案,通过受保护的文件访问保护策略信息Scenario: Access protection policy information from a protected file

打开并读取受 RMS 保护的文件 rms _ sample/mainwindow.xamlOpens and reads an RMS protected file Source: rms_sample/mainwindow.cpp

说明:在从用户处获取文件名后,读取证书(参见 MainWindow::addCertificates),使用客户端 ID 和重定向 URL 设置身份验证回调,调用 ConvertFromPFile(参见以下代码示例),然后读取保护策略名称、说明和内容有效性日期。Description: After getting a file name from the user, reading the certificates (see MainWindow::addCertificates), setting up the authorization callback with Client ID and Redirect URL, calling ConvertFromPFile (see following code example), then reading out the protection policy name, description and content validity date.

C + +C++:

  void MainWindow::ConvertFromPFILE(const string& fileIn,
      const string& clientId,
      const string& redirectUrl,
      const string& clientEmail) 
  {
  // add trusted certificates using HttpHelpers of RMS and Auth SDKs
  addCertificates();
  
  // create shared in/out streams
  auto inFile = make_shared<ifstream>(
  fileIn, ios_base::in | ios_base::binary);
  
  if (!inFile->is_open()) {
   AddLog("ERROR: Failed to open ", fileIn.c_str());
  return;
  }
  
  string fileOut;
  
  // generate output filename
  auto pos = fileIn.find_last_of('.');
  
  if (pos != string::npos) {
   fileOut = fileIn.substr(0, pos);
  }
  
   // create streams
  auto outFile = make_shared<fstream>(
  fileOut, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
  
  if (!outFile->is_open()) {
   AddLog("ERROR: Failed to open ", fileOut.c_str());
   return;
    }
  
  try
  {
  // create authentication context
  AuthCallback auth(clientId, redirectUrl);
  
  // process conversion
  auto pfs = PFileConverter::ConvertFromPFile(
    clientEmail,
    inFile,
    outFile,
    auth,
    this->consent);
  
  AddLog("Successfully converted to ", fileOut.c_str());
  }
  catch (const rmsauth::Exception& e)
  {
  AddLog("ERROR: ", e.error().c_str());
  }
  catch (const rmscore::exceptions::RMSException& e) {
  AddLog("ERROR: ", e.what());
  }
  inFile->close();
  outFile->close();
  }

创建受保护的文件流 rms _ sample/pfileconverter.cppCreate a protected file stream Source: rms_sample/pfileconverter.cpp

说明:此方法通过 SDK 方法( ProtectedFileStream::获取)创建受保护的文件流,然后将其返回给调用方。Description: This method creates a protected file stream from the passed in backing stream through the SDK method, ProtectedFileStream::Acquire, which is then returned to the caller.

C + +C++:

  shared_ptr<GetProtectedFileStreamResult>PFileConverter::ConvertFromPFile(
  const string           & userId,
  shared_ptr<istream>      inStream,
  shared_ptr<iostream>     outStream,
  IAuthenticationCallback& auth,
  IConsentCallback       & consent)
  {
  auto inIStream = rmscrypto::api::CreateStreamFromStdStream(inStream);
  
  auto fsResult = ProtectedFileStream::Acquire(
  inIStream,
  userId,
  auth,
  consent,
  POL_None,
  static_cast<ResponseCacheFlags>(RESPONSE_CACHE_INMEMORY
                                  | RESPONSE_CACHE_ONDISK));
  
  if ((fsResult.get() != nullptr) && (fsResult->m_status == Success) &&
    (fsResult->m_stream != nullptr)) {
  auto pfs = fsResult->m_stream;
  
  // preparing
  readPosition  = 0;
  writePosition = 0;
  totalSize     = pfs->Size();
  
  // start threads
  for (size_t i = 0; i < THREADS_NUM; ++i) {
    threadPool.push_back(thread(WorkerThread,
                                static_pointer_cast<iostream>(outStream), pfs,
                                false));
  }
  
  for (thread& t: threadPool) {
    if (t.joinable()) {
      t.join();
    }
  }
  }
    return fsResult;
  }

方案:使用模板创建新的受保护文件Scenario: Create a new protected file using a template

使用用户选定的模板 保护文件rms _ sample/mainwindow.xamlProtects a file with a user selected template Source: rms_sample/mainwindow.cpp

说明:在从用户处获取文件名,读取证书(参见 MainWindow::addCertificates)并使用客户端 ID 和重定向 URL 设置身份验证回调之后,所选文件将通过调用 ConvertToPFileTemplates 进行保护(参见下方代码示例)。Description: After getting a file name from the user, reading the certificates (see MainWindow::addCertificates) and setting up the authorization callback with Client ID and Redirect URL, the selected file is protected by calling ConvertToPFileTemplates (see following code example).

C + +C++:

  void MainWindow::ConvertToPFILEUsingTemplates(const string& fileIn,
                                            const string& clientId,
                                            const string& redirectUrl,
                                            const string& clientEmail) 
  {
  // generate output filename
  string fileOut = fileIn + ".pfile";
  
  // add trusted certificates using HttpHelpers of RMS and Auth SDKs
  addCertificates();
  
  // create shared in/out streams
  auto inFile = make_shared<ifstream>(
  fileIn, ios_base::in | ios_base::binary);
  auto outFile = make_shared<fstream>(
  fileOut, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
  
  if (!inFile->is_open()) {
  AddLog("ERROR: Failed to open ", fileIn.c_str());
  return;
  }
  
  if (!outFile->is_open()) {
  AddLog("ERROR: Failed to open ", fileOut.c_str());
  return;
  }
  
  // find file extension
  string fileExt;
  auto   pos = fileIn.find_last_of('.');
  
  if (pos != string::npos) {
  fileExt = fileIn.substr(pos);
  }
  
  try {
  // create authentication callback
  AuthCallback auth(clientId, redirectUrl);
  
  // process conversion
  PFileConverter::ConvertToPFileTemplates(
    clientEmail, inFile, fileExt, outFile, auth,
    this->consent, this->templates);
  
  AddLog("Successfully converted to ", fileOut.c_str());
  }
 catch (const rmsauth::Exception& e) {
  AddLog("ERROR: ", e.error().c_str());
  outFile->close();
  remove(fileOut.c_str());
  }
  catch (const rmscore::exceptions::RMSException& e) {
  AddLog("ERROR: ", e.what());
  
  outFile->close();
  remove(fileOut.c_str());
  }
  inFile->close();
  outFile->close();
  }

使用通过模板 创建的策略来保护文件rms _ sample/pfileconverter.cppProtects a file using a policy created from a template Source: rms_sample/pfileconverter.cpp

说明:提取与用户关联的模板列表,随后使用所选模板创建转而用于保护文件的策略。Description: A list of templates associated with the user is fetched and selected template is then used to create a policy which in turn is used to protect the file.

C + +C++:

  void PFileConverter::ConvertToPFileTemplates(const string           & userId,
                                           shared_ptr<istream>      inStream,
                                           const string           & fileExt,
                                           std::shared_ptr<iostream>outStream,
                                           IAuthenticationCallback& auth,
                                           IConsentCallback& /*consent*/,
                                           ITemplatesCallback     & templ)
  {
  auto templates = TemplateDescriptor::GetTemplateList(userId, auth);
  
  rmscore::modernapi::AppDataHashMap signedData;
  
  size_t pos = templ.SelectTemplate(templates);
  
  if (pos < templates.size()) {
  auto policy = UserPolicy::CreateFromTemplateDescriptor(
    templates[pos],
    userId,
    auth,
    USER_AllowAuditedExtraction,
    signedData);
 
  ConvertToPFileUsingPolicy(policy, inStream, fileExt, outStream);
  }
  }

保护给定策略 的文件rms _ sample/pfileconverter.cppProtects a file given a policy Source: rms_sample/pfileconverter.cpp

说明:使用给定策略创建受保护的文件流,然后保护此文件。Description: Create a protected file stream using the given policy then protect that file.

C + +C++:

  void PFileConverter::ConvertToPFileUsingPolicy(shared_ptr<UserPolicy>   policy,
                                             shared_ptr<istream>      inStream,
                                             const string           & fileExt,
                                             std::shared_ptr<iostream>outStream)
  {
  if (policy.get() != nullptr) {
  auto outIStream = rmscrypto::api::CreateStreamFromStdStream(outStream);
  auto pStream    = ProtectedFileStream::Create(policy, outIStream, fileExt);
  
  // preparing
  readPosition  = 0;
  writePosition = pStream->Size();
  
  inStream->seekg(0, ios::end);
  totalSize = inStream->tellg();
  
  // start threads
  for (size_t i = 0; i < THREADS_NUM; ++i) {
    threadPool.push_back(thread(WorkerThread,
                                static_pointer_cast<iostream>(inStream),
                                pStream,
                                true));
  }
  
  for (thread& t: threadPool) {
    if (t.joinable()) {
      t.join();
    }
  }
  
  pStream->Flush();
  }

方案:使用自定义保护来保护文件Scenario: Protect a file using custom protection

使用自定义保护 保护文件rms _ sample/mainwindow.xamlProtects a file using custom protection Source: rms_sample/mainwindow.cpp

说明:在从用户处获取文件名,读取证书(参见 MainWindow::addCertificates),从用户处收集权限信息,并使用客户端 ID 和重定向 URL 设置身份验证回调之后,所选文件将通过调用 ConvertToPFilePredefinedRights 进行保护(参见下方代码示例)。Description: After getting a file name from the user, reading the certificates (see MainWindow::addCertificates), collecting rights information from the user, and setting up the authorization callback with Client ID and Redirect URL, the selected file is projected by calling ConvertToPFilePredefinedRights (see following code example).

C + +C++:

  void MainWindow::ConvertToPFILEUsingRights(const string            & fileIn,
                                         const vector<UserRights>& userRights,
                                         const string            & clientId,
                                         const string            & redirectUrl,
                                         const string            & clientEmail)
  {
  // generate output filename
  string fileOut = fileIn + ".pfile";
  
  // add trusted certificates using HttpHelpers of RMS and Auth SDKs
  addCertificates();
  
  // create shared in/out streams
  auto inFile = make_shared<ifstream>(
  fileIn, ios_base::in | ios_base::binary);
  auto outFile = make_shared<fstream>(
  fileOut, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
  
  if (!inFile->is_open()) {
  AddLog("ERROR: Failed to open ", fileIn.c_str());
  return;
  }
  
  if (!outFile->is_open()) {
  AddLog("ERROR: Failed to open ", fileOut.c_str());
  return;
  }
  
  // find file extension
  string fileExt;
  auto   pos = fileIn.find_last_of('.');
  
  if (pos != string::npos) {
  fileExt = fileIn.substr(pos);
  }
  
  // is anything to add
  if (userRights.size() == 0) {
  AddLog("ERROR: ", "Please fill email and check rights");
  return;
  }
  
  
  try {
  // create authentication callback
  AuthCallback auth(clientId, redirectUrl);
  
  // process conversion
  PFileConverter::ConvertToPFilePredefinedRights(
    clientEmail,
    inFile,
    fileExt,
    outFile,
    auth,
    this->consent,
    userRights);
  
  AddLog("Successfully converted to ", fileOut.c_str());
  }
  catch (const rmsauth::Exception& e) {
  AddLog("ERROR: ", e.error().c_str());
  
  outFile->close();
  remove(fileOut.c_str());
  }
  catch (const rmscore::exceptions::RMSException& e) {
  AddLog("ERROR: ", e.what());
  
  outFile->close();
  remove(fileOut.c_str());
  }
  inFile->close();
  outFile->close();
  }

创建保护策略,授予用户所选权限 rms _ sample/pfileconverter.cppCreates a protection policy give user selected rights Source: rms_sample/pfileconverter.cpp

说明:创建策略描述符并填充用户的权限信息,然后使用策略描述符来创建用户策略。Description: Create a policy descriptor and fill it with the user's rights information then, use the policy descriptor to create a user policy. 此策略可通过调用 ConvertToPFileUsingPolicy 来保护所选文件(参见本主题上一部分中的所述内容)。This policy is used to protect the selected file via a call to ConvertToPFileUsingPolicy (see this described in a previous section of this topic).

C + +C++:

  void PFileConverter::ConvertToPFilePredefinedRights(
  const string            & userId,
  shared_ptr<istream>       inStream,
  const string            & fileExt,
  shared_ptr<iostream>      outStream,
  IAuthenticationCallback & auth,
  IConsentCallback& /*consent*/,
  const vector<UserRights>& userRights)
  {
  auto endValidation = chrono::system_clock::now() + chrono::hours(48);
  
  
  PolicyDescriptor desc(userRights);
  
  desc.Referrer(make_shared<string>("https://client.test.app"));
  desc.ContentValidUntil(endValidation);
  desc.AllowOfflineAccess(false);
  desc.Name("Test Name");
  desc.Description("Test Description");
  
  auto policy = UserPolicy::Create(desc, userId, auth,
                                 USER_AllowAuditedExtraction);
  ConvertToPFileUsingPolicy(policy, inStream, fileExt, outStream);

WorkerThread - 一种支持方法WorkerThread - a supporting method

WorkerThread() 方法由先前的两个示例方案(“创建受保护的文件流”**** 和“在给定策略的情况下保护文件”****)按以下方式进行调用:The WorkerThread() method is called by two of the previous example scenarios; Create a protected file stream and Protects a file given a policy in the following manner:

C + +C++:

  threadPool.push_back(thread(WorkerThread,
                                static_pointer_cast<iostream>(outStream), pfs,
                                false));

支持方法 WorkerThread()Supporting method, WorkerThread()

C + +C++:

  static mutex   threadLocker;
  static int64_t totalSize     = 0;
  static int64_t readPosition  = 0;
  static int64_t writePosition = 0;
  static vector<thread> threadPool;
  
  static void WorkerThread(shared_ptr<iostream>           stdStream,
                       shared_ptr<ProtectedFileStream>pStream,
                       bool                           modeWrite) {
  vector<uint8_t> buffer(4096);
  int64_t bufferSize = static_cast<int64_t>(buffer.size());
  
  while (totalSize - readPosition > 0) {
  // lock
  threadLocker.lock();
  
  // check remain
  if (totalSize - readPosition <= 0) {
    threadLocker.unlock();
    return;
  }
  
  // get read/write offset
  int64_t offsetRead  = readPosition;
  int64_t offsetWrite = writePosition;
  int64_t toProcess   = min(bufferSize, totalSize - readPosition);
  readPosition  += toProcess;
  writePosition += toProcess;
  
  // no need to lock more
  threadLocker.unlock();
  
  if (modeWrite) {
    // stdStream is not thread safe!!!
    try {
      threadLocker.lock();
  
      stdStream->seekg(offsetRead);
      stdStream->read(reinterpret_cast<char *>(&buffer[0]), toProcess);
      threadLocker.unlock();
      auto written =
        pStream->WriteAsync(
          buffer.data(), toProcess, offsetWrite, std::launch::deferred).get();
  
      if (written != toProcess) {
        throw rmscore::exceptions::RMSStreamException("Error while writing data");
      }
    }
    catch (exception& e) {
      qDebug() << "Exception: " << e.what();
    }
  } else {
    auto read =
      pStream->ReadAsync(&buffer[0],
                         toProcess,
                         offsetRead,
                         std::launch::deferred).get();
  
    if (read == 0) {
      break;
    }
  
    try {
      // stdStream is not thread safe!!!
      threadLocker.lock();
  
      // seek to write
      stdStream->seekp(offsetWrite);
      stdStream->write(reinterpret_cast<const char *>(buffer.data()), read);
      threadLocker.unlock();
    }
    catch (exception& e) {
      qDebug() << "Exception: " << e.what();
    }
  }
  }
  }

方案:RMS 身份验证Scenario: RMS authentication

以下示例展示了两种不同的身份验证方法,即在使用 UI 和不使用 UI 的情况下获取 Azure 身份验证 oAuth2 令牌。The following examples show two different authentication approaches; obtaining Azure Authentication oAuth2 token using UI and without UI. 正在通过 UI 获取 OAuth2 身份验证令牌rmsauth _ sample/mainwindow.xamlAcquiring oAuth2 Authentication Token with UI Source: rmsauth_sample/mainwindow.cpp

步骤 1:创建Rmsauth:: FileCache对象的共享点。Step 1: Create a shared point of rmsauth::FileCache object. 说明:可设置缓存路径或使用默认路径。Description: You can set cache path or use default.

C + +C++:

  auto FileCachePtr = std::make_shared< rmsauth::FileCache>();

步骤 2:创建 rmsauth::AuthenticationContext 对象 说明:指定 Azure 颁发机构 URIFileCache 对象。Step 2: Create rmsauth::AuthenticationContext object Description: Specify Azure authority URI and FileCache object.

C + +C++:

  AuthenticationContext authContext(
                            std::string("https://sts.aadrm.com/_sts/oauth/authorize"),
                            AuthorityValidationType::False,
                            FileCachePtr);

步骤 3:调用AuthContext对象的acquireToken方法并指定下一个参数:说明:Step 3: Call acquireToken method of authContext object and specify next parameters: Description:

  • 请求资源 - 想要访问的受保护资源Requested resource - protected resource you want to access
  • 客户端唯一 ID - 通常为 GUIDClient unique ID - usually a GUID
  • 重定向 URI - 在提取身份验证令牌后重新寻址的 URIRedirection URI - the URI which will be readdressed after authentication token fetched
  • 身份验证提示行为 - 若设置 PromptBehavior::Auto,则库将尝试使用缓存并在必要时刷新令牌Authentication prompt behavior - if you set PromptBehavior::Auto the library tries to use cache and refresh token if necessary
  • 用户 ID:提示窗口中显示的用户名User ID - User name displayed in the prompt window

C + +C++:

  auto result = authContext.acquireToken(
              std::string("api.aadrm.com"),
              std::string("4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7"),
              std::string("https://client.test.app"),
              PromptBehavior::Auto,
              std::string("john.smith@msopentechtest01.onmicrosoft.com"));

步骤 4:从结果中获取访问令牌说明:调用Result-> accessToken () 方法Step 4: Get access token from result Description: Call result-> accessToken() method

注意 任何身份验证库方法都可能引发 rmsauth::ExceptionNote Any of the authentication library methods may raise rmsauth::Exception

没有 UI 的情况下获取 OAuth2 身份验证令牌rmsauth _ sample/mainwindow.xamlAcquiring oAuth2 Authentication Token without UI Source: rmsauth_sample/mainwindow.cpp

步骤 1:创建 rmsauth::FileCache 对象的共享点 说明:可设置缓存路径或使用默认路径Step 1: Create a shared point of rmsauth::FileCache object Description: You can set cache path or use default

C + +C++:

  auto FileCachePtr = std::make_shared< rmsauth::FileCache>();

步骤 2:创建 UserCredential 对象 说明:指定用户登录名密码Step 2:Create UserCredential object Description: Specify user login and password

C + +C++:

  auto userCred = std::make_shared<UserCredential>("john.smith@msopentechtest01.onmicrosoft.com",
                                               "SomePass");

步骤 3:创建 rmsauth::AuthenticationContext 对象 说明:指定 Azure 颁发机构 URIFileCache 对象Step 3:Create rmsauth::AuthenticationContext object Description: Specify Azure authority URI and FileCache object

C + +C++:

  AuthenticationContext authContext(
                      std::string("https://sts.aadrm.com/_sts/oauth/authorize"),
                      AuthorityValidationType::False,
                      FileCachePtr);

步骤 4:调用authContextacquireToken方法并指定参数:Step 4: Call the acquireToken method of authContext and specify parameters:

  • 请求资源 - 想要访问的受保护资源Requested resource - protected resource you want to access
  • 客户端唯一 ID - 通常为 GUIDClient unique ID - usually a GUID
  • 用户凭据 - 传递所创建的对象User credentials - pass the created object

C + +C++:

  auto result = authContext.acquireToken(
              std::string("api.aadrm.com"),
              std::string("4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7"),
              userCred);

步骤 5:从结果中获取访问令牌说明:调用Result-> accessToken () 方法Step 5: Get access token from result Description: Call result-> accessToken() method

注意 任何身份验证库方法都可能引发 rmsauth::ExceptionNote Any of the authentication library methods may raise rmsauth::Exception