Linux-kodexempel

Viktigt

Versioner av Microsoft Rights Management Service SDK som släpptes före mars 2020 är inaktuella. program som använder tidigare versioner måste uppdateras för att använda versionen från mars 2020. Fullständig information finns i utfasningsmeddelandet.

Inga ytterligare förbättringar planeras för Microsoft Rights Management Service SDK. Vi rekommenderar starkt att du använder Microsoft Information Protection SDK för klassificerings-, märknings- och skyddstjänster.

I det här avsnittet presenteras viktiga scenarier och kodelement för Linux-versionen av RMS SDK.

Kodfragmenten nedan kommer från exempelprogram, rms_sample och rmsauth_sample. Mer information finns i samples i GitHub-lagret.

Scenario: Komma åt skyddsprincipinformation från en skyddad fil

Öppnar och läser en RMS-skyddad filKälla: rms_sample/mainwindow.cpp

Beskrivning: När ett filnamn hämtas från användaren, läs certifikaten (se MainWindow::addCertificates), ställ in auktoriseringsåteranrop med klient-ID och omdirigerings-URL, anropa ConvertFromPFile (se följande kodexempel) och läs sedan ut skyddsprincipnamnet, beskrivningen och innehållets giltighetsdatum.

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

Skapa en skyddad filströmKälla: rms_sample/pfileconverter.cpp

Beskrivning: Den här metoden skapar en skyddad filström från den skickade backströmmen via SDK-metoden ProtectedFileStream::Acquire, som sedan returneras till anroparen.

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: Skapa en ny skyddad fil med en mall

Skyddar en fil med en användarvald mallKälla: rms_sample/mainwindow.cpp

Beskrivning: När ett filnamn hämtas från användaren, läs certifikaten (se MainWindow::addCertificates) och ställ in auktoriseringsåteranrop med klient-ID och omdirigerings-URL. Den valda filen skyddas genom att anropa ConvertToPFileTemplates (se följande kodexempel).

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

Skyddar en fil med en princip som skapats från en mallKälla: rms_sample/pfileconverter.cpp

Beskrivning: En lista över mallar som är associerade med användaren hämtas och den valda mallen används sedan för att skapa en princip som i sin tur används för att skydda filen.

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

Skyddar en fil med en principKälla: rms_sample/pfileconverter.cpp

Beskrivning: Skapa en skyddad filström med hjälp av den angivna principen och sedan skydda filen.

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: Skydda en fil med anpassat skydd

Skyddar en fil med anpassat skyddKälla: rms_sample/mainwindow.cpp

Beskrivning: När ett filnamn hämtas från användaren, läs certifikaten (se MainWindow::addCertificates) och ställ in auktoriseringsåteranrop med klient-ID och omdirigerings-URL. Den valda filen projiceras genom att anropa ConvertToPFilePredefinedRights (se följande kodexempel).

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

Skapar en skyddsprincip som ger användaren valda rättigheterKälla: rms_sample/pfileconverter.cpp

Beskrivning: Skapa en principbeskrivning, fyll den med användarens rättighetsinformation och använd sedan principbeskrivningen till att skapa en användarprincip. Den här principen används för att skydda den valda filen via ett anrop till ConvertToPFileUsingPolicy (se beskrivningen av det här tidigare i det här avsnittet).

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 - en stödmetod

WorkerThread()-metoden anropas av två tidigare exempelscenarier, Skapa en skyddad filström och Skyddar en fil med en angiven princip på följande sätt:

C++:

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

Stödmetod, 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();
    }
  }
  }
  }

Scenario: RMS-autentisering

I följande exempel visas två olika autentiseringsmetoder: erhålla oAuth2-token för Azure-autentisering med och utan användargränssnitt. Hämtar oAuth2-autentiseringstoken med UISource: rmsauth_sample/mainwindow.cpp

Steg 1: Skapa en delad punkt för rmsauth::FileCache-objekt . Beskrivning: Du kan ange cachesökvägen eller använda standardsökvägen.

C++:

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

Steg 2: Skapa objektet rmsauth::AuthenticationContext Beskrivning: Ange utfärdar-URI för Azure och FileCache-objekt.

C++:

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

Steg 3: Anropa metoden acquireToken för authContext-objektet och ange nästa parametrar: Beskrivning:

  • Begärd resurs - en skyddad resurs som du vill komma åt
  • Unikt klient-ID - vanligtvis ett GUID
  • Omdirigerings-URI - Den URI som ska omadresseras efter att autentiseringstoken hämtas
  • Funktionalitet för autentiseringsuppmaning - Om du ställer in PromptBehavior::Auto försöker biblioteket använda cache och uppdatera token om det behövs
  • Användar-ID - Användarnamnet visas i uppmaningsfönstret

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"));

Steg 4: Hämta åtkomsttoken från resultat Beskrivning: Anropa result-> accessToken()-metoden

Observera Någon av autentiseringsbiblioteksmetoderna kan generera rmsauth::Exception

Hämtar oAuth2-autentiseringstoken utan UISource: rmsauth_sample/mainwindow.cpp

Steg 1: Skapa en delad punkt av ett rmsauth::FileCache-objekt Beskrivning: Du kan ange cachesökvägen eller använda standardsökvägen

C++:

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

Steg 2: Skapa ett UserCredential-objekt Beskrivning: Ange användarinloggning och lösenord

C++:

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

Steg 3: Skapa objektet rmsauth::AuthenticationContext Beskrivning: Ange utfärdar-URI för Azure och FileCache-objekt

C++:

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

Steg 4: Anropa metoden acquireToken för authContext och ange parametrar:

  • Begärd resurs - en skyddad resurs som du vill komma åt
  • Unikt klient-ID - vanligtvis ett GUID
  • Användarens autentiseringsuppgifter - Överför det skapade objektet

C++:

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

Steg 5: Hämta åtkomsttoken från resultat Beskrivning: Anropa result-> accessToken()-metoden

Observera Någon av autentiseringsbiblioteksmetoderna kan generera rmsauth::Exception