Linux 程式碼範例

重要

2020年3月之前發行的 Microsoft Rights Management Service SDK 版本已被取代;使用舊版的應用程式必須更新為使用2020年3月版本。 如需完整的詳細資訊,請參閱淘汰 通知

Microsoft Rights Management Service SDK 尚未規劃任何進一步的增強功能。 我們強烈建議採用 Microsoft 資訊保護 SDK 來進行分類、標記和保護服務。

本主題介紹 Linux 版 RMS SDK 的重要案例與程式碼元素。

下列程式碼片段來自範例應用程式、 rms _ 範例>rmsauth _ 範例。 如需詳細資訊,請參閱 GitHub 儲存機制的範例

案例︰從受保護的檔案存取保護原則資訊

開啟和讀取 RMS 受保護 的檔案 來源rms _ 範例/mainwindow .cpp

描述︰從使用者取得檔案名稱之後,讀取憑證 (請參閱 MainWindow::addCertificates)、利用用戶端識別碼和重新導向 URL 設定授權回呼、呼叫 ConvertFromPFile (請參閱下列程式碼範例),然後詳閱保護原則名稱、描述和內容有效日期。

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 _ 範例/pfileconverter.cpp .cpp

描述:這個方法會透過 SDK 方法 >protectedfilestream::取得,從傳入的支援資料流程建立受保護的檔案資料流程,然後傳回給呼叫者。

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;
  }

案例︰使用範本建立新的受保護檔案

使用使用者選取的範本 保護檔案 來源rms _ 範例/mainwindow .cpp

描述︰從使用者取得檔案名稱、讀取憑證 (請參閱 MainWindow::addCertificates) 並利用用戶端識別碼和重新導向 URL 設定授權回呼之後,可透過呼叫 ConvertToPFileTemplates (請參閱下列程式碼範例) 保護選取的檔案。

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 _ 範例/pfileconverter.cpp .cpp

描述︰擷取與使用者相關聯的範本清單,然後使用選取的範本建立原則,接著使用該原則保護檔案。

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 _ 範例/pfileconverter.cpp .cpp

描述︰使用指定的原則建立受保護的檔案資料流,然後保護該檔案。

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();
  }

案例︰使用自訂保護來保護檔案

使用自訂保護 來保護檔案 來源rms _ 範例/mainwindow .cpp

描述︰從使用者取得檔案名稱、讀取憑證 (請參閱 MainWindow::addCertificates)、從使用者收集權限資訊並利用用戶端識別碼和重新導向 URL 設定授權回呼之後,可透過呼叫 ConvertToPFilePredefinedRights (請參閱下列程式碼範例) 保護選取的檔案。

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 _ 範例/pfileconverter.cpp .cpp

描述︰建立原則描述元,並填入使用者的權限資訊,然後使用原則描述元建立使用者原則。 此原則可用來透過呼叫 ConvertToPFileUsingPolicy (請參閱本主題前一節所述的此內容) 保護選取的檔案。

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() 方法;以下列方式 建立受保護的檔案資料流保護指定原則的檔案

C + +

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

支援的方法,WorkerThread()

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 驗證

下列範例會示範兩種不同的驗證方法;使用和不使用 UI 取得 Azure 驗證 oAuth2 權杖。 使用 UI 取得 oAuth2 驗證權杖 Source>rmsauth _ sample/mainwindow .cpp

步驟 1:建立 >rmsauth:: FileCache 物件的共用點。 描述︰您可以設定快取路徑或使用預設值。

C + +

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

步驟 2︰建立 rmsauth::AuthenticationContext 物件。描述︰指定 Azure 授權單位 URIFileCache 物件。

C + +

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

步驟 3:呼叫 >aquiretoken 物件的 acquireToken 方法,並指定下一個參數: Description:

  • 要求的資源 - 您想要存取的受保護資源
  • 用戶端唯一識別碼 - 通常是 GUID
  • 重新導向 URI - 擷取驗證權杖之後重新解決的 URI
  • 驗證提示行為 - 如果您設定 PromptBehavior::Auto,程式庫會嘗試使用快取並在必要時重新整理權杖
  • 使用者識別碼 - 提示字元視窗中顯示的使用者名稱

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:從結果取得存取權杖描述:呼叫 結果-> AccessToken ( # B1 方法

注意 任何驗證程式庫方法都可能會引發 rmsauth::Exception

沒有 UI 的情況下取得 oAuth2 Authentication 權杖 Source>rmsauth _ sample/mainwindow .cpp

步驟 1︰建立 rmsauth::FileCache 物件的共用點。描述︰您可以設定快取路徑或使用預設值

C + +

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

步驟 2︰建立 UserCredential 物件。描述︰指定使用者登入和密碼

C + +

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

步驟 3︰建立 rmsauth::AuthenticationContext 物件。描述︰指定 Azure 授權單位 URI 和 FileCache 物件

C + +

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

步驟 4:呼叫 >aquiretokenacquireToken 方法,並指定參數:

  • 要求的資源 - 您想要存取的受保護資源
  • 用戶端唯一識別碼 - 通常是 GUID
  • 使用者認證 - 傳遞建立的物件

C + +

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

步驟 5:從結果取得存取權杖描述:呼叫 結果-> AccessToken ( # B1 方法

注意 任何驗證程式庫方法都可能會引發 rmsauth::Exception