Linux 코드 예제
중요
2020년 3월 이전에 릴리스된 Microsoft Rights Management Service SDK 버전은 더 이상 사용되지 않습니다. 2020년 3월 릴리스를 사용하려면 이전 버전을 사용하는 애플리케이션을 업데이트해야 합니다. 자세한 내용은 사용 중단 알림을 참조하세요.
Microsoft Rights Management Service SDK에 대한 추가 개선 사항은 계획되지 않았습니다. 분류, 레이블 지정 및 보호 서비스에 Microsoft Information Protection SDK를 채택하는 것이 좋습니다.
이 항목에서는 Linux 버전의 RMS SDK에 대한 중요한 시나리오 및 코드 요소를 소개합니다.
아래 코드 조각은 샘플 애플리케이션, rms_sample 및 rmsauth_sample. 자세한 내용은 GitHub 리포지토리에서 샘플을 참조하세요.
시나리오: 보호된 파일에서 보호 정책 정보 액세스
RMS로 보호된 fileSource를 열고 읽습니다.rms_sample/mainwindow.cpp
설명: 사용자로부터 파일 이름을 받은 후 인증서를 읽고(MainWindow::addCertificates 참조), 클라이언트 ID 및 리디렉션 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();
}
보호된 파일 streamSource 만들기: rms_sample/pfileconverter.cpp
설명: 이 메서드는 SDK 메서드인 ProtectedFileStream::Acquire를 통해 전달된 백업 스트림에서 보호된 파일 스트림을 만든 다음 호출자에게 반환됩니다.
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;
}
시나리오: 템플릿을 사용하여 새 보호된 파일 만들기
사용자가 선택한 templateSource를 사용하여 파일을 보호합니다.rms_sample/mainwindow.cpp
설명: 사용자로부터 파일 이름을 받은 후 인증서를 읽고(MainWindow::addCertificates 참조), 클라이언트 ID 및 리디렉션 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();
}
templateSource: rms_sample/pfileconverter.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);
}
}
policySource: rms_sample/pfileconverter.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();
}
시나리오: 사용자 지정 보호를 사용하여 파일 보호
사용자 지정 protectionSource를 사용하여 파일 보호: rms_sample/mainwindow.cpp
설명: 사용자로부터 파일 이름을 받은 후 인증서를 읽고(MainWindow::addCertificates 참조), 사용자로부터 권한 정보를 수집하고, 클라이언트 ID 및 리디렉션 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();
}
사용자에게 선택한 rightsSource를 제공하는 보호 정책을 만듭니다.rms_sample/pfileconverter.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를 사용하거나 UI 없이 Azure 인증 oAuth2 토큰을 가져오는 두 가지 인증 방법을 보여 줍니다. UISource를 사용하여 oAuth2 인증 토큰 획득: rmsauth_sample/mainwindow.cpp
1단계: rmsauth::FileCache 개체의 공유 지점을 만듭니다. 설명: 캐시 경로를 설정하거나 기본값을 사용할 수 있습니다.
C++:
auto FileCachePtr = std::make_shared< rmsauth::FileCache>();
2단계: rmsauth::AuthenticationContext 개체를 만듭니다. 설명: Azure 기관 URI 및 FileCache 개체를 지정합니다.
C++:
AuthenticationContext authContext(
std::string("https://sts.aadrm.com/_sts/oauth/authorize"),
AuthorityValidationType::False,
FileCachePtr);
3단계: authContext 개체의 acquireToken 메서드를 호출하고 다음 매개 변수를 지정합니다. 설명:
- 요청된 리소스 - 액세스하려는 보호된 리소스입니다.
- 클라이언트 고유 ID - 대체로 GUID입니다.
- 리디렉션 URI - 인증 토큰을 가져온 후 다시 주소가 지정되는 URI입니다.
- 인증 프롬프트 동작 - PromptBehavior::Auto를 설정하면 라이브러리에서 필요한 경우 캐시 및 새로 고침 토큰을 사용하려고 합니다.
- 사용자 ID - 프롬프트 창에 표시되는 사용자 이름입니다.
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() 메서드를 호출합니다.
참고 인증 라이브러리 방법 중 어느 것이든 rmsauth::Exception을 발생할 수 있습니다.
UISource 없이 oAuth2 인증 토큰 획득: 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단계: authContext의 acquireToken 메서드를 호출하고 매개 변수를 지정합니다.
- 요청된 리소스 - 액세스하려는 보호된 리소스입니다.
- 클라이언트 고유 ID - 대체로 GUID입니다.
- 사용자 자격 증명 - 생성된 개체를 전달합니다.
C++:
auto result = authContext.acquireToken(
std::string("api.aadrm.com"),
std::string("4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7"),
userCred);
5단계: 결과에서 액세스 토큰을 가져옵니다. 설명: result-> accessToken() 메서드를 호출합니다.
참고 인증 라이브러리 방법 중 어느 것이든 rmsauth::Exception을 발생할 수 있습니다.