From b7e8f38a8344f4a80c0130e6a2ae65e28ced811a Mon Sep 17 00:00:00 2001 From: Hervey Wilson Date: Fri, 19 Jun 2015 08:04:00 -0700 Subject: [PATCH] Initial commit --- .gitignore | 24 + LICENSE.md | 21 + README.md | 14 + docs/how_to_build_it.md | 143 + docs/how_to_use_it.md | 39 + samples/rms_sample/main.cpp | 21 + samples/rms_sample/mainwindow.cpp | 446 +++ samples/rms_sample/mainwindow.h | 85 + samples/rms_sample/mainwindow.ui | 185 + samples/rms_sample/pfileconverter.cpp | 233 ++ samples/rms_sample/pfileconverter.h | 63 + samples/rms_sample/rightsdialog.cpp | 31 + samples/rms_sample/rightsdialog.h | 35 + samples/rms_sample/rightsdialog.ui | 78 + samples/rms_sample/rms_sample.pro | 40 + samples/rms_sample/templatesdialog.ui | 96 + samples/rmsauth_sample/MainWindow.cpp | 103 + samples/rmsauth_sample/MainWindow.h | 38 + samples/rmsauth_sample/MainWindow.ui | 415 +++ samples/rmsauth_sample/main.cpp | 19 + samples/rmsauth_sample/rmsauth_sample.pro | 24 + samples/samples.pro | 4 + scripts/build_and_test.sh | 127 + scripts/build_windows.ps1 | 65 + scripts/pkg/deb/DEBIAN/changelog | 5 + scripts/pkg/deb/DEBIAN/control | 7 + scripts/pkg/deb/DEBIAN/copyright | 21 + scripts/pkg/deb/DEBIAN/postinst | 1 + scripts/pkg/deb/DEBIAN/postrm | 1 + scripts/pkg/deb/etc/ld.so.conf.d/rms-sdk.conf | 2 + scripts/pkg/make_pkg.sh | 18 + sdk/rms_sdk/Common/Common.pro | 20 + sdk/rms_sdk/Common/CommonTypes.h | 48 + sdk/rms_sdk/Common/FrameworkSpecificTypes.h | 29 + sdk/rms_sdk/Common/ResultException.h | 119 + sdk/rms_sdk/Common/tools.cpp | 72 + sdk/rms_sdk/Common/tools.h | 26 + sdk/rms_sdk/Consent/Consent.h | 67 + sdk/rms_sdk/Consent/Consent.pro | 23 + .../Consent/DocumentTrackingConsent.cpp | 23 + sdk/rms_sdk/Consent/DocumentTrackingConsent.h | 28 + .../DocumentTrackingConsentManager.cpp | 50 + .../Consent/DocumentTrackingConsentManager.h | 33 + sdk/rms_sdk/Consent/IConsentManager.cpp | 29 + sdk/rms_sdk/Consent/IConsentManager.h | 30 + sdk/rms_sdk/Consent/SeriveUrlConsentManager.h | 39 + sdk/rms_sdk/Consent/ServiceUrlConsent.cpp | 39 + sdk/rms_sdk/Consent/ServiceUrlConsent.h | 30 + .../Consent/ServiceUrlConsentManager.cpp | 68 + sdk/rms_sdk/Core/Core.pro | 17 + sdk/rms_sdk/Core/ProtectionPolicy.cpp | 580 ++++ sdk/rms_sdk/Core/ProtectionPolicy.h | 254 ++ .../GetSymKeySample/GetSymKeySample.pro | 25 + sdk/rms_sdk/GetSymKeySample/data/sample.ptxt | Bin 0 -> 36575 bytes sdk/rms_sdk/GetSymKeySample/main.cpp | 211 ++ sdk/rms_sdk/Json/IJsonSerializer.h | 38 + sdk/rms_sdk/Json/Json.pro | 17 + sdk/rms_sdk/Json/jsonserializer.cpp | 663 ++++ sdk/rms_sdk/Json/jsonserializer.h | 36 + .../ModernAPI/AuthenticationCallbackImpl.h | 51 + .../ModernAPI/AuthenticationParameters.h | 62 + sdk/rms_sdk/ModernAPI/CacheControl.h | 23 + sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.cpp | 113 + sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.h | 38 + sdk/rms_sdk/ModernAPI/ConsentResult.h | 53 + sdk/rms_sdk/ModernAPI/ConsentType.h | 27 + .../ModernAPI/CustomProtectedStream.cpp | 156 + sdk/rms_sdk/ModernAPI/CustomProtectedStream.h | 73 + sdk/rms_sdk/ModernAPI/HttpHelper.cpp | 43 + sdk/rms_sdk/ModernAPI/HttpHelper.h | 29 + .../ModernAPI/IAuthenticationCallback.h | 39 + .../ModernAPI/IAuthenticationCallbackImpl.h | 34 + sdk/rms_sdk/ModernAPI/IConsent.h | 54 + sdk/rms_sdk/ModernAPI/IConsentCallback.h | 37 + sdk/rms_sdk/ModernAPI/IConsentCallbackImpl.h | 24 + sdk/rms_sdk/ModernAPI/ModernAPI.pro | 74 + sdk/rms_sdk/ModernAPI/ModernAPIExport.h | 39 + sdk/rms_sdk/ModernAPI/PolicyDescriptor.cpp | 190 ++ sdk/rms_sdk/ModernAPI/PolicyDescriptor.h | 196 ++ sdk/rms_sdk/ModernAPI/ProtectedFileStream.cpp | 279 ++ sdk/rms_sdk/ModernAPI/ProtectedFileStream.h | 112 + sdk/rms_sdk/ModernAPI/RMSExceptions.h | 215 ++ sdk/rms_sdk/ModernAPI/TemplateDescriptor.cpp | 66 + sdk/rms_sdk/ModernAPI/TemplateDescriptor.h | 78 + sdk/rms_sdk/ModernAPI/UserPolicy.cpp | 362 ++ sdk/rms_sdk/ModernAPI/UserPolicy.h | 116 + sdk/rms_sdk/ModernAPI/UserRights.h | 62 + sdk/rms_sdk/ModernAPI/UserRoles.h | 62 + sdk/rms_sdk/ModernAPI/consent.h | 62 + sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.cpp | 137 + sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.h | 63 + sdk/rms_sdk/ModernAPI/rights.h | 152 + sdk/rms_sdk/ModernAPI/roles.h | 58 + sdk/rms_sdk/PFile/IPfileHeaderReader.h | 33 + sdk/rms_sdk/PFile/IPfileHeaderWriter.h | 34 + sdk/rms_sdk/PFile/PFile.pro | 28 + sdk/rms_sdk/PFile/PfileHeader.cpp | 62 + sdk/rms_sdk/PFile/PfileHeader.h | 52 + sdk/rms_sdk/PFile/PfileHeaderReader.cpp | 228 ++ sdk/rms_sdk/PFile/PfileHeaderReader.h | 60 + sdk/rms_sdk/PFile/PfileHeaderWriter.cpp | 164 + sdk/rms_sdk/PFile/PfileHeaderWriter.h | 51 + sdk/rms_sdk/PFile/basetypes.h | 20 + sdk/rms_sdk/Platform/Common/Common.pro | 1 + sdk/rms_sdk/Platform/Filesystem/FileQt.cpp | 116 + sdk/rms_sdk/Platform/Filesystem/FileQt.h | 58 + .../Platform/Filesystem/FileSystemQt.cpp | 64 + .../Platform/Filesystem/FileSystemQt.h | 30 + .../Platform/Filesystem/Filesystem.pro | 29 + sdk/rms_sdk/Platform/Filesystem/IFile.h | 43 + sdk/rms_sdk/Platform/Filesystem/IFileSystem.h | 38 + .../Platform/Http/DnsServerResolverQt.cpp | 54 + .../Platform/Http/DnsServerResolverQt.h | 27 + sdk/rms_sdk/Platform/Http/Http.pro | 30 + sdk/rms_sdk/Platform/Http/HttpClientQt.cpp | 178 + sdk/rms_sdk/Platform/Http/HttpClientQt.h | 59 + .../Platform/Http/IDnsServerResolver.h | 31 + sdk/rms_sdk/Platform/Http/IHttpClient.h | 59 + sdk/rms_sdk/Platform/Http/IUri.cpp.autosave | 3 + sdk/rms_sdk/Platform/Http/IUri.h | 32 + sdk/rms_sdk/Platform/Http/UriQt.cpp | 37 + sdk/rms_sdk/Platform/Http/UriQt.h | 35 + sdk/rms_sdk/Platform/Http/mscertificates.h | 90 + sdk/rms_sdk/Platform/Json/IJsonArray.h | 45 + sdk/rms_sdk/Platform/Json/IJsonArrayQtImpl.h | 47 + sdk/rms_sdk/Platform/Json/IJsonObject.h | 63 + sdk/rms_sdk/Platform/Json/IJsonParser.h | 34 + sdk/rms_sdk/Platform/Json/Json.pro | 29 + sdk/rms_sdk/Platform/Json/JsonArrayQt.cpp | 67 + sdk/rms_sdk/Platform/Json/JsonArrayQt.h | 47 + sdk/rms_sdk/Platform/Json/JsonObjectQt.cpp | 267 ++ sdk/rms_sdk/Platform/Json/JsonObjectQt.h | 70 + sdk/rms_sdk/Platform/Json/JsonParserQt.cpp | 73 + sdk/rms_sdk/Platform/Json/JsonParserQt.h | 28 + sdk/rms_sdk/Platform/Logger/Logger.h | 98 + sdk/rms_sdk/Platform/Logger/Logger.pro | 24 + sdk/rms_sdk/Platform/Logger/LoggerImplQt.cpp | 55 + sdk/rms_sdk/Platform/Logger/LoggerImplQt.h | 28 + sdk/rms_sdk/Platform/Logger/logger_global.h | 20 + sdk/rms_sdk/Platform/Platform.pro | 12 + .../Platform/Settings/ILanguageSettings.h | 30 + .../Platform/Settings/ILocalSettings.h | 33 + .../Platform/Settings/LanguageSettings.cpp | 25 + .../Platform/Settings/LanguageSettings.h | 21 + .../Platform/Settings/LocalSettingsQt.cpp | 74 + .../Platform/Settings/LocalSettingsQt.h | 35 + sdk/rms_sdk/Platform/Settings/Settings.pro | 27 + sdk/rms_sdk/Platform/Xml/DomAttributeQt.cpp | 188 ++ sdk/rms_sdk/Platform/Xml/DomAttributeQt.h | 68 + sdk/rms_sdk/Platform/Xml/DomDocumentQt.cpp | 258 ++ sdk/rms_sdk/Platform/Xml/DomDocumentQt.h | 78 + sdk/rms_sdk/Platform/Xml/DomElementQt.cpp | 248 ++ sdk/rms_sdk/Platform/Xml/DomElementQt.h | 77 + sdk/rms_sdk/Platform/Xml/DomNamedNodeMap.h | 20 + sdk/rms_sdk/Platform/Xml/DomNodeList.h | 19 + sdk/rms_sdk/Platform/Xml/DomNodeQt.cpp | 167 + sdk/rms_sdk/Platform/Xml/DomNodeQt.h | 64 + sdk/rms_sdk/Platform/Xml/IDomAttribute.h | 25 + sdk/rms_sdk/Platform/Xml/IDomDocument.h | 32 + sdk/rms_sdk/Platform/Xml/IDomElement.h | 31 + sdk/rms_sdk/Platform/Xml/IDomNode.h | 78 + sdk/rms_sdk/Platform/Xml/Xml.pro | 33 + .../RestClients/AuthenticationHandler.cpp | 265 ++ .../RestClients/AuthenticationHandler.h | 34 + sdk/rms_sdk/RestClients/CXMLUtils.cpp | 199 ++ sdk/rms_sdk/RestClients/CXMLUtils.h | 47 + sdk/rms_sdk/RestClients/DnsClientResult.cpp | 64 + sdk/rms_sdk/RestClients/DnsClientResult.h | 41 + sdk/rms_sdk/RestClients/DnsLookupClient.cpp | 79 + sdk/rms_sdk/RestClients/DnsLookupClient.h | 36 + sdk/rms_sdk/RestClients/Domain.cpp | 96 + sdk/rms_sdk/RestClients/Domain.h | 52 + sdk/rms_sdk/RestClients/IDnsLookupClient.h | 34 + sdk/rms_sdk/RestClients/IPublishClient.h | 31 + sdk/rms_sdk/RestClients/IRestClientCache.h | 66 + .../RestClients/IRestServiceUrlClient.h | 62 + .../RestClients/IServiceDiscoveryClient.h | 35 + sdk/rms_sdk/RestClients/ITemplatesClient.h | 31 + .../RestClients/IUsageRestrictionsClient.h | 39 + sdk/rms_sdk/RestClients/LicenseParser.cpp | 98 + sdk/rms_sdk/RestClients/LicenseParser.h | 35 + sdk/rms_sdk/RestClients/PublishClient.cpp | 86 + sdk/rms_sdk/RestClients/PublishClient.h | 37 + sdk/rms_sdk/RestClients/RestClientCache.cpp | 806 +++++ sdk/rms_sdk/RestClients/RestClientCache.h | 143 + .../RestClients/RestClientErrorHandling.cpp | 133 + .../RestClients/RestClientErrorHandling.h | 20 + sdk/rms_sdk/RestClients/RestClients.pro | 58 + sdk/rms_sdk/RestClients/RestHttpClient.cpp | 163 + sdk/rms_sdk/RestClients/RestHttpClient.h | 66 + sdk/rms_sdk/RestClients/RestObjects.h | 152 + .../RestClients/RestServiceUrlClient.cpp | 438 +++ .../RestClients/RestServiceUrlClient.h | 88 + sdk/rms_sdk/RestClients/RestServiceUrls.cpp | 76 + sdk/rms_sdk/RestClients/RestServiceUrls.h | 34 + .../RestClients/ServiceDiscoveryClient.cpp | 114 + .../RestClients/ServiceDiscoveryClient.h | 34 + .../RestClients/ServiceDiscoveryDetails.h | 28 + sdk/rms_sdk/RestClients/TemplatesClient.cpp | 58 + sdk/rms_sdk/RestClients/TemplatesClient.h | 24 + .../RestClients/UsageRestrictionsClient.cpp | 228 ++ .../RestClients/UsageRestrictionsClient.h | 46 + sdk/rms_sdk/UnitTests/UnitTests.pro | 5 + sdk/rms_sdk/UnitTests/crypto_ut/crypto_ut.pro | 26 + .../platform_ut/PlatformFileSystemTest.cpp | 45 + .../platform_ut/PlatformFileSystemTest.h | 22 + .../platform_ut/PlatformFileTest.cpp | 147 + .../UnitTests/platform_ut/PlatformFileTest.h | 25 + .../platform_ut/PlatformHttpClientTest.cpp | 48 + .../platform_ut/PlatformHttpClientTest.h | 23 + .../platform_ut/PlatformJsonArrayTest.cpp | 104 + .../platform_ut/PlatformJsonArrayTest.h | 28 + .../platform_ut/PlatformJsonObjectTest.cpp | 282 ++ .../platform_ut/PlatformJsonObjectTest.h | 45 + .../UnitTests/platform_ut/PlatformXmlTest.cpp | 64 + .../UnitTests/platform_ut/PlatformXmlTest.h | 24 + .../UnitTests/platform_ut/TestHelpers.h | 23 + .../platform_ut/data/log_114704-3103.log | 1 + .../platform_ut/data/log_121328-3103.log | 1 + .../platform_ut/data/log_121401-3103.log | 1 + .../platform_ut/data/log_172531-3103.log | 1 + .../platform_ut/data/log_172708-3103.log | 1 + .../platform_ut/data/log_172945-3103.log | 1 + .../platform_ut/data/log_173020-3103.log | 1 + sdk/rms_sdk/UnitTests/platform_ut/data/pl.xml | 693 ++++ .../UnitTests/platform_ut/data/testJson1.json | 26 + .../UnitTests/platform_ut/data/testRead.txt | 2 + .../UnitTests/platform_ut/data/testXPath1.xml | 20 + .../UnitTests/platform_ut/data/testXPath2.xml | 57 + .../platform_ut/data/testreadall.txt | 10 + .../UnitTests/platform_ut/data/testsize.h | 47 + sdk/rms_sdk/UnitTests/platform_ut/main.cpp | 31 + .../UnitTests/platform_ut/platform_ut.pro | 47 + sdk/rms_sdk/include/QtCrypto/QtCrypto | 1 + sdk/rms_sdk/include/QtCrypto/qca.h | 48 + sdk/rms_sdk/include/QtCrypto/qca_basic.h | 1033 ++++++ sdk/rms_sdk/include/QtCrypto/qca_cert.h | 2676 +++++++++++++++ sdk/rms_sdk/include/QtCrypto/qca_core.h | 1732 ++++++++++ sdk/rms_sdk/include/QtCrypto/qca_export.h | 52 + sdk/rms_sdk/include/QtCrypto/qca_keystore.h | 798 +++++ sdk/rms_sdk/include/QtCrypto/qca_publickey.h | 1540 +++++++++ sdk/rms_sdk/include/QtCrypto/qca_safetimer.h | 70 + .../include/QtCrypto/qca_securelayer.h | 1256 +++++++ .../include/QtCrypto/qca_securemessage.h | 958 ++++++ sdk/rms_sdk/include/QtCrypto/qca_support.h | 1111 ++++++ sdk/rms_sdk/include/QtCrypto/qca_textfilter.h | 327 ++ sdk/rms_sdk/include/QtCrypto/qca_tools.h | 853 +++++ sdk/rms_sdk/include/QtCrypto/qca_version.h | 81 + sdk/rms_sdk/include/QtCrypto/qcaprovider.h | 3002 +++++++++++++++++ sdk/rms_sdk/include/QtCrypto/qpipe.h | 534 +++ sdk/rms_sdk/rms_sdk.pro | 17 + .../UnitTests/InteracriveTests.cpp | 69 + sdk/rmsauth_sdk/UnitTests/InteractiveTests.h | 22 + .../UnitTests/NonInteracriveTests.cpp | 284 ++ .../UnitTests/NonInteractiveTests.h | 31 + sdk/rmsauth_sdk/UnitTests/UnitTests.pro | 30 + sdk/rmsauth_sdk/UnitTests/main.cpp | 40 + sdk/rmsauth_sdk/WebAuthDialog/Autosaver.cpp | 86 + sdk/rmsauth_sdk/WebAuthDialog/Autosaver.h | 68 + sdk/rmsauth_sdk/WebAuthDialog/CookieJar.cpp | 593 ++++ sdk/rmsauth_sdk/WebAuthDialog/CookieJar.h | 161 + sdk/rmsauth_sdk/WebAuthDialog/Dialog.cpp | 183 + sdk/rmsauth_sdk/WebAuthDialog/Dialog.h | 58 + sdk/rmsauth_sdk/WebAuthDialog/Dialog.ui | 128 + .../WebAuthDialog/WebAuthDialog.pro | 40 + .../WebAuthDialog/images/loading.gif | Bin 0 -> 4400 bytes sdk/rmsauth_sdk/WebAuthDialog/res.qrc | 5 + .../rmsauth/AcquireTokenForClientHandler.cpp | 24 + .../rmsauth/AcquireTokenHandlerBase.cpp | 273 ++ .../AcquireTokenInteractiveHandler.cpp | 244 ++ .../AcquireTokenNonInteractiveHandler.cpp | 100 + .../AcquireTokenNonInteractiveHandlerQt.cpp | 35 + .../rmsauth/AuthenticationContext.cpp | 89 + .../rmsauth/AuthenticationRequest.cpp | 11 + .../rmsauth/AuthenticationResult.cpp | 40 + .../rmsauth/AuthenticationResultQt.cpp | 67 + sdk/rmsauth_sdk/rmsauth/Authenticator.cpp | 130 + .../rmsauth/AuthenticatorTemplate.cpp | 58 + .../rmsauth/AuthenticatorTemplateList.cpp | 52 + .../rmsauth/AuthenticatorTemplateQt.cpp | 58 + sdk/rmsauth_sdk/rmsauth/CallState.cpp | 19 + sdk/rmsauth_sdk/rmsauth/ClientAssertion.cpp | 15 + .../rmsauth/ClientAssertionCertificate.cpp | 17 + sdk/rmsauth_sdk/rmsauth/ClientCredential.cpp | 28 + sdk/rmsauth_sdk/rmsauth/ClientKey.cpp | 45 + sdk/rmsauth_sdk/rmsauth/DateTime.cpp | 45 + sdk/rmsauth_sdk/rmsauth/DateTimeQt.cpp | 65 + sdk/rmsauth_sdk/rmsauth/DateTimeQt.h | 39 + .../rmsauth/FileCacheEncrypted.cpp | 78 + sdk/rmsauth_sdk/rmsauth/FileCacheQt.cpp | 120 + sdk/rmsauth_sdk/rmsauth/Guid.cpp | 22 + sdk/rmsauth_sdk/rmsauth/GuidQt.cpp | 55 + sdk/rmsauth_sdk/rmsauth/GuidQt.h | 34 + sdk/rmsauth_sdk/rmsauth/HttpHelperQt.cpp | 400 +++ sdk/rmsauth_sdk/rmsauth/HttpHelperQt.h | 49 + sdk/rmsauth_sdk/rmsauth/IWebUI.cpp | 16 + sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.cpp | 154 + sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.h | 55 + sdk/rmsauth_sdk/rmsauth/Logger.cpp | 81 + sdk/rmsauth_sdk/rmsauth/LoggerImplQt.cpp | 20 + sdk/rmsauth_sdk/rmsauth/OAuth2ResponseQt.cpp | 194 ++ sdk/rmsauth_sdk/rmsauth/RequestParameters.cpp | 71 + .../rmsauth/RequestParametersQt.cpp | 20 + sdk/rmsauth_sdk/rmsauth/RmsauthIdHelper.cpp | 30 + sdk/rmsauth_sdk/rmsauth/RmsauthIdHelperQt.cpp | 32 + sdk/rmsauth_sdk/rmsauth/TokenCache.cpp | 228 ++ sdk/rmsauth_sdk/rmsauth/TokenCacheItem.cpp | 19 + sdk/rmsauth_sdk/rmsauth/TokenCacheKey.cpp | 62 + sdk/rmsauth_sdk/rmsauth/TokenCacheQt.cpp | 103 + sdk/rmsauth_sdk/rmsauth/Url.cpp | 47 + sdk/rmsauth_sdk/rmsauth/UrlQt.cpp | 65 + sdk/rmsauth_sdk/rmsauth/UrlQt.h | 37 + sdk/rmsauth_sdk/rmsauth/UserAssertion.cpp | 45 + sdk/rmsauth_sdk/rmsauth/UserCredential.cpp | 31 + sdk/rmsauth_sdk/rmsauth/UserIdentifier.cpp | 54 + sdk/rmsauth_sdk/rmsauth/UserInfoQt.cpp | 56 + .../rmsauth/UserRealmDiscoveryResponseQt.cpp | 72 + sdk/rmsauth_sdk/rmsauth/WebUIQt.cpp | 111 + sdk/rmsauth_sdk/rmsauth/rmsauth.pro | 144 + .../rmsauth/AcquireTokenForClientHandler.h | 29 + .../rmsauth/rmsauth/AcquireTokenHandlerBase.h | 74 + .../rmsauth/AcquireTokenInteractiveHandler.h | 60 + .../AcquireTokenNonInteractiveHandler.h | 41 + .../rmsauth/rmsauth/AuthenticationContext.h | 61 + .../rmsauth/rmsauth/AuthenticationRequest.h | 258 ++ .../rmsauth/rmsauth/AuthenticationResult.h | 90 + .../rmsauth/rmsauth/Authenticator.h | 74 + .../rmsauth/rmsauth/AuthenticatorTemplate.h | 51 + .../rmsauth/AuthenticatorTemplateList.h | 29 + .../rmsauth/rmsauth/AuthorityType.h | 23 + .../rmsauth/rmsauth/AuthorizationResult.h | 56 + sdk/rmsauth_sdk/rmsauth/rmsauth/CallState.h | 39 + .../rmsauth/rmsauth/ClientAssertion.h | 31 + .../rmsauth/ClientAssertionCertificate.h | 30 + .../rmsauth/rmsauth/ClientCredential.h | 35 + sdk/rmsauth_sdk/rmsauth/rmsauth/ClientKey.h | 48 + sdk/rmsauth_sdk/rmsauth/rmsauth/Constants.h | 352 ++ sdk/rmsauth_sdk/rmsauth/rmsauth/DateTime.h | 46 + sdk/rmsauth_sdk/rmsauth/rmsauth/Entities.h | 135 + sdk/rmsauth_sdk/rmsauth/rmsauth/Exceptions.h | 89 + sdk/rmsauth_sdk/rmsauth/rmsauth/FileCache.h | 41 + .../rmsauth/rmsauth/FileCacheEncrypted.h | 35 + sdk/rmsauth_sdk/rmsauth/rmsauth/Guid.h | 40 + sdk/rmsauth_sdk/rmsauth/rmsauth/HttpHelper.h | 84 + sdk/rmsauth_sdk/rmsauth/rmsauth/IWebUI.h | 37 + sdk/rmsauth_sdk/rmsauth/rmsauth/IdToken.h | 28 + sdk/rmsauth_sdk/rmsauth/rmsauth/Logger.h | 119 + .../rmsauth/rmsauth/OAuth2Response.h | 34 + .../rmsauth/rmsauth/OAuthConstants.h | 193 ++ .../rmsauth/rmsauth/PromptBehavior.h | 20 + .../rmsauth/rmsauth/RequestParameters.h | 42 + .../rmsauth/rmsauth/RmsauthIdHelper.h | 29 + sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCache.h | 67 + .../rmsauth/rmsauth/TokenCacheItem.h | 53 + .../rmsauth/rmsauth/TokenCacheKey.h | 67 + .../rmsauth/TokenCacheNotificationArgs.h | 48 + .../rmsauth/rmsauth/TokenSubjectType.h | 26 + sdk/rmsauth_sdk/rmsauth/rmsauth/Url.h | 52 + .../rmsauth/rmsauth/UserAssertion.h | 37 + .../rmsauth/rmsauth/UserCredential.h | 46 + .../rmsauth/rmsauth/UserIdentifier.h | 52 + sdk/rmsauth_sdk/rmsauth/rmsauth/UserInfo.h | 83 + .../rmsauth/UserRealmDiscoveryResponse.h | 60 + .../rmsauth/rmsauth/rmsauthExport.h | 19 + sdk/rmsauth_sdk/rmsauth/rmsauth/types.h | 73 + sdk/rmsauth_sdk/rmsauth/rmsauth/utils.h | 40 + sdk/rmsauth_sdk/rmsauth/utils.cpp | 122 + sdk/rmsauth_sdk/rmsauth/utilsQt.cpp | 22 + sdk/rmsauth_sdk/rmsauth_sdk.pro | 9 + .../Crypto/Cbc4kCryptoProvider.cpp | 307 ++ .../Crypto/Cbc4kCryptoProvider.h | 78 + .../Crypto/Cbc512NoPaddingCryptoProvider.cpp | 294 ++ .../Crypto/Cbc512NoPaddingCryptoProvider.h | 75 + .../CryptoStreams/Crypto/Crypto.pro | 29 + .../CryptoStreams/Crypto/CryptoConstants.h | 19 + .../Crypto/EcbCryptoProvider.cpp | 98 + .../CryptoStreams/Crypto/EcbCryptoProvider.h | 56 + .../CryptoAPI/BlockBasedProtectedStream.cpp | 485 +++ .../CryptoAPI/BlockBasedProtectedStream.h | 111 + .../CryptoStreams/CryptoAPI/CachedBlock.cpp | 282 ++ .../CryptoStreams/CryptoAPI/CachedBlock.h | 59 + .../CryptoStreams/CryptoAPI/CryptoAPI.cpp | 180 + .../CryptoStreams/CryptoAPI/CryptoAPI.h | 59 + .../CryptoStreams/CryptoAPI/CryptoAPI.pro | 59 + .../CryptoStreams/CryptoAPI/CryptoAPIExport.h | 39 + .../CryptoStreams/CryptoAPI/ICryptoEngine.h | 39 + .../CryptoStreams/CryptoAPI/ICryptoHash.h | 32 + .../CryptoStreams/CryptoAPI/ICryptoKey.h | 34 + .../CryptoStreams/CryptoAPI/ICryptoProvider.h | 53 + .../CryptoStreams/CryptoAPI/ICryptoStream.h | 50 + .../CryptoStreams/CryptoAPI/IStream.h | 76 + .../CryptoAPI/RMSCryptoExceptions.h | 157 + .../CryptoAPI/SimpleProtectedStream.cpp | 348 ++ .../CryptoAPI/SimpleProtectedStream.h | 98 + .../CryptoAPI/StdStreamAdapter.cpp | 248 ++ .../CryptoAPI/StdStreamAdapter.h | 66 + .../CryptoStreams/CryptoStreams.pro | 11 + .../Platform/Crypto/AESCryptoKey.cpp | 141 + .../Platform/Crypto/AESCryptoKey.h | 58 + .../CryptoStreams/Platform/Crypto/Crypto.pro | 27 + .../Platform/Crypto/CryptoEngine.cpp | 62 + .../Platform/Crypto/CryptoEngine.h | 31 + .../Platform/Crypto/CryptoHash.cpp | 65 + .../Platform/Crypto/CryptoHash.h | 37 + .../Platform/KeyStorage/IKeyStorage.cpp | 33 + .../Platform/KeyStorage/IKeyStorage.h | 33 + .../Platform/KeyStorage/KeyStorage.pro | 44 + .../Platform/KeyStorage/KeyStorageOSX.cpp | 28 + .../Platform/KeyStorage/KeyStorageOSX.h | 34 + .../Platform/KeyStorage/KeyStoragePosix.cpp | 98 + .../Platform/KeyStorage/KeyStoragePosix.h | 34 + .../Platform/KeyStorage/KeyStorageWindows.cpp | 28 + .../Platform/KeyStorage/KeyStorageWindows.h | 34 + .../Platform/KeyStorage/base64.cpp | 130 + .../Platform/KeyStorage/base64.h | 22 + .../CryptoStreams/Platform/Platform.pro | 7 + .../UnitTests/CryptedStreamTests.cpp | 67 + .../UnitTests/CryptedStreamTests.h | 24 + .../UnitTests/CryptoAPITests.cpp | 52 + sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.h | 25 + .../UnitTests/KeyStorageTests.cpp | 57 + sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.h | 22 + .../UnitTests/PlatformCryptoTest.cpp | 327 ++ .../UnitTests/PlatformCryptoTest.h | 42 + sdk/rmscrypto_sdk/UnitTests/TestHelpers.h | 23 + sdk/rmscrypto_sdk/UnitTests/UnitTests.pro | 44 + sdk/rmscrypto_sdk/UnitTests/main.cpp | 23 + sdk/rmscrypto_sdk/rmscrypto_sdk.pro | 7 + sdk/sdk.pro | 6 + 429 files changed, 48790 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 docs/how_to_build_it.md create mode 100644 docs/how_to_use_it.md create mode 100644 samples/rms_sample/main.cpp create mode 100644 samples/rms_sample/mainwindow.cpp create mode 100644 samples/rms_sample/mainwindow.h create mode 100644 samples/rms_sample/mainwindow.ui create mode 100644 samples/rms_sample/pfileconverter.cpp create mode 100644 samples/rms_sample/pfileconverter.h create mode 100644 samples/rms_sample/rightsdialog.cpp create mode 100644 samples/rms_sample/rightsdialog.h create mode 100644 samples/rms_sample/rightsdialog.ui create mode 100644 samples/rms_sample/rms_sample.pro create mode 100644 samples/rms_sample/templatesdialog.ui create mode 100644 samples/rmsauth_sample/MainWindow.cpp create mode 100644 samples/rmsauth_sample/MainWindow.h create mode 100644 samples/rmsauth_sample/MainWindow.ui create mode 100644 samples/rmsauth_sample/main.cpp create mode 100644 samples/rmsauth_sample/rmsauth_sample.pro create mode 100644 samples/samples.pro create mode 100755 scripts/build_and_test.sh create mode 100755 scripts/build_windows.ps1 create mode 100644 scripts/pkg/deb/DEBIAN/changelog create mode 100644 scripts/pkg/deb/DEBIAN/control create mode 100644 scripts/pkg/deb/DEBIAN/copyright create mode 100755 scripts/pkg/deb/DEBIAN/postinst create mode 100755 scripts/pkg/deb/DEBIAN/postrm create mode 100644 scripts/pkg/deb/etc/ld.so.conf.d/rms-sdk.conf create mode 100755 scripts/pkg/make_pkg.sh create mode 100644 sdk/rms_sdk/Common/Common.pro create mode 100644 sdk/rms_sdk/Common/CommonTypes.h create mode 100644 sdk/rms_sdk/Common/FrameworkSpecificTypes.h create mode 100644 sdk/rms_sdk/Common/ResultException.h create mode 100644 sdk/rms_sdk/Common/tools.cpp create mode 100644 sdk/rms_sdk/Common/tools.h create mode 100644 sdk/rms_sdk/Consent/Consent.h create mode 100644 sdk/rms_sdk/Consent/Consent.pro create mode 100644 sdk/rms_sdk/Consent/DocumentTrackingConsent.cpp create mode 100644 sdk/rms_sdk/Consent/DocumentTrackingConsent.h create mode 100644 sdk/rms_sdk/Consent/DocumentTrackingConsentManager.cpp create mode 100644 sdk/rms_sdk/Consent/DocumentTrackingConsentManager.h create mode 100644 sdk/rms_sdk/Consent/IConsentManager.cpp create mode 100644 sdk/rms_sdk/Consent/IConsentManager.h create mode 100644 sdk/rms_sdk/Consent/SeriveUrlConsentManager.h create mode 100644 sdk/rms_sdk/Consent/ServiceUrlConsent.cpp create mode 100644 sdk/rms_sdk/Consent/ServiceUrlConsent.h create mode 100644 sdk/rms_sdk/Consent/ServiceUrlConsentManager.cpp create mode 100644 sdk/rms_sdk/Core/Core.pro create mode 100644 sdk/rms_sdk/Core/ProtectionPolicy.cpp create mode 100644 sdk/rms_sdk/Core/ProtectionPolicy.h create mode 100644 sdk/rms_sdk/GetSymKeySample/GetSymKeySample.pro create mode 100644 sdk/rms_sdk/GetSymKeySample/data/sample.ptxt create mode 100644 sdk/rms_sdk/GetSymKeySample/main.cpp create mode 100644 sdk/rms_sdk/Json/IJsonSerializer.h create mode 100644 sdk/rms_sdk/Json/Json.pro create mode 100644 sdk/rms_sdk/Json/jsonserializer.cpp create mode 100644 sdk/rms_sdk/Json/jsonserializer.h create mode 100644 sdk/rms_sdk/ModernAPI/AuthenticationCallbackImpl.h create mode 100644 sdk/rms_sdk/ModernAPI/AuthenticationParameters.h create mode 100644 sdk/rms_sdk/ModernAPI/CacheControl.h create mode 100644 sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.cpp create mode 100644 sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.h create mode 100644 sdk/rms_sdk/ModernAPI/ConsentResult.h create mode 100644 sdk/rms_sdk/ModernAPI/ConsentType.h create mode 100644 sdk/rms_sdk/ModernAPI/CustomProtectedStream.cpp create mode 100644 sdk/rms_sdk/ModernAPI/CustomProtectedStream.h create mode 100644 sdk/rms_sdk/ModernAPI/HttpHelper.cpp create mode 100644 sdk/rms_sdk/ModernAPI/HttpHelper.h create mode 100644 sdk/rms_sdk/ModernAPI/IAuthenticationCallback.h create mode 100644 sdk/rms_sdk/ModernAPI/IAuthenticationCallbackImpl.h create mode 100644 sdk/rms_sdk/ModernAPI/IConsent.h create mode 100644 sdk/rms_sdk/ModernAPI/IConsentCallback.h create mode 100644 sdk/rms_sdk/ModernAPI/IConsentCallbackImpl.h create mode 100644 sdk/rms_sdk/ModernAPI/ModernAPI.pro create mode 100644 sdk/rms_sdk/ModernAPI/ModernAPIExport.h create mode 100644 sdk/rms_sdk/ModernAPI/PolicyDescriptor.cpp create mode 100644 sdk/rms_sdk/ModernAPI/PolicyDescriptor.h create mode 100644 sdk/rms_sdk/ModernAPI/ProtectedFileStream.cpp create mode 100644 sdk/rms_sdk/ModernAPI/ProtectedFileStream.h create mode 100644 sdk/rms_sdk/ModernAPI/RMSExceptions.h create mode 100644 sdk/rms_sdk/ModernAPI/TemplateDescriptor.cpp create mode 100644 sdk/rms_sdk/ModernAPI/TemplateDescriptor.h create mode 100644 sdk/rms_sdk/ModernAPI/UserPolicy.cpp create mode 100644 sdk/rms_sdk/ModernAPI/UserPolicy.h create mode 100644 sdk/rms_sdk/ModernAPI/UserRights.h create mode 100644 sdk/rms_sdk/ModernAPI/UserRoles.h create mode 100644 sdk/rms_sdk/ModernAPI/consent.h create mode 100644 sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.cpp create mode 100644 sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.h create mode 100644 sdk/rms_sdk/ModernAPI/rights.h create mode 100644 sdk/rms_sdk/ModernAPI/roles.h create mode 100644 sdk/rms_sdk/PFile/IPfileHeaderReader.h create mode 100644 sdk/rms_sdk/PFile/IPfileHeaderWriter.h create mode 100644 sdk/rms_sdk/PFile/PFile.pro create mode 100644 sdk/rms_sdk/PFile/PfileHeader.cpp create mode 100644 sdk/rms_sdk/PFile/PfileHeader.h create mode 100644 sdk/rms_sdk/PFile/PfileHeaderReader.cpp create mode 100644 sdk/rms_sdk/PFile/PfileHeaderReader.h create mode 100644 sdk/rms_sdk/PFile/PfileHeaderWriter.cpp create mode 100644 sdk/rms_sdk/PFile/PfileHeaderWriter.h create mode 100644 sdk/rms_sdk/PFile/basetypes.h create mode 100644 sdk/rms_sdk/Platform/Common/Common.pro create mode 100644 sdk/rms_sdk/Platform/Filesystem/FileQt.cpp create mode 100644 sdk/rms_sdk/Platform/Filesystem/FileQt.h create mode 100644 sdk/rms_sdk/Platform/Filesystem/FileSystemQt.cpp create mode 100644 sdk/rms_sdk/Platform/Filesystem/FileSystemQt.h create mode 100644 sdk/rms_sdk/Platform/Filesystem/Filesystem.pro create mode 100644 sdk/rms_sdk/Platform/Filesystem/IFile.h create mode 100644 sdk/rms_sdk/Platform/Filesystem/IFileSystem.h create mode 100644 sdk/rms_sdk/Platform/Http/DnsServerResolverQt.cpp create mode 100644 sdk/rms_sdk/Platform/Http/DnsServerResolverQt.h create mode 100644 sdk/rms_sdk/Platform/Http/Http.pro create mode 100644 sdk/rms_sdk/Platform/Http/HttpClientQt.cpp create mode 100644 sdk/rms_sdk/Platform/Http/HttpClientQt.h create mode 100644 sdk/rms_sdk/Platform/Http/IDnsServerResolver.h create mode 100644 sdk/rms_sdk/Platform/Http/IHttpClient.h create mode 100644 sdk/rms_sdk/Platform/Http/IUri.cpp.autosave create mode 100644 sdk/rms_sdk/Platform/Http/IUri.h create mode 100644 sdk/rms_sdk/Platform/Http/UriQt.cpp create mode 100644 sdk/rms_sdk/Platform/Http/UriQt.h create mode 100644 sdk/rms_sdk/Platform/Http/mscertificates.h create mode 100644 sdk/rms_sdk/Platform/Json/IJsonArray.h create mode 100644 sdk/rms_sdk/Platform/Json/IJsonArrayQtImpl.h create mode 100644 sdk/rms_sdk/Platform/Json/IJsonObject.h create mode 100644 sdk/rms_sdk/Platform/Json/IJsonParser.h create mode 100644 sdk/rms_sdk/Platform/Json/Json.pro create mode 100644 sdk/rms_sdk/Platform/Json/JsonArrayQt.cpp create mode 100644 sdk/rms_sdk/Platform/Json/JsonArrayQt.h create mode 100644 sdk/rms_sdk/Platform/Json/JsonObjectQt.cpp create mode 100644 sdk/rms_sdk/Platform/Json/JsonObjectQt.h create mode 100644 sdk/rms_sdk/Platform/Json/JsonParserQt.cpp create mode 100644 sdk/rms_sdk/Platform/Json/JsonParserQt.h create mode 100644 sdk/rms_sdk/Platform/Logger/Logger.h create mode 100644 sdk/rms_sdk/Platform/Logger/Logger.pro create mode 100644 sdk/rms_sdk/Platform/Logger/LoggerImplQt.cpp create mode 100644 sdk/rms_sdk/Platform/Logger/LoggerImplQt.h create mode 100644 sdk/rms_sdk/Platform/Logger/logger_global.h create mode 100644 sdk/rms_sdk/Platform/Platform.pro create mode 100644 sdk/rms_sdk/Platform/Settings/ILanguageSettings.h create mode 100644 sdk/rms_sdk/Platform/Settings/ILocalSettings.h create mode 100644 sdk/rms_sdk/Platform/Settings/LanguageSettings.cpp create mode 100644 sdk/rms_sdk/Platform/Settings/LanguageSettings.h create mode 100644 sdk/rms_sdk/Platform/Settings/LocalSettingsQt.cpp create mode 100644 sdk/rms_sdk/Platform/Settings/LocalSettingsQt.h create mode 100644 sdk/rms_sdk/Platform/Settings/Settings.pro create mode 100644 sdk/rms_sdk/Platform/Xml/DomAttributeQt.cpp create mode 100644 sdk/rms_sdk/Platform/Xml/DomAttributeQt.h create mode 100644 sdk/rms_sdk/Platform/Xml/DomDocumentQt.cpp create mode 100644 sdk/rms_sdk/Platform/Xml/DomDocumentQt.h create mode 100644 sdk/rms_sdk/Platform/Xml/DomElementQt.cpp create mode 100644 sdk/rms_sdk/Platform/Xml/DomElementQt.h create mode 100644 sdk/rms_sdk/Platform/Xml/DomNamedNodeMap.h create mode 100644 sdk/rms_sdk/Platform/Xml/DomNodeList.h create mode 100644 sdk/rms_sdk/Platform/Xml/DomNodeQt.cpp create mode 100644 sdk/rms_sdk/Platform/Xml/DomNodeQt.h create mode 100644 sdk/rms_sdk/Platform/Xml/IDomAttribute.h create mode 100644 sdk/rms_sdk/Platform/Xml/IDomDocument.h create mode 100644 sdk/rms_sdk/Platform/Xml/IDomElement.h create mode 100644 sdk/rms_sdk/Platform/Xml/IDomNode.h create mode 100644 sdk/rms_sdk/Platform/Xml/Xml.pro create mode 100644 sdk/rms_sdk/RestClients/AuthenticationHandler.cpp create mode 100644 sdk/rms_sdk/RestClients/AuthenticationHandler.h create mode 100644 sdk/rms_sdk/RestClients/CXMLUtils.cpp create mode 100644 sdk/rms_sdk/RestClients/CXMLUtils.h create mode 100644 sdk/rms_sdk/RestClients/DnsClientResult.cpp create mode 100644 sdk/rms_sdk/RestClients/DnsClientResult.h create mode 100644 sdk/rms_sdk/RestClients/DnsLookupClient.cpp create mode 100644 sdk/rms_sdk/RestClients/DnsLookupClient.h create mode 100644 sdk/rms_sdk/RestClients/Domain.cpp create mode 100644 sdk/rms_sdk/RestClients/Domain.h create mode 100644 sdk/rms_sdk/RestClients/IDnsLookupClient.h create mode 100644 sdk/rms_sdk/RestClients/IPublishClient.h create mode 100644 sdk/rms_sdk/RestClients/IRestClientCache.h create mode 100644 sdk/rms_sdk/RestClients/IRestServiceUrlClient.h create mode 100644 sdk/rms_sdk/RestClients/IServiceDiscoveryClient.h create mode 100644 sdk/rms_sdk/RestClients/ITemplatesClient.h create mode 100644 sdk/rms_sdk/RestClients/IUsageRestrictionsClient.h create mode 100644 sdk/rms_sdk/RestClients/LicenseParser.cpp create mode 100644 sdk/rms_sdk/RestClients/LicenseParser.h create mode 100644 sdk/rms_sdk/RestClients/PublishClient.cpp create mode 100644 sdk/rms_sdk/RestClients/PublishClient.h create mode 100644 sdk/rms_sdk/RestClients/RestClientCache.cpp create mode 100644 sdk/rms_sdk/RestClients/RestClientCache.h create mode 100644 sdk/rms_sdk/RestClients/RestClientErrorHandling.cpp create mode 100644 sdk/rms_sdk/RestClients/RestClientErrorHandling.h create mode 100644 sdk/rms_sdk/RestClients/RestClients.pro create mode 100644 sdk/rms_sdk/RestClients/RestHttpClient.cpp create mode 100644 sdk/rms_sdk/RestClients/RestHttpClient.h create mode 100644 sdk/rms_sdk/RestClients/RestObjects.h create mode 100644 sdk/rms_sdk/RestClients/RestServiceUrlClient.cpp create mode 100644 sdk/rms_sdk/RestClients/RestServiceUrlClient.h create mode 100644 sdk/rms_sdk/RestClients/RestServiceUrls.cpp create mode 100644 sdk/rms_sdk/RestClients/RestServiceUrls.h create mode 100644 sdk/rms_sdk/RestClients/ServiceDiscoveryClient.cpp create mode 100644 sdk/rms_sdk/RestClients/ServiceDiscoveryClient.h create mode 100644 sdk/rms_sdk/RestClients/ServiceDiscoveryDetails.h create mode 100644 sdk/rms_sdk/RestClients/TemplatesClient.cpp create mode 100644 sdk/rms_sdk/RestClients/TemplatesClient.h create mode 100644 sdk/rms_sdk/RestClients/UsageRestrictionsClient.cpp create mode 100644 sdk/rms_sdk/RestClients/UsageRestrictionsClient.h create mode 100644 sdk/rms_sdk/UnitTests/UnitTests.pro create mode 100644 sdk/rms_sdk/UnitTests/crypto_ut/crypto_ut.pro create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformFileSystemTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformFileSystemTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformFileTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformFileTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformHttpClientTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformHttpClientTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformJsonArrayTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformJsonArrayTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformJsonObjectTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformJsonObjectTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformXmlTest.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/PlatformXmlTest.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/TestHelpers.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_114704-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_121328-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_121401-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_172531-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_172708-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_172945-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/log_173020-3103.log create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/pl.xml create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testJson1.json create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testRead.txt create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testXPath1.xml create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testXPath2.xml create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testreadall.txt create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/data/testsize.h create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/main.cpp create mode 100644 sdk/rms_sdk/UnitTests/platform_ut/platform_ut.pro create mode 100644 sdk/rms_sdk/include/QtCrypto/QtCrypto create mode 100644 sdk/rms_sdk/include/QtCrypto/qca.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_basic.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_cert.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_core.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_export.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_keystore.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_publickey.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_safetimer.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_securelayer.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_securemessage.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_support.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_textfilter.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_tools.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qca_version.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qcaprovider.h create mode 100644 sdk/rms_sdk/include/QtCrypto/qpipe.h create mode 100644 sdk/rms_sdk/rms_sdk.pro create mode 100644 sdk/rmsauth_sdk/UnitTests/InteracriveTests.cpp create mode 100644 sdk/rmsauth_sdk/UnitTests/InteractiveTests.h create mode 100644 sdk/rmsauth_sdk/UnitTests/NonInteracriveTests.cpp create mode 100644 sdk/rmsauth_sdk/UnitTests/NonInteractiveTests.h create mode 100644 sdk/rmsauth_sdk/UnitTests/UnitTests.pro create mode 100644 sdk/rmsauth_sdk/UnitTests/main.cpp create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/Autosaver.cpp create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/Autosaver.h create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/CookieJar.cpp create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/CookieJar.h create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/Dialog.cpp create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/Dialog.h create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/Dialog.ui create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/WebAuthDialog.pro create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/images/loading.gif create mode 100644 sdk/rmsauth_sdk/WebAuthDialog/res.qrc create mode 100644 sdk/rmsauth_sdk/rmsauth/AcquireTokenForClientHandler.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AcquireTokenHandlerBase.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AcquireTokenInteractiveHandler.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandler.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandlerQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticationContext.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticationRequest.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticationResult.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticationResultQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/Authenticator.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplate.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateList.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/CallState.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/ClientAssertion.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/ClientAssertionCertificate.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/ClientCredential.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/ClientKey.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/DateTime.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/DateTimeQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/DateTimeQt.h create mode 100644 sdk/rmsauth_sdk/rmsauth/FileCacheEncrypted.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/FileCacheQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/Guid.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/GuidQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/GuidQt.h create mode 100644 sdk/rmsauth_sdk/rmsauth/HttpHelperQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/HttpHelperQt.h create mode 100644 sdk/rmsauth_sdk/rmsauth/IWebUI.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.h create mode 100644 sdk/rmsauth_sdk/rmsauth/Logger.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/LoggerImplQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/OAuth2ResponseQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/RequestParameters.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/RequestParametersQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/RmsauthIdHelper.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/RmsauthIdHelperQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/TokenCache.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/TokenCacheItem.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/TokenCacheKey.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/TokenCacheQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/Url.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UrlQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UrlQt.h create mode 100644 sdk/rmsauth_sdk/rmsauth/UserAssertion.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UserCredential.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UserIdentifier.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UserInfoQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/UserRealmDiscoveryResponseQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/WebUIQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth.pro create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenForClientHandler.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenHandlerBase.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenInteractiveHandler.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenNonInteractiveHandler.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationContext.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationRequest.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationResult.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Authenticator.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplate.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplateList.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorityType.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorizationResult.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/CallState.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertion.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertionCertificate.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/ClientCredential.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/ClientKey.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Constants.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/DateTime.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Entities.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Exceptions.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/FileCache.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/FileCacheEncrypted.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Guid.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/HttpHelper.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/IWebUI.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/IdToken.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Logger.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/OAuth2Response.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/OAuthConstants.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/PromptBehavior.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/RequestParameters.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/RmsauthIdHelper.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCache.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheItem.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheKey.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheNotificationArgs.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/TokenSubjectType.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/Url.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/UserAssertion.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/UserCredential.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/UserIdentifier.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/UserInfo.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/UserRealmDiscoveryResponse.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/rmsauthExport.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/types.h create mode 100644 sdk/rmsauth_sdk/rmsauth/rmsauth/utils.h create mode 100644 sdk/rmsauth_sdk/rmsauth/utils.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth/utilsQt.cpp create mode 100644 sdk/rmsauth_sdk/rmsauth_sdk.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/Crypto.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/CryptoConstants.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPIExport.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoEngine.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoHash.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoKey.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoProvider.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoStream.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/IStream.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/RMSCryptoExceptions.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/CryptoStreams.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/Crypto.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorage.pro create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.cpp create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.h create mode 100644 sdk/rmscrypto_sdk/CryptoStreams/Platform/Platform.pro create mode 100644 sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.cpp create mode 100644 sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.h create mode 100644 sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.cpp create mode 100644 sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.h create mode 100644 sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.cpp create mode 100644 sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.h create mode 100644 sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.cpp create mode 100644 sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.h create mode 100644 sdk/rmscrypto_sdk/UnitTests/TestHelpers.h create mode 100644 sdk/rmscrypto_sdk/UnitTests/UnitTests.pro create mode 100644 sdk/rmscrypto_sdk/UnitTests/main.cpp create mode 100644 sdk/rmscrypto_sdk/rmscrypto_sdk.pro create mode 100644 sdk/sdk.pro diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..63d3c4d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Build Artifacts +*.o +build/ +bin/ +dest/ +*.deb +*.bz2 +*build.log + +# Qt Build Artifacts +Makefile* +.qmake.stash +/sdk/**/moc_* +/sdk/**/ui_* +/sdk/**/tst_* +/samples/**/ui_* +**.pro.user +debug +release + +*.exe +.DS_Store +*.dat + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..65831805 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Open Technologies, Inc. + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..723305c5 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# RMS SDK for portable C++ + +- [How to Build](./docs/how_to_build_it.md) +- [How to Use](./docs/how_to_use_it.md) + +Alternatively, run the script in `./scripts/build_and_test.sh`. + +## Contributing + +Before we can accept your pull request, you'll need to electronically complete Microsoft Open Tech's [Contributor License Agreement](https://cla.msopentech.com/). If you've done this for other Microsoft Open Tech projects, then you're already covered. + +## License + +Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. Licensed under the MIT license. diff --git a/docs/how_to_build_it.md b/docs/how_to_build_it.md new file mode 100644 index 00000000..88b1b0f6 --- /dev/null +++ b/docs/how_to_build_it.md @@ -0,0 +1,143 @@ +## How to build libs and sample apps + +Straightforward steps for building libraries and samples on supported platforms. + +--- +## Supported targets +- [Ubuntu 14.04](#ubuntu-1404) +- [OpenSUSE 13.2](#opensuse-132) +- [CentOS 7](#centos-7) + +Libs and samples have been successfully compiled on Windows and OSX as well, but these are not fully supported at this time. + +### Ubuntu 14.04 + +1. Install dev dependencies: + ``` + sudo apt-get install qt5-default + sudo apt-get install libqt5webkit5-dev + sudo apt-get install libqt5xmlpatterns5-dev + sudo apt-get install libssl-dev + sudo apt-get install libsecret-1-dev + ``` + +2. Clone this repo: + ``` + sudo apt-get install git + git clone https://github.com/AzureAD/rms-sdk-for-cpp + cd rms-sdk-for-cpp + ``` + +3. Build and install libraries: + ``` + cd sdk + qmake + make + sudo make install + ``` + +4. Build sample applications: + ``` + cd ../samples + qmake + make + ``` + +5. Run sample applications: + ``` + cd ../bin + ./rms_sample # RMS sample + ./rmsauth_sample # auth sample + ``` + +6. Create a tarball (to deploy apps): + ``` + tar czf sample_apps.tar.gz ./rms_sample ./rmsauth_sample ./librmsauth.so ./librmsauthWebAuthDialog.so ./librms.so + ``` + +### OpenSUSE 13.2 + +1. Install dev dependencies: + ``` + sudo zypper install libqt5-qtbase-devel + sudo zypper install libQt5WebKitWidgets-devel + sudo zypper install libQt5XmlPatterns-devel + sudo zypper install libopenssl-devel + ``` + +2. Clone this repo + ``` + sudo zypper install git + git clone https://github.com/AzureAD/rms-sdk-for-cpp + ``` + +3. Build and install libraries: + ``` + cd sdk + qmake-qt5 + make + sudo make install + ``` + +4. Build sample applications: + ``` + cd ../samples + qmake-qt5 + make + ``` + +5. Run sample applications: + ``` + cd ../bin + ./rms_sample # RMS sample + ./rmsauth_sample # auth sample + ``` +6. Create a tarball (to deploy apps): + ``` + tar czf sample_apps.tar.gz ./rms_sample ./rmsauth_sample ./librmsauth.so ./librmsauthWebAuthDialog.so ./librms.so + ``` + +### CentOS 7 + +1. Install dev dependencies: + ``` + sudo yum groupinstall "Development Tools" + wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm + sudo rpm -ivh epel-release-7-5.noarch.rpm + sudo yum --enablerepo=epel install qt5-qtbase-devel + sudo yum --enablerepo=epel install qt5-qtwebkit-devel + sudo yum --enablerepo=epel install qt5-qtxmlpatterns-devel + sudo yum install openssl-devel + ``` + +2. Clone this repo: + ``` + git clone https://github.com/AzureAD/rms-sdk-for-cpp + ``` + +3. Build and install libraries: + ``` + cd sdk + qmake-qt5 + make + sudo make install + ``` + +4. Build sample applications: + ``` + cd ../samples + qmake-qt5 + make + ``` + +5. Run sample applications: + ``` + cd ../bin + ./rms_sample # RMS sample + ./rmsauth_sample # auth sample + ``` + +6. Create a tarball (to deploy apps): + ``` + tar czf sample_apps.tar.gz ./rms_sample ./rmsauth_sample ./librmsauth.so ./librmsauthWebAuthDialog.so ./librms.so ./librmscrypto.so + ``` diff --git a/docs/how_to_use_it.md b/docs/how_to_use_it.md new file mode 100644 index 00000000..4be79aa1 --- /dev/null +++ b/docs/how_to_use_it.md @@ -0,0 +1,39 @@ +## How to install and use apps on user systems + +These instructions utilize the tarball created in [how_to_build_it.md](./how_to_build_it.md), copied to the home directory of a user system. + +1. Install run-time dependencies: + + * Ubuntu 14.04 + ``` + sudo apt-get install libqt5xmlpatterns5 + sudo apt-get install libsecret-1-0 + ``` + + * OpenSUSE 13.2 + ``` + sudo zypper install libQt5WebKitWidgets5 + sudo zypper install libQt5Xml5 + ``` + + * CentOS 7 + ``` + wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm + sudo rpm -ivh epel-release-7-5.noarch.rpm + sudo yum --enablerepo=epel install qt5-qtwebkit + ``` + +2. Unpack the tarball: + ``` + cd ~ + mkdir ~/sample_apps + tar -xzf ~/sample_apps.tar.gz -C ~/sample_apps + ``` + +3. Run the apps: + ``` + cd ~/sample_apps + export LD_LIBRARY_PATH=`pwd` + ./rms_sample # RMS sample + ./rmsauth_sample # auth sample + ``` diff --git a/samples/rms_sample/main.cpp b/samples/rms_sample/main.cpp new file mode 100644 index 00000000..c4c80732 --- /dev/null +++ b/samples/rms_sample/main.cpp @@ -0,0 +1,21 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "mainwindow.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow window; + + window.show(); + + a.exec(); +} diff --git a/samples/rms_sample/mainwindow.cpp b/samples/rms_sample/mainwindow.cpp new file mode 100644 index 00000000..d5f6c1e4 --- /dev/null +++ b/samples/rms_sample/mainwindow.cpp @@ -0,0 +1,446 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mainwindow.h" +#include "ui_templatesdialog.h" +#include "rightsdialog.h" +#include "ui_mainwindow.h" + +using namespace std; +using namespace rmsauth; + +AuthCallback::AuthCallback(const QString& clientId, const QString& redirectUrl) + : clientId_(clientId) + , redirectUrl_(redirectUrl) +{ + FileCachePtr = std::make_shared(); +} + +string AuthCallback::GetToken(shared_ptr& ap) { + string redirect = + ap->Scope().empty() ? redirectUrl_.toStdString() : ap->Scope(); + + try + { + if (redirect.empty()) { + throw rmscore::exceptions::RMSInvalidArgumentException( + "redirect Url is empty"); + } + + if (clientId_.isEmpty()) { + throw rmscore::exceptions::RMSInvalidArgumentException("client Id is empty"); + } + + AuthenticationContext authContext( + ap->Authority(), AuthorityValidationType::False, FileCachePtr); + auto result = authContext.acquireToken(ap->Resource(), + clientId_.toStdString(), redirect, + PromptBehavior::Auto); + return result->accessToken(); + } + catch (const rmsauth::Exception& ex) + { + cout << "!!!!! Auth error: " << ex.error() << endl; + throw; + } + + return ""; +} + +ConsentList ConsentCallback::Consents(ConsentList& /*consents*/) { + ConsentList result; + + return result; +} + +size_t TemplatesCallback::SelectTemplate( + std::vector& templates) +{ + // show dialog + auto selectTemplateDlg = new QDialog(0, 0); + + Ui_TemplatesDialog selectTemplate; + + selectTemplate.setupUi(selectTemplateDlg); + + for (size_t pos = 0, last = templates.size(); pos < last; ++pos) { + selectTemplate.comboBoxTemplates->insertItem(0, QString::fromStdString( + templates[pos].Name())); + } + + selectTemplateDlg->exec(); + + return static_cast(selectTemplate.comboBoxTemplates->currentIndex()); +} + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) + +{ + ui->setupUi(this); + + + qDebug() << "---- Start! -----"; +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_certificatesPathButton_clicked() +{ + QString dir = + QFileDialog::getExistingDirectory(this, tr( + "Select certificates directory"), + ui->ineEdit_certificatesPath->text(), + QFileDialog::ShowDirsOnly | + QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty()) { + ui->ineEdit_certificatesPath->setText(dir); + } +} + +void MainWindow::addCertificates() { + auto dirStr = ui->ineEdit_certificatesPath->text(); + QDir dir(dirStr); + auto filesList = dir.entryInfoList(); + std::vector buffer; + + for (auto& fileName : filesList) { + ifstream file( + fileName.absoluteFilePath().toStdString(), + ios_base::in | ios_base::binary | ios_base::ate); + + if (!file.is_open()) continue; + + buffer.resize(file.tellg()); + file.seekg(0, ios::beg); + + if (file.read(reinterpret_cast(buffer.data()), buffer.size())) { + // add certificate to RmsAuth + if (!rmsauth::HttpHelper::addCACertificateBase64(buffer)) { + rmsauth::HttpHelper::addCACertificateDer(buffer); + } + + // add certificate to RMS + if (!rmscore::modernapi::HttpHelper::addCACertificateBase64(buffer)) { + rmscore::modernapi::HttpHelper::addCACertificateDer(buffer); + } + } + file.close(); + } +} + +void MainWindow::on_encryptPFILETemplatesButton_clicked() +{ + QString fileIn = QFileDialog::getOpenFileName(this, tr( + "Select file to encrypt")); + QString fileOut = fileIn + ".pfile"; + + if (!fileIn.isEmpty()) { + // add certificates + addCertificates(); + + auto inFile = std::make_shared( + fileIn.toStdString(), ios_base::in | ios_base::binary); + auto outFile = std::make_shared( + fileOut.toStdString(), + ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary); + + if (!inFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileIn); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + if (!outFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileOut); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + auto fileParts = fileIn.split("."); + QString fileExt = fileParts.at(fileParts.size() - 1); + fileExt = "." + fileExt; + + try { + AuthCallback auth( + ui->lineEdit_clientId->text(), ui->lineEdit_redirectUrl->text()); + PFileConverter::ConvertToPFileTemplates( + ui->lineEdit_clientEmail->text().toStdString(), + inFile, + fileExt.toStdString(), + outFile, + auth, + this->consent, + this->templates); + this->ui->textBrowser->insertPlainText("Successfully converted to '"); + this->ui->textBrowser->insertPlainText(fileOut); + this->ui->textBrowser->insertPlainText("'\n"); + } + catch (const rmsauth::Exception& e) { + this->ui->textBrowser->insertPlainText("ERROR: "); + this->ui->textBrowser->insertPlainText(e.error().c_str()); + this->ui->textBrowser->insertPlainText("\n"); + + outFile->close(); + std::remove(fileOut.toStdString().c_str()); + } + + inFile->close(); + outFile->close(); + } +} + +void MainWindow::on_fromPFILEButton_clicked() +{ + QString fileIn = + QFileDialog::getOpenFileName(this, tr("Select file to decrypt")); + QString fileOut; + + if (!fileIn.isEmpty()) { + // add certificates + addCertificates(); + + auto inFile = std::make_shared( + fileIn.toStdString(), ios_base::in | ios_base::binary); + + if (!inFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileIn); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + // check extension + QStringList fileParts = fileIn.split("."); + fileOut = fileIn.mid(0, fileIn.size() - fileParts.at( + fileParts.size() - 1).size() - 1); + + // create streams + auto outFile = std::make_shared( + fileOut.toStdString(), + ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary); + + if (!outFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileOut); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + try + { + AuthCallback auth( + ui->lineEdit_clientId->text(), ui->lineEdit_redirectUrl->text()); + auto pfs = PFileConverter::ConvertFromPFile( + this->ui->lineEdit_clientEmail->text().toStdString(), + inFile, + outFile, + auth, + this->consent); + + cout << "Policy Name: " << pfs->m_stream->Policy()->Name() << endl; + cout << "Policy Description: " << pfs->m_stream->Policy()->Description() << + endl; + time_t tmp = std::chrono::system_clock::to_time_t( + pfs->m_stream->Policy()->ContentValidUntil()); + std::tm time; + memset(&time, 0, sizeof(time)); +#if defined _WIN32 + localtime_s(&time, &tmp); +#else // if defined _WIN32 + time = *std::localtime(&tmp); +#endif // if defined _WIN32 + cout << "Policy ContentValidUntil: " << + time.tm_mon << "-" << time.tm_mday << "-" << time.tm_year << " " << + time.tm_hour << ":" << time.tm_min << "." << time.tm_sec << endl; + + // cout << "Policy ContentValidUntil: " << + // pfs->m_stream->Policy()->ContentValidUntil() << endl; + + this->ui->textBrowser->insertPlainText(QString( + "Successfully converted to '%1'\n").arg( + fileOut)); + } + catch(const rmsauth::Exception& e) + { + this->ui->textBrowser->insertPlainText("ERROR: "); + this->ui->textBrowser->insertPlainText(e.error().c_str()); + this->ui->textBrowser->insertPlainText("\n"); + } + inFile->close(); + outFile->close(); + } +} + +void MainWindow::on_encryptPFILERightsButton_clicked() +{ + QString fileIn = QFileDialog::getOpenFileName(this, tr( + "Select file to encrypt")); + QString fileOut = fileIn + ".pfile"; + + if (!fileIn.isEmpty()) { + // add certificates + addCertificates(); + + auto inFile = std::make_shared( + fileIn.toStdString(), ios_base::in | ios_base::binary); + auto outFile = std::make_shared( + fileOut.toStdString(), + ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary); + + if (!inFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileIn); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + if (!outFile->is_open()) { + this->ui->textBrowser->insertPlainText("ERROR: Failed to open '"); + this->ui->textBrowser->insertPlainText(fileOut); + this->ui->textBrowser->insertPlainText("\n"); + return; + } + + auto fileParts = fileIn.split("."); + QString fileExt = fileParts.at(fileParts.size() - 1); + fileExt = "." + fileExt; + + vector userRights = openRightsDlg(); + + // is anything to add + if (userRights.size() == 0) { + this->ui->textBrowser->insertPlainText( + "Please fill email and check rights\n'"); + return; + } + + + try { + AuthCallback auth( + ui->lineEdit_clientId->text(), ui->lineEdit_redirectUrl->text()); + PFileConverter::ConvertToPFilePredefinedRights( + ui->lineEdit_clientEmail->text().toStdString(), + inFile, + fileExt.toStdString(), + outFile, + auth, + this->consent, + userRights); + this->ui->textBrowser->insertPlainText("Successfully converted to '"); + this->ui->textBrowser->insertPlainText(fileOut); + this->ui->textBrowser->insertPlainText("'\n"); + } + catch (const rmsauth::Exception& e) { + this->ui->textBrowser->insertPlainText("ERROR: "); + this->ui->textBrowser->insertPlainText(e.error().c_str()); + this->ui->textBrowser->insertPlainText("\n"); + + outFile->close(); + std::remove(fileOut.toStdString().c_str()); + } + inFile->close(); + outFile->close(); + } +} + +std::vectorMainWindow::openRightsDlg() { + RightsDialog dlg; + QStandardItemModel model(&dlg); + QStringList columnsNames { "User email" }; + + vector userRights; + + columnsNames.push_back(QString::fromStdString(CommonRights::Owner())); + columnsNames.push_back(QString::fromStdString(CommonRights::View())); + columnsNames.push_back(QString::fromStdString(EditableDocumentRights::Edit())); + columnsNames.push_back(QString::fromStdString(EditableDocumentRights::Export())); + columnsNames.push_back(QString::fromStdString(EditableDocumentRights::Extract())); + columnsNames.push_back(QString::fromStdString(EditableDocumentRights::Print())); + columnsNames.push_back(QString::fromStdString(EditableDocumentRights::Comment())); + + + model.setHorizontalHeaderLabels(columnsNames); + + for (int row = 0; row < 10; ++row) { + for (int col = 0, colMax = columnsNames.size(); col < colMax; ++col) { + QStandardItem *item = new QStandardItem; + + if (col > 0) { + item->setCheckable(true); + item->setCheckState(Qt::Unchecked); + item->setFlags( + Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + model.setItem(row, col, item); + } + } + + dlg.InitRightsList(model); + + if (dlg.exec() != QDialog::Accepted) { + return userRights; + } + + // now create rights list + for (auto row = 0, rowMax = model.rowCount(); row < rowMax; row++) { + rmscore::modernapi::UserList users; + rmscore::modernapi::RightList rights; + QString tmpStr; + + for (int col = 0; col < 6; ++col) { + QStandardItem *item = model.item(row, col); + + if (item == nullptr) continue; + + if (col == 0) { + tmpStr = item->text(); + + if (!tmpStr.isEmpty()) { + users.push_back(tmpStr.toStdString()); + } + } else { + rights.push_back(columnsNames[col].toStdString()); + } + } + + // check for validity + if ((users.size() > 0) && (rights.size() > 0)) { + userRights.push_back(UserRights(users, rights)); + } + } + return userRights; +} diff --git a/samples/rms_sample/mainwindow.h b/samples/rms_sample/mainwindow.h new file mode 100644 index 00000000..b00ca564 --- /dev/null +++ b/samples/rms_sample/mainwindow.h @@ -0,0 +1,85 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "pfileconverter.h" + +using namespace rmscore::modernapi; +using namespace std; + +class AuthCallback : public IAuthenticationCallback { +private: + + std::shared_ptr FileCachePtr; + QString clientId_; + QString redirectUrl_; + +public: + + AuthCallback(const QString& clientId, const QString& redirectUrl); + virtual string GetToken(shared_ptr& ap) override; +}; + +class ConsentCallback : public IConsentCallback { +public: + + virtual ConsentList Consents(ConsentList& consents) override; +}; + +class TemplatesCallback : public ITemplatesCallback { +public: + + virtual size_t SelectTemplate(std::vector& templates) override; +}; + + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow { + Q_OBJECT + +public: + + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + + void on_certificatesPathButton_clicked(); + void on_encryptPFILETemplatesButton_clicked(); + + void on_fromPFILEButton_clicked(); + + void on_encryptPFILERightsButton_clicked(); + +private: + + Ui::MainWindow *ui; + ConsentCallback consent; + TemplatesCallback templates; + + void addCertificates(); + std::vector openRightsDlg(); +}; + +#endif // MAINWINDOW_H diff --git a/samples/rms_sample/mainwindow.ui b/samples/rms_sample/mainwindow.ui new file mode 100644 index 00000000..63ea5117 --- /dev/null +++ b/samples/rms_sample/mainwindow.ui @@ -0,0 +1,185 @@ + + + MainWindow + + + + 0 + 0 + 614 + 345 + + + + MainWindow + + + + + + + + + + + + + Resource ID + + + + + + + Redirect URI + + + + + + + 4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7 + + + + + + + Client ID + + + + + + + https://client.test.app + + + + + + + Certificates path + + + + + + + Browse... + + + + + + + api.aadrm.com + + + + + + + Encrypt PFILE (templates) + + + + + + + ./certificates/ + + + + + + + + 0 + 0 + + + + Decrypt PFILE + + + + + + + Client Email + + + + + + + john.smith@msopentechtest01.onmicrosoft.com + + + + + + + Encrypt PFILE (rights) + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + + + + + + + + TopToolBarArea + + + false + + + + + + + lineEdit_clientId + lineEdit_clientEmail + lineEdit_redirectUrl + lineEdit_resourseId + ineEdit_certificatesPath + textBrowser + encryptPFILETemplatesButton + encryptPFILERightsButton + fromPFILEButton + certificatesPathButton + + + + diff --git a/samples/rms_sample/pfileconverter.cpp b/samples/rms_sample/pfileconverter.cpp new file mode 100644 index 00000000..46bb01e9 --- /dev/null +++ b/samples/rms_sample/pfileconverter.cpp @@ -0,0 +1,233 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include "pfileconverter.h" + +using namespace rmscore::modernapi; +using namespace std; + +static mutex threadLocker; +static int64_t totalSize = 0; +static int64_t readPosition = 0; +static int64_t writePosition = 0; +static vector threadPool; + +#define THREADS_NUM 12 + + +static void WorkerThread(shared_ptr stdStream, + shared_ptrpStream, + bool modeWrite) { + vector buffer(4096); + int64_t bufferSize = static_cast(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(); + qDebug() << "WRITE offsetRead = " << offsetRead << " offsetWrite = " << + offsetWrite << " toProcess = " << toProcess; + + stdStream->seekg(offsetRead); + stdStream->read(reinterpret_cast(&buffer[0]), toProcess); + threadLocker.unlock(); + auto written = + pStream->Write(buffer.data(), toProcess); + + 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, false).get(); + + if (read == 0) { + break; + } + + try { + // stdStream is not thread safe!!! + threadLocker.lock(); + + qDebug() << "READ offsetRead = " << offsetRead << " offsetWrite = " << + offsetWrite << " toProcess = " << toProcess; + + // seek to write + stdStream->seekp(offsetWrite); + stdStream->write(reinterpret_cast(buffer.data()), read); + threadLocker.unlock(); + } + catch (exception& e) { + qDebug() << "Exception: " << e.what(); + } + } + } +} + +PFileConverter::PFileConverter() +{} + +PFileConverter::~PFileConverter() +{} + +void PFileConverter::ConvertToPFilePredefinedRights( + const string & userId, + shared_ptr inStream, + const string & fileExt, + shared_ptr outStream, + IAuthenticationCallback & auth, + IConsentCallback& /*consent*/, + const vector& userRights) +{ + auto endValidation = chrono::system_clock::now() + chrono::hours(8760); + + + PolicyDescriptor desc(userRights); + + desc.Referrer(make_shared("https://client.test.app")); + desc.ContentValidUntil(endValidation); + desc.OfflineCacheLifetimeInDays(2); + + auto policy = + shared_ptr(UserPolicy::Create(desc, userId, auth, + USER_AllowAuditedExtraction)); + ConvertToPFileUsingPolicy(policy, inStream, fileExt, outStream); +} + +void PFileConverter::ConvertToPFileTemplates(const string & userId, + shared_ptr inStream, + const string & fileExt, + std::shared_ptroutStream, + IAuthenticationCallback& auth, + IConsentCallback& /*consent*/, + ITemplatesCallback & templ) +{ + auto templates = TemplateDescriptor::GetTemplateList(userId, auth); + + unordered_map signedData; + + size_t pos = templ.SelectTemplate(templates); + + if (pos < templates.size()) { + auto policy = + shared_ptr(UserPolicy::CreateFromTemplateDescriptor(templates[ + pos], + userId, + auth, + USER_AllowAuditedExtraction, + signedData)); + + ConvertToPFileUsingPolicy(policy, inStream, fileExt, outStream); + } +} + +void PFileConverter::ConvertToPFileUsingPolicy(shared_ptr policy, + shared_ptr inStream, + const string & fileExt, + std::shared_ptroutStream) +{ + 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(); + qDebug() << "Total size = " << totalSize; + + // start threads + threadPool.push_back(thread(WorkerThread, + static_pointer_cast(inStream), pStream, + true)); + + for (thread& t: threadPool) { + if (t.joinable()) { + t.join(); + } + } + + pStream->Flush(); + } +} + +shared_ptrPFileConverter::ConvertFromPFile( + const string & userId, + shared_ptr inStream, + shared_ptr outStream, + IAuthenticationCallback& auth, + IConsentCallback & consent) +{ + auto inIStream = rmscrypto::api::CreateStreamFromStdStream(inStream); + + auto fsResult = ProtectedFileStream::Acquire(inIStream, + userId, + auth, + consent, + POL_None, + static_cast( + 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(outStream), pfs, + false)); + } + + for (thread& t: threadPool) { + if (t.joinable()) { + t.join(); + } + } + } + return fsResult; +} diff --git a/samples/rms_sample/pfileconverter.h b/samples/rms_sample/pfileconverter.h new file mode 100644 index 00000000..8c7a653a --- /dev/null +++ b/samples/rms_sample/pfileconverter.h @@ -0,0 +1,63 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef PFILECONVERTER_H +#define PFILECONVERTER_H +#include +#include +#include +#include + +class ITemplatesCallback { +public: + + virtual size_t SelectTemplate( + std::vector& templates) = + 0; +}; + + +class PFileConverter { +public: + + PFileConverter(); + ~PFileConverter(); + + static void ConvertToPFilePredefinedRights( + const std::string & userId, + std::shared_ptr inStream, + const std::string & fileExt, + std::shared_ptr outStream, + rmscore::modernapi::IAuthenticationCallback & auth, + rmscore::modernapi::IConsentCallback & consent, + const std::vector& userRights); + static void ConvertToPFileTemplates( + const std::string & userId, + std::shared_ptr inStream, + const std::string & fileExt, + std::shared_ptr outStream, + rmscore::modernapi::IAuthenticationCallback& auth, + rmscore::modernapi::IConsentCallback & consent, + ITemplatesCallback & templ); + static std::shared_ptr + ConvertFromPFile(const std::string & userId, + std::shared_ptr inStream, + std::shared_ptr outStream, + rmscore::modernapi::IAuthenticationCallback& auth, + rmscore::modernapi::IConsentCallback & consent); + +private: + + static void ConvertToPFileUsingPolicy( + std::shared_ptrpolicy, + std::shared_ptr inStream, + const std::string & fileExt, + std::shared_ptr outStream); +}; + +#endif // PFILECONVERTER_H diff --git a/samples/rms_sample/rightsdialog.cpp b/samples/rms_sample/rightsdialog.cpp new file mode 100644 index 00000000..e455eb11 --- /dev/null +++ b/samples/rms_sample/rightsdialog.cpp @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "rightsdialog.h" +#include "ui_rightsdialog.h" + +RightsDialog::RightsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::RightsDialog) +{ + ui->setupUi(this); +} + +RightsDialog::~RightsDialog() +{ + delete ui; +} + +void RightsDialog::InitRightsList(QStandardItemModel& model) { + ui->UserRightsView->setModel(&model); + ui->UserRightsView->resizeRowsToContents(); + + for (int i = 1; i < 8; ++i) { + ui->UserRightsView->setColumnWidth(i, 65); + } +} diff --git a/samples/rms_sample/rightsdialog.h b/samples/rms_sample/rightsdialog.h new file mode 100644 index 00000000..30bdb5a2 --- /dev/null +++ b/samples/rms_sample/rightsdialog.h @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef RIGHTSDIALOG_H +#define RIGHTSDIALOG_H + +#include +#include +#include + +namespace Ui { +class RightsDialog; +} + +class RightsDialog : public QDialog { + Q_OBJECT + +public: + + explicit RightsDialog(QWidget *parent = 0); + ~RightsDialog(); + + void InitRightsList(QStandardItemModel& model); + +private: + + Ui::RightsDialog *ui; +}; + +#endif // RIGHTSDIALOG_H diff --git a/samples/rms_sample/rightsdialog.ui b/samples/rms_sample/rightsdialog.ui new file mode 100644 index 00000000..6fdb796a --- /dev/null +++ b/samples/rms_sample/rightsdialog.ui @@ -0,0 +1,78 @@ + + + RightsDialog + + + + 0 + 0 + 627 + 300 + + + + Specify users and rights + + + + + 10 + 240 + 601 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 10 + 601 + 221 + + + + + + + + buttonBox + accepted() + RightsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + RightsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/samples/rms_sample/rms_sample.pro b/samples/rms_sample/rms_sample.pro new file mode 100644 index 00000000..8fb1b092 --- /dev/null +++ b/samples/rms_sample/rms_sample.pro @@ -0,0 +1,40 @@ +REPO_ROOT = $$PWD/../.. +DESTDIR = $$REPO_ROOT/bin/ +TARGET = rms_sample + +TEMPLATE = app + +QT += core gui xml xmlpatterns widgets webkitwidgets network +CONFIG += c++11 debug_and_release +CONFIG -= app_bundle + +INCLUDEPATH += $$REPO_ROOT/sdk/rmsauth_sdk/rmsauth +INCLUDEPATH += $$REPO_ROOT/sdk/rms_sdk/ModernAPI +INCLUDEPATH += $$REPO_ROOT/sdk/rms_sdk/ +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -L$$DESTDIR -lrmsauthd -lrmsauthWebAuthDialogd -lrmsd -lrmscryptod +}else { + LIBS += -L$$DESTDIR -lrmsauth -lrmsauthWebAuthDialog -lrms -lrmscrypto +} + +SOURCES +=\ + main.cpp\ + mainwindow.cpp \ + pfileconverter.cpp \ + rightsdialog.cpp + +HEADERS +=\ + mainwindow.h \ + pfileconverter.h \ + rightsdialog.h + +FORMS +=\ + mainwindow.ui \ + templatesdialog.ui \ + rightsdialog.ui + +OTHER_FILES += \ + data/test.txt diff --git a/samples/rms_sample/templatesdialog.ui b/samples/rms_sample/templatesdialog.ui new file mode 100644 index 00000000..5f9e9bee --- /dev/null +++ b/samples/rms_sample/templatesdialog.ui @@ -0,0 +1,96 @@ + + + TemplatesDialog + + + + 0 + 0 + 400 + 107 + + + + Dialog + + + + + 10 + 60 + 381 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 20 + 151 + 16 + + + + + 10 + + + + Select template from list: + + + + + + 200 + 17 + 181 + 22 + + + + + + + + buttonBox + accepted() + TemplatesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TemplatesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/samples/rmsauth_sample/MainWindow.cpp b/samples/rmsauth_sample/MainWindow.cpp new file mode 100644 index 00000000..44eea9fd --- /dev/null +++ b/samples/rmsauth_sample/MainWindow.cpp @@ -0,0 +1,103 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "MainWindow.h" +#include "ui_MainWindow.h" +#include + + +using namespace rmsauth; + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_pushButtonGetToken_ac_clicked() +{ + auto authority = ui->lineEdit_authority_ac->text().toStdString(); + auto redirectUri = ui->lineEdit_redirectUri_ac->text().toStdString(); + auto resource = ui->lineEdit_resource_ac->text().toStdString(); + auto clientId = ui->lineEdit_clientId_ac->text().toStdString(); + std::vector intToPromptBehavior{PromptBehavior::Auto, PromptBehavior::Always, PromptBehavior::Never}; + PromptBehavior pb(intToPromptBehavior[ui->comboBox_promptBehavior->currentIndex()]); + + try + { + AuthenticationContext authContext(authority, AuthorityValidationType::False, nullptr); + auto result = authContext.acquireToken(resource, clientId, redirectUri, pb); + + ui->textBrowser_ac->append("Access token: " + QString::fromStdString(result->accessToken())); + } + catch(const Exception& ex) + { + ui->textBrowser_ac->append("Exception: " + QString::fromStdString(ex.error())); + } + catch(...) + { + ui->textBrowser_ac->append("Exception: Unknown"); + } +} + +void MainWindow::on_pushButtonGetToken_cc_clicked() +{ + auto authority = ui->lineEdit_authority_cc->text().toStdString(); + auto clientId = ui->lineEdit_clientId_cc->text().toStdString(); + auto redirectUri = ui->lineEdit_redirectUri_cc->text().toStdString(); + auto resource = ui->lineEdit_resource_cc->text().toStdString(); + auto clientSecret = ui->lineEdit_clientSecret->text().toStdString(); + + try + { + AuthenticationContext authContext(authority, AuthorityValidationType::False, nullptr); + auto clientCredential = std::make_shared(clientId, clientSecret); + auto result = authContext.acquireToken(resource, clientCredential); + ui->textBrowser_cc->append("Access token: " + QString::fromStdString(result->accessToken())); + } + catch(const Exception& ex) + { + ui->textBrowser_cc->append("Exception: " + QString::fromStdString(ex.error())); + } + catch(...) + { + ui->textBrowser_cc->append("Exception: Unknown"); + } +} + +void MainWindow::on_pushButtonGetToken_pwd_clicked() +{ + auto authority = ui->lineEdit_authority_pwd->text().toStdString(); + auto clientId = ui->lineEdit_clientId_pwd->text().toStdString(); + auto redirectUri = ui->lineEdit_redirectUri_pwd->text().toStdString(); + auto resource = ui->lineEdit_resource_pwd->text().toStdString(); + auto userName = ui->lineEdit_userName->text().toStdString(); + auto userPassword = ui->lineEdit_password->text().toStdString(); + try + { + AuthenticationContext authContext(authority, AuthorityValidationType::False, nullptr); + auto userCredential = std::make_shared(userName, userPassword); + auto result = authContext.acquireToken(resource, clientId, userCredential); + ui->textBrowser_pwd->append("Access token: " + QString::fromStdString(result->accessToken())); + } + catch(const Exception& ex) + { + ui->textBrowser_pwd->append("Exception: " + QString::fromStdString(ex.error())); + } + catch(...) + { + ui->textBrowser_pwd->append("Exception: Unknown"); + } + +} diff --git a/samples/rmsauth_sample/MainWindow.h b/samples/rmsauth_sample/MainWindow.h new file mode 100644 index 00000000..dabf7dcc --- /dev/null +++ b/samples/rmsauth_sample/MainWindow.h @@ -0,0 +1,38 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + + void on_pushButtonGetToken_ac_clicked(); + + void on_pushButtonGetToken_cc_clicked(); + + void on_pushButtonGetToken_pwd_clicked(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/samples/rmsauth_sample/MainWindow.ui b/samples/rmsauth_sample/MainWindow.ui new file mode 100644 index 00000000..2ce68783 --- /dev/null +++ b/samples/rmsauth_sample/MainWindow.ui @@ -0,0 +1,415 @@ + + + MainWindow + + + + 0 + 0 + 753 + 410 + + + + RmsAuth Sample + + + + + + + 0 + + + + authorization_code + + + + + + + + + + client_id + + + lineEdit_clientId_ac + + + + + + + 4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7 + + + + + + + resource + + + lineEdit_clientId_ac + + + + + + + api.aadrm.com + + + + + + + redirect_uri + + + lineEdit_clientId_ac + + + + + + + https://client.test.app + + + + + + + authority + + + lineEdit_clientId_ac + + + + + + + https://sts.aadrm.com/_sts/oauth/authorize + + + + + + + prompt + + + lineEdit_clientId_ac + + + + + + + Auto + + + 0 + + + 3 + + + true + + + + Auto + + + + + Always + + + + + Never + + + + + + + + + + + + Get token + + + + + + + + + + + + + + + client_credentials + + + + + + + + + + client_id + + + lineEdit_clientId_ac + + + + + + + 4e921ad9-69cb-4223-af1a-3a73620815e8 + + + + + + + resource + + + lineEdit_clientId_ac + + + + + + + https://rms.joshgav.com + + + + + + + redirect_uri + + + lineEdit_clientId_ac + + + + + + + https://rms.joshgav.com, https://localhost:8080/oauth2/token + + + + + + + authority + + + lineEdit_clientId_ac + + + + + + + https://login.microsoftonline.com/msopentechtest01.onmicrosoft.com/oauth2/token + + + + + + + client_secret + + + lineEdit_clientId_ac + + + + + + + + + + + + + + + + Get token + + + + + + + + + + + + + password + + + + + + + + + + client_id + + + lineEdit_clientId_ac + + + + + + + 4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7 + + + + + + + resource + + + lineEdit_clientId_ac + + + + + + + https://outlook.office365.com + + + + + + + redirect_uri + + + lineEdit_clientId_ac + + + + + + + https://client.test.app + + + + + + + authority + + + lineEdit_clientId_ac + + + + + + + https://login.microsoftonline.com/common/oauth2/token + + + + + + + user_name + + + lineEdit_clientId_ac + + + + + + + + + + + + + + password + + + lineEdit_clientId_ac + + + + + + + + + + + + + + + + Get token + + + + + + + + + + + + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/samples/rmsauth_sample/main.cpp b/samples/rmsauth_sample/main.cpp new file mode 100644 index 00000000..2e0df533 --- /dev/null +++ b/samples/rmsauth_sample/main.cpp @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "MainWindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/samples/rmsauth_sample/rmsauth_sample.pro b/samples/rmsauth_sample/rmsauth_sample.pro new file mode 100644 index 00000000..3c27a4a8 --- /dev/null +++ b/samples/rmsauth_sample/rmsauth_sample.pro @@ -0,0 +1,24 @@ +REPO_ROOT = $$PWD/../.. +DESTDIR = $$REPO_ROOT/bin/ +TARGET = rmsauth_sample + +QT += core gui widgets +TEMPLATE = app +CONFIG += c++11 debug_and_release warn_on +CONFIG -= app_bundle + +INCLUDEPATH = $$REPO_ROOT/sdk/rmsauth_sdk/rmsauth + +SOURCES += main.cpp\ + MainWindow.cpp + +HEADERS += MainWindow.h + +FORMS += MainWindow.ui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -L$$DESTDIR -lrmsauthd -lrmsauthWebAuthDialogd +} else { + LIBS += -L$$DESTDIR -lrmsauth -lrmsauthWebAuthDialog +} diff --git a/samples/samples.pro b/samples/samples.pro new file mode 100644 index 00000000..93dbc0ba --- /dev/null +++ b/samples/samples.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS += rms_sample \ + rmsauth_sample diff --git a/scripts/build_and_test.sh b/scripts/build_and_test.sh new file mode 100755 index 00000000..5b81da38 --- /dev/null +++ b/scripts/build_and_test.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +log() { + local file_name=${0##*/} + local timestamp=$(date +"%Y-%m-%d %H:%M:%S") + echo "$timestamp $file_name: $1" +} + +QMAKE=qmake +LIB_SUFFIX=.so +UT_SUFFIX= +STRIP_OPTIONS=--strip-unneeded +VARS="CONFIG+=release" +TARGET_DIR=./build/release + +BUILD=true +DEBUG=false +TEST=false +SAMPLE=true +while [ $# -gt 0 ]; do + case $1 in + debug) DEBUG=true + ;; + test) TEST=true + ;; + sample) SAMPLE=true + ;; + esac + shift +done + +if [ `uname` == 'Darwin' ]; then + LIB_SUFFIX=.dylib + STRIP_OPTIONS= +elif [`uname` == 'Linux' ]; then + DISTRO=$(awk -F '=' '{if($1=="DISTRIB_ID") print $2;}' /etc/lsb-release) + if [ $DISTRO == "" ]; then + log "Error reading DISTRO" + exit 1 + elif [ $DISTRO == "Ubuntu" ]; then + type qmake >/dev/null 2>&1 || { echo >&2 log "qmake is required but not installed."; exit 1; } + else # CentOS & OpenSUSE + QMAKE=qmake-qt5 + type qmake-qt5 >/dev/null 2>&1 || { echo >&2 log "qmake-qt5 is required but not installed."; exit 1; } + fi +fi + +#get the script location +pushd `dirname $0` > /dev/null +SCRIPT_DIR=`pwd` +REPO_ROOT=$SCRIPT_DIR/.. +popd > /dev/null +echo "SCRIPT_DIR: $SCRIPT_DIR" +echo "REPO_ROOT : $REPO_ROOT" + +if [ $DEBUG == 'true' ]; then + echo "DEBUG Build" + VARS="CONFIG+=debug" + TARGET_DIR=./build/debug + LIB_SUFFIX=d${LIB_SUFFIX} + UT_SUFFIX=d +fi + +if [ $BUILD == 'true' ]; then + echo "=== Building sdk libraries ===" + echo "--> Entering sdk directory..." + cd $REPO_ROOT/sdk + $QMAKE $VARS -recursive + echo "--> Running make, please see sdk_build.log for details..." + make > sdk_build.log 2>&1 + cd $REPO_ROOT +fi + +echo "=== Prepping reusable libs and includes in ${TARGET_DIR}" +mkdir -p ${TARGET_DIR}/usr/include/rms +mkdir -p ${TARGET_DIR}/usr/include/rmsauth +mkdir -p ${TARGET_DIR}/usr/include/rmscrypto +mkdir -p ${TARGET_DIR}/usr/lib + +cp bin/librms${LIB_SUFFIX} ${TARGET_DIR}/usr/lib +cp bin/librmsauth${LIB_SUFFIX} ${TARGET_DIR}/usr/lib +cp bin/librmscrypto${LIB_SUFFIX} ${TARGET_DIR}/usr/lib +cp bin/librmsauthWebAuthDialog${LIB_SUFFIX} ${TARGET_DIR}/usr/lib + +strip ${STRIP_OPTIONS} ${TARGET_DIR}/usr/lib/librms${LIB_SUFFIX} > /dev/null 2>&1 +strip ${STRIP_OPTIONS} ${TARGET_DIR}/usr/lib/librmsauth${LIB_SUFFIX} > /dev/null 2>&1 +strip ${STRIP_OPTIONS} ${TARGET_DIR}/usr/lib/librmsauthWebAuthDialog${LIB_SUFFIX} > /dev/null 2>&1 +strip ${STRIP_OPTIONS} ${TARGET_DIR}/usr/lib/librmscrypto${LIB_SUFFIX} > /dev/null 2>&1 + +cp sdk/rms_sdk/ModernAPI/*.h ${TARGET_DIR}/usr/include/rms +cp sdk/rmsauth_sdk/rmsauth/rmsauth/*.h ${TARGET_DIR}/usr/include/rmsauth +cp sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/*.h ${TARGET_DIR}/usr/include/rmscrypto + +if [ $TEST == 'true' ]; then + echo "--> Starting unit tests..." + cd $REPO_ROOT/bin + export LD_LIBRARY_PATH=`pwd` + if [ -e "./tests/rmsauthUnitTests$UT_SUFFIX" ]; then + # Please use --interactive option to start interactive test cases as well + ./tests/rmsauthUnitTests$UT_SUFFIX #--interactive + else + echo "!!! unit tests for rmsauth not found" + fi + if [ -e "./tests/rmscryptoUnitTests$UT_SUFFIX" ]; then + ./tests/rmsCryptoUnitTests$UT_SUFFIX + else + echo "!!! unit tests for rmscrypto not found" + fi + if [ -e "./tests/rmsplatformUnitTests$UT_SUFFIX" ]; then + ./tests/rmsplatformUnitTests$UT_SUFFIX + else + echo "!!! unit tests for rmsplatform not found" + fi +fi + +if [ $SAMPLE == 'true' ]; then + echo "=== Building sample applications ===" + echo "--> Entering samples directory..." + cd $REPO_ROOT/samples + $QMAKE $VARS -recursive + echo "--> Running make, please see sdk_build.log for details..." + make > sample_apps_build.log 2>&1 + cd $REPO_ROOT +fi + +echo "=== This was built:" +find $REPO_ROOT/bin diff --git a/scripts/build_windows.ps1 b/scripts/build_windows.ps1 new file mode 100755 index 00000000..072750f7 --- /dev/null +++ b/scripts/build_windows.ps1 @@ -0,0 +1,65 @@ +## THIS IS A WIP + +## REPO_ROOT\scripts\build_windows.ps1 +$REPO_ROOT = Resolve-Path -Path "${Script:PSScriptRoot}\.." +Write-Host ("REPO_ROOT: {0}" -f $REPO_ROOT) -ForegroundColor Yellow + +$QtVersion = '5.4.2' + +$QT_DIR = 'c:\Qt\Qt{0}\{1}\msvc2013_64' -f $QtVersion, [System.Version]::Parse($QtVersion).ToString(2) +$QT_BIN = '{0}\bin' -f $QT_DIR +$QMAKE = '{0}\qmake.exe' -f $QT_BIN + +Write-Host "=== Adding QT DLLs to Path" +if (($env:Path -split ';') -notcontains $QT_BIN) { + [System.Environment]::SetEnvironmentVariable('Path', ('{0};{1}' -f $env:Path, $QT_BIN), [System.EnvironmentVariableTarget]::Machine) +} + +$QT_TOOLS_BIN = 'C:\Qt\Qt{0}\Tools\QtCreator\bin' -f $QtVersion +$JOM = '{0}\jom.exe' -f $QT_TOOLS_BIN + +$VSVersion = '12.0' +$VC_DIR = 'C:\Program Files (x86)\Microsoft Visual Studio {0}\VC' -f $VSVersion +$VC_BIN_DIR = '{0}\bin' -f $VC_DIR +$VC_INCLUDE_DIR = '{0}\include' -f $VC_DIR +$env:Path += ';{0}' -f $VC_BIN_DIR + +$env:INCLUDE = '{0};{1}' -f $VC_INCLUDE_DIR,'C:\Program Files (x86)\Windows Kits\8.1\Include\shared;C:\Program Files (x86)\Windows Kits\8.1\Include\um' +$env:LIB = "${REPO_ROOT}\third_party\lib\eay;C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64;C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib;${QT_DIR}\lib" + + +#region InstallChoco +$ChocoInstallVariableName = "ChocolateyInstall" +$ChocoPath = [Environment]::GetEnvironmentVariable($ChocoInstallVariableName, [System.EnvironmentVariableTarget]::User) +$ChocoExePath = 'C:\ProgramData\Chocolatey\bin' +if ($ChocoPath) { + $ChocoExePath = Join-Path $ChocoPath 'bin' +} + +if (!(Test-Path $ChocoExePath)) { + Write-Verbose -Message '=== Installing Chocolatey' + Invoke-Expression (Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' | % Content) +} else { + Write-Verbose -Message ('=== Choco available at {0}' -f $ChocoExePath) +} +#endregion + +function Test-ChocoPackageInstall { + param($PackageName) + + $output = choco list $PackageName --local-only + if ($output -notmatch '0 packages installed.') { + return $true + } + + return $false +} + +if (-not (Test-ChocoPackageInstall openssl.light)) { + Write-Verbose -Message '=== Installing OpenSSL' + choco install openssl.light --force -y +} + +cd "${REPO_ROOT}\sdk" +& $QMAKE +& $JOM diff --git a/scripts/pkg/deb/DEBIAN/changelog b/scripts/pkg/deb/DEBIAN/changelog new file mode 100644 index 00000000..5a7621e6 --- /dev/null +++ b/scripts/pkg/deb/DEBIAN/changelog @@ -0,0 +1,5 @@ +rms-sdk (1.0.0-1) unstable; urgency=low + + * Initial release (Closes: #nnnn) + + -- User Thu, 07 May 2015 18:14:34 +0300 diff --git a/scripts/pkg/deb/DEBIAN/control b/scripts/pkg/deb/DEBIAN/control new file mode 100644 index 00000000..872ea652 --- /dev/null +++ b/scripts/pkg/deb/DEBIAN/control @@ -0,0 +1,7 @@ +Package: rms-sdk +Version: 1.0-1 +Maintainer: Andrei Pogoreltcev +Architecture: amd64 +Section: libs +Depends: libgl1-mesa-dev, libssl-dev, libc-dev +Description: Microsoft Azure Rights Management library with ADAL diff --git a/scripts/pkg/deb/DEBIAN/copyright b/scripts/pkg/deb/DEBIAN/copyright new file mode 100644 index 00000000..65831805 --- /dev/null +++ b/scripts/pkg/deb/DEBIAN/copyright @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Open Technologies, Inc. + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/scripts/pkg/deb/DEBIAN/postinst b/scripts/pkg/deb/DEBIAN/postinst new file mode 100755 index 00000000..8b0c8224 --- /dev/null +++ b/scripts/pkg/deb/DEBIAN/postinst @@ -0,0 +1 @@ +/sbin/ldconfig diff --git a/scripts/pkg/deb/DEBIAN/postrm b/scripts/pkg/deb/DEBIAN/postrm new file mode 100755 index 00000000..8b0c8224 --- /dev/null +++ b/scripts/pkg/deb/DEBIAN/postrm @@ -0,0 +1 @@ +/sbin/ldconfig diff --git a/scripts/pkg/deb/etc/ld.so.conf.d/rms-sdk.conf b/scripts/pkg/deb/etc/ld.so.conf.d/rms-sdk.conf new file mode 100644 index 00000000..ea0a95d6 --- /dev/null +++ b/scripts/pkg/deb/etc/ld.so.conf.d/rms-sdk.conf @@ -0,0 +1,2 @@ +# rms-sdk default configuration +/usr/lib/rms-sdk diff --git a/scripts/pkg/make_pkg.sh b/scripts/pkg/make_pkg.sh new file mode 100755 index 00000000..eb8881ff --- /dev/null +++ b/scripts/pkg/make_pkg.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +mkdir dist +cp -r ./deb/DEBIAN/ ./dist/ +cp -r ./deb/etc ./dist/ +cd dist + +md5deep -r -l usr > DEBIAN/md5sum + +find ./ -type d -exec chmod 755 {} \; +find ./ -type f -exec chmod 644 {} \; +find ./ -iname '*.so*' -type f -exec chmod +x {} \; +chmod +x ./DEBIAN/postinst +chmod +x ./DEBIAN/postrm + +cd .. +fakeroot dpkg-deb --build dist +mv -f dist.deb rms-sdk_1.0_x64.deb diff --git a/sdk/rms_sdk/Common/Common.pro b/sdk/rms_sdk/Common/Common.pro new file mode 100644 index 00000000..3813b23a --- /dev/null +++ b/sdk/rms_sdk/Common/Common.pro @@ -0,0 +1,20 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/rms +TARGET = modcommon + + +TEMPLATE = lib +QT += core + +CONFIG += staticlib warn_on c++11 debug_and_release + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +HEADERS += CommonTypes.h \ + FrameworkSpecificTypes.h \ + tools.h + +SOURCES += \ + tools.cpp diff --git a/sdk/rms_sdk/Common/CommonTypes.h b/sdk/rms_sdk/Common/CommonTypes.h new file mode 100644 index 00000000..75e94a47 --- /dev/null +++ b/sdk/rms_sdk/Common/CommonTypes.h @@ -0,0 +1,48 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_COMMONTYPES_H_ +#define _RMS_LIB_COMMONTYPES_H_ + +#include +#include +#include +#include "FrameworkSpecificTypes.h" +#include "../Platform/Http/IUri.h" + +namespace rmscore { +namespace common { +template +using TIterable = std::vector; +using ByteArray = TIterable; +using CharArray = TIterable; +using StringArray = TIterable; +using IUri = rmscore::platform::http::IUri; +using UrlArray = TIterable>; + +struct HashConstString +{ + long operator()(const std::string& str) const { + return static_cast(std::hash()(str)); + } +}; +template +using HashMapString = std::unordered_map; + + +#ifdef _MSC_VER +# define snprintf _snprintf +#else +# define _strcmpi strcasecmp +# define _stricmp strcasecmp +# define _strnicmp strncasecmp +#endif // _MSC_VER +} // namespace common +} // namespace rmscore + +#endif // _RMS_LIB_COMMONTYPES_H_ diff --git a/sdk/rms_sdk/Common/FrameworkSpecificTypes.h b/sdk/rms_sdk/Common/FrameworkSpecificTypes.h new file mode 100644 index 00000000..46f4f020 --- /dev/null +++ b/sdk/rms_sdk/Common/FrameworkSpecificTypes.h @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_FRAMEWORKSPESIFIC_H_ +#define _RMS_LIB_FRAMEWORKSPESIFIC_H_ +#include +#include +#include +#include +#include +#include "CommonTypes.h" + +namespace rmscore { +namespace common { +using DateTime = QDateTime; +using Event = QMutex; +using Mutex = QMutex; +using MutexLocker = QMutexLocker; +using Locale = QLocale; +using DataStream = QDataStream; +using IODevice = QIODevice; +} // namespace common +} // namespace rmscore +#endif // _RMS_LIB_FRAMEWORKSPESIFIC_H_ diff --git a/sdk/rms_sdk/Common/ResultException.h b/sdk/rms_sdk/Common/ResultException.h new file mode 100644 index 00000000..bc3f58dd --- /dev/null +++ b/sdk/rms_sdk/Common/ResultException.h @@ -0,0 +1,119 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PROTECTIONEXCEPTION_H_ +#define _RMS_LIB_PROTECTIONEXCEPTION_H_ + +namespace rmslib { +namespace common { +#include + +class ResultException +{ +public: + + ResultException(int hr, PCWSTR wszFile, PCWSTR wszFunction, DWORD dwLine); + ResultException(int hr, PCWSTR wszFile, PCWSTR wszFunction, DWORD dwLine, PCWSTR wszMessageFormat, ...); + + HRESULT GetHResult() const + { + return m_hr; + } + + const std::string& GetMessage() const + { + return m_message; + } + + const std::string& GetFile() const + { + return m_file; + } + + const std::string& GetFunction() const + { + return m_function; + } + + DWORD GetLine() const + { + return m_dwLine; + } + +private: + + void Initialize(HRESULT hr, PCWSTR wszFile, PCWSTR wszFunction, DWORD dwLine, PCWSTR wszMessageFormat, va_list args); + +private: + + HRESULT m_hr; + std::string m_message; + std::string m_file; + std::string m_function; + DWORD m_dwLine; +}; +} // namespace common +} // namespace rmslib + +#define THROW_HR(hr, ...) \ +{ \ + prot::ResultException exc((hr), __FILEW__, __FUNCTIONW__, __LINE__, __VA_ARGS__); \ + prot::Logger::LogException(exc); \ + throw exc; \ +} + +#define FAIL_HR_X(hr, ...) \ +{ \ + THROW_HR((hr), __VA_ARGS__); \ +} + +#define CHECK_HR_X(hr, ...) \ +{ \ + if (FAILED((hr))) { FAIL_HR_X((hr), __VA_ARGS__); } \ +} + +#define CHECK_BOOL_X_HR(b, hr, ...) \ +{ \ + if (FALSE == (b)) { FAIL_HR_X((hr), __VA_ARGS__); } \ +} + +#define CHECK_BOOL_X(b, ...) \ +{ \ + CHECK_BOOL_X_HR((b), E_UNEXPECTED, __VA_ARGS__); \ +} + +#define CHECK_BOOL_X_ARG(b, ...) \ +{ \ + CHECK_BOOL_X_HR((b), E_INVALIDARG, __VA_ARGS__); \ +} + +#define CHECK_BOOL_X_GLE(b, ...) \ +{ \ + CHECK_BOOL_X_HR((b), HRESULT_FROM_WIN32(GetLastError()), __VA_ARGS__); \ +} + +#define CHECK_PTR_X_HR(p, hr, ...) \ +{ \ + if (nullptr == (p)) { FAIL_HR_X((hr), __VA_ARGS__); } \ +} + +#define CHECK_PTR_X(p, ...) \ +{ \ + CHECK_PTR_X_HR((p), E_UNEXPECTED, __VA_ARGS__); \ +} + +#define CHECK_PTR_X_ARG(p, ...) \ +{ \ + CHECK_PTR_X_HR((p), E_INVALIDARG, __VA_ARGS__); \ +} + +#define CHECK_PTR_X_GLE(p, ...) \ +{ \ + CHECK_PTR_X_HR((p), HRESULT_FROM_WIN32(GetLastError()), __VA_ARGS__); \ +} +#endif //_RMS_LIB_PROTECTIONEXCEPTION_H_ diff --git a/sdk/rms_sdk/Common/tools.cpp b/sdk/rms_sdk/Common/tools.cpp new file mode 100644 index 00000000..e753f823 --- /dev/null +++ b/sdk/rms_sdk/Common/tools.cpp @@ -0,0 +1,72 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "tools.h" + +#define TIME_CONVERSION_MS_TO_100NS 10000 + +using namespace std; + +namespace rmscore { +namespace common { +uint64_t timeToWinFileTime(const QDateTime& dateTime) { + // Definition of FILETIME from MSDN: + // Contains a 64-bit value representing the number of 100-nanosecond intervals + // since January 1, 1601 (UTC). + QDateTime origin(QDate(1601, 1, 1), QTime(0, 0, 0, 0), Qt::UTC); + + // Get offset - note we need 100-nanosecond intervals, hence we multiply by + // 10000. + return TIME_CONVERSION_MS_TO_100NS * origin.msecsTo(dateTime); +} + +ByteArray ConvertBase64ToBytes(const ByteArray& base64str) { + QByteArray ba; + + ba.append(QByteArray(reinterpret_cast(base64str.data()), + static_cast(base64str.size()))); + + auto convArray = QByteArray::fromBase64(ba); + + return ByteArray(convArray.begin(), convArray.end()); +} + +string timeToString(const QDateTime& dateTime) { + if (!dateTime.isNull()) + { + // return dateTime.toString("yyyy-MM-DDThh:mm:ssZ").toStdString(); + return dateTime.toString(Qt::ISODate).toStdString(); + } + else + { + return string(); + } +} + +ByteArray ConvertBytesToBase64(const ByteArray& bytes) { + return ConvertBytesToBase64(bytes.data(), bytes.size()); +} + +ByteArray ConvertBytesToBase64(const void *bytes, const size_t size) +{ + QByteArray ba; + + ba.append(reinterpret_cast(bytes), static_cast(size)); + + auto convArray = ba.toBase64(); + + return ByteArray(convArray.begin(), convArray.end()); +} + +string GenerateAGuid() +{ + return QUuid::createUuid().toString().toStdString(); +} +} // namespace common +} // namespace rmscore diff --git a/sdk/rms_sdk/Common/tools.h b/sdk/rms_sdk/Common/tools.h new file mode 100644 index 00000000..7ba41568 --- /dev/null +++ b/sdk/rms_sdk/Common/tools.h @@ -0,0 +1,26 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_TOOLS_H_ +#define _RMS_LIB_TOOLS_H_ + +#include "CommonTypes.h" +#include "FrameworkSpecificTypes.h" + +namespace rmscore { +namespace common { +uint64_t timeToWinFileTime(const QDateTime& dateTime); +std::string timeToString(const QDateTime& dateTime); +ByteArray ConvertBase64ToBytes(const ByteArray& base64str); +ByteArray ConvertBytesToBase64(const ByteArray& bytes); +ByteArray ConvertBytesToBase64(const void *bytes, + const size_t size); +std::string GenerateAGuid(); +} // namespace common +} // namespace rmscore +#endif // _RMS_LIB_TOOLS_H_ diff --git a/sdk/rms_sdk/Consent/Consent.h b/sdk/rms_sdk/Consent/Consent.h new file mode 100644 index 00000000..69d772cf --- /dev/null +++ b/sdk/rms_sdk/Consent/Consent.h @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CONSENT +#define CONSENT + +#include +#include + +#include "../ModernAPI/IConsent.h" +#include "../Common/CommonTypes.h" + +namespace rmscore { namespace consent { + +/// +/// Consent for accessing end user license url +/// +class Consent : public modernapi::IConsent +{ +public: + virtual const modernapi::ConsentResult& Result() const override + { + return this->result_; + } + +// virtual void ConsentResult(const modernapi::ConsentResult& value) override +// { +// this->result_ = value; +// } + + virtual modernapi::ConsentType Type() const override + { + return this->type_; + } + + virtual const std::vector Urls() const override + { + return this->urls_; + } + + virtual const std::string User() const override + { + return this->user_; + } + + virtual const std::string Domain() const override + { + return this->domain_; + } + +protected: + modernapi::ConsentResult result_; + modernapi::ConsentType type_; + std::vector urls_; + std::string user_; + std::string domain_; +}; + +} // namespace consent +} // namespace rmscore +#endif // CONSENT + diff --git a/sdk/rms_sdk/Consent/Consent.pro b/sdk/rms_sdk/Consent/Consent.pro new file mode 100644 index 00000000..b54460b5 --- /dev/null +++ b/sdk/rms_sdk/Consent/Consent.pro @@ -0,0 +1,23 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/rms +TARGET = modconsent + +QT -= gui +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} +SOURCES += IConsentManager.cpp \ + DocumentTrackingConsentManager.cpp \ + ServiceUrlConsentManager.cpp \ + ServiceUrlConsent.cpp \ + DocumentTrackingConsent.cpp + +HEADERS += IConsentManager.h \ + DocumentTrackingConsentManager.h \ + SeriveUrlConsentManager.h \ + ServiceUrlConsent.h \ + DocumentTrackingConsent.h \ + Consent.h diff --git a/sdk/rms_sdk/Consent/DocumentTrackingConsent.cpp b/sdk/rms_sdk/Consent/DocumentTrackingConsent.cpp new file mode 100644 index 00000000..a986ca3a --- /dev/null +++ b/sdk/rms_sdk/Consent/DocumentTrackingConsent.cpp @@ -0,0 +1,23 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "DocumentTrackingConsent.h" +#include "../ModernAPI/ConsentType.h" + + +namespace rmscore { namespace consent { + +DocumentTrackingConsent::DocumentTrackingConsent(const std::string& email, const std::string& domain) +{ + this->user_ = email; + this->domain_ = domain; + this->type_ = modernapi::ConsentType::DocumentTrackingConsent; +} + +} // namespace consent +} // namespace rmscore diff --git a/sdk/rms_sdk/Consent/DocumentTrackingConsent.h b/sdk/rms_sdk/Consent/DocumentTrackingConsent.h new file mode 100644 index 00000000..6a531896 --- /dev/null +++ b/sdk/rms_sdk/Consent/DocumentTrackingConsent.h @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DOCUMENTTRACKINGCONSENT +#define DOCUMENTTRACKINGCONSENT + +#include "Consent.h" + +namespace rmscore { +namespace consent { +/// +/// Consent for tracking document +/// +class DocumentTrackingConsent : public Consent +{ +public: + DocumentTrackingConsent(const std::string &email, const std::string& domain); +}; + +} // namespace consent +} // namespace rmscore +#endif // DOCUMENTTRACKINGCONSENT + diff --git a/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.cpp b/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.cpp new file mode 100644 index 00000000..9e22eed4 --- /dev/null +++ b/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.cpp @@ -0,0 +1,50 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "DocumentTrackingConsentManager.h" +#include "../ModernAPI/ConsentResult.h" +#include "../ModernAPI/IConsent.h" + +namespace rmscore { +namespace consent { + +DocumentTrackingConsentManager::DocumentTrackingConsentManager(std::shared_ptr consent, bool /*isAutoApproved*/) + : m_consent(consent) +// , m_approved(isAutoApproved) +{} + +bool DocumentTrackingConsentManager::ShouldGetConsent() +{ + /* if (ConsentDBHelper::GetInstance().Initialize() && + (m_consent->Domain != nullptr)) + { + return !(m_approved || + ConsentDBHelper::GetInstance().IsDocumentTrackingConsentnPresent( + m_consent + -> + User->Data(), m_consent->Domain->Data())); + }*/ + + return false; +} + +void DocumentTrackingConsentManager::PersistConsentResult(const modernapi::ConsentResult &result) +{ + if (result.ShowAgain() || (m_consent->Domain().empty())) return; + + /* if (ConsentDBHelper::GetInstance().Initialize()) + { + ConsentDBHelper::GetInstance().AddDocumentTrackingConsent( + m_consent->User->Data(), + m_consent->Domain->Data()); + }*/ +} +} // namespace consent +} // namespace rmscore diff --git a/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.h b/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.h new file mode 100644 index 00000000..592ddd48 --- /dev/null +++ b/sdk/rms_sdk/Consent/DocumentTrackingConsentManager.h @@ -0,0 +1,33 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_DOCUMENTTRACKINGCONSENTMANAGER_H_ +#define _RMS_LIB_DOCUMENTTRACKINGCONSENTMANAGER_H_ + + +#include "IConsentManager.h" + +namespace rmscore { namespace consent { + +class DocumentTrackingConsentManager : public IConsentManager +{ +public: + + DocumentTrackingConsentManager(std::shared_ptr consent, bool isAutoApproved); + virtual bool ShouldGetConsent() override; + virtual void PersistConsentResult(const modernapi::ConsentResult& result) override; + +private: + std::shared_ptr m_consent; +// bool m_approved; +}; + +} // namespace consent +} // namespace rmscore + +#endif // _RMS_LIB_DOCUMENTTRACKINGCONSENTMANAGER_H_ diff --git a/sdk/rms_sdk/Consent/IConsentManager.cpp b/sdk/rms_sdk/Consent/IConsentManager.cpp new file mode 100644 index 00000000..c57631a8 --- /dev/null +++ b/sdk/rms_sdk/Consent/IConsentManager.cpp @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "../ModernAPI/IConsent.h" +#include "../ModernAPI/ConsentType.h" +#include "IConsentManager.h" +#include "SeriveUrlConsentManager.h" +#include "DocumentTrackingConsentManager.h" + +namespace rmscore { namespace consent { + +std::shared_ptr IConsentManager::Create(std::shared_ptr consent, bool bAutoApproved) +{ + if (consent->Type() == modernapi::ConsentType::ServiceUrlConsent) + { + return std::make_shared(consent, bAutoApproved); + } + else + { + return std::make_shared(consent, bAutoApproved); + } +} +} // namespace consent +} // namespace rmscore diff --git a/sdk/rms_sdk/Consent/IConsentManager.h b/sdk/rms_sdk/Consent/IConsentManager.h new file mode 100644 index 00000000..7704e21b --- /dev/null +++ b/sdk/rms_sdk/Consent/IConsentManager.h @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_ICONSENTMANAGER_H_ +#define _RMS_LIB_ICONSENTMANAGER_H_ + +#include +#include +#include +#include "../ModernAPI/IConsent.h" + +namespace rmscore { +namespace consent { +class IConsentManager +{ +public: + virtual bool ShouldGetConsent() = 0; + virtual void PersistConsentResult(const modernapi::ConsentResult& result) = 0; + +public: + static std::shared_ptr Create(std::shared_ptr consent, bool bAutoApproved); +}; +} // namespace consent +} // namespace rmscore +#endif // _RMS_LIB_ICONSENTMANAGER_H_ diff --git a/sdk/rms_sdk/Consent/SeriveUrlConsentManager.h b/sdk/rms_sdk/Consent/SeriveUrlConsentManager.h new file mode 100644 index 00000000..0cb8979d --- /dev/null +++ b/sdk/rms_sdk/Consent/SeriveUrlConsentManager.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_SERVICEURLCONSENTMANAGER_H_ +#define _RMS_LIB_SERVICEURLCONSENTMANAGER_H_ + +#include +#include +#include "IConsentManager.h" +#include "../ModernAPI/IConsent.h" +#include "../ModernAPI/ConsentResult.h" +#include "../ModernAPI/ConsentType.h" + +namespace rmscore { +namespace consent { + +class ServiceUrlConsentManager : public IConsentManager { +public: + + ServiceUrlConsentManager(std::shared_ptr consent, + bool isAutoApproved); + virtual bool ShouldGetConsent() override; + virtual void PersistConsentResult(const modernapi::ConsentResult& result) override; + +private: + + std::shared_ptr m_consent; + std::vector m_urls; +// bool m_approved; + const std::string m_cloudDomain = "api.aadrm.com"; +}; +} // namespace consent +} // namespace rmscore +#endif // _RMS_LIB_SERVICEURLCONSENTMANAGER_H_ diff --git a/sdk/rms_sdk/Consent/ServiceUrlConsent.cpp b/sdk/rms_sdk/Consent/ServiceUrlConsent.cpp new file mode 100644 index 00000000..c19247e7 --- /dev/null +++ b/sdk/rms_sdk/Consent/ServiceUrlConsent.cpp @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "ServiceUrlConsent.h" +#include "../ModernAPI/ConsentType.h" + +namespace rmscore { namespace consent { + +ServiceUrlConsent::ServiceUrlConsent(const std::string& email, const std::vector &urls) +{ + for_each( + urls.begin(), urls.end(), + [&](std::string url) + { + auto urlProtocolLength = url.length(); + + if (urlProtocolLength > 4) urlProtocolLength = 4; + std::string urlProtocol = url.substr(0, urlProtocolLength); + + std::transform(urlProtocol.begin(), urlProtocol.end(), + urlProtocol.begin(), tolower); + + if (urlProtocol.compare("http") != 0) url.insert(0, "https://"); + + this->urls_.push_back(url); + }); + + this->user_ = email; + this->type_ = modernapi::ConsentType::ServiceUrlConsent; +} + +} // namespace consent +} // namespace rmscore + diff --git a/sdk/rms_sdk/Consent/ServiceUrlConsent.h b/sdk/rms_sdk/Consent/ServiceUrlConsent.h new file mode 100644 index 00000000..6bab0e56 --- /dev/null +++ b/sdk/rms_sdk/Consent/ServiceUrlConsent.h @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef SERVICEURLCONSENT +#define SERVICEURLCONSENT + +#include "Consent.h" + +namespace rmscore { namespace consent { + +/// +/// Consent for accessing end user license url +/// +class ServiceUrlConsent : public Consent +{ +public: + ServiceUrlConsent(const std::string& email, const common::StringArray& urls); + +}; + +} // namespace consent +} // namespace rmscore + +#endif // SERVICEURLCONSENT + diff --git a/sdk/rms_sdk/Consent/ServiceUrlConsentManager.cpp b/sdk/rms_sdk/Consent/ServiceUrlConsentManager.cpp new file mode 100644 index 00000000..ab9808f0 --- /dev/null +++ b/sdk/rms_sdk/Consent/ServiceUrlConsentManager.cpp @@ -0,0 +1,68 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "SeriveUrlConsentManager.h" +#include "../Common/CommonTypes.h" +#include "../ModernAPI/IConsent.h" + +using namespace std; +using namespace rmscore::modernapi; + +namespace rmscore { +namespace consent { + +ServiceUrlConsentManager::ServiceUrlConsentManager(std::shared_ptr consent, + bool /*isAutoApproved*/) + : m_consent(consent) +// , m_approved(isAutoApproved) +{ + if (!m_consent->Urls().empty()) + { + for (auto& url : m_consent->Urls()) + { + if (_stricmp(m_cloudDomain.c_str(), url.c_str()) != 0) + { + this->m_urls.push_back(url); + } + } + } +} + +bool ServiceUrlConsentManager::ShouldGetConsent() +{ + if (m_urls.empty()) { + return false; + } + + /* if (ConsentDBHelper::GetInstance().Initialize()) + { + return !(m_approved || + ConsentDBHelper::GetInstance().IsApprovedServiceDomainPresent( + m_consent-> + User-> + Data(), m_urls.at(0))); + }*/ + + return false; +} + +void ServiceUrlConsentManager::PersistConsentResult(const ConsentResult& result) +{ + if (result.ShowAgain() || (m_urls.size() == 0)) return; + + /* + if (ConsentDBHelper::GetInstance().Initialize()) + { + ConsentDBHelper::GetInstance().AddApprovedServiceDomain( + m_consent->User->Data(), m_urls.at(0)); + }*/ +} +} // namespace consent +} // namespace rmscore diff --git a/sdk/rms_sdk/Core/Core.pro b/sdk/rms_sdk/Core/Core.pro new file mode 100644 index 00000000..5cfac336 --- /dev/null +++ b/sdk/rms_sdk/Core/Core.pro @@ -0,0 +1,17 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/rms +TARGET = modcore + +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release +QT += core +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI + +SOURCES += ProtectionPolicy.cpp + +HEADERS += ProtectionPolicy.h diff --git a/sdk/rms_sdk/Core/ProtectionPolicy.cpp b/sdk/rms_sdk/Core/ProtectionPolicy.cpp new file mode 100644 index 00000000..3f65660f --- /dev/null +++ b/sdk/rms_sdk/Core/ProtectionPolicy.cpp @@ -0,0 +1,580 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include "ProtectionPolicy.h" +#include "../ModernAPI/RMSExceptions.h" +#include "../RestClients/IUsageRestrictionsClient.h" +#include "../RestClients/IPublishClient.h" +#include "../Common/tools.h" + +using namespace rmscore::modernapi; +using namespace rmscore::restclients; +using namespace std; + +namespace rmscore { +namespace core { +static AccessStatus MapAccessStatus(string& accessStatus) { + if (0 == _stricmp("AccessGranted", accessStatus.c_str())) { + return ACCESS_STATUS_ACCESS_GRANTED; + } else if (0 == _stricmp("AccessDenied", accessStatus.c_str())) { + return ACCESS_STATUS_ACCESS_DENIED; + } else if (0 == _stricmp("ContentExpired", accessStatus.c_str())) { + return ACCESS_STATUS_ACCESS_EXPIRED; + } else { + ostringstream str; + + str << "Got an invalid AccessStatus (" << accessStatus.c_str() << + ") from the server."; + throw exceptions::RMSNetworkException( + str.str(), exceptions::RMSNetworkException::ServerError); + } +} + +static rmscrypto::api::CipherMode MapCipherMode(string& cipherMode) { + if (0 == + _stricmp("MICROSOFT.CBC4K", + cipherMode.c_str())) return rmscrypto::api::CIPHER_MODE_CBC4K; + + if (0 == _stricmp("MICROSOFT.CBC512.NOPADDING", cipherMode.c_str())) { + return rmscrypto::api::CIPHER_MODE_CBC512NOPADDING; + } else if (0 == _stricmp("MICROSOFT.ECB", cipherMode.c_str())) { + return rmscrypto::api::CIPHER_MODE_ECB; + } else { + ostringstream str; + + str << "Got an invalid CipherMode (" << cipherMode.c_str() << + ") from the server."; + throw exceptions::RMSNetworkException( + str.str(), exceptions::RMSNetworkException::ServerError); + } +} + +shared_ptrProtectionPolicy::Acquire( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + modernapi::IAuthenticationCallbackImpl& authCallback, + const string & email, + const bool bOffline, + common::Event & hCancelEvent, + modernapi::ResponseCacheFlags cacheMask) +{ + EmnptyConsentCallbackImpl consentCallback; + + return ProtectionPolicy::Acquire(pbPublishLicense, + cbPublishLicense, + authCallback, + consentCallback, + email, + bOffline, + hCancelEvent, + cacheMask); +} + +shared_ptrProtectionPolicy::Acquire( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + modernapi::IAuthenticationCallbackImpl& authCallback, + modernapi::IConsentCallbackImpl & consentCallback, + const string & email, + const bool bOffline, + common::Event & hCancelEvent, + modernapi::ResponseCacheFlags cacheMask) +{ + if (pbPublishLicense == nullptr) throw exceptions::RMSNullPointerException( + "pbPublishLicense is null pointer"); + + + qDebug() << " +ProtectionPolicy::Acquire"; + + shared_ptr pProtectionPolicy; + try { + pProtectionPolicy = GetCachedProtectionPolicy(pbPublishLicense, + cbPublishLicense, + email); + } catch (exceptions::RMSException) { + // create a usage restrictions client object + shared_ptr pClient = + IUsageRestrictionsClient::Create(); + + // create a usage restrictions request structure + UsageRestrictionsRequest request = + { + pbPublishLicense, (uint32_t)cbPublishLicense + }; + + // get the usage restrictions + std::shared_ptr response = + pClient->GetUsageRestrictions(request, + authCallback, + consentCallback, + email, + bOffline, + hCancelEvent, + cacheMask); + + // log the response + qDebug() << + "ProtectionPolicy::Acquire got a usage restrictions response" << endl + << "AccessStatus: " << response->accessStatus.c_str() << endl + << "Id: " << response->id.c_str() << endl + << "Name: " << response->name.c_str() << endl + << "Referrer: " << response->referrer.c_str() << endl + << "Owner: " << response->owner.c_str() << endl + << "CipherMode: " << response->key.cipherMode.c_str() << endl + << "contentValidUntil: " << response->contentValidUntil.c_str() << + endl + << "licenseValidUntil: " << response->licenseValidUntil.c_str() << + endl + << "contentId: " << response->contentId.c_str() << endl; + + // create and initialize a new protection policy object from the received + // response + pProtectionPolicy = shared_ptr(new ProtectionPolicy()); + pProtectionPolicy->Initialize(pbPublishLicense, cbPublishLicense, response); + pProtectionPolicy->SetRequester(email); + + // add the newly acquired protection policy to cache + if (cacheMask & modernapi::RESPONSE_CACHE_INMEMORY) { + AddProtectionPolicyToCache(pProtectionPolicy); + } + } + qDebug() << " -ProtectionPolicy::Acquire"; + + return pProtectionPolicy; +} // ProtectionPolicy::Acquire + +std::shared_ptrProtectionPolicy::Create( + const bool bPreferDeprecatedAlgorithms, + const bool bAllowAuditedExtraction, + const string & templateId, + modernapi::IAuthenticationCallbackImpl& authenticationCallback, + const string & email, + const platform::json::StringDictionary& signedAppData) +{ + qDebug() << " +ProtectionPolicy::Create(using template)"; + + auto pPublishClient = IPublishClient::Create(); + + // create a request + auto request = PublishUsingTemplateRequest { + bPreferDeprecatedAlgorithms, bAllowAuditedExtraction, templateId, + signedAppData + }; + + // do the REST call + auto response = pPublishClient->PublishUsingTemplate(request, + authenticationCallback, + email); + + // log the response + qDebug() << + "ProtectionPolicy ::Create got a publish response" << endl + << "Id: " << response.id.c_str() << endl + << "Name: " << response.name.c_str() << endl + << "Referrer: '" << response.referrer.c_str() << endl + << "Owner: " << response.owner.c_str() << endl + << "CipherMode: " << response.key.cipherMode.c_str() << endl + << "ContentId: " << response.contentId.c_str() << endl; + + // create and initialize a new protection policy object from the received + // response + auto pProtectionPolicy = make_shared(); + + pProtectionPolicy->Initialize(response, bAllowAuditedExtraction, -1, + response.signedApplicationData); + + qDebug() << " - ProtectionPolicy::Create"; + + return pProtectionPolicy; +} // ProtectionPolicy::Create + +shared_ptrProtectionPolicy::Create( + const bool bPreferDeprecatedAlgorithms, + const bool bAllowAuditedExtraction, + PolicyDescriptorImpl & descriptor, + modernapi::IAuthenticationCallbackImpl& authenticationCallback, + const string & email) +{ + if (descriptor.userRightsList.empty() && descriptor.userRolesList.empty()) { + throw exceptions::RMSInvalidArgumentException( + "Got an invalid response from the server : args are empty."); + } + qDebug() << " +ProtectionPolicy::Create(custom)"; + + auto pPublishClient = IPublishClient::Create(); + + // create a request + auto request = PublishCustomRequest( + bPreferDeprecatedAlgorithms, bAllowAuditedExtraction + ); + + request.name = descriptor.name; + request.description = descriptor.description; + + common::Locale loc; + + request.language = loc.name().toStdString(); + + request.encryptedApplicationData = descriptor.encryptedApplicationData; + request.signedApplicationData = descriptor.signedApplicationData; + + // initialize rights of the request + // Either rights or roles will be present in the policy descriptor + if (descriptor.userRightsList.size() != 0) { + for_each(begin(descriptor.userRightsList), end(descriptor.userRightsList), + [ =, &request]( + const UserRightsImpl& userRightsImpl) { + if (userRightsImpl.users.empty() || userRightsImpl.rights.empty()) { + throw exceptions::RMSInvalidArgumentException( + "Got an invalid response from the server : args are empty."); + } + auto userRightsRequest = UserRightsRequest { userRightsImpl.users, userRightsImpl.rights }; + + request.userRightsList.emplace_back(userRightsRequest); + }); + } else { + for_each(begin(descriptor.userRolesList), end(descriptor.userRolesList), + [ =, &request]( + const UserRolesImpl& userRolesImpl) { + if (userRolesImpl.users.empty() || userRolesImpl.roles.empty()) { + throw exceptions::RMSInvalidArgumentException( + "Got an invalid response from the server : args are empty."); + } + auto userRolesRequest = UserRolesRequest { userRolesImpl.users, userRolesImpl.roles }; + + request.userRolesList.emplace_back(userRolesRequest); + }); + } + + // initialize validity times + request.nIntervalTime = descriptor.nIntervalTime; + request.ftLicenseValidUntil = descriptor.ftContentValidUntil; + + // Add the referral Info + if (descriptor.referrer.size() > + 0) request.wsReferralInfo = descriptor.referrer; + + // do the REST call + + auto response = pPublishClient->PublishCustom(request, + authenticationCallback, + email); + + // log the response + qDebug() << "ProtectionPolicy ::Create got a publish response with Id ='" << + response.id.c_str() << "',Name = '" << response.name.c_str() << + "',Referrer = '" << response.referrer.c_str() << "', Owner = '" << + response.owner.c_str() << "', CipherMode : '" << + response.key.cipherMode.c_str() << + "',ContentId: '" << response.contentId.c_str(); + + // create and initialize a new protection policy object from the received + // response + auto pProtectionPolicy = shared_ptr(new ProtectionPolicy()); + + pProtectionPolicy->Initialize(response, + bAllowAuditedExtraction, + descriptor.nIntervalTime, + request.signedApplicationData, + request.encryptedApplicationData); + pProtectionPolicy->SetRequester(email); + + qDebug() << " - ProtectionPolicy::Create"; + + // add the newly created protection policy to cache + AddProtectionPolicyToCache(pProtectionPolicy); + + return pProtectionPolicy; +} // ProtectionPolicy::Create + +ProtectionPolicy::ProtectionPolicy() : m_accessStatus(ACCESS_STATUS_ACCESS_DENIED), + m_dwIntervalTime(0) { + m_requester = ""; + m_ftValidityTimeFrom = std::chrono::system_clock::from_time_t(0); + m_ftValidityTimeUntil = std::chrono::system_clock::from_time_t(0); +} + +void ProtectionPolicy::Initialize( + const uint8_t *pbPublishLicense, + size_t cbPublishLicense, + std::shared_ptrresponse) +{ + // initializing protection policy from the consumption response + + m_accessStatus = MapAccessStatus(response->accessStatus); + m_id = response->id; + m_name = response->name; + m_description = response->description; + m_owner = response->owner; + m_referrer = response->referrer; + m_rights = response->rights; + m_issuedTo = response->issuedTo; + m_contentId = response->contentId; + + InitializeValidityTime(response->ftContentValidUntil); + InitializeIntervalTime(response->ftLicenseValidUntil); + + // Check whether roles are present + if (response->roles.size() != 0) m_roles = response->roles; + + // custom policy for the owner + if (!response->customPolicy.bIsNull) { + for_each(begin(response->customPolicy.userRightsList), end( + response->customPolicy.userRightsList), + [this](UserRightsResponse& userRights) { + UserRightsImpl userRightsImpl; + userRightsImpl.users = userRights.users; + userRightsImpl.rights = userRights.rights; + m_userRightsList.emplace_back(userRightsImpl); + }); + + m_bHasUserRightsInformation = true; + + for_each(begin(response->customPolicy.userRolesList), end( + response->customPolicy.userRolesList), + [this](UserRolesResponse& userRoles) { + UserRolesImpl userRolesImpl; + userRolesImpl.users = userRoles.users; + userRolesImpl.roles = userRoles.roles; + m_userRolesList.emplace_back(userRolesImpl); + }); + } else { + m_userRightsList = vector(); + m_userRolesList = vector(); + m_bHasUserRightsInformation = false; + } + m_signedApplicationData = response->signedApplicationData; + m_encryptedApplicationData = response->encryptedApplicationData; + + // if access is granted verify the key and create a crypto provider + if (ACCESS_STATUS_ACCESS_GRANTED == + m_accessStatus) InitializeKey(response->key); + + // initialize the publishing license + m_publishLicense.resize(cbPublishLicense); +#ifdef Q_OS_WIN32 + memcpy_s(&m_publishLicense[0], + m_publishLicense.size(), pbPublishLicense, cbPublishLicense); +#else // ifdef Q_OS_WIN32 + memcpy(&m_publishLicense[0], pbPublishLicense, cbPublishLicense); +#endif // ifdef Q_OS_WIN32 +} // ProtectionPolicy::Initialize + +void ProtectionPolicy::Initialize( + PublishResponse & response, + bool bAllowAuditedExtraction, + int + nIntervalTime, + const platform::json::StringDictionary& signedData, + const platform::json::StringDictionary& encryptedData) +{ + // initializing protection policy from the publishing response (here the user + // is the owner) + + m_accessStatus = ACCESS_STATUS_ACCESS_GRANTED; + m_id = response.id; + m_name = response.name; + m_description = response.description; + m_owner = response.owner; + m_referrer = response.referrer; + m_rights = vector{ + string { + "OWNER" + } + }; + m_issuedTo = response.owner; + m_contentId = response.contentId; + + m_ftValidityTimeFrom = std::chrono::system_clock::from_time_t(0); + m_ftValidityTimeUntil = std::chrono::system_clock::from_time_t(0); + + m_dwIntervalTime = + (nIntervalTime >= 0) ? static_cast(nIntervalTime) : USHRT_MAX; + + m_bAllowAuditedExtraction = bAllowAuditedExtraction; + + // if access is granted verify the key and create a crypto provider + if (ACCESS_STATUS_ACCESS_GRANTED == + m_accessStatus) InitializeKey(response.key); + + // initialize the publishing license + m_publishLicense = response.serializedLicense; + + // set the Application Data + m_signedApplicationData = signedData; + m_encryptedApplicationData = encryptedData; +} // ProtectionPolicy::Initialize + +void ProtectionPolicy::InitializeKey(restclients::KeyDetailsResponse& response) { + if (response.value.empty()) throw exceptions::RMSInvalidArgumentException( + "Got an invalid response from the server : access is granted but the key is empty."); + + + + try { + std::vector key(common::ConvertBase64ToBytes(response.value)); + m_cipherMode = MapCipherMode(response.cipherMode); + m_pCryptoProvider = rmscrypto::api::CreateCryptoProvider(m_cipherMode, key); + } catch (exceptions::RMSException) { + throw exceptions::RMSNetworkException( + "Got an invalid base64 as a key value from the server.", + exceptions::RMSNetworkException::ServerError); + } +} + +void ProtectionPolicy::InitializeValidityTime( + const std::chrono::time_point& ftContentValidUntil) { + if (std::chrono::system_clock::to_time_t(ftContentValidUntil) > 0) { + // The REST service doesn't return us the form time of the validity time + // range, so setting it to now + m_ftValidityTimeFrom = std::chrono::system_clock::now(); + m_ftValidityTimeUntil = ftContentValidUntil; + } else { + m_ftValidityTimeFrom = std::chrono::system_clock::from_time_t(0); + m_ftValidityTimeUntil = std::chrono::system_clock::from_time_t(0); + } +} + +int64_t daysTo(const std::chrono::time_point& l, + const std::chrono::time_point& r) { + return std::chrono::duration_cast(l - r).count() / 24; +} + +int64_t msecsTo(const std::chrono::time_point& l, + const std::chrono::time_point& r) { + return std::chrono::duration_cast(l - r).count(); +} + +void ProtectionPolicy::InitializeIntervalTime( + const std::chrono::time_point& ftLicenseValidUntil) { + if (std::chrono::system_clock::to_time_t(ftLicenseValidUntil) > 0) { + // if the licenseValidUntil and contentValidUntil are the same then there is + // no interval time set, so we set it to USHRT_MAX + if (daysTo(m_ftValidityTimeUntil, ftLicenseValidUntil) == 0) { + m_dwIntervalTime = USHRT_MAX; + } else { + auto dt = std::chrono::system_clock::now(); + int64_t iIntervalTime = daysTo(dt, ftLicenseValidUntil); + + if (iIntervalTime <= 0) m_dwIntervalTime = 0; + else m_dwIntervalTime = min(static_cast(USHRT_MAX), iIntervalTime); + } + } else { + m_dwIntervalTime = USHRT_MAX; + } +} // ProtectionPolicy::InitializeIntervalTime + +bool ProtectionPolicy::AccessCheck(const string& right) const { + auto i = + find_if(begin(m_rights), end(m_rights), [right]( + const string& grantedRight) { + return 0 == + _stricmp("OWNER", grantedRight.c_str()) || 0 == _stricmp(right.c_str(), + grantedRight + .c_str()); + }); + + return end(m_rights) != i; +} + +uint64_t ProtectionPolicy::GetValidityTimeDuration() const { + return msecsTo(m_ftValidityTimeFrom, m_ftValidityTimeUntil); +} + +bool ProtectionPolicy::IsIssuedToOwner() const { + return 0 == _stricmp(m_owner.c_str(), m_issuedTo.c_str()); +} + +std::shared_ptrProtectionPolicy::GetCachedProtectionPolicy( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + const string requester) +{ + common::MutexLocker lock(&s_cachedProtectionPoliciesMutex); + + if (pbPublishLicense == nullptr) { + throw exceptions::RMSNullPointerException("NULL pointer exception"); + } + + + if (s_pCachedProtectionPolicies == nullptr) { + throw exceptions::RMSNotFoundException("No cached policy found"); + } + + // find in the list of cached protection policies + auto i = + find_if(begin(*s_pCachedProtectionPolicies), end( + *s_pCachedProtectionPolicies), + [pbPublishLicense, cbPublishLicense, requester](const + shared_ptr< + ProtectionPolicy>& + pProtectionPolicy) { + // return if the PL matches + const std::vector& pl = pProtectionPolicy->GetPublishLicense(); + + bool cacheFound = (pl.size()) == cbPublishLicense && + 0 == memcmp(pbPublishLicense, + &pl[0], + pl.size()); + + if (cacheFound && !requester.empty()) { + string expecteddRequester(requester); + transform(expecteddRequester.begin(), expecteddRequester.end(), + expecteddRequester.begin(), ::tolower); + string cachedRequester(pProtectionPolicy->GetRequester()); + transform(cachedRequester.begin(), cachedRequester.end(), + cachedRequester.begin(), ::tolower); + + cacheFound = (expecteddRequester == cachedRequester); + } + return static_cast(cacheFound); + }); + + if (i == s_pCachedProtectionPolicies->end()) { + throw exceptions::RMSNotFoundException("No cached policy found"); + } + + shared_ptr pCachedPolicy = *i; + + // push to front as the most recently used if it's not already + if (begin(*s_pCachedProtectionPolicies) != i) { + s_pCachedProtectionPolicies->erase(i); + s_pCachedProtectionPolicies->push_front(pCachedPolicy); + } + return *i; +} // ProtectionPolicy::GetCachedProtectionPolicy + +void ProtectionPolicy::AddProtectionPolicyToCache( + shared_ptrpProtectionPolicy) { + common::MutexLocker lock(&s_cachedProtectionPoliciesMutex); + + if (nullptr == + s_pCachedProtectionPolicies) s_pCachedProtectionPolicies = + new CachedProtectionPolicies(); + s_pCachedProtectionPolicies->push_front(pProtectionPolicy); + + const uint32_t dwMaxCacheEntries = 32; + + if (s_pCachedProtectionPolicies->size() > dwMaxCacheEntries) { + // if we've reached the max cache size, ditch the least recently used + // protection policy + s_pCachedProtectionPolicies->pop_back(); + } +} + +// NOTE: We don't delete the cache deliberately. We leak the cache on dll unload +// as it is not safe to call all +// the destructors on dll unload. +ProtectionPolicy::CachedProtectionPolicies *ProtectionPolicy:: +s_pCachedProtectionPolicies = nullptr; +common::Mutex ProtectionPolicy::s_cachedProtectionPoliciesMutex; +} // namespace core +} // namespace rmscore diff --git a/sdk/rms_sdk/Core/ProtectionPolicy.h b/sdk/rms_sdk/Core/ProtectionPolicy.h new file mode 100644 index 00000000..a2df9c15 --- /dev/null +++ b/sdk/rms_sdk/Core/ProtectionPolicy.h @@ -0,0 +1,254 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PROTECTIONPOLICY_H_ +#define _RMS_LIB_PROTECTIONPOLICY_H_ + +#include +#include +#include +#include "../Common/CommonTypes.h" +#include "../Common/FrameworkSpecificTypes.h" +#include "../ModernAPI/IConsentCallbackImpl.h" +#include "../ModernAPI/IAuthenticationCallbackImpl.h" +#include "../ModernAPI/ProtectedFileStream.h" +#include "../RestClients/RestObjects.h" + +namespace rmscore { +namespace core { +enum AccessStatus { + ACCESS_STATUS_ACCESS_GRANTED, + ACCESS_STATUS_ACCESS_DENIED, + ACCESS_STATUS_ACCESS_EXPIRED, +}; +struct UserRightsImpl { + common::StringArray users; + common::StringArray rights; +}; +struct UserRolesImpl { + common::StringArray users; + common::StringArray roles; +}; +struct PolicyDescriptorImpl { + std::string name; + std::string description; + std::vector userRightsList; + std::vector userRolesList; + std::chrono::time_point ftContentValidUntil; + int nIntervalTime; + std::string referrer; + platform::json::StringDictionary signedApplicationData; + platform::json::StringDictionary encryptedApplicationData; +}; + +class EmnptyConsentCallbackImpl : public modernapi::IConsentCallbackImpl { +public: + + virtual void Consents(const std::string& /*email*/, + const std::string& /*domain*/, + const + common::StringArray& /*urls*/) {} +}; + +class ProtectionPolicy { +public: + + AccessStatus GetAccessStatus() const { + return m_accessStatus; + } + + bool AccessCheck(const std::string& right) const; + const std::string GetId() const { + return m_id; + } + + const std::string GetName() const { + return m_name; + } + + const std::string GetDescription() const { + return m_description; + } + + const std::string GetOwner() const { + return m_owner; + } + + const std::string GetReferrer() const { + return m_referrer; + } + + const std::string GetIssuedTo() const { + return m_issuedTo; + } + + const std::string GetContentId() const { + return m_contentId; + } + + const std::string GetRequester() const { + return m_requester; + } + + void SetRequester(const std::string& requester) { + m_requester = requester; + } + + bool IsIssuedToOwner() const; + std::chrono::time_point GetValidityTimeFrom() const { + return m_ftValidityTimeFrom; + } + + uint64_t GetValidityTimeDuration() const; + + uint32_t GetIntervalTime() const { + return m_dwIntervalTime; + } + + bool IsAdhoc() const { + return m_id.empty() || m_name.empty() || 0 == m_id.compare( + "00000000-0000-0000-0000-000000000000"); + } + + bool HasUserRightsInformation() const { + return m_bHasUserRightsInformation; + } + + const std::vectorGetUserRightsList() const { + return m_userRightsList; + } + + const std::vectorGetUserRolesList() const { + return m_userRolesList; + } + + const platform::json::StringDictionary GetSignedApplicationData() const { + return m_signedApplicationData; + } + + const platform::json::StringDictionary GetEncryptedApplicationData() const { + return m_encryptedApplicationData; + } + + rmscrypto::api::CipherMode GetCipherMode() const { + return m_cipherMode; + } + + std::shared_ptrGetCryptoProvider() const { + return m_pCryptoProvider; + } + + const common::ByteArray GetPublishLicense() const { + return m_publishLicense; + } + +public: + + static std::shared_ptrAcquire( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + modernapi::IAuthenticationCallbackImpl& authCallback, + const std::string & email, + const bool bOffline, + common::Event & hCancelEvent, + modernapi::ResponseCacheFlags cacheMask); + static std::shared_ptrAcquire( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + modernapi::IAuthenticationCallbackImpl& authCallback, + modernapi::IConsentCallbackImpl & consentCallback, + const std::string & email, + const bool bOffline, + common::Event & hCancelEvent, + modernapi::ResponseCacheFlags cacheMask); + static std::shared_ptrCreate( + const bool bPreferDeprecatedAlgorithms, + const bool bAllowAuditedExtraction, + const std::string & templateId, + modernapi::IAuthenticationCallbackImpl& authenticationCallback, + const std::string & email, + const platform::json::StringDictionary& signedAppData); + static std::shared_ptrCreate( + const bool bPreferDeprecatedAlgorithms, + const bool bAllowAuditedExtraction, + PolicyDescriptorImpl & descriptor, + modernapi::IAuthenticationCallbackImpl& authenticationCallback, + const std::string & email); + static std::shared_ptrGetCachedProtectionPolicy( + const uint8_t *pbPublishLicense, + const size_t cbPublishLicense, + const std::string requester = std::string()); + + ProtectionPolicy(); + + void Initialize( + const uint8_t *pbPublishLicense, + size_t cbPublishLicense, + std::shared_ptrresponse); + + void Initialize(restclients::PublishResponse & response, + bool bAllowAuditedExtraction, + int + nIntervalTime, + const platform::json::StringDictionary& signedData = + platform::json::StringDictionary(), + const + platform::json::StringDictionary & encryptedData = + platform::json::StringDictionary()); + + void InitializeValidityTime(const std::chrono::time_point &ftContentValidUntil); + void InitializeIntervalTime(const std::chrono::time_point &ftLicenseValidUntil); + + void InitializeKey(restclients::KeyDetailsResponse& response); + + static void AddProtectionPolicyToCache( + std::shared_ptrpProtectionPolicy); + +private: + + // undefined + ProtectionPolicy(const ProtectionPolicy&); + + ProtectionPolicy& operator=(const ProtectionPolicy&); + +private: + + AccessStatus m_accessStatus; + std::string m_id; + std::string m_name; + std::string m_description; + std::string m_owner; + std::string m_referrer; + std::string m_issuedTo; + std::string m_contentId; + std::string m_requester; + std::chrono::time_point m_ftValidityTimeFrom; + std::chrono::time_point m_ftValidityTimeUntil; + uint32_t m_dwIntervalTime; + std::vector m_rights; + std::vector m_roles; + common::ByteArray m_publishLicense; + rmscrypto::api::CipherMode m_cipherMode; + std::shared_ptr m_pCryptoProvider; + bool m_bAllowAuditedExtraction; + bool m_bHasUserRightsInformation; + std::vector m_userRightsList; + std::vector m_userRolesList; + platform::json::StringDictionary m_signedApplicationData; + platform::json::StringDictionary m_encryptedApplicationData; + +private: + + typedef std::list >CachedProtectionPolicies; + + static CachedProtectionPolicies *s_pCachedProtectionPolicies; + static common::Mutex s_cachedProtectionPoliciesMutex; +}; +} // namespace core +} // namespace rmscore +#endif // _RMS_LIB_PROTECTIONPOLICY_H_ diff --git a/sdk/rms_sdk/GetSymKeySample/GetSymKeySample.pro b/sdk/rms_sdk/GetSymKeySample/GetSymKeySample.pro new file mode 100644 index 00000000..dddd3d6e --- /dev/null +++ b/sdk/rms_sdk/GetSymKeySample/GetSymKeySample.pro @@ -0,0 +1,25 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2015-04-01T13:58:04 +# +#------------------------------------------------- + +QT += core xml xmlpatterns network webkitwidgets + +QT += gui widgets + +TARGET = getsymkeysample +CONFIG += console c++11 debug_and_release +CONFIG -= app_bundle + +TEMPLATE = app + + +SOURCES += main.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +LIBS += -L../../bin/rms/ -lrms_sdk + +win32:LIBS += -L../../../lib/ -lssleay32MDd -llibeay32MDd -lGdi32 -lUser32 -lAdvapi32 +else:LIBS += -lssl -lcrypto diff --git a/sdk/rms_sdk/GetSymKeySample/data/sample.ptxt b/sdk/rms_sdk/GetSymKeySample/data/sample.ptxt new file mode 100644 index 0000000000000000000000000000000000000000..727524d0b111344d1976d4f531002e123257c3e7 GIT binary patch literal 36575 zcmeIb$35qXMfuJYr^*OTFcAtdfw)F->#96_cg>jj#(iiWU2C|g#TUv-{t7H7=z#p3dX3!e&4**Z6Ck*K|B5Q*j_-_-``|emLJ@uuLscP z-~IZ~zBKLl5@vpr#xLW?dCb8)G~3JKZ!fQ}U~q5dW@ulQysBRMc$lj31)LK3qyJL1 z!@H^YkHACu-@!xqx4_ST4SxQA|IM#{^$-93uYUC}z~67a{^7p^-@w7I$94RF{?~u_ z=I__KdYR*X08iq#U!h+kU;X{J-?+W1eEK2w)eAVS8GifKSKofaYX|RT+`9O;Uw!wC z%{f~I1SMY);uS$}81@^S{RaNz;5Rm>$Orl6 zy*>3C$<)-(T=4eeZ|>Kdtb9C*k~f6@4T5|Fzx(_f`1?&AL`yJb{id1UexvbcQMiF# z9X^c0dOhCd!&l$_mlV!YIC)@R8JeJ935GtrGQ@#@rAY}B5Sl$O{NcX>T|RvK&6NYA zQ3TKkis1Nf-u(Guiq_4Pg`0SI;RHdntlxaNudH2P^ti9{;mth1fEOj4`aW*PYJ2k} z$373oIQsfUYrqFX7l(P0gB1>5q#m65=6wjmco^QTjj(M-aOv0o@vpyu-*)30_`{gs z4>x=>(6=-Dalr2fd+gh(dzB;5Kt6779?pkpaPkJcKf_nwTCeCU`HG?7A4ZcHiZaA2 zN+AS-Vl0Ndq6|Z`Zw}DlQv#(~2K{78=GVCzvM~EkzV|}?sH6IwS7hNLdf$G-DM!te zZzuIz)8f8?zx(qWoio9--bC}I@oTW$x+wrc;Wb{nwgLSIod-|(F22M~*hb*x`0ZCY zn3**0aqO#aDU!tLx9i|8e)|plv8``^)NI{GQ#FBs|ERgZA7YC5>Sf4xaC;QNh_Akd zysEuFxRI}dvX9w|#}raT6l@Vpb+Y06slTgfexXi}M3e_IIvq?gx7aN~+j|kzPZPF7 z%?mZ-dP3$}X(j(S^Vn5IsGL5?rV?RLq@IWX?{%hD?ir>R$a<_OW|Qr@RU?bIp_B4Z zT3ub%C}YiMO)7fnblPQ1${u1Hi8m(VvR;PYes=iqCv$I!!X3=Lr--(wyq{(3Z~L9;a>HPf$7PhX*SMWN$TY~RbnUaTbGsLf4_?+?~ ze2j~{GTs%IKW^ffi8ko1D4#o%fR@) zdyjrRz@HkkxQ@Nw#N+EP8azwz5=*h%tH1%VNDvYA%5g09N}>pjVhk#Y681+Ao?wy? zA%f^NWQYLV#1CItG@xI7A|&HDiAX<0zXrR}*Ny+R??-+8b`$&q=jok5*G>5<$U3K3 z;D!6}JJ_zk(`x+cHIKmJ0?Xlhs|G9y@N8e-J=@Q(72o%998K`om?GI%BKBDztEu2M zW&(^1>40Ea>eJ~Gz+->6H~peD@`H`~?M!@boqX~teJ8j6Nrd&wWdyJk1&I@B24zs{ zL+3tjYXD4f2kyp!hMlYU5gLBd{=NB#KHu*6Z}H{t8p#jA=le$C?`{LX8wPj3okRfG z1rA{2HywC+Bmc!F?6(f!-q&{$`t<-bnXkUR*ln;V4>!BcxP0p}S$#g5i(4CdT9~84 z5~OmwJXj?hWMNYhmrLYo90_c5&!!?J9Xsr%SgbiA;@nlWVLkCyyY^2cevw;;+V=X9 zU7&$1WAr%o`&=Gvh-h6JJ(Ew?-grvc2)-K*PrXaj)9w#^sc5@q2o}K?PuJNb=)*QW=Tj*}s;(H*-mON-5F zfsKs4O*hJ>*9{Jy|ac@ucc4=Eu?PPJ^|z737&wWPmzStK2cFoCAvrxAM7Od$ni#>c;)~c&>m;J6KbA*b zp-Gqouar*QPM!1MaQ4Eiuz;#7+_G+f&y8|94Y>uhDnMq4mfgapI*X4B=Jy(nasN}6C^Z*8N9e@WqAM_ zoVXdmo_7&xs{`3O6UkxHu?p2`$FC%fDi^!I}ICc~po>AxI`9PMY zzhkb89M6c64ap_n`4H;8qyQi5LSQ~b>_pR`T`vmchJdB5%5cN}aD$h3& z#}DM9n?RoM0Zuk2VJC*9mE^rYHkaPICjQf$iKjG$xK^4ya_M9z_w`QAh!}ZZ?!CY> z&*e5NSfokGaj~Vk$>a$Vo|IbNoS@P~LpU4ErMvUYcp ziQ@1Px&`jBO?ZopoT@~`bxBD%nb}&8EDN$2X0#7XorKB!Q-2}X#Oo$^qD=KhFzL(DR629kBG{{Ud2E#-;AFe5v%lqO&vTKHS%56;QS!n(j78%y1C zpHWKiHeD(vL>23LKOt)#kOS>ppORqTX&ntLIXEB_xt+MCoO;|0nFmFN+GHZp)aAsX zt?^ytRwUO4jX|x1#*n4)^Sgd3LnXAwpjjRMoM8T=87?v$>bw1zm79C>^5YY(yvK6( z@J$Jb$j@wHU;C%S8|Dy*E#$yfX%o*&9!g^46Roqh8!jogo7~zFi??5)VFf}y^lC)?&12rA@ephp9k;tGy1^TIJT{RoVo zb3LSW&>9o3>CVLykACdWN8z}v=3#lP65LGK&ZBJuw8;gdaF;P;Ct`YrxjyQFKy~%b zz!4b@!U->j37a}^nw#SgxjfbPWr!!3el zT3~fejzGC`ONh4d4`{O};N4g*)h6Y*VVf(PNi>{q$^ljUPK5nKPPJnPOXf*F?{^NZ zW~?Nb0NmS(^43|cNr4H-Q?r949;#>{t@LRn(wx^P{ zPwn_B!jqmQZZV)9xa2WZW-e```^p)7(H>Z&(Mx`jlPH5owkkh3+PbWfvy9r!1%Ia}A(;FY{`BzrcM0Tka7l1BOaFW60*K zZ>qhR_tyws>Wj6APTgg8FdoMWe(F4ij?cpC*szOB=MarvsyykVx_BBBwO0K1KT;^33f{u9$Di3hv`ZE#FTtlrA?4 zkz;&qU9!ksIJ@xhc1(T9bD_W=jVxvGl0crBl14dq9x7U)@8gYAhtZ!Z_O5ISZ_Pli z97n1agjGQaJN23)haeNW>6O7>Nl|NLsX>@zOBWYxC`WF=0{4_c7q@A{O>QQZ2xxma zTJ;*VX62Um%VNhs^?6i;1D+{P61WPfON{eA9hesg)>#9$tbQLKkkJC_oC#ak%b9xDe#={p3V>bykh&~ffTbQtA;{!*wHzc<#4!>TKOdUBX6#U zQ8Db95jU+43y6WA>{d3ngSQ$CQZd|U!8h0=i>Y`#F6A0|=ypTx2Y2pVgWpW)#@{SX z%rwi_nVG%^wmkwxN`#KLX`73D61-l9$fQ#B(Lt}a(@=eSR_$wS!`B_jF*O6$ z)!h52YD@Ra)xR)Rk(zW<-7uK0=&H2zLphzfF}>TZ)Z66!iZ#ONv(Il=+G!_|n2{}` ztj^j=>mZzM7sbucfO+g4r?=Na4k#9_8QnCmVae^`+MOP3HJX&!T{gD6^3^($S}T}7 zA-H$mJWxU>5N9bv5Uyg+bi#1S$WOk!!kiSHx9oX5TkM4R5_ z=|m_^DJ-N?hkKr0*Gk8zxp zG>bBPn5<)oFNdKJ8857d7^c{@?4Rs2h4r2nolB4#GqoGNyWOLMa3=ZQ<$;MNA`?A` z8uPv({H;!D_KdjWDN?ZK4d~M=1p|E&_qVi#VaJ1PJI?893oUba9`?uK)SMqlRTQMc z0h0<_E0_4{NXj5(g6b{^?xylE5x~5}o^=r*xJLpTHRr%nc4mF%*at4xWd|x;638xX zm%PS)n(S5AZM(OxY%oC-M?4F|3MNNuHNs@%V11RfI@xl$W~Zf+dv zYcR!h$%f7v;aKBbX|dT#gq-{drPmG%Y6De0JPOeYS&i{jtn_qloC|wu_-7Ty0ij3q z6KO69awv5qYqi#crUzb@o`-B5j@yO~wee-4WHsdHn+D-oVwpDrqY&t#AqJeVg(7dV z8pX%DmnBnAIBipJYqt3-4fntdIrZ2xK?9}fue+D=P6efR4&l3_ikPd5UxDe#b5hY9 z*a4NT9lK(}X7v}`r|)1IN}EEC=|P=54JBcmopEb7NgiKpu1>`eN+O$NK(Q$ISo zKzP)&+=!IAWi}(`*~!7S@p1*oLwJrfVGgp2@^j*+6_7Gyj9vq5oy*KYR8l@TFsX?e zv3tzSp1UPJ5m_vZIy%U%-V8z%KGzLtj{dBxxQj$|nDx;*R3=bj{mQv=wZ4z@!%A#p zJ)6w=u#gqEh5Wh;lPf=;0&Vvvn9cb^bewzmj2d9&4LzTEqazYRTLr-K#uBZ4AzXC| z+^w?tO;UQcRI=b1+@8hJJhdkz5Wx$yNnTmDhy=?nB30y^?~mNO9Gc8EP3{2B#Jm$s zRC6q$3&#r$aUBbtOnX^WjR(NCf=Qk@qG~MHL@Gj=fl-!5a~7cci*VWfH$I_boD?(f zYs0OYpM59b&BaomLBMRKv)MIcwq}CqvDqQmI7(abU{=#gRky)9!XwBoz;R{Z@zdlL zx*9J1LvO{&AGD+y`QkZ`z;A@{h`JAkrGyFEvttcFL=zZ#V#wsIQpa77#H-JW?Li{h zXMEH&-(lH}=AxCZxgMgLV|UwwS*?UDw(MIzlyHd+Y7sqPQRNlwOvX1Q_wgf5i^#b* zg@;R(jm0ykRpNfW{TBDbdJ2H1aR_(-zi>+{Ft6yYFh4*JnX~!Bz1n7T6`GON#3@&7 z1-v(?Q9H)?=;%>8vioG+r7n)eAA-{;bt zFljR)j>)oO#w9bECGyy_nx3Q-DJ+1JfaQjE&peakVeBW@BU7AP#?sLhAtjv69a7&P zR~<=Pq8(v8RA)-Z?WcnHvx_fBBVJNq*|7}wR&~}T;{)S#%ce*)^~d4LaeGW(rG-}T zIjbW8#ZS*%z4BYi6WAyZJ9E&GvAm$?<=iCZ#weIQ9PaE2uU*r7d%hm`Ry$#Pg?OGc zpYvmyK>M~>$Z01H2JEeeW!A8U3wk)p=fUt-?tJu~5vPxRRJrGC39JhvYTwG6)H+YC zp6+bC4mg)RS=6@Hqg|(;@4sR;chkMIhYOzgqo?8aiBM80eLQ1BKhNqjQ7CM@Nv1Oc zjI^Xc8^Nj^pM3f#Zj44x4ZqA7`cQ5#8Ns`uaJo#M;=)786FzrK--MZ|K-Q2Gym$1Q z@~{Q_rP-jdzpr=OXi)$X9F0Fsv8@O2+z8>Wpq>fCVMTrqS~@MRQW^ zWuJV zes;Kl6jUU<-yj1m?11N4$g-VHrGll_WzCNdWO9$O=cdWR^Qg}S;?G_aj3v8(E zaKK98UK|cHc}8obkW`zyWkxL(GXLD-hB#eRr6GXx=LukaMpLv`-r?h_fQXkMKItQM zI02=)OS?q38vpuuCj2e+MN^X)^Ux7hTRz=2#bcj}ulJ`pn8*G}QOkid&Q@#|HMFZ$ ze1R^Q9VcFyb-=&@vBW(~-Ncm~`Tmq|c17^9xbC0r|H{?QOv1G+Hsm5r>+VuV`Q~8$ z6bm`j4!Zzdf;~y=0k|XA#;0>EXQ^3G#Jk0u&lh%EE&qHvQ8_c+C$qOkImy}$4*3Op z?Cr&7^P4jFbjHj7$oL)SgbRJjccspY`gz($CK*$4iSyd264tbna3=~(v}GYmhx=oO zIG+bDlfwZjD#xPw2OGsIh9534@{o4sM)eI-dM5YFjtu$2@k!!cHkOerV zyO%u)M^`(SF1d(4V$RLf@U#6_jdRsQ37PX}DCC171V(sp$yoPI+Rjf!U4T`H!HIJ( zBSHAUCSq(sfZUR=k~j;N)rR+@Y(Ie+x$O8hUJ>@eJqBVmbS{L|WAi+)H3UiM1pL`C zLgp=G93J#mc7YsO&um?hUC>U)+8O1JK3EUnjUo{%;;QqdhO*&oLB)uVDSQm_&&qFG zD4cvgdxRL1zE-SGNYnJM$W`~!d}X|xtcn8 zaIW?so^bMP2lC#{g2$xfld2(3?;5A*Pu^qviAUT?k%EH;Z*Ld6-=dz>5ne9?U%^Hf!X%f<;T z6>Mp|CjEl=fmRLm6sm=a0ns)sT6c`3@vSKm?h0%{xszL6ay&$2-w~+Q9aqr@pk0(i76e{0UV78gBkl=41gy;y|V~Vff!1Fwqrm~b}rwGpngITvDq{(2B zs~z+x)HBmvwV>|DnDL{UEUzH&0=FfK!5W>rJx+yIkO$W$R8NS_%XDPRtK!e)5HTHy z2{Pv)7xM9h%b0bK%!`@;>vBSW_Wu26pC9ldBrBIa@NM1~wD$Mn&aClXmnVp)wESwR zVq`R&;Q>z#lu8T<_G2ROAEt~e$0zXNJ;G!rn7fHStJwn=E%jpPpens}cfIA(Bci)k+SZ2#%~M9SC@UR*S#?g5iO1mno|Db^LGqEx;3 z%HxPuwv1LmA4q4UHLT`_Iw`c&C&8~Lw z@X##j_D<~kNd^87idX9X(2%s@Q9TuCzyp~Xm96cpgXG7BRi@AxG!2AgrnigGchbUy zcghNwcbF)laTvDbB8K%DCj!?i$={trKT8^HzK z0G2KavLp*%y$_fCND28`wPaoR+KfR2cpsZJ*bDtW=Dy?geD&?EpW@Hn4SvHh0pXbP z@ygxqCWznvUUcn?ei5wy5Ph}LuSszINB#ha`8xs%#;0dnCl0U^J~`zh58!=&-!TW? z&{;kcj`@a|(WGB}J4}7zhwZS5jO_Ft-_Jc;h-uP^& z*lW9~`$OhUJ?*4qEI?p9hIR=EKxmVvEL8bCs!MTvu)v%gj12Dh3K`rQA2?tNJVDLk zAhby|1kGhfmB6}bjGil1Qeksyu|}#5&luvBBWs!Fx&!r_yYE_FMa(Bbyq`Q)_zlzO zJ>Td9!{|Hq5c)OXaeT@*0+bQ)YKb5a_XA<+_Y#cI-=IGr7=22Q`CjNb7&u^*ybs-P z`&S_b!FI_T2HKl-@sT6*UHGL>`dGmF(JPIR;VXf}6bM95;#U$2V-#pIESh`>ME@9m z`P1y2FA?y6IU>)O2>7=VzJFxQ`xjc!kC{T>lPrJ5w4m=eQJ>?x{BnlWAI|*w!b<$Y zO8kxy`V-8KPpJ{_seXTv?c0=(r<-*&wY&ZS?D~20p1c51!n@-NkO%L7e}C57*8&_D zv@0Mt1IFaLQ{IuBP40RWf5dmjUvWT?eurN^$9KlC4@W=noj+*@e%IVP3i9t|-+fA` zc|ViCfSyF51mMG-gM&%TNG?Gz#ge>WL+ou%i)epK~R93WCm*co``Ly8_i z(6!r7d?~cpvZx0yV$%+@^P_H6k#@XYbWS*u0f@Q=zL1j(6SpZoa4O)N!5HFlpmAxU zm}asGk?QyInOn$u7;tSTDG2MM8h}K7Ok(Q9mW7fvu47>&0u`LrWcGa4SUnrI&Xz3~ zi*lkAA5~1`-6Wh6V2cn<)hoGFCjkSh)u*#WtJWDG)>d#y)et;|i!WzDq9Pw*g=RK( zCm#3Y!P6eBAyi|w>Q(4(d|<130X0c4t>_cDn3{R&V1GtSa}q&xxr?XedUu{JDKLm_ z1RZdmU{??ZRhCxW`L?Q1TM=3=0)m6P$>OiDE~3QJ0!Xn{3n6xWeUd_Ob_e^!yAD`19`Sdbi`kF$o_@ zHakhikdv*MHtUUjNX}QGycFdk4~eg<#bn*kHZ)1<=fajig5@a~1EVV3=kx~ybh+}6E=OY%U_4!zD z<&A4|23HzVWli>ckffD|!#Wzm2xfPAwP;OI`eS?Yw&>^2rGS{Bd&DXdg+fN{1@o=vny( zp6IJ-fV*upg-)Y|X zIVOQY6me)$)r70eNac+^8LlYE<6zc~tFa}!m|DmxcGdL|W?yaoJl{%asBk`KJ^HaM zdV$54tFU>)vU-N6Ya;|N{JcQdxAOla$O_)|-vUfW7f^5L*nTOwD68Na*zp(^-OhNL}O?}r6 zAU%QbE)&KF#{C~oP#H&OdgjWKkm{%SXq*sbK%Q^`Xd(<2uvKDYbLDphF`Uk zh4V#|2Q~_MkV&B!U{A#~V>DW&gzU$&GD-iij;V9=L4056fxzkI7AAE~a) zN30;v>*R2{72IiPuVjekHyc{0jJj4)T03O47`Rt9&|+SN@+;#+E(maeh))FWCzk7<$_MlP74jSPfDh8xC8gh_~ z$oRR4V?S8MZx5t1u{{!05Taejh``E1?+~vF8f2Q@H&^y0m6!Er>@4uA;cWfFbBs4A0ICq+|8FNSd8 zXt#TWK$UIT5M+Yd*emN@3_QMY2XjHJ9&s)Y5TXf!Z>1ZZ-yJ1L8x-*sY(7@P?2NQ# zu~HX|>4n#8rUEfIxlNSjxg-UMIb0EVocd@#IWX^TmwSF!yz(4fCJ~pj&^=n!_26n% z1qiJQC7q0oop4mW*$nAKilzgy+JA#OkH9oE`WD0;R z$-`*EQ_EC>98I^a)j>orj_>tT!he}w@JHwY-{Jq?hn;_nwEvp4g_vaLLGEm7dIo69 z^Ql&z+o@ft>Ql$rhcWydJs>~S%54NZ5*mIUdFFaPN5yu&Q+`VNF363R8xKGTySRl5 z{PM%$^5B!}Sw|5s8$jfi?6NnLo05BZrOuV&XeAHKJ5H+D>=QdvfMJ+r;nlanZ^{v1#P`b){7whp zyA0L8AX=D4*@OZ)s$W4mL{L}&1#UqQKuo>T3?8z8_XE-)6TjRU_%lobJV%i@PjRmz zO5tz3knt;z@cb(#fyCnoMzgFazQ6HX!22sDMPFJjZTRaFD~{@dj1Aba|U zjM^XFm;ZDzvTC3LJJ}Q}@Ci}~d~tC|x4VlbeLd{jH5cq?#gticPHaWIK8(0bfT9i3^IsF{$usRwJ8?c{>HovyF@MI& z`jUzLeQ}CEwxGlpW7D6^*!0n*13ZU6Ui_a?4*w#8{10bi*E2@{{f%*?z;LQx#p~$t`CDwI`3d`XW`USTzaVjG-@MQopIxd ztu$#|JCjYeKt}l8S#q7vw=BC=L#&qf)X}>f1{qe@$y!>uk|q#E+T5YkWiPZH z>+X*w{bU~g%$^(sENAK!r9Uj^cW?WIVKeWXEmQZWYM*hC_TYjiu_%T$*5r+&F&F_hPR&{Iw{A zdkOs80)M5Ca9M5v?=6gV8kw`@Eav7{t|?}%z(WKHQVj$UDezj6QT47I6Qn;nF80v0 z2k|DsfaPpi1M!iGuM6vwg2zu5$JM!iyhyrDBMLk}FloDaQB27Nq!rZTQ^D~&B69vR zVD5{W@KdE&-tuk#w$y|_KU(@jQQLBJaJFj^zzzrwcuqLso1j5~WUXC|u5)yy?CtmJZa( z^vXbClG-82Ob)j~FP)+(b`=X0_kuwUz=0s2EBSnekxF|A(~>?~y71QKx)QW3NE!}b zt6fY&b2hIzAXGWeN}d@Nr0(sw`c8v1dwx`>}-v|TRd6UT2wFIdn$kJ=SP zVq+q5xTrNqe5`UHT|S|~31Gx2@x7mJo>xG|j>$5EJ;R-bl6VxO`!HWFKKkGu^{CZyMv(GsfDqq8 z;PX`ud(KAcbyZ=qsbOZL2Gi+cRtB}n3jBOUYvXY}lig}hExhXUIasTMjQ5~|#qNMA zCm>BAk%7uC1sPpB6%mI@w?&M#K(w@cS(mGqw?YOu*wq>!trKgpN;N^-z&O=c^^uCu zbgO{!|Abg7Vx!&}W3^9+E655<=_*uwB(j zyxMr+TI!;kW+a0S_aM7o395DZCtgX9yiE{Y0f}+@f3jEg~B7p}rVIoky7?h4ge4j;-2oyK|M@5-t+m1iS^!Dz&zZs+n z(w++o2hLjFpqjP(gf1Qb3{qKq`oUA@(jx=Qps3q5sQg2D zYv~wR)hF4BLr~!9bQZi4xmo);Aut@Mb>7)Ms5`=-8sA?$s8Gje$@prQKj+Y;>Y1)@ zw7hu0<|me*o&(<1%9HmP+IIG8l`afZRHUGsg7XvPIL;RVx4Q(8{O*3$r08WlJl}LQ zDnOM@Bg9R0t^TPY%`Y0(7Y*w#reXcr5bqzd!TdELUgX2J`vviW(%{_3;EbOj%e_g= zIh>#>%s@?Kos}=LU)0S)8pr!nt3IVn|0!*i?+`B!pJ}rllyjICO3d%DRim0k`3+Hc zkmZo-?x6JH?3W483lRXF(0$`d83T3yd^lJ$t_}ySyJAIafCND;@~GwpXJGYdvC5nL z^N)!KMMYg^KOpEm*9v0I2D!MEXS;O)d^Loes5D;?I^R9En6>NFZPcg-Js5x= z8kSQ`!1f@_zU3i~+Q{qqtf(qE(=L_6M!LtrywO;ac&7``ZgAPk-g2+(YRIpBwSyEy z(bg$yC%8xLsYA=X9oIse-6n#OBR4)Pu9mSZUHSv>)#vM&2g^~a2YH(1C3&pKG!@0P z)tdo^LG3|J^J98N&!DDVAEeO}R9Oa;M18Ml4$~%3uNCKv--~#E_2ui!41Ae^f4(#D zf6@Q*fA+uq+yAZpzq}s*;L-y{P+KV Do1fhq literal 0 HcmV?d00001 diff --git a/sdk/rms_sdk/GetSymKeySample/main.cpp b/sdk/rms_sdk/GetSymKeySample/main.cpp new file mode 100644 index 00000000..e45624f5 --- /dev/null +++ b/sdk/rms_sdk/GetSymKeySample/main.cpp @@ -0,0 +1,211 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +//#include +#include +#include +#include +#include +#include +#include +#include "../PFile/IPfileHeaderReader.h" +#include "../PFile/PfileHeader.h" +#include "../Platform/Logger/Logger.h" +#include "../RestClients/LicenseParser.h" +#include "../RestClients/Domain.h" +#include "../RestClients/IDnsLookupClient.h" +#include "../RestClients/IServiceDiscoveryClient.h" +#include "./../ModernAPI/IAuthenticationCallback.h" +#include "./../ModernAPI/AuthenticationCallbackImpl.h" +#include "../Common/CommonTypes.h" +#include "../AuthDialog/Dialog.h" + +using namespace rmslib::pfile; +using namespace rmslib::restclients; +using namespace rmslib::common; +using namespace rmslib::modernapi; +using namespace std; + +StringArray GetPossibleDomains(std::string& domain); +class AuthCallback : public IAuthenticationCallback { +public: + + virtual std::string GetToken( + std::shared_ptr& ap) override + { + Dialog w; + w.resource = ap->Resource().data(); + w.client_id = ap->UserId().data(); + w.redirect_uri = ap->Scope().data(); + w.authorizeEp = ap->Authority().data(); + w.tokenEp = ap->Authority().data(); + w.exec(); + if(w.result() == QDialog::Accepted) + { + qDebug() << "token: " << w.accessToken; + return w.accessToken.toStdString(); + } + return std::string(); + } + +}; + +const QString RMS_QUERY_PREFIX = "_rmsdisco._http._tcp."; + + +int main(int argc, char *argv[]) +{ +// QCoreApplication a(argc, argv); + QApplication a(argc, argv); + qDebug() << "Hello world"; + +// Dialog w; +// w.exec(); +// if(w.result() == QDialog::Accepted) +// { +// qDebug() << "token: " << w.accessToken; + +// } + + +// --> Get domain from pfile header + QString pfilePath = QString(SRCDIR) + "data/Sample.ptxt"; + QFile pfile(pfilePath); + if(!pfile.open(QIODevice::ReadOnly)) + { + Logger::Error("Can't open the file: %s", pfilePath.toStdString().data()); + return 0; + } + + auto pfReader = IPfileHeaderReader::Create(); + QDataStream instream(&pfile); + shared_ptr pheader = pfReader->Read(instream); + + auto baMetadata = pheader->GetMetadata(); + string strMetadata((char*)&baMetadata[0], baMetadata.size()); + // qDebug() << strMetadata.data(); + + auto baPl = pheader->GetPublishingLicense(); + // std::string strPl((char*)&baPl[0], baPl.size()); + // Logger::Debug("PL:\n%s", strPl.data()); + + auto domains = LicenseParser::ExtractDomainsFromPublishingLicense(&baPl[0], baPl.size()); + +// --> Service discovery call + + auto dnsLookupClient = IDnsLookupClient::Create(); + for (auto domain : domains) + { + + qDebug() << "==> domain: " << domain->GetOriginalInput().data(); + + // DNS lookup to find discovery service URL. + //auto dnsClientResult = dnsLookupClient->LookupDiscoveryService(domain); + //auto discoveryUrl = dnsClientResult->GetDiscoveryUrl(); + // Query Discovery service for services details. +// auto serviceDiscoveryClient = IServiceDiscoveryClient::Create(); + + + + + std::string domainString = domain->GetDomainStringForDnsLookup(); + qDebug() << "--> domainString: " << domainString.data(); + + auto possibleDomains = GetPossibleDomains(domainString); + + + for(auto pd: possibleDomains) + { + + + qDebug() << "--> possible domain: " << pd.data(); + QString dnsRequest = RMS_QUERY_PREFIX + pd.data(); + qDebug() << "--> dnsRequest: " << dnsRequest; + +/* + auto dns = new QDnsLookup(); + QEventLoop loop; + QObject::connect(dns, SIGNAL(finished()), &loop, SLOT(quit())); + + dns->setType(QDnsLookup::SRV); + dns->setName(dnsRequest); + dns->lookup(); + qDebug() << "running loop..."; + loop.exec(); + qDebug() << "loop quited"; + + + // Check the lookup succeeded. + if (dns->error() != QDnsLookup::NoError) + { + qWarning() << "DNS lookup failed"; + dns->deleteLater(); + continue; + } + + // Handle the results. + qDebug() << "dns->canonicalNameRecords(): " << dns->canonicalNameRecords().count(); +*/ +// qDebug() << "dns->hostAddressRecords(): " << dns->hostAddressRecords().count(); +// qDebug() << "dns->mailExchangeRecords(): " << dns->mailExchangeRecords().count(); +// qDebug() << "dns->nameServerRecords(): " << dns->nameServerRecords().count(); +// qDebug() << "dns->pointerRecords(): " << dns->pointerRecords().count(); +// qDebug() << "dns->serviceRecords(): " << dns->serviceRecords().count(); +// qDebug() << "dns->textRecords(): " << dns->textRecords().count(); +/* + foreach (const auto &record, dns->canonicalNameRecords()) + { + + string discoveryUrl = record.value().toStdString(); + qDebug() << "record value: " << discoveryUrl.data(); + string userId("4a63455a-cfa1-4ac6-bd2e-0d046cf1c3f7"); + + AuthCallback ac; + AuthenticationCallbackImpl authCallbackImpl(ac,userId); + + auto list = serviceDiscoveryClient->GetServiceDiscoveryDetails( + *domain, authCallbackImpl, discoveryUrl); + + + + + } + dns->deleteLater(); +*/ + } + } + qDebug() << " --> Service discovery call done!"; + + +// --> Send PL to EUL and get SK + rights + +// --> Decrypt data + + return a.exec(); +} + +StringArray GetPossibleDomains(std::string& domain) +{ + const int MINIMUM_NUMBER_OF_ELEMENTS_IN_DOMAIN = 1; + + vector possibleDomains; + vector members = Domain::SplitDomains(domain); + int numberElements = static_cast(members.size()) - + MINIMUM_NUMBER_OF_ELEMENTS_IN_DOMAIN; + + for (int i = 0, lengthFromStart = 0; i < numberElements; ++i) + { + possibleDomains.push_back(domain.substr(lengthFromStart)); + lengthFromStart += static_cast(members[i].length()) + 1; + } + + return possibleDomains; +} + + + diff --git a/sdk/rms_sdk/Json/IJsonSerializer.h b/sdk/rms_sdk/Json/IJsonSerializer.h new file mode 100644 index 00000000..b7b91528 --- /dev/null +++ b/sdk/rms_sdk/Json/IJsonSerializer.h @@ -0,0 +1,38 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_IJSONSERIALIZER_H_ +#define _RMS_LIB_IJSONSERIALIZER_H_ + +#include "../RestClients/RestObjects.h" +#include +#include +#include + +namespace rmscore { +namespace json { + +class IJsonSerializer +{ +public: + virtual common::ByteArray SerializeUsageRestrictionsRequest(const restclients::UsageRestrictionsRequest& request) = 0; + virtual common::ByteArray SerializePublishUsingTemplateRequest(const restclients::PublishUsingTemplateRequest& request) = 0; + virtual common::ByteArray SerializePublishCustomRequest(const restclients::PublishCustomRequest& request) = 0; + + virtual restclients::UsageRestrictionsResponse DeserializeUsageRestrictionsResponse(common::ByteArray &sResponse) = 0; + virtual restclients::ServerErrorResponse DeserializeErrorResponse(common::ByteArray &sResponse) = 0; + virtual restclients::TemplateListResponse DeserializeTemplateListResponse(common::ByteArray &sResponse) = 0; + virtual restclients::PublishResponse DeserializePublishResponse(common::ByteArray &sResponse) = 0; + virtual restclients::ServiceDiscoveryListResponse DeserializeServiceDiscoveryResponse(common::ByteArray &sResponse) = 0; + +public: + static std::shared_ptr Create(); +}; +} // namespace json +} // namespace rmscore +#endif //_RMS_LIB_IJSONSERIALIZER_H_ diff --git a/sdk/rms_sdk/Json/Json.pro b/sdk/rms_sdk/Json/Json.pro new file mode 100644 index 00000000..7c9747f6 --- /dev/null +++ b/sdk/rms_sdk/Json/Json.pro @@ -0,0 +1,17 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/rms +TARGET = modjson + +QT -= gui +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} +SOURCES += \ + JsonSerializer.cpp + +HEADERS += \ + IJsonSerializer.h \ + JsonSerializer.h diff --git a/sdk/rms_sdk/Json/jsonserializer.cpp b/sdk/rms_sdk/Json/jsonserializer.cpp new file mode 100644 index 00000000..7a620ea2 --- /dev/null +++ b/sdk/rms_sdk/Json/jsonserializer.cpp @@ -0,0 +1,663 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../ModernAPI/RMSExceptions.h" +#include "../Common/tools.h" +#include "../Common/FrameworkSpecificTypes.h" +#include "../Platform/Json/IJsonObject.h" +#include "../Platform/Json/IJsonArray.h" +#include "../Platform/Json/IJsonParser.h" +#include "jsonserializer.h" + +using namespace std; +using namespace rmscore::platform::json; +using namespace rmscore::common; +using namespace rmscore::restclients; + +namespace rmscore { +namespace json { +ByteArray JsonSerializer::SerializeUsageRestrictionsRequest( + const UsageRestrictionsRequest& request) +{ + // convert the PL to base64 encoded string + ByteArray base64PL(ConvertBytesToBase64(request.pbPublishLicense, + request.cbPublishLicense)); + + auto pJsonObject = IJsonObject::Create(); + + pJsonObject->SetNamedValue("SerializedPublishingLicense", base64PL); + + return pJsonObject->Stringify(); +} + +common::ByteArray JsonSerializer::SerializePublishUsingTemplateRequest( + const PublishUsingTemplateRequest& request) +{ + auto pJson = IJsonObject::Create(); + + pJson->SetNamedBool("PreferDeprecatedAlgorithms", + request.bPreferDeprecatedAlgorithms); + pJson->SetNamedBool("AllowAuditedExtraction", + request.bAllowAuditedExtraction); + pJson->SetNamedString("TemplateId", request.templateId); + + if (!request.signedApplicationData.empty()) + { + auto pSignedApplicationDataJson = IJsonObject::Create(); + + for_each( + begin(request.signedApplicationData), + end(request.signedApplicationData), + [ = ](const pair& appData) + { + // pSignedApplicationDataJson->SetNamedString(appData.name, + // appData.value); + pSignedApplicationDataJson->SetNamedString(appData.first, + appData.second); + }); + + pJson->SetNamedObject("SignedApplicationData", *pSignedApplicationDataJson); + } + + return pJson->Stringify(); +} + +common::ByteArray JsonSerializer::SerializePublishCustomRequest( + const PublishCustomRequest& request) +{ + auto pJson = IJsonObject::Create(); + + // Request + // { + // "PreferDeprecatedAlgorithms": ..., + // "AllowAuditedExtraction": ..., + // "ReferralInfo":..., + // "Descriptors": [ + // { "Name": "Protected by Microsoft AADRM service", + // "Description" : "This email is protected with Microsoft AADRM + // service. Your actions may be audited", + // "Language" : "en-us" + // }], + // "SignedApplicationData": { + // "SignedAppDataName1": "EncryptedAppDataValue1" + // "SignedAppDataName2": "EncryptedAppDataValue2" + // ... + // }, + // "Policy" : { + // ... + // } + + pJson->SetNamedBool("PreferDeprecatedAlgorithms", + request.bPreferDeprecatedAlgorithms); + pJson->SetNamedBool("AllowAuditedExtraction", + request.bAllowAuditedExtraction); + + // Add ReferralInfo only when referrer is set + if (request.wsReferralInfo.length() > 0) + { + pJson->SetNamedString("ReferralInfo", request.wsReferralInfo); + } + + // Add Descriptors + auto pDescriptorObjectArray = IJsonArray::Create(); + auto pDescriptorObject = IJsonObject::Create(); + pDescriptorObject->SetNamedString("Name", request.name); + pDescriptorObject->SetNamedString("Description", request.description); + pDescriptorObject->SetNamedString("Language", request.language); + pDescriptorObjectArray->Append(*pDescriptorObject); + pJson->SetNamedArray("Descriptors", *pDescriptorObjectArray); + + + if (!request.signedApplicationData.empty()) + { + auto pSignedApplicationDataJson = IJsonObject::Create(); + + for_each( + begin(request.signedApplicationData), + end(request.signedApplicationData), + [ = ](const pair& appData) + { + pSignedApplicationDataJson->SetNamedString(appData.first, + appData.second); + }); + + pJson->SetNamedObject("SignedApplicationData", *pSignedApplicationDataJson); + } + + auto pPolicyJson = IJsonObject::Create(); + + // the user rights list json in the policy looks something like this: + // "Policy": { + // ... + // "UserRights": [ + // { + // "Users": [user11, user12, ...] + // "Rights": [right11, right12, ...] + // }, + // { + // "Users": [user21, user22, ...] + // "Rights": [right21, right22, ...] + // }, + // ... + // ], + // "UserRoles":[ + // { + // "Users": [user1, user2, ...], + // "Roles": [role1, role2, ...] + // }, + // ... + // ], + // ... + // } + + + AddUserRightsOrRolesInCustomRequest(pPolicyJson.get(), request); + + if (request.nIntervalTime >= 0) + { + pPolicyJson->SetNamedNumber("IntervalTimeInDays", + static_cast(request.nIntervalTime)); + } + + if (std::chrono::system_clock::to_time_t(request.ftLicenseValidUntil) > 0) + { + common::DateTime dt = common::DateTime::fromTime_t(std::chrono::system_clock::to_time_t( + request. + ftLicenseValidUntil)); + pPolicyJson->SetNamedString("LicenseValidUntil", dt.toString().toStdString()); + } + + // the appdata should look like this: + // "Policy": { + // ... + // "EncryptedApplicationData": { + // "EncryptedAppDataName1": "EncryptedAppDataValue1" + // "EncryptedAppDataName2": "EncryptedAppDataValue2" + // ... + // }, + // ... + // } + + if (!request.encryptedApplicationData.empty()) + { + auto pEncryptedApplicationDataJson = IJsonObject::Create(); + + for_each( + begin(request.encryptedApplicationData), + end(request.encryptedApplicationData), + [ = ](const pairappData) + { + pEncryptedApplicationDataJson->SetNamedString(appData.first. + c_str(), + appData.second. + c_str()); + }); + + pPolicyJson->SetNamedObject("EncryptedApplicationData", + *pEncryptedApplicationDataJson); + } + + pJson->SetNamedObject("Policy", *pPolicyJson); + return pJson->Stringify(); +} + +void JsonSerializer::AddUserRightsOrRolesInCustomRequest( + IJsonObject *pPolicyJson, + const PublishCustomRequest& request) +{ + auto userName = "Users"; + auto UserProperty = request.userRightsList.size() != + 0 ? "Rights" : "Roles"; + auto jsonArrayName = request.userRightsList.size() != + 0 ? "UserRights" : "UserRoles"; + auto pUserRightsOrRolesListJson = IJsonArray::Create(); + + if (request.userRightsList.size() != 0) + { + for_each( + begin(request.userRightsList), + end(request.userRightsList), + [ = ](const UserRightsRequest& userRights) + { + auto pUsersJson = IJsonArray::Create(); + + for_each( + begin(userRights.users), + end(userRights.users), + [ = ](const string& user) + { + pUsersJson->Append(user); + }); + + auto pRightsJson = IJsonArray::Create(); + + for_each( + begin(userRights.rights), + end(userRights.rights), + [ = ](const string& right) + { + pRightsJson->Append(right); + }); + + auto pUserRightsJson = IJsonObject::Create(); + + pUserRightsJson->SetNamedArray(userName, *pUsersJson); + pUserRightsJson->SetNamedArray(UserProperty, *pRightsJson); + + pUserRightsOrRolesListJson->Append(*pUserRightsJson); + }); + } + else + { + for_each( + begin(request.userRolesList), + end(request.userRolesList), + [ = ](const UserRolesRequest& useroles) + { + auto pUsersJson = IJsonArray::Create(); + + for_each( + begin(useroles.users), + end(useroles.users), + [ = ](const string& user) + { + pUsersJson->Append(user); + }); + + auto pRolesJson = IJsonArray::Create(); + + for_each( + begin(useroles.roles), + end(useroles.roles), + [ = ](const string& role) + { + pRolesJson->Append(role); + }); + + auto pUserRolesJson = IJsonObject::Create(); + + pUserRolesJson->SetNamedArray(userName, *pUsersJson); + pUserRolesJson->SetNamedArray(UserProperty, *pRolesJson); + + pUserRightsOrRolesListJson->Append(*pUserRolesJson); + }); + } + + pPolicyJson->SetNamedArray(jsonArrayName, *pUserRightsOrRolesListJson); +} + +UsageRestrictionsResponse JsonSerializer::DeserializeUsageRestrictionsResponse( + common::ByteArray& sResponse) +{ + shared_ptr pJsonParser = IJsonParser::Create(); + + // parse the JSON + shared_ptr pJsonResponse = pJsonParser->Parse(sResponse); + + UsageRestrictionsResponse response; + + if (pJsonResponse == nullptr) return response; + + response.accessStatus = pJsonResponse->GetNamedString("AccessStatus"); + response.id = pJsonResponse->GetNamedString("Id"); + response.name = pJsonResponse->GetNamedString("Name"); + response.description = pJsonResponse->GetNamedString("Description"); + response.referrer = + ProcessReferrerResponse(pJsonResponse->GetNamedString("Referrer")); + response.owner = pJsonResponse->GetNamedString("Owner"); + response.issuedTo = pJsonResponse->GetNamedString("IssuedTo"); + response.contentId = pJsonResponse->GetNamedString("ContentId"); + + // Key + if (pJsonResponse->HasName("Key") && !pJsonResponse->IsNull("Key")) + { + shared_ptr pJsonKey = pJsonResponse->GetNamedObject("Key"); + response.key.algorithm = pJsonKey->GetNamedString("Algorithm"); + response.key.cipherMode = pJsonKey->GetNamedString("CipherMode"); + response.key.value = pJsonKey->GetNamedValue("Value"); + + // BUG 101481: There is a bug in PROD where the AccessStatus field is + // missing. When the fix reaches production, the below + // statement should be removed. + if (response.accessStatus.empty()) + { + response.accessStatus = "AccessGranted"; + } + } + else + { + // BUG 101481: There is a bug in PROD where the AccessStatus field is + // missing. When the fix reaches production, the below + // statement should be removed. + if (response.accessStatus.empty()) + { + response.accessStatus = "AccessDenied"; + } + } + + // Rights + response.rights = pJsonResponse->GetNamedStringArray("Rights"); + + if (pJsonResponse->HasName("Roles") && !pJsonResponse->IsNull("Roles")) + { + response.roles = pJsonResponse->GetNamedStringArray("Roles"); + } + + // expiry times + response.contentValidUntil = + pJsonResponse->GetNamedString("ContentValidUntil"); + response.licenseValidUntil = + pJsonResponse->GetNamedString("LicenseValidUntil"); + + // parse expiry times + if (!response.contentValidUntil.empty()) + { + auto tmp = common::DateTime::fromString(QString::fromStdString(response. + contentValidUntil)); + response.ftContentValidUntil = std::chrono::system_clock::from_time_t( + tmp.toTime_t()); + } + else + { + response.ftContentValidUntil = std::chrono::system_clock::from_time_t(0); + } + + if (!response.licenseValidUntil.empty()) + { + auto tmp = + common::DateTime::fromString(QString::fromStdString( + response.licenseValidUntil)); + response.ftLicenseValidUntil = std::chrono::system_clock::from_time_t( + tmp.toTime_t()); + } + else + { + response.ftLicenseValidUntil = std::chrono::system_clock::from_time_t(0); + } + + // custom policy response + if (pJsonResponse->HasName("Policy") && !pJsonResponse->IsNull("Policy")) + { + auto pJsonPolicy = pJsonResponse->GetNamedObject("Policy"); + + response.customPolicy.nIntervalTime = + static_cast(round(pJsonPolicy->GetNamedNumber("IntervalTimeInDays", + -1.0))); + response.customPolicy.bAllowAuditedExtraction = pJsonPolicy->GetNamedBool( + "AllowAuditedExtraction", + false); + + // UserRights looks something like this + // "UserRights": [ + // {"Users": ["user11", "user12", ...], "Rights": ["right11", + // "right12"], ... } + // {"Users": ["user21", "user22", ...], "Rights": ["right21", + // "right22"], ... } + // ... + // ] + auto pJsonUserRightsList = pJsonPolicy->GetNamedArray("UserRights"); + + for (unsigned iUserRights = 0; iUserRights < pJsonUserRightsList->Size(); + ++iUserRights) + { + auto pJsonUserRights = pJsonUserRightsList->GetObjectAt(iUserRights); + + UserRightsResponse userRights; + userRights.users = pJsonUserRights->GetNamedStringArray("Users"); + userRights.rights = pJsonUserRights->GetNamedStringArray("Rights"); + + response.customPolicy.userRightsList.emplace_back(move(userRights)); + } + + // if UserRoles are present add them too + if (pJsonPolicy->HasName("UserRoles") && !pJsonPolicy->IsNull("UserRoles")) + { + auto pJsonUserRolesList = pJsonPolicy->GetNamedArray("UserRoles"); + + for (unsigned iUserRoles = 0; iUserRoles < pJsonUserRolesList->Size(); + ++iUserRoles) + { + auto pJsonUserRoles = pJsonUserRolesList->GetObjectAt(iUserRoles); + + UserRolesResponse userRoles; + userRoles.users = pJsonUserRoles->GetNamedStringArray("Users"); + userRoles.roles = pJsonUserRoles->GetNamedStringArray("Roles"); + + response.customPolicy.userRolesList.emplace_back(move(userRoles)); + } + } + + response.customPolicy.bIsNull = false; + } + else + { + response.customPolicy.bIsNull = true; + } + + // signed application data + if (pJsonResponse->HasName("SignedApplicationData") && + !pJsonResponse->IsNull("SignedApplicationData")) + { + auto pJsonSignedAppData = pJsonResponse->GetNamedObject( + "SignedApplicationData"); + response.signedApplicationData = pJsonSignedAppData->ToStringDictionary(); + } + + // encrypted application data + if (pJsonResponse->HasName("EncryptedApplicationData") && + !pJsonResponse->IsNull("EncryptedApplicationData")) + { + auto pJsonEncryptedAppData = pJsonResponse->GetNamedObject( + "EncryptedApplicationData"); + response.encryptedApplicationData = + pJsonEncryptedAppData->ToStringDictionary(); + } + + return response; +} + +ServerErrorResponse JsonSerializer::DeserializeErrorResponse( + ByteArray& sResponse) +{ + shared_ptr pJsonParser = IJsonParser::Create(); + + // parse the JSON + shared_ptr pJsonResponse = pJsonParser->Parse(sResponse); + + ServerErrorResponse response; + + // code + if (pJsonResponse->HasName("Code") && !pJsonResponse->IsNull("Code")) + { + response.code = pJsonResponse->GetNamedString("Code"); + } + + // messsage + if (pJsonResponse->HasName("Message") && !pJsonResponse->IsNull("Message")) + { + response.message = pJsonResponse->GetNamedString("Message"); + } + + return response; +} + +TemplateListResponse JsonSerializer::DeserializeTemplateListResponse( + ByteArray& sResponse) +{ + auto pJsonParser = IJsonParser::Create(); + + // template list should be an array + auto pJsonArray = pJsonParser->ParseArray(sResponse); + + TemplateListResponse response; + + for (uint32_t index = 0; index < pJsonArray->Size(); ++index) + { + auto pTemplateJson = pJsonArray->GetObjectAt(index); + + auto atemplate = TemplateResponse { + pTemplateJson->GetNamedString("Id"), + pTemplateJson->GetNamedString("Name"), + pTemplateJson->GetNamedString("Description") + }; + + if (atemplate.id.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty atemplate.id"); + } + + if (atemplate.name.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty atemplate.name"); + } + + if (atemplate.description.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty atemplate.description"); + } + + response.templates.emplace_back(move(atemplate)); + } + + return response; +} + +PublishResponse JsonSerializer::DeserializePublishResponse(ByteArray& sResponse) +{ + auto pJsonParser = IJsonParser::Create(); + + // parse the JSON + auto pJson = pJsonParser->Parse(sResponse); + + PublishResponse response; + + response.serializedLicense = + ConvertBase64ToBytes(pJson->GetNamedValue("SerializedPublishingLicense")); + response.id = pJson->GetNamedString("Id"); + response.name = pJson->GetNamedString("Name"); + response.description = pJson->GetNamedString("Description"); + response.referrer = pJson->GetNamedString("Referrer"); + response.owner = pJson->GetNamedString("Owner"); + response.contentId = pJson->GetNamedString("ContentId"); + + auto pJsonKey = pJson->GetNamedObject("Key"); + + response.key.algorithm = pJsonKey->GetNamedString("Algorithm"); + response.key.cipherMode = pJsonKey->GetNamedString("CipherMode"); + response.key.value = pJsonKey->GetNamedValue("Value"); + + // signed application data + if (pJson->HasName("SignedApplicationData") && + !pJson->IsNull("SignedApplicationData")) + { + auto pJsonSignedAppData = pJson->GetNamedObject("SignedApplicationData"); + response.signedApplicationData = pJsonSignedAppData->ToStringDictionary(); + } + + // encrypted application data + if (pJson->HasName("EncryptedApplicationData") && + !pJson->IsNull("EncryptedApplicationData")) + { + auto pJsonEncryptedAppData = + pJson->GetNamedObject("EncryptedApplicationData"); + response.encryptedApplicationData = + pJsonEncryptedAppData->ToStringDictionary(); + } + + if (response.serializedLicense.empty()) + { + throw exceptions::RMSInvalidArgumentException( + "empty response.serializedLicense"); + } + + if (response.owner.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.owner"); + } + + if (response.key.value.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.key.value"); + } + + if (response.key.algorithm.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.key.algorithm"); + } + + if (response.key.cipherMode.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.key.cipherMode"); + } + return response; +} + +ServiceDiscoveryListResponse JsonSerializer::DeserializeServiceDiscoveryResponse( + ByteArray& sResponse) +{ + auto pJsonParser = IJsonParser::Create(); + + // service discovery response should be an array + auto pJsonArray = pJsonParser->ParseArray(sResponse); + + ServiceDiscoveryListResponse response; + + for (uint32_t index = 0; index < pJsonArray->Size(); ++index) + { + auto pTemplateJson = pJsonArray->GetObjectAt(index); + + auto endpoint = ServiceDiscoveryResponse { + pTemplateJson->GetNamedString("Name"), + pTemplateJson->GetNamedString("Uri") + }; + + if (endpoint.name.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.endpoint.name"); + } + + if (endpoint.uri.empty()) + { + throw exceptions::RMSInvalidArgumentException("empty response.endpoint.uri"); + } + + response.serviceEndpoints.emplace_back(move(endpoint)); + } + + return response; +} + +string JsonSerializer::ProcessReferrerResponse(string&& referrerResponse) +{ + if (!referrerResponse.empty()) + { + try + { + common::IUri::Create(referrerResponse); + return move(referrerResponse); + } + catch (exceptions::RMSException) + { + string withMailTo = "mailto:" + referrerResponse; + common::IUri::Create(withMailTo); + return move(withMailTo); + } + } + else + { + return referrerResponse; + } +} + +shared_ptrIJsonSerializer::Create() +{ + return make_shared(); +} +} // namespace json +} // namespace rmscore diff --git a/sdk/rms_sdk/Json/jsonserializer.h b/sdk/rms_sdk/Json/jsonserializer.h new file mode 100644 index 00000000..655cdfe4 --- /dev/null +++ b/sdk/rms_sdk/Json/jsonserializer.h @@ -0,0 +1,36 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_JSONSERIALIZER_H_ +#define _RMS_LIB_JSONSERIALIZER_H_ + +#include "../Platform/Json/IJsonObject.h" +#include "IJsonSerializer.h" + +namespace rmscore { +namespace json { +class JsonSerializer : public IJsonSerializer +{ +public: + virtual common::ByteArray SerializeUsageRestrictionsRequest(const restclients::UsageRestrictionsRequest& request) override; + virtual common::ByteArray SerializePublishUsingTemplateRequest(const restclients::PublishUsingTemplateRequest& request) override; + virtual common::ByteArray SerializePublishCustomRequest(const restclients::PublishCustomRequest& request) override; + + virtual restclients::UsageRestrictionsResponse DeserializeUsageRestrictionsResponse(common::ByteArray &sResponse) override; + virtual restclients::ServerErrorResponse DeserializeErrorResponse(common::ByteArray &sResponse) override; + virtual restclients::TemplateListResponse DeserializeTemplateListResponse(common::ByteArray &sResponse) override; + virtual restclients::PublishResponse DeserializePublishResponse(common::ByteArray &sResponse) override; + virtual restclients::ServiceDiscoveryListResponse DeserializeServiceDiscoveryResponse(common::ByteArray &sResponse) override; + +private: + std::string ProcessReferrerResponse(std::string&& referrerResponse); + void AddUserRightsOrRolesInCustomRequest(platform::json::IJsonObject* pPolicyJson, const restclients::PublishCustomRequest& request); +}; +} // namespace json +} // namespace rmscore +#endif // _MICROSOFT_PROTECTION_JSONSERIALIZER_H_ diff --git a/sdk/rms_sdk/ModernAPI/AuthenticationCallbackImpl.h b/sdk/rms_sdk/ModernAPI/AuthenticationCallbackImpl.h new file mode 100644 index 00000000..5c81bf98 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/AuthenticationCallbackImpl.h @@ -0,0 +1,51 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_AUTHENTICATIONCALLBACKIMPL_H_ +#define _RMS_LIB_AUTHENTICATIONCALLBACKIMPL_H_ + +#include "IAuthenticationCallbackImpl.h" +#include "IAuthenticationCallback.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class DLL_PUBLIC_RMS AuthenticationCallbackImpl : public IAuthenticationCallbackImpl { +public: + + AuthenticationCallbackImpl(IAuthenticationCallback& callback, + const std::string & userId) + : m_callback(callback) + , m_userId(userId) + {} + + virtual bool NeedsChallenge() const override { + return true; + } + + virtual std::string GetAccessToken(const AuthenticationChallenge& challenge) + override + { + auto parameters = std::make_shared( + challenge.authority, + challenge.resource, + challenge.scope, + m_userId); + + return m_callback.GetToken(parameters); + } + +private: + + IAuthenticationCallback& m_callback; + std::string m_userId; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_AUTHENTICATIONCALLBACKIMPL_H_ diff --git a/sdk/rms_sdk/ModernAPI/AuthenticationParameters.h b/sdk/rms_sdk/ModernAPI/AuthenticationParameters.h new file mode 100644 index 00000000..85d3d2c8 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/AuthenticationParameters.h @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_AUTHENTICATIONCALLBACK_H_ +#define _RMS_LIB_AUTHENTICATIONCALLBACK_H_ + +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +/** + * @brief Coordinates for OAuth authentication with Azure AD or AD FS. + */ +class DLL_PUBLIC_RMS AuthenticationParameters { +public: + + std::string Authority() + { + return m_authority; + } + + std::string Resource() + { + return m_resource; + } + + std::string Scope() + { + return m_scope; + } + + std::string UserId() + { + return m_userId; + } + + AuthenticationParameters(const std::string& authority, + const std::string& resource, + const std::string& scope, + const std::string& userId) + : m_authority(authority) + , m_resource(resource) + , m_scope(scope) + , m_userId(userId) + {} + +private: + + std::string m_authority; + std::string m_resource; + std::string m_scope; + std::string m_userId; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_AUTHENTICATIONCALLBACK_H_ diff --git a/sdk/rms_sdk/ModernAPI/CacheControl.h b/sdk/rms_sdk/ModernAPI/CacheControl.h new file mode 100644 index 00000000..247c8aaf --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/CacheControl.h @@ -0,0 +1,23 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_CACHECONTROL_H +#define _RMS_LIB_CACHECONTROL_H + +namespace rmscore { +namespace modernapi { +enum ResponseCacheFlags { + RESPONSE_CACHE_NOCACHE = 0x00, + RESPONSE_CACHE_INMEMORY= 0x01, + RESPONSE_CACHE_ONDISK = 0x02, + RESPONSE_CACHE_CRYPTED = 0x04, +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_CACHECONTROL_H + diff --git a/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.cpp b/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.cpp new file mode 100644 index 00000000..ba5528d2 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.cpp @@ -0,0 +1,113 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "IConsent.h" +#include "ConsentCallbackImpl.h" +#include "IConsentCallback.h" +#include "../Consent/DocumentTrackingConsent.h" +#include "../Consent/ServiceUrlConsent.h" +#include "../Consent/DocumentTrackingConsentManager.h" +#include "../Consent/SeriveUrlConsentManager.h" +#include "../ModernAPI/RMSExceptions.h" + +using namespace std; +using namespace rmscore::consent; +using namespace rmscore::modernapi; + +namespace rmscore { +namespace modernapi { +ConsentCallbackImpl::ConsentCallbackImpl(IConsentCallback & callback, + const std::string& userId, + bool isPublishing) + : m_callback(callback) + , m_userId(make_shared(userId)) + , m_isPublishing(isPublishing) +{} + +void ConsentCallbackImpl::Consents(const string & email, + const string & domain, + const std::vector& urls) +{ + vector ret; + + // Create doctracking consents + // Create service url consents + // call the callback with all consents + // Get the return value and create a vector with updated consents + // return that vector + + // Create Serviceurl consent + auto serviceConsent = std::make_shared(email, urls); + + // Create doctracking consent + auto docConsent = std::make_shared(email, + domain); + + ConsentList consentCollection; + + + auto serviceManager = IConsentManager::Create(serviceConsent, m_isPublishing); + auto documentManager = IConsentManager::Create(docConsent, m_isPublishing); + + // In case of Azure, there wont be any ServiceURL consent. We will add the + // document tracking consent only. + // In case of On-Prem, we will show serviceurl consent. This has information + // about doc tracking as well. + // So no need to add doc tracking if we have already added serviceurl consent. + + if (serviceManager->ShouldGetConsent()) + { + consentCollection.push_back(serviceConsent); + } + + if ((consentCollection.size() == 0) && documentManager->ShouldGetConsent()) + { + consentCollection.push_back(docConsent); + } + + // Nothing to consent - just return. + if (consentCollection.size() == 0) + { + return; + } + + // call user callback + auto results = m_callback.Consents(consentCollection); + + for (auto result : results) + { + // if (!result->Result()) continue; + + // Persist the result. + // If it is accepted - persist. If consent is not accepted - throw + + if (result->Result().Accepted() && !result->Result().ShowAgain()) + { + // Consent manager to persist this result. + if (result->Type() == ConsentType::ServiceUrlConsent) + { + serviceManager->PersistConsentResult(result->Result()); + } + else + { + documentManager->PersistConsentResult(result->Result()); + } + } + + // Handle the result + if (!result->Result().Accepted()) + { + throw exceptions::RMSNetworkException("User did not consent", + exceptions::RMSNetworkException::UserNotConsented); + } + } +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.h b/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.h new file mode 100644 index 00000000..f5ec5f36 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ConsentCallbackImpl.h @@ -0,0 +1,38 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_CONSENTCALLBACKIMPL_H_ +#define _RMS_LIB_CONSENTCALLBACKIMPL_H_ + +#include +#include "IConsentCallbackImpl.h" +#include "IConsentCallback.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class ConsentCallbackImpl : public IConsentCallbackImpl { +public: + + ConsentCallbackImpl(IConsentCallback & callback, + const std::string& userId, + bool isPublishing); + virtual void Consents(const std::string & email, + const std::string & domain, + const std::vector& urls) override; + +protected: + + IConsentCallback& m_callback; + std::shared_ptr m_userId; + bool m_isPublishing; + std::shared_ptr m_domain; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_CONSENTCALLBACKIMPL_H_ diff --git a/sdk/rms_sdk/ModernAPI/ConsentResult.h b/sdk/rms_sdk/ModernAPI/ConsentResult.h new file mode 100644 index 00000000..6481424b --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ConsentResult.h @@ -0,0 +1,53 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CONSENTRESULT +#define CONSENTRESULT + +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class ConsentResult { +public: + + ConsentResult(bool accepted = false, + bool showAgain = true, + const std::string& userId = "undef") + : accepted(accepted) + , showAgain(showAgain) + , userId(userId) + {} + + bool Accepted() const + { + return this->accepted; + } + + bool ShowAgain() const + { + return this->showAgain; + } + + const std::string& UserId() const + { + return this->userId; + } + +private: + + bool accepted; + bool showAgain; + std::string userId; +}; +} // namespace modernapi +} // namespace rmscore + + +#endif // CONSENTRESULT diff --git a/sdk/rms_sdk/ModernAPI/ConsentType.h b/sdk/rms_sdk/ModernAPI/ConsentType.h new file mode 100644 index 00000000..5066fa6d --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ConsentType.h @@ -0,0 +1,27 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CONSENTTYPE +#define CONSENTTYPE +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +enum class ConsentType : char +{ + // consent type for document tracking + DocumentTrackingConsent = 0, + + // consent type for contacting a service url + ServiceUrlConsent = 1 +}; +} // namespace modernapi +} // namespace rmscore + + +#endif // CONSENTTYPE diff --git a/sdk/rms_sdk/ModernAPI/CustomProtectedStream.cpp b/sdk/rms_sdk/ModernAPI/CustomProtectedStream.cpp new file mode 100644 index 00000000..3f7dcf3b --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/CustomProtectedStream.cpp @@ -0,0 +1,156 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../ModernAPI/RMSExceptions.h" +#include "../Core/ProtectionPolicy.h" +#include +#include "CustomProtectedStream.h" + +using namespace std; +using namespace rmscrypto::api; +namespace rmscore { +namespace modernapi { +CustomProtectedStream::CustomProtectedStream(shared_ptrpImpl) + : m_pImpl(pImpl) +{} + +CustomProtectedStream::~CustomProtectedStream() +{} + +shared_ptrCustomProtectedStream::Create( + shared_ptrpolicy, + SharedStream stream, + uint64_t contentStartPosition, + uint64_t contentSize) +{ + qDebug() << "+CustomProtectedStream::Create"; + + if (policy.get() == nullptr) { + throw exceptions::RMSInvalidArgumentException("Invalid policy argument"); + } + auto pCryptoProvider = policy->GetImpl()->GetCryptoProvider(); + + // create an IStreamImpl implementation of the backing stream + auto pBackingStreamImpl = stream; + + // We want the cache block size to be 512 for cbc512, 4096 for cbc4k + // In case of ECB blocksize is 16, Keep cache block size to be 4k. + uint64_t nProtectedStreamBlockSize = pCryptoProvider->GetBlockSize() == + 512 ? 512 : 4096; + + // The protected stream block size must be a multiple of crypto + // provider's block size, + // otherwise the stream can't encrypt/decypt correctly. + if (0 != nProtectedStreamBlockSize % pCryptoProvider->GetBlockSize()) { + throw exceptions::RMSCryptographyException("Invalid block size"); + } + + auto pProtectedStreamImpl = BlockBasedProtectedStream::Create(pCryptoProvider, + pBackingStreamImpl, + contentStartPosition, + contentSize, + nProtectedStreamBlockSize); + + auto result = + shared_ptr(new CustomProtectedStream( + pProtectedStreamImpl)); + + qDebug() << "-CustomProtectedStream::Create"; + return result; +} + +uint64_t CustomProtectedStream::GetEncryptedContentLength( + std::shared_ptrpolicy, + uint64_t contentLength) +{ + if (policy.get() == nullptr) { + throw exceptions::RMSNullPointerException("Invalid policy argument"); + } + return policy->GetImpl()->GetCryptoProvider()->GetCipherTextSize( + contentLength); +} + +shared_futureCustomProtectedStream::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return m_pImpl->ReadAsync(pbBuffer, cbBuffer, cbOffset, fCreateBackingThread); +} + +shared_futureCustomProtectedStream::WriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return m_pImpl->WriteAsync(cpbBuffer, cbBuffer, cbOffset, fCreateBackingThread); +} + +futureCustomProtectedStream::FlushAsync(bool fCreateBackingThread) { + return m_pImpl->FlushAsync(fCreateBackingThread); +} + +int64_t CustomProtectedStream::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) +{ + return m_pImpl->Read(pbBuffer, cbBuffer); +} + +int64_t CustomProtectedStream::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) +{ + return m_pImpl->Write(cpbBuffer, cbBuffer); +} + +bool CustomProtectedStream::Flush() { + return m_pImpl->Flush(); +} + +SharedStream CustomProtectedStream::Clone() +{ + return static_pointer_cast( + shared_ptr(new CustomProtectedStream(m_pImpl->Clone()))); +} + +void CustomProtectedStream::Seek(uint64_t u64Position) +{ + m_pImpl->Seek(u64Position); +} + +bool CustomProtectedStream::CanRead() +{ + return m_pImpl->CanRead(); +} + +bool CustomProtectedStream::CanWrite() +{ + return m_pImpl->CanWrite(); +} + +uint64_t CustomProtectedStream::Position() +{ + return m_pImpl->Position(); +} + +uint64_t CustomProtectedStream::Size() +{ + return m_pImpl->Size(); +} + +void CustomProtectedStream::Size(uint64_t u64Value) +{ + m_pImpl->Size(u64Value); +} + +shared_ptrCustomProtectedStream::GetImpl() +{ + return m_pImpl; +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/CustomProtectedStream.h b/sdk/rms_sdk/ModernAPI/CustomProtectedStream.h new file mode 100644 index 00000000..ff6dcd69 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/CustomProtectedStream.h @@ -0,0 +1,73 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_CUSTOMPROTECTEDSTREAM_H_ +#define _RMS_LIB_CUSTOMPROTECTEDSTREAM_H_ + +#include "UserPolicy.h" +#include "IStream.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class DLL_PUBLIC_RMS CustomProtectedStream : public rmscrypto::api::IStream { +public: + + static std::shared_ptrCreate( + std::shared_ptrpolicy, + rmscrypto::api::SharedStream stream, + uint64_t contentStartPosition, + uint64_t contentSize); + + static uint64_t GetEncryptedContentLength( + std::shared_ptrpolicy, + uint64_t contentLength); + + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::futureFlushAsync(bool fCreateBackingThread) + override; + + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual rmscrypto::api::SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + + // + virtual ~CustomProtectedStream(); + +protected: + + CustomProtectedStream(std::shared_ptrpImpl); + std::shared_ptrGetImpl(); + +private: + + std::shared_ptr m_pImpl; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_CUSTOMPROTECTEDSTREAM_H_ diff --git a/sdk/rms_sdk/ModernAPI/HttpHelper.cpp b/sdk/rms_sdk/ModernAPI/HttpHelper.cpp new file mode 100644 index 00000000..a22d7eea --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/HttpHelper.cpp @@ -0,0 +1,43 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "HttpHelper.h" + +namespace rmscore { +namespace modernapi { +bool addCACertificate(const std::vector& certificate, + QSsl::EncodingFormat format) { + QSslConfiguration SslConfiguration(QSslConfiguration::defaultConfiguration()); + + QList certificates = SslConfiguration.caCertificates(); + + QList cert = QSslCertificate::fromData( + QByteArray(reinterpret_cast(certificate.data()), + static_cast(certificate.size())), format); + + if (cert.length() == 0) return false; + + certificates.append(cert); + + SslConfiguration.setCaCertificates(certificates); + QSslConfiguration::setDefaultConfiguration(SslConfiguration); + + return true; +} + +bool HttpHelper::addCACertificateBase64(const std::vector& certificate) { + return addCACertificate(certificate, QSsl::Pem); +} + +bool HttpHelper::addCACertificateDer(const std::vector& certificate) { + return addCACertificate(certificate, QSsl::Der); +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/HttpHelper.h b/sdk/rms_sdk/ModernAPI/HttpHelper.h new file mode 100644 index 00000000..58873ebb --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/HttpHelper.h @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_HTTPHELPER_H +#define _RMS_LIB_HTTPHELPER_H + +#include +#include + +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class DLL_PUBLIC_RMS HttpHelper { +public: + + // to use trusted CA put certificates + static bool addCACertificateBase64(const std::vector& certificate); + static bool addCACertificateDer(const std::vector& certificate); +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_HTTPHELPER_H diff --git a/sdk/rms_sdk/ModernAPI/IAuthenticationCallback.h b/sdk/rms_sdk/ModernAPI/IAuthenticationCallback.h new file mode 100644 index 00000000..a1413979 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/IAuthenticationCallback.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_IAUTHENTICATIONCALLBACK_H_ +#define _RMS_LIB_IAUTHENTICATIONCALLBACK_H_ + +#include +#include +#include "AuthenticationParameters.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +/** + * @brief IAuthenticationCallback interface to provide strategy for getting usable access token. + * + * Apps should implement this interface, specifically the GetToken method, to return an + * access token for use by the API client. + */ +class IAuthenticationCallback { +public: + + /** + * @brief Override to return an access token clients can attach to outbound API calls. + * @param authenticationParamaters {@link AuthenticationParameters} Coordinates for OAuth calls. + * @return A usable access token. + */ + virtual std::string GetToken( + std::shared_ptr& authenticationParameters) = 0; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_IAUTHENTICATIONCALLBACK_H_ diff --git a/sdk/rms_sdk/ModernAPI/IAuthenticationCallbackImpl.h b/sdk/rms_sdk/ModernAPI/IAuthenticationCallbackImpl.h new file mode 100644 index 00000000..295b324b --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/IAuthenticationCallbackImpl.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_IAUTHENTICATIONCALLBACKIMPL_H_ +#define _RMS_LIB_IAUTHENTICATIONCALLBACKIMPL_H_ + +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +struct AuthenticationChallenge +{ + std::string authority; + std::string resource; + std::string scope; +}; + +class IAuthenticationCallbackImpl { +public: + + virtual bool NeedsChallenge() const = + 0; + virtual std::string GetAccessToken(const AuthenticationChallenge& challenge) = + 0; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_IAUTHENTICATIONCALLBACKIMPL_H_ diff --git a/sdk/rms_sdk/ModernAPI/IConsent.h b/sdk/rms_sdk/ModernAPI/IConsent.h new file mode 100644 index 00000000..16d1a7e6 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/IConsent.h @@ -0,0 +1,54 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ICONSENT +#define ICONSENT + +#include +#include +#include "ConsentType.h" +#include "ConsentResult.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +// TODO: figure out why it's an interface +class IConsent { +public: + + /// + /// Gets or sets the consent result + /// + virtual const ConsentResult& Result() const = 0; + + // virtual void ConsentResult(const ConsentResult& value) = 0; + + /// + /// Gets the type of consent + /// + virtual ConsentType Type() const = 0; + + /// + /// Gets the list of urls that need to consented. + /// + virtual const std::vectorUrls() const = 0; + + /// + /// Gets the user id + /// + virtual const std::string User() const = 0; + + /// + /// Gets the domain information + /// + virtual const std::string Domain() const = 0; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // ICONSENT diff --git a/sdk/rms_sdk/ModernAPI/IConsentCallback.h b/sdk/rms_sdk/ModernAPI/IConsentCallback.h new file mode 100644 index 00000000..e1b13e67 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/IConsentCallback.h @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_ICONSENTCALLBACK_H_ +#define _RMS_LIB_ICONSENTCALLBACK_H_ + +#include +#include "IConsent.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +using ConsentList = std::vector >; + +/// +/// Interface for displaying consents. This callback is provided by app +// developer to know when and which consent notifications to display to user. +/// +class IConsentCallback { +public: + + /// + /// Apps should implement this method and return consents + /// + /// List of Consents + /// Access token + virtual ConsentList Consents(ConsentList& consents) = 0; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_ICONSENTCALLBACK_H_ diff --git a/sdk/rms_sdk/ModernAPI/IConsentCallbackImpl.h b/sdk/rms_sdk/ModernAPI/IConsentCallbackImpl.h new file mode 100644 index 00000000..86bf2602 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/IConsentCallbackImpl.h @@ -0,0 +1,24 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_ICONSENTCALLBACKIMPL_H_ +#define _RMS_LIB_ICONSENTCALLBACKIMPL_H_ +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +class IConsentCallbackImpl { +public: + + virtual void Consents(const std::string & email, + const std::string & domain, + const std::vector& urls) = 0; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_ICONSENTCALLBACKIMPL_H_ diff --git a/sdk/rms_sdk/ModernAPI/ModernAPI.pro b/sdk/rms_sdk/ModernAPI/ModernAPI.pro new file mode 100644 index 00000000..08dde366 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ModernAPI.pro @@ -0,0 +1,74 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin +TARGET = rms + +LIBS += -L$$REPO_ROOT/bin/ -L$$REPO_ROOT/bin/rms/ -L$$REPO_ROOT/bin/rms/platform/ +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI + +DEFINES += RMS_LIBRARY + +TEMPLATE = lib +QT += core xml xmlpatterns widgets network +QT -= gui +CONFIG += plugin c++11 debug_and_release warn_on +QMAKE_CFLAGS_WARN_ON -= -W3 +QMAKE_CFLAGS_WARN_ON += -W4 + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -lmodprotectedfiled -lmodcored -lmodrestclientsd -lmodconsentd -lmodcommond -lmodjsond -lrmscryptod + LIBS += -lplatformhttpd -lplatformloggerd -lplatformxmld -lplatformjsond -lplatformfilesystemd -lplatformsettingsd +} else { + LIBS += -lmodprotectedfile -lmodcore -lmodrestclients -lmodconsent -lmodcommon -lmodjson -lrmscrypto + LIBS += -lplatformhttp -lplatformlogger -lplatformxml -lplatformjson -lplatformfilesystem -lplatformsettings +} + +SOURCES += \ + UserPolicy.cpp \ + TemplateDescriptor.cpp \ + ConsentCallbackImpl.cpp \ + PolicyDescriptor.cpp \ + ProtectedFileStream.cpp \ + CustomProtectedStream.cpp \ + ext/QTStreamImpl.cpp \ + HttpHelper.cpp + +HEADERS += \ + UserPolicy.h \ + IAuthenticationCallback.h \ + IConsentCallback.h \ + TemplateDescriptor.h \ + rights.h \ + ConsentCallbackImpl.h \ + IConsentCallbackImpl.h \ + AuthenticationCallbackImpl.h \ + IAuthenticationCallbackImpl.h \ + ConsentResult.h \ + IConsent.h \ + Roles.h \ + PolicyDescriptor.h \ + UserRights.h \ + UserRoles.h \ + AuthenticationParameters.h \ + consent.h \ + ConsentType.h \ + ProtectedFileStream.h \ + CustomProtectedStream.h \ + ext/QTStreamImpl.h \ + HttpHelper.h \ + ModernAPIExport.h \ + CacheControl.h \ + RMSExceptions.h + +win32:LIBS += -L$$REPO_ROOT/third_party/lib/eay/ -lssleay32MDd -llibeay32MDd -lGdi32 -lUser32 -lAdvapi32 +else:LIBS += -lssl -lcrypto + +unix { + contains(QMAKE_HOST.arch, x86_64) { + target.path = /usr/lib64 + INSTALLS += target + } else { + target.path += /usr/lib + INSTALLS += target + } +} diff --git a/sdk/rms_sdk/ModernAPI/ModernAPIExport.h b/sdk/rms_sdk/ModernAPI/ModernAPIExport.h new file mode 100644 index 00000000..8c27fa4e --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ModernAPIExport.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_CRYPTO_EXPORT_H_ +#define _RMS_CRYPTO_EXPORT_H_ + +// This code produces too many warnings + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RMS_LIBRARY + #ifdef __GNUC__ + #define DLL_PUBLIC_RMS __attribute__ ((dllexport)) + #else + #define DLL_PUBLIC_RMS __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. + #endif + #else + #ifdef __GNUC__ + #define DLL_PUBLIC_RMS __attribute__ ((dllimport)) + #else + #define DLL_PUBLIC_RMS __declspec(dllimport) // Note: actually gcc seems to also supports this syntax. + #endif + #endif + #define DLL_LOCAL +#else + #if __GNUC__ >= 4 + #define DLL_PUBLIC_RMS __attribute__ ((visibility ("default"))) + #define DLL_LOCAL_RMS __attribute__ ((visibility ("hidden"))) + #else + #define DLL_PUBLIC_RMS + #define DLL_LOCAL_RMS + #endif +#endif + +#endif // _RMS_CRYPTO_EXPORT_H_ diff --git a/sdk/rms_sdk/ModernAPI/PolicyDescriptor.cpp b/sdk/rms_sdk/ModernAPI/PolicyDescriptor.cpp new file mode 100644 index 00000000..e8172cde --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/PolicyDescriptor.cpp @@ -0,0 +1,190 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +#include "../Core/ProtectionPolicy.h" +#include "../ModernAPI/RMSExceptions.h" +#include "PolicyDescriptor.h" + +using namespace std; +using namespace rmscore::common; +using namespace rmscore::core; + +namespace rmscore { +namespace modernapi { +template +static void ValidateInputRefObjectCollection(const TIterable& collection) +{ + for (auto& item : collection) { + if (item.empty()) { + throw exceptions::RMSInvalidArgumentException("Invalid item"); + } + } +} + +void UserRights::ValidateUsers(UserList& users) +{ + ValidateInputRefObjectCollection(users); +} + +void UserRights::ValidateRights(RightList& rights) +{ + ValidateInputRefObjectCollection(rights); +} + +UserRoles::UserRoles(UserList& users, RoleList& roles) + : users(users) + , roles(roles) +{ + ValidateUsers(users); + ValidateRoles(roles); +} + +void UserRoles::ValidateUsers(UserList& users) +{ + ValidateInputRefObjectCollection(users); +} + +void UserRoles::ValidateRoles(RoleList& roles) +{ + ValidateInputRefObjectCollection(roles); +} + +PolicyDescriptor::PolicyDescriptor(const std::vector &userRightsList) + : name_() + , description_() + , userRightsList_(userRightsList) + , userRolesList_() + , contentValidUntil_() + , nOfflineCacheLifetimeInDays_( + OfflineCacheLifetimeConstants::CacheNeverExpires()) + , referrer_() + , encryptedAppData_() + , signedAppData_() +{ + ValidateUserRightsList(userRightsList); +} + +PolicyDescriptor::PolicyDescriptor(const std::vector &userRolesList) + : name_() + , description_() + , userRightsList_() + , userRolesList_(userRolesList) + , contentValidUntil_() + , nOfflineCacheLifetimeInDays_( + OfflineCacheLifetimeConstants::CacheNeverExpires()) + , referrer_() + , encryptedAppData_() + , signedAppData_() +{ + ValidateUserRolesList(userRolesList); +} + +PolicyDescriptor::PolicyDescriptor(std::shared_ptr policy) + : name_() + , description_() + , userRightsList_() + , contentValidUntil_() + , nOfflineCacheLifetimeInDays_( + OfflineCacheLifetimeConstants::CacheNeverExpires()) + , referrer_() + , encryptedAppData_() + , signedAppData_() +{ + if (!policy->IsAdhoc()) { + throw exceptions::RMSInvalidArgumentException("Invalid policy argument"); + } + + name_ = policy->GetName(); + description_ = policy->GetDescription(); + nOfflineCacheLifetimeInDays_ = + (USHRT_MAX != + policy->GetIntervalTime()) ? policy->GetIntervalTime() : + OfflineCacheLifetimeConstants::CacheNeverExpires(); + referrer_ = std::make_shared(policy->GetReferrer()); + + auto timeFrom = policy->GetValidityTimeFrom(); + auto dur = policy->GetValidityTimeDuration(); + if (std::chrono::system_clock::to_time_t(timeFrom) > 0 && (0ull != dur)) + { + contentValidUntil_ = timeFrom + std::chrono::milliseconds( + policy->GetValidityTimeDuration()); + } + else + { + contentValidUntil_ = std::chrono::system_clock::from_time_t(0); + } + + if (policy->HasUserRightsInformation()) + { + vector userRightsList; + + for (auto userRightsImpl : policy->GetUserRightsList()) + { + vector users; + + for (auto userImpl : userRightsImpl.users) + { + users.push_back(userImpl); + } + + vector rights; + + for (auto rightImpl : userRightsImpl.rights) + { + rights.push_back(rightImpl); + } + + userRightsList.push_back(UserRights(users, rights)); + } + + userRightsList_ = userRightsList; + + // In consumption flow, we might get roles as well. + vector userRolesList; + + for (auto userRolesImpl : policy->GetUserRolesList()) + { + vector users; + + for (auto userImpl : userRolesImpl.users) + { + users.push_back(userImpl); + } + + vector roles; + + for (auto& roleImpl : userRolesImpl.roles) + { + roles.push_back(roleImpl); + } + userRolesList.push_back(UserRoles(users, roles)); + } + + userRolesList_ = userRolesList; + } +} + +void PolicyDescriptor::ValidateUserRightsList(const std::vector &userRightsList) +{ + for (const auto& userRight : userRightsList) { + ValidateInputRefObjectCollection(userRight.Users()); + ValidateInputRefObjectCollection(userRight.Rights()); + } +} + +void PolicyDescriptor::ValidateUserRolesList(const std::vector &userRolesList) +{ + for (const auto& userRole : userRolesList) { + ValidateInputRefObjectCollection(userRole.Users()); + ValidateInputRefObjectCollection(userRole.Roles()); + } +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/PolicyDescriptor.h b/sdk/rms_sdk/ModernAPI/PolicyDescriptor.h new file mode 100644 index 00000000..e6568855 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/PolicyDescriptor.h @@ -0,0 +1,196 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef POLICYDESCRIPTOR_H +#define POLICYDESCRIPTOR_H + +#include +#include +#include +#include + +#include "ModernAPIExport.h" + +#include "UserRoles.h" +#include "UserRights.h" + +struct HashConstString +{ + long operator()(const std::string& str) const { + return static_cast(std::hash()(str)); + } +}; + +template +using HashMapString = std::unordered_map; + +namespace rmscore { +namespace core { +class ProtectionPolicy; +} + +namespace modernapi { +using AppDataHashmap = HashMapString; + +/** + * @brief Specifies users and rights assigned for a file. + */ +class DLL_PUBLIC_RMS PolicyDescriptor { +public: + + PolicyDescriptor(const std::vector& userRightsList); + + PolicyDescriptor(const std::vector& userRolesList); + + const std::string& Name() + { + return this->name_; + } + + void Name(std::string& value) + { + this->name_ = value; + } + + const std::string& Description() + { + return this->description_; + } + + void Description(const std::string& value) + { + this->description_ = value; + } + + /** + * @brief Gets the user's rights list. + * + * The value of the UserRightsList property will be null if the current + * user doesn't have access to the user rights information (i.e., is not the + * owner and does not have the VIEWRIGHTSDATA right). + * + * @return List of users and their rights for this file. + */ + const std::vector& UserRightsList() const + { + return this->userRightsList_; + } + + const std::vector& UserRolesList() + { + return this->userRolesList_; + } + + const std::chrono::time_point& ContentValidUntil() + { + return this->contentValidUntil_; + } + + void ContentValidUntil(const std::chrono::time_point& value) + { + this->contentValidUntil_ = value; + } + + int OfflineCacheLifetimeInDays() + { + return this->nOfflineCacheLifetimeInDays_; + } + + void OfflineCacheLifetimeInDays(int value) + { + this->nOfflineCacheLifetimeInDays_ = value; + } + + std::shared_ptrReferrer() const + { + return this->referrer_; + } + + void Referrer(std::shared_ptruri) + { + this->referrer_ = uri; + } + + const AppDataHashmap& EncryptedAppData() + { + return this->encryptedAppData_; + } + + void EncryptedAppData(const AppDataHashmap& value) + { + this->encryptedAppData_ = value; + } + + const AppDataHashmap& SignedAppData() + { + return this->signedAppData_; + } + + void SignedAppData(const AppDataHashmap& value) + { + this->signedAppData_ = value; + } + +public: + + PolicyDescriptor(std::shared_ptr policy); + +private: + + std::string name_; + std::string description_; + + std::vector userRightsList_; + std::vector userRolesList_; + + std::chrono::time_point contentValidUntil_; + int nOfflineCacheLifetimeInDays_; + + std::shared_ptr referrer_; + AppDataHashmap encryptedAppData_; + AppDataHashmap signedAppData_; + +private: + + static void ValidateUserRightsList( + const std::vector& userRightsList); + static void ValidateUserRolesList( + const std::vector& userRolesList); +}; + +/** + * @brief Constants for PolicyDescriptor.OfflineCacheLifetimeInDays property. + */ +class DLL_PUBLIC_RMS OfflineCacheLifetimeConstants { +public: + + /** + * @brief The content shoudn't be accessed offline at all + */ + static int NoCache() + { + return 0; + } + + /** + * @brief The offline cache for the content shouldn't expire + */ + static int CacheNeverExpires() + { + return -1; + } + +private: + + // undefined private default constructor + OfflineCacheLifetimeConstants(); +}; +} // m_namespace modernapi +} // m_namespace rmscore + +#endif // POLICYDESCRIPTOR_H diff --git a/sdk/rms_sdk/ModernAPI/ProtectedFileStream.cpp b/sdk/rms_sdk/ModernAPI/ProtectedFileStream.cpp new file mode 100644 index 00000000..369b7460 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ProtectedFileStream.cpp @@ -0,0 +1,279 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include "../PFile/PfileHeaderReader.h" +#include "../PFile/PfileHeaderWriter.h" +#include "../ModernAPI/RMSExceptions.h" +#include "../Core/ProtectionPolicy.h" +#include "ProtectedFileStream.h" + +using namespace rmscore::common; +using namespace rmscrypto::api; +using namespace rmscore::pfile; +using namespace std; + +namespace rmscore { +namespace modernapi { +GetProtectedFileStreamResult::GetProtectedFileStreamResult( + GetUserPolicyResultStatus status, + std::shared_ptr referrer, + std::shared_ptrstream) + : m_status(status) + , m_referrer(referrer) + , m_stream(stream) +{} + +ProtectedFileStream::ProtectedFileStream(SharedStream pImpl, + shared_ptrpolicy, + string & originalFileExtension) + : m_policy(policy) + , m_originalFileExtension(originalFileExtension) + , m_pImpl(pImpl) +{} + +ProtectedFileStream::~ProtectedFileStream() {} + +shared_ptrProtectedFileStream::Acquire( + SharedStream stream, + const string & userId, + IAuthenticationCallback& authenticationCallback, + IConsentCallback & consentCallback, + PolicyAcquisitionOptions options, + ResponseCacheFlags cacheMask) +{ + qDebug() << "+ProtectedFileStream::Get"; + + // Read PfileHeader from the stream + shared_ptr headerReader = IPfileHeaderReader::Create(); + shared_ptr header = nullptr; + + shared_ptr policy = nullptr; + GetUserPolicyResultStatus status = GetUserPolicyResultStatus::Success; + shared_ptr referrer; + PfileHeader *pHeader = nullptr; + + shared_ptr cp; + + try { + header = headerReader->Read(stream); + pHeader = header.get(); + qDebug() << + "ProtectedFileStream: Read pfile header. Major version: " << + pHeader->GetMajorVersion() << ", minor version: " << + pHeader->GetMinorVersion() << ", file extension: '" << + pHeader->GetFileExtension().c_str() << "', content start position: " << + pHeader->GetContentStartPosition() << ", original file size: " << + pHeader->GetOriginalFileSize() << "."; + } catch (exceptions::RMSException& e) { + if ((e.error() != exceptions::RMSException::PFileError) || + (static_cast(e).reason() != + exceptions::RMSPFileException::NotPFile)) + { + throw; + } + } + if (pHeader != nullptr) { + ByteArray publishingLicense = pHeader->GetPublishingLicense(); + auto policyRequest = UserPolicy::Acquire(publishingLicense, + userId, + authenticationCallback, + consentCallback, + options, + cacheMask); + + if ((policyRequest->Status == GetUserPolicyResultStatus::Success) && + (policyRequest->Policy != nullptr)) { + // Successfully retrieved the policy + policy = policyRequest->Policy; + } + status = policyRequest->Status; + referrer = policyRequest->Referrer; + } + + ProtectedFileStream *protectedFileStream = CreateProtectedFileStream(policy, + stream, + header); + + auto result = make_shared( + move(status), referrer, + shared_ptr(protectedFileStream)); + return result; +} + +shared_ptrProtectedFileStream::Create( + shared_ptrpolicy, + SharedStream stream, + const string & originalFileExtension) +{ + qDebug() << "+ProtectedFileStream::Create"; + + shared_ptr pHeader; + + if (policy.get() != nullptr) + { + auto headerWriter = IPfileHeaderWriter::Create(); + + auto publishingLicense = policy->SerializedPolicy(); + ByteArray metadata; // No metadata + + // calculate content size + uint32_t contentStartPosition = + static_cast(originalFileExtension.size() + + publishingLicense.size() + + + metadata.size() + 454); + pHeader = make_shared(move(publishingLicense), + originalFileExtension, + contentStartPosition, + static_cast(-1), // No known + // originalFileSize + move(metadata), + static_cast(2), // Major + // version + static_cast(1), // Minor + // version + CleartextRedirectHeader); + + headerWriter->Write(stream, pHeader); + stream->Flush(); + } + + auto result = CreateProtectedFileStream(policy, stream, pHeader); + + qDebug() << "-ProtectedFileStream::Create"; + return shared_ptr(result); +} + +ProtectedFileStream * ProtectedFileStream::CreateProtectedFileStream( + shared_ptrpolicy, + SharedStream stream, + shared_ptr + header) { + // create an IStreamImpl implementation of the backing stream + auto pBackingStreamImpl = stream->Clone(); + uint64_t nProtectedStreamBlockSize = 4096; + + shared_ptr pCryptoProvider = nullptr; + ulong contentStartPosition = 0; + string fileExtension; + + // Disallow deprecated algorithms + // There is no value in encrypting PFILEs in ECB mode, So treat the + // deprecated flags for PFILEs as CBC4K mode + // Check if deprecated flag is set, if yes - create a new crypto provider. + if (policy->DoesUseDeprecatedAlgorithms()) { + pCryptoProvider = CreateCryptoProvider(CipherMode::CIPHER_MODE_CBC4K, + policy->GetImpl()->GetCryptoProvider()->GetKey()); + } else { + pCryptoProvider = policy->GetImpl()->GetCryptoProvider(); + } + + // We want the cache block size to be 512 for cbc512, 4096 for cbc4k + // In case of ECB blocksize is 16, Keep cache block size to be 4k. + nProtectedStreamBlockSize = pCryptoProvider->GetBlockSize() == 512 ? 512 : 4096; + + // The protected stream block size must be a multiple of crypto provider's + // block size, + // otherwise the stream can't encrypt/decypt correctly. + if (0 != + nProtectedStreamBlockSize % + pCryptoProvider->GetBlockSize()) throw exceptions::RMSStreamException( + "Invalid block size"); + + contentStartPosition = header->GetContentStartPosition(); + fileExtension = header->GetFileExtension(); + + auto pProtectedStreamImpl = BlockBasedProtectedStream::Create(pCryptoProvider, + pBackingStreamImpl, + contentStartPosition, + stream->Size() - + contentStartPosition, + nProtectedStreamBlockSize); + + return new ProtectedFileStream(pProtectedStreamImpl, policy, + fileExtension); +} + +shared_futureProtectedFileStream::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return m_pImpl->ReadAsync(pbBuffer, cbBuffer, cbOffset, fCreateBackingThread); +} + +shared_futureProtectedFileStream::WriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return m_pImpl->WriteAsync(cpbBuffer, cbBuffer, cbOffset, fCreateBackingThread); +} + +futureProtectedFileStream::FlushAsync(bool fCreateBackingThread) { + return m_pImpl->FlushAsync(fCreateBackingThread); +} + +int64_t ProtectedFileStream::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) +{ + return m_pImpl->Read(pbBuffer, cbBuffer); +} + +int64_t ProtectedFileStream::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) +{ + return m_pImpl->Write(cpbBuffer, cbBuffer); +} + +bool ProtectedFileStream::Flush() { + return m_pImpl->Flush(); +} + +SharedStream ProtectedFileStream::Clone() +{ + return shared_ptr(new ProtectedFileStream(m_pImpl->Clone(), m_policy, + m_originalFileExtension)); +} + +void ProtectedFileStream::Seek(uint64_t u64Position) +{ + m_pImpl->Seek(u64Position); +} + +uint64_t ProtectedFileStream::Position() +{ + return m_pImpl->Position(); +} + +bool ProtectedFileStream::CanRead() +{ + return m_pImpl->CanRead(); +} + +bool ProtectedFileStream::CanWrite() +{ + return m_pImpl->CanWrite(); +} + +uint64_t ProtectedFileStream::Size() +{ + return m_pImpl->Size(); +} + +void ProtectedFileStream::Size(uint64_t u64Value) +{ + m_pImpl->Size(u64Value); +} +} // namespace stream +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/ProtectedFileStream.h b/sdk/rms_sdk/ModernAPI/ProtectedFileStream.h new file mode 100644 index 00000000..56fb15b9 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ProtectedFileStream.h @@ -0,0 +1,112 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PROTECTEDFILESTREAM_H_ +#define _RMS_LIB_PROTECTEDFILESTREAM_H_ + +#include +#include "UserPolicy.h" +#include "ModernAPIExport.h" +#include "CacheControl.h" + +namespace rmscore { +namespace pfile { +class PfileHeader; +} + +namespace modernapi { +class ProtectedFileStream; + +struct DLL_PUBLIC_RMS GetProtectedFileStreamResult +{ + GetUserPolicyResultStatus m_status; + std::shared_ptr m_referrer; + std::shared_ptrm_stream; + + GetProtectedFileStreamResult(GetUserPolicyResultStatus status, + std::shared_ptr referrer, + std::shared_ptrstream); +}; + +class DLL_PUBLIC_RMS ProtectedFileStream : public rmscrypto::api::IStream { +public: + + virtual ~ProtectedFileStream(); + ProtectedFileStream(rmscrypto::api::SharedStream pImpl, + std::shared_ptrpolicy, + std::string & originalFileExtension); + + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::futureFlushAsync(bool fCreateBackingThread) + override; + + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual rmscrypto::api::SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + + static std::shared_ptrAcquire( + rmscrypto::api::SharedStream stream, + const std::string & userId, + IAuthenticationCallback & authenticationCallback, + IConsentCallback & consentCallback, + PolicyAcquisitionOptions options, + ResponseCacheFlags cacheMask + = static_cast(RESPONSE_CACHE_INMEMORY | + RESPONSE_CACHE_ONDISK | + RESPONSE_CACHE_CRYPTED)); + + static std::shared_ptrCreate( + std::shared_ptrpolicy, + rmscrypto::api::SharedStream stream, + const std::string & originalFileExtension); + + std::shared_ptrPolicy() { + return m_policy; + } + + std::string OriginalFileExtension() { + return m_originalFileExtension; + } + +private: + + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + + static ProtectedFileStream* CreateProtectedFileStream( + std::shared_ptr policy, + rmscrypto::api::SharedStream stream, + std::shared_ptrheader); + +private: + + std::shared_ptr m_policy; + std::string m_originalFileExtension; + std::shared_ptr m_pImpl; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_PROTECTEDFILESTREAM_H_ diff --git a/sdk/rms_sdk/ModernAPI/RMSExceptions.h b/sdk/rms_sdk/ModernAPI/RMSExceptions.h new file mode 100644 index 00000000..2c880367 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/RMSExceptions.h @@ -0,0 +1,215 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_EXCEPTIONS_H +#define _RMS_LIB_EXCEPTIONS_H +#include +#include + +#ifndef _NOEXCEPT +#if __GNUC__ >= 4 +#define _NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#endif +#endif + +namespace rmscore { +namespace exceptions { +class RMSException : public std::exception { +public: + + enum ExceptionTypes { + LogicError = 0 + }; + enum ErrorTypes { + InvalidArgument = 0, + NullPointer, + NotFound, + NetworkError, + CryptoError, + StreamError, + PFileError, + RightsError + }; + + RMSException(const ExceptionTypes type, + const int error, + const std::string & message) _NOEXCEPT + : type_(type), error_(error), message_(message.c_str()) + {} + + RMSException(const ExceptionTypes type, + const int error, + const char *const & message) _NOEXCEPT + : type_(type), error_(error), message_(message) + {} + + virtual ~RMSException() _NOEXCEPT {} + + virtual const char * what() const _NOEXCEPT override { + return message_; + } + + virtual ExceptionTypes type() const _NOEXCEPT { + return type_; + } + + virtual int error() const _NOEXCEPT { + return error_; + } + +private: + + ExceptionTypes type_; + int error_; + const char * message_; +}; + +class RMSLogicException : public RMSException { +public: + + RMSLogicException(const int error, + const std::string& message) _NOEXCEPT + : RMSException(LogicError, error, message) {} + + RMSLogicException(const int error, + const char *const& message) _NOEXCEPT + : RMSException(LogicError, error, message) {} + + virtual ~RMSLogicException() _NOEXCEPT {} +}; + +class RMSInvalidArgumentException : public RMSLogicException { +public: + + RMSInvalidArgumentException(const std::string& message) _NOEXCEPT + : RMSLogicException(InvalidArgument, message) {} + + RMSInvalidArgumentException(const char *const& message) _NOEXCEPT + : RMSLogicException(InvalidArgument, message) {} + + virtual ~RMSInvalidArgumentException() _NOEXCEPT {} +}; + +class RMSNullPointerException : public RMSLogicException { +public: + + RMSNullPointerException(const std::string& message) _NOEXCEPT + : RMSLogicException(NullPointer, message) {} + + RMSNullPointerException(const char *const& message) _NOEXCEPT + : RMSLogicException(NullPointer, message) {} + + virtual ~RMSNullPointerException() _NOEXCEPT {} +}; + +class RMSNotFoundException : public RMSLogicException { +public: + + RMSNotFoundException(const std::string& message) _NOEXCEPT + : RMSLogicException(NullPointer, message) {} + + RMSNotFoundException(const char *const& message) _NOEXCEPT + : RMSLogicException(NullPointer, message) {} + + virtual ~RMSNotFoundException() _NOEXCEPT {} +}; + +class RMSNetworkException : public RMSLogicException { +public: + + enum Reason { + ServerError = 0, + UserNotConsented, + ServiceNotAvailable, + OnPremNotSupported, + InvalidPL, + ServiceDisabled, + DeviceRejected, + NeedsOnline + }; + + + RMSNetworkException(const std::string& message, Reason reason) _NOEXCEPT + : RMSLogicException(NetworkError, message), reason_(reason) {} + + RMSNetworkException(const char *const& message, Reason reason) _NOEXCEPT + : RMSLogicException(NetworkError, message), reason_(reason) {} + + virtual ~RMSNetworkException() _NOEXCEPT {} + + virtual Reason reason() const _NOEXCEPT { + return reason_; + } + +private: + + Reason reason_; // additional reason for this error +}; + +class RMSCryptographyException : public RMSLogicException { +public: + + RMSCryptographyException(const std::string& message) _NOEXCEPT + : RMSLogicException(NetworkError, message) {} + + RMSCryptographyException(const char *const& message) _NOEXCEPT + : RMSLogicException(NetworkError, message) {} + + virtual ~RMSCryptographyException() _NOEXCEPT {} +}; +class RMSStreamException : public RMSLogicException { +public: + + RMSStreamException(const std::string& message) _NOEXCEPT + : RMSLogicException(StreamError, message) {} + + RMSStreamException(const char *const& message) _NOEXCEPT + : RMSLogicException(StreamError, message) {} + + virtual ~RMSStreamException() _NOEXCEPT {} +}; +class RMSPFileException : public RMSLogicException { +public: + + enum Reason { + NotPFile = 0, + NotSupportedVersion, + BadArguments, + }; + + RMSPFileException(const std::string& message, Reason reason) _NOEXCEPT + : RMSLogicException(PFileError, message), reason_(reason) {} + + RMSPFileException(const char *const& message, Reason reason) _NOEXCEPT + : RMSLogicException(PFileError, message), reason_(reason) {} + + virtual ~RMSPFileException() _NOEXCEPT {} + + virtual Reason reason() const _NOEXCEPT { + return reason_; + } + +private: + + Reason reason_; // additional reason for this error +}; + +class RMSRightsException : public RMSLogicException { +public: + + RMSRightsException(const std::string& message) _NOEXCEPT + : RMSLogicException(PFileError, message) {} + + RMSRightsException(const char *const& message) _NOEXCEPT + : RMSLogicException(PFileError, message) {} + + virtual ~RMSRightsException() _NOEXCEPT {} +}; +} // namespace exceptions +} // namespace rmscore +#endif // _RMS_LIB_EXCEPTIONS_H diff --git a/sdk/rms_sdk/ModernAPI/TemplateDescriptor.cpp b/sdk/rms_sdk/ModernAPI/TemplateDescriptor.cpp new file mode 100644 index 00000000..2f530f5b --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/TemplateDescriptor.cpp @@ -0,0 +1,66 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "../Core/ProtectionPolicy.h" +#include "../RestClients/TemplatesClient.h" +#include "../ModernAPI/RMSExceptions.h" +#include "TemplateDescriptor.h" +#include "AuthenticationCallbackImpl.h" + +using namespace std; +using namespace rmscore::common; +using namespace rmscore::core; +using namespace rmscore::restclients; + +namespace rmscore { +namespace modernapi { +TemplateDescriptor::TemplateDescriptor(const string& id, + const string& name, + const string& description) + : m_id(id) + , m_name(name) + , m_description(description) +{} + +TemplateDescriptor::TemplateDescriptor(std::shared_ptr policy) + : m_id(policy->GetId()) + , m_name(policy->GetName()) + , m_description(policy->GetDescription()) +{ + if (policy->IsAdhoc()) { + throw exceptions::RMSInvalidArgumentException("Invalid policy"); + } +} + +std::vector TemplateDescriptor::GetTemplateList( + std::string userId, + IAuthenticationCallback& authenticationCallback) +{ + TIterable result; + auto authenticationCallbackImpl = + AuthenticationCallbackImpl { authenticationCallback, userId }; + + auto pTemplatesClient = ITemplatesClient::Create(); + auto response = pTemplatesClient->GetTemplates( + authenticationCallbackImpl, + userId); + + for_each( + begin(response.templates), + end(response.templates), + [&](const TemplateResponse& templateResponse) + { + result.push_back(move(TemplateDescriptor(templateResponse.id, + templateResponse.name, + templateResponse.description))); + }); + + return result; +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/TemplateDescriptor.h b/sdk/rms_sdk/ModernAPI/TemplateDescriptor.h new file mode 100644 index 00000000..904f504e --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/TemplateDescriptor.h @@ -0,0 +1,78 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_TEMPLATEDESCRIPTOR_H_ +#define _RMS_LIB_TEMPLATEDESCRIPTOR_H_ + +#include "IAuthenticationCallback.h" +#include "ModernAPIExport.h" + +namespace rmscore { +namespace core { +class ProtectionPolicy; +} +namespace modernapi { +/// +/// Template information +/// +class DLL_PUBLIC_RMS TemplateDescriptor { +public: + + /// + /// Template Id + /// + std::string TemplateId() { + return m_id; + } + + /// + /// Policy name + /// + std::string Name() { + return m_name; + } + + /// + /// Policy description + /// + std::string Description() { + return m_description; + } + + + /** + * @brief Get list of templates for current tenant. + * @param userId The email address of the user for whom the templates + * are being retrieved. This email address will be used to discover the RMS + * service instance (either ADRMS server or Azure RMS) that the user's + * organization is using. This parameter is also used as a hint for userId for + * user authentication, i.e., it will be passed to + * IAuthenticationCallback.GetToken() in the AuthenticationParameters structure. + * @param authenticationCallback Callback to utilize for auth. + * @return the list of templates + */ + static std::vectorGetTemplateList( + std::string userId, + IAuthenticationCallback& authenticationCallback); + + + TemplateDescriptor(const std::string& id, + const std::string& name, + const std::string& description); + TemplateDescriptor(std::shared_ptrpolicy); + +private: + + std::string m_id; + std::string m_name; + std::string m_description; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_TEMPLATEDESCRIPTOR_H_ diff --git a/sdk/rms_sdk/ModernAPI/UserPolicy.cpp b/sdk/rms_sdk/ModernAPI/UserPolicy.cpp new file mode 100644 index 00000000..0dbb62b5 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/UserPolicy.cpp @@ -0,0 +1,362 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../Common/tools.h" +#include "../Core/ProtectionPolicy.h" +#include "../ModernAPI/RMSExceptions.h" + +#include "UserPolicy.h" +#include "TemplateDescriptor.h" +#include "PolicyDescriptor.h" +#include "AuthenticationCallbackImpl.h" +#include "rights.h" +#include "ConsentCallbackImpl.h" + +using namespace rmscore::core; +using namespace rmscrypto::api; +using namespace rmscore::modernapi; +using namespace std; + +namespace rmscore { +namespace modernapi { +GetUserPolicyResult::GetUserPolicyResult(GetUserPolicyResultStatus&& status, + std::shared_ptr referrer, + std::shared_ptr policy) : + Status(status), + Referrer(referrer), Policy(policy) {} + +UserPolicy::UserPolicy(shared_ptrpImpl) : m_pImpl(pImpl) { + if (pImpl->IsAdhoc()) m_policyDescriptor = + make_shared(pImpl); + else m_templateDescriptor = make_shared(pImpl); +} + +shared_ptrUserPolicy::Acquire( + std::vector& serializedPolicy, + const string & userId, + IAuthenticationCallback & authenticationCallback, + IConsentCallback & consentCallback, + PolicyAcquisitionOptions options, + ResponseCacheFlags cacheMask) +{ + qDebug() << "+UserPolicy::AcquireAsync"; + + AuthenticationCallbackImpl authenticationCallbackImpl(authenticationCallback, + userId); + ConsentCallbackImpl consentCallbackImpl(consentCallback, userId, false); + common::Event ev; + + shared_ptr pImpl = ProtectionPolicy::Acquire( + serializedPolicy.data(), + serializedPolicy.size(), + authenticationCallbackImpl, + consentCallbackImpl, + userId, + (PolicyAcquisitionOptions::POL_OfflineOnly == + (options & PolicyAcquisitionOptions::POL_OfflineOnly)), + ev, cacheMask); + + auto referrer = make_shared(pImpl->GetReferrer()); + + shared_ptr result; + + switch (pImpl->GetAccessStatus()) { + case AccessStatus::ACCESS_STATUS_ACCESS_GRANTED: + + result = make_shared(GetUserPolicyResultStatus::Success, + referrer, + make_shared(pImpl)); + break; + + case AccessStatus::ACCESS_STATUS_ACCESS_DENIED: + + result = make_shared(GetUserPolicyResultStatus::NoRights, + referrer, + nullptr); + break; + + case AccessStatus::ACCESS_STATUS_ACCESS_EXPIRED: + + result = make_shared(GetUserPolicyResultStatus::Expired, + referrer, + nullptr); + break; + + default: + throw exceptions::RMSInvalidArgumentException("Invalid Access Status"); + } // switch + + qDebug() << "-UserPolicy::AcquireAsync"; + return result; +} // UserPolicy::Acquire + +UserPolicy * UserPolicy::CreateFromTemplateDescriptor( + modernapi::TemplateDescriptor& templateDescriptor, + const string& userId, + IAuthenticationCallback& authenticationCallback, + UserPolicyCreationOptions options, + unordered_map& signedAppData) { + qDebug() << "+UserPolicy::CreateFromTemplateDescriptorAsync"; + + AuthenticationCallbackImpl authenticationCallbackImpl(authenticationCallback, + userId); + + platform::json::StringDictionary signedApplicationData; + + if (!signedAppData.empty()) { + for (auto& p : signedAppData) { + auto name = p.first; + auto value = p.second; + + signedApplicationData[name] = value; + } + } + auto templ = templateDescriptor.TemplateId(); + + auto pImpl = ProtectionPolicy::Create( + UserPolicyCreationOptions::USER_PreferDeprecatedAlgorithms == (options & + UserPolicyCreationOptions + :: + USER_PreferDeprecatedAlgorithms), + UserPolicyCreationOptions::USER_AllowAuditedExtraction == (options & + UserPolicyCreationOptions + :: + USER_AllowAuditedExtraction), + templ, + authenticationCallbackImpl, + userId, + signedApplicationData); + auto result = new UserPolicy(pImpl); + + qDebug() << "-UserPolicy::CreateFromTemplateDescriptorAsync"; + return result; +} // UserPolicy::CreateFromTemplateDescriptor + +UserPolicy * UserPolicy::Create(modernapi::PolicyDescriptor& policyDescriptor, + const string & userId, + IAuthenticationCallback & authenticationCallback, + UserPolicyCreationOptions options) { + qDebug() << "+UserPolicy::CreateAsync"; + + auto authenticationCallbackImpl = AuthenticationCallbackImpl { + authenticationCallback, userId + }; + PolicyDescriptorImpl policyDescriptorImpl; + + if (!policyDescriptor.Name().empty()) policyDescriptorImpl.name = + policyDescriptor.Name(); + + if (!policyDescriptor.Description().empty()) policyDescriptorImpl.description = + policyDescriptor.Description(); + policyDescriptorImpl.nIntervalTime = + policyDescriptor.OfflineCacheLifetimeInDays(); + policyDescriptorImpl.ftContentValidUntil = policyDescriptor.ContentValidUntil(); + + auto ref = policyDescriptor.Referrer(); + + if ((ref != nullptr) && + !ref->empty()) policyDescriptorImpl.referrer = *ref.get(); + + // Either rights list or roles list need to be not nullptr + + auto userRightsList = policyDescriptor.UserRightsList(); + + if (!userRightsList.empty()) { + for_each(begin(userRightsList), end(userRightsList), [&policyDescriptorImpl]( + UserRights& userRights) { + UserRightsImpl userRightsImpl; + auto users = userRights.Users(); + + transform(begin(users), end(users), back_inserter(userRightsImpl.users), + []( + string& user) { + return user; + }); + + auto rights = userRights.Rights(); + + transform(begin(rights), end(rights), + back_inserter(userRightsImpl.rights), []( + string& right) { + return right; + }); + + policyDescriptorImpl.userRightsList.emplace_back(move(userRightsImpl)); + }); + } else { // if (policyDescriptor.UserRolesList != nullptr) + auto roles = policyDescriptor.UserRolesList(); + + for_each(begin(roles), end(roles), + [&policyDescriptorImpl](UserRoles& userRoles) { + UserRolesImpl userRolesImpl; + auto users = userRoles.Users(); + + transform(begin(users), end(users), back_inserter(userRolesImpl.users), + []( + string& user) { + return user; + }); + + auto roles = userRoles.Roles(); + + transform(begin(roles), end(roles), back_inserter(userRolesImpl.roles), + []( + string& role) { + return role; + }); + + policyDescriptorImpl.userRolesList.emplace_back(move(userRolesImpl)); + }); + } + + if (!policyDescriptor.EncryptedAppData().empty()) { + auto encryptedAppData = policyDescriptor.EncryptedAppData(); + + for (auto& p : encryptedAppData) { + auto name = p.first; + auto value = p.second; + + policyDescriptorImpl.encryptedApplicationData[name] = value; + } + } + + if (!policyDescriptor.SignedAppData().empty()) { + auto signedAppData = policyDescriptor.SignedAppData(); + + for (auto& p : signedAppData) { + auto name = p.first; + auto value = p.second; + + policyDescriptorImpl.signedApplicationData[name] = value; + } + } + + auto pImpl = ProtectionPolicy::Create( + UserPolicyCreationOptions::USER_PreferDeprecatedAlgorithms == (options & + UserPolicyCreationOptions + :: + USER_PreferDeprecatedAlgorithms), + UserPolicyCreationOptions::USER_AllowAuditedExtraction == (options & + UserPolicyCreationOptions + :: + USER_AllowAuditedExtraction), + policyDescriptorImpl, + authenticationCallbackImpl, + userId); + auto result = new UserPolicy(pImpl); + + result->m_policyDescriptor->ContentValidUntil( + policyDescriptor.ContentValidUntil()); + + qDebug() << "-UserPolicy::CreateAsync"; + return result; +} // UserPolicy::Create + +bool UserPolicy::AccessCheck(string& right) { + return m_pImpl->AccessCheck(right); +} + +UserPolicyType UserPolicy::Type() { + if (m_pImpl->IsAdhoc()) return UserPolicyType::Custom; + else return UserPolicyType::TemplateBased; +} + +string UserPolicy::Name() { + return m_pImpl->GetName(); +} + +string UserPolicy::Description() { + return m_pImpl->GetDescription(); +} + +shared_ptrUserPolicy::TemplateDescriptor() { + return m_templateDescriptor; +} + +shared_ptrUserPolicy::PolicyDescriptor() { + return m_policyDescriptor; +} + +string UserPolicy::Owner() { + return m_pImpl->GetOwner(); +} + +string UserPolicy::IssuedTo() { + return m_pImpl->GetIssuedTo(); +} + +bool UserPolicy::IsIssuedToOwner() { + return m_pImpl->IsIssuedToOwner(); +} + +string UserPolicy::ContentId() { + return m_pImpl->GetContentId(); +} + +unordered_mapUserPolicy::EncryptedAppData() { + auto enctryptedAppDataImpl = m_pImpl->GetEncryptedApplicationData(); + + unordered_map encryptedAppData; + + for_each(begin(enctryptedAppDataImpl), end(enctryptedAppDataImpl), + [&](const pair + & appDataEntry) { + encryptedAppData[appDataEntry.first] = appDataEntry.second; + }); + + return encryptedAppData; +} + +unordered_mapUserPolicy::SignedAppData() { + auto signedAppDataImpl = m_pImpl->GetSignedApplicationData(); + + unordered_map signedAppData; + + for_each(begin(signedAppDataImpl), end(signedAppDataImpl), + [&](const pair + & appDataEntry) { + signedAppData[appDataEntry.first] = appDataEntry.second; + }); + + return signedAppData; +} + +std::chrono::time_pointUserPolicy::ContentValidUntil() +{ + std::chrono::time_point contentValidUntil; + + contentValidUntil = m_pImpl->GetValidityTimeFrom() + + (std::chrono::milliseconds)( + m_pImpl->GetValidityTimeDuration()); + return contentValidUntil; +} + +bool UserPolicy::DoesUseDeprecatedAlgorithms() { + return CipherMode::CIPHER_MODE_ECB == m_pImpl->GetCipherMode(); +} + +bool UserPolicy::IsAuditedExtractAllowed() { + auto ae = CommonRights::AuditedExtract(); + + return m_pImpl->AccessCheck(ae); +} + +std::vectorUserPolicy::SerializedPolicy() { + const auto& pl = m_pImpl->GetPublishLicense(); + + return pl; +} + +shared_ptrUserPolicy::GetImpl() { + return m_pImpl; +} +} // namespace modernapi +} // namespace rmscore diff --git a/sdk/rms_sdk/ModernAPI/UserPolicy.h b/sdk/rms_sdk/ModernAPI/UserPolicy.h new file mode 100644 index 00000000..d60146af --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/UserPolicy.h @@ -0,0 +1,116 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_USERPOLICY_H_ +#define _RMS_LIB_USERPOLICY_H_ + +#include +#include +#include + +#include "IAuthenticationCallback.h" +#include "IConsentCallback.h" +#include "ModernAPIExport.h" +#include "CacheControl.h" + +namespace rmscore { +namespace core { +class ProtectionPolicy; +} + +namespace modernapi { +class TemplateDescriptor; +class PolicyDescriptor; + +enum GetUserPolicyResultStatus { + Success = 0, NoRights = 1, Expired = 2 +}; + +class UserPolicy; + +struct DLL_PUBLIC_RMS GetUserPolicyResult { + GetUserPolicyResult(GetUserPolicyResultStatus&& status, + std::shared_ptrreferrer, + std::shared_ptr policy); + + GetUserPolicyResultStatus Status; + std::shared_ptrReferrer; + std::shared_ptr Policy; +}; +enum PolicyAcquisitionOptions { + POL_None = 0x0, POL_OfflineOnly = 0x1 +}; +enum UserPolicyCreationOptions { + USER_None = 0x0, + USER_AllowAuditedExtraction = 0x1, // specifies whether the + // content can be opened in a non-RMS aware app or not + USER_PreferDeprecatedAlgorithms = 0x2, // specifies whether the + // deprecated algorithms (ECB) is preferred or not +}; +enum UserPolicyType { + TemplateBased = 0, Custom = 1, +}; + +class DLL_PUBLIC_RMS UserPolicy { +public: + + static std::shared_ptr Acquire( + std::vector& serializedPolicy, + const std::string & userId, + IAuthenticationCallback & authenticationCallback, + IConsentCallback & consentCallback, + PolicyAcquisitionOptions options, + ResponseCacheFlags cacheMask); + + static UserPolicy* CreateFromTemplateDescriptor( + TemplateDescriptor & templateDescriptor, + const std::string & userId, + IAuthenticationCallback & authenticationCallback, + UserPolicyCreationOptions options, + std::unordered_map& signedAppData); + + static UserPolicy* Create(PolicyDescriptor & policyDescriptor, + const std::string & userId, + IAuthenticationCallback & authenticationCallback, + UserPolicyCreationOptions options); + + bool AccessCheck(std::string& right); + UserPolicyType Type(); + + std::string Name(); + std::string Description(); + std::shared_ptr TemplateDescriptor(); + std::shared_ptr PolicyDescriptor(); + std::string Owner(); + std::string IssuedTo(); + + bool IsIssuedToOwner(); + + std::string ContentId(); + std::unordered_map EncryptedAppData(); + std::unordered_map SignedAppData(); + std::chrono::time_pointContentValidUntil(); + + bool DoesUseDeprecatedAlgorithms(); + bool IsAuditedExtractAllowed(); + + std::vector SerializedPolicy(); + + UserPolicy(std::shared_ptrpImpl); + std::shared_ptr GetImpl(); + +private: + + std::shared_ptr m_pImpl; + std::shared_ptr m_templateDescriptor; + std::shared_ptr m_policyDescriptor; +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_USERPOLICY_H_ diff --git a/sdk/rms_sdk/ModernAPI/UserRights.h b/sdk/rms_sdk/ModernAPI/UserRights.h new file mode 100644 index 00000000..60afbfed --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/UserRights.h @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERRIGHTS +#define USERRIGHTS +#include +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +typedef std::vector UserList; +typedef std::vector RightList; + +/// +/// User rights +/// +class DLL_PUBLIC_RMS UserRights { +public: + + /// + /// .ctor + /// + UserRights(const UserList& users, const RightList& rights) : users(users), + rights(rights) {} + + /// + /// The users to whom the rights are granted + /// + const UserList& Users() const + { + return this->users; + } + + /// + /// The rights that are granted + /// + const RightList& Rights() const + { + return this->rights; + } + +private: + + UserList users; + RightList rights; + +private: + + void ValidateUsers(UserList& users); + void ValidateRights(RightList& rights); +}; +} // namespace modernapi +} // namespace rmscore + + +#endif // USERRIGHTS diff --git a/sdk/rms_sdk/ModernAPI/UserRoles.h b/sdk/rms_sdk/ModernAPI/UserRoles.h new file mode 100644 index 00000000..48a4d345 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/UserRoles.h @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERROLES +#define USERROLES +#include +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +typedef std::vector UserList; +typedef std::vector RoleList; + +/// +/// User rights +/// +class DLL_PUBLIC_RMS UserRoles { +public: + + /// + /// .ctor + /// + UserRoles(UserList& users, + RoleList& roles); + + /// + /// The users to whom the rights are granted + /// + const UserList& Users() const + { + return this->users; + } + + /// + /// The roles of the users + /// + const RoleList& Roles() const + { + return this->roles; + } + +private: + + UserList users; + RoleList roles; + +private: + + void ValidateUsers(UserList& users); + void ValidateRoles(RoleList& roles); +}; +} // namespace modernapi +} // namespace rmscore + + +#endif // USERROLES diff --git a/sdk/rms_sdk/ModernAPI/consent.h b/sdk/rms_sdk/ModernAPI/consent.h new file mode 100644 index 00000000..e3495244 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/consent.h @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_CONSENT_H_ +#define _RMS_LIB_CONSENT_H_ + +#include +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +enum ConsentType { + DocumentTrackingConsent = 0, ServiceUrlConsent = 1 +}; + +class DLL_PUBLIC_RMS ConsentResult { +public: + + ConsentResult(bool accepted, + bool showAgain, + const std::string& userId); + + bool Accepted() const { + return this->accepted; + } + + bool ShowAgain() const { + return this->showAgain; + } + + const std::string& UserId() const { + return this->userId; + } + +private: + + bool accepted; + bool showAgain; + const std::string userId; +}; + +// TODO: figure out why it's an interface +class DLL_PUBLIC_RMS IConsent { +public: + + ConsentResult *Result; + ConsentType Type; + common::UrlArray Urls; + std::string User; + std::string Domain; + + IConsent() : Result(nullptr) {} +}; +} // namespace modernapi +} // namespace rmscore +#endif // _RMS_LIB_CONSENT_H_ diff --git a/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.cpp b/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.cpp new file mode 100644 index 00000000..1b60e818 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.cpp @@ -0,0 +1,137 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "QTStreamImpl.h" +using namespace rmscrypto::api; +using namespace std; + + +SharedStream QTStreamImpl::Create(QSharedPointerstream) { + auto self = new QTStreamImpl(stream); + + return static_pointer_cast(shared_ptr(self)); +} + +QTStreamImpl::QTStreamImpl(QSharedPointerstream) + : stream_(stream) {} + +shared_futureQTStreamImpl::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + auto selfPtr = shared_from_this(); + + return std::async(fCreateBackingThread ? launch::async : launch::deferred, []( + std::shared_ptrself, + uint8_t *buffer, + const int64_t size, + int64_t offset) -> int64_t { + // first lock object + unique_locklock(self->locker_); + + // seek to position and read + self->stream_->device()->seek(offset); + auto ret = static_cast(self->stream_->readRawData( + reinterpret_cast(buffer), + static_cast(size))); + return ret; + }, selfPtr, pbBuffer, cbBuffer, cbOffset); +} + +shared_futureQTStreamImpl::WriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + auto selfPtr = shared_from_this(); + + return std::async(fCreateBackingThread ? launch::async : launch::deferred, []( + std::shared_ptrself, + const uint8_t *buffer, + const int64_t size, + int64_t offset) -> int64_t { + // first lock object + unique_locklock(self->locker_); + + qDebug() << "Write " << size << " bytes at offset = " << offset << " from buffer = " << buffer; + // seek to position and write + self->stream_->device()->seek(offset); + auto ret = static_cast(self->stream_->writeRawData( + reinterpret_cast(buffer), + static_cast(size))); + return ret; + }, selfPtr, cpbBuffer, cbBuffer, cbOffset); +} + +std::futureQTStreamImpl::FlushAsync(bool /*fCreateBackingThread*/) { + // it's not used in QDataStream + std::promise val; + std::future res = val.get_future(); + + val.set_value(true); + return res; +} + +void QTStreamImpl::Seek(uint64_t u64Position) { + // first lock object + unique_lock lock(locker_); + stream_->device()->seek(u64Position); +} + +int64_t QTStreamImpl::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) { + return ReadAsync(pbBuffer, cbBuffer, Position(), false).get(); +} + +int64_t QTStreamImpl::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) { + return WriteAsync(cpbBuffer, cbBuffer, Position(), false).get(); +} + +bool QTStreamImpl::Flush() { + return FlushAsync(false).get(); +} + +SharedStream QTStreamImpl::Clone() { + // first lock object + unique_lock lock(locker_); + auto self = + new QTStreamImpl(QSharedPointer::create(stream_->device())); + + return static_pointer_cast(shared_ptr(self)); +} + +bool QTStreamImpl::CanRead() { + // first lock object + unique_lock lock(locker_); + return (stream_->device()->openMode() & QIODevice::ReadOnly) == + QIODevice::ReadOnly; +} + +bool QTStreamImpl::CanWrite() { + // first lock object + unique_lock lock(locker_); + return (stream_->device()->openMode() & QIODevice::WriteOnly) == + QIODevice::WriteOnly; +} + +uint64_t QTStreamImpl::Position() { + // first lock object + unique_lock lock(locker_); + return stream_->device()->pos(); +} + +uint64_t QTStreamImpl::Size() { + // first lock object + unique_lock lock(locker_); + return stream_->device()->size(); +} + +void QTStreamImpl::Size(uint64_t /*u64Value*/) {} diff --git a/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.h b/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.h new file mode 100644 index 00000000..ff23b08f --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/ext/QTStreamImpl.h @@ -0,0 +1,63 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_QDATASTREAM_H_ +#define _RMS_LIB_QDATASTREAM_H_ + +#include +#include "../ModernAPIExport.h" +#include +#include +#include + +class DLL_PUBLIC_RMS QTStreamImpl : public rmscrypto::api::IStream, + public std::enable_shared_from_this +{ +public: + + static rmscrypto::api::SharedStream Create(QSharedPointerstream); + virtual ~QTStreamImpl() {} + + + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::future FlushAsync(bool fCreateBackingThread) + override; + + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual rmscrypto::api::SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + +private: + + QTStreamImpl(QSharedPointerstream); + QTStreamImpl() = delete; + + QSharedPointer stream_; + std::mutex locker_; // QDataStream is not thread safe!!! +}; +#endif // ifndef _RMS_LIB_QDATASTREAM_H_ diff --git a/sdk/rms_sdk/ModernAPI/rights.h b/sdk/rms_sdk/ModernAPI/rights.h new file mode 100644 index 00000000..752b32a9 --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/rights.h @@ -0,0 +1,152 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_RIGHTS_H_ +#define _RMS_LIB_RIGHTS_H_ + +#include +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { + +/** + * @brief Rights supported universally + */ +class DLL_PUBLIC_RMS CommonRights { +public: + +public: + + static const std::string Owner() + { + return "OWNER"; + } + + static const std::string View() + { + return "VIEW"; + } + + static const std::vector All() + { + return std::vector{ CommonRights::View(), CommonRights::Owner() }; + } + + static std::string AuditedExtract() + { + return "AUDITEDEXTRACT"; + } + +private: + + CommonRights() = delete; + friend class Rights; +}; + +/** + * @brief Rights that apply to editable documents. + */ +class DLL_PUBLIC_RMS EditableDocumentRights { +public: + + static const std::string Edit() + { + return "EDIT"; + } + + static const std::string Export() + { + return "EXPORT"; + } + + static const std::string Extract() + { + return "EXTRACT"; + } + + static const std::string Print() + { + return "PRINT"; + } + + static const std::string Comment() + { + return "COMMENT"; + } + + static const std::vector All() + { + return std::vector{ + CommonRights::View(), + EditableDocumentRights::Edit(), + EditableDocumentRights::Extract(), + EditableDocumentRights::Print(), + EditableDocumentRights::Comment(), + CommonRights::Owner() + }; + } + +private: + + EditableDocumentRights() = delete; +}; + +/** + * @brief Rights that apply to email. + */ +class DLL_PUBLIC_RMS EmailRights { +public: + + static const std::string Reply() + { + return "REPLY"; + } + + static const std::string ReplyAll() + { + return "REPLYALL"; + } + + static const std::string Forward() + { + return "FORWARD"; + } + + static const std::string Extract() + { + return EditableDocumentRights::Extract(); + } + + static const std::string Print() + { + return EditableDocumentRights::Print(); + } + + static const std::vector All() + { + return std::vector{ + CommonRights::View(), + EmailRights::Reply(), + EmailRights::ReplyAll(), + EmailRights::Forward(), + EditableDocumentRights::Extract(), + EditableDocumentRights::Print(), + CommonRights::Owner() + }; + } + +private: + + EmailRights() = delete; +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_RIGHTS_H_ diff --git a/sdk/rms_sdk/ModernAPI/roles.h b/sdk/rms_sdk/ModernAPI/roles.h new file mode 100644 index 00000000..f42351db --- /dev/null +++ b/sdk/rms_sdk/ModernAPI/roles.h @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_ROLES_H_ +#define _RMS_LIB_ROLES_H_ + +#include +#include "ModernAPIExport.h" + +namespace rmscore { +namespace modernapi { +/// +/// This class provides implementation for obtaining roles for protecting documents +/// +class DLL_PUBLIC_RMS Roles { +public: + + /// + /// User will only be able to view the document. They cannot edit, copy, or print it. + /// + static const std::string Viewer() + { + return "VIEWER"; + } + + /// + /// User will be able to view and edit the document. They cannot copy or print it. + /// + static const std::string Reviewer() + { + return "REVIEWER"; + } + + /// + /// User will be able to view, edit, copy, and print the document. + /// + static const std::string Author() + { + return "AUTHOR"; + } + + /// + /// User will have all permissions. + /// + static const std::string CoOwner() + { + return "COOWNER"; + } +}; +} // namespace modernapi +} // namespace rmscore + +#endif // _RMS_LIB_ROLES_H_ diff --git a/sdk/rms_sdk/PFile/IPfileHeaderReader.h b/sdk/rms_sdk/PFile/IPfileHeaderReader.h new file mode 100644 index 00000000..a4cc8641 --- /dev/null +++ b/sdk/rms_sdk/PFile/IPfileHeaderReader.h @@ -0,0 +1,33 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_IPFILEHEADERREADER_H_ +#define _RMS_LIB_IPFILEHEADERREADER_H_ + +#include +#include +#include "../Common/FrameworkSpecificTypes.h" + +namespace rmscore { +namespace pfile { +class PfileHeader; + +class IPfileHeaderReader { +public: + + virtual ~IPfileHeaderReader() {} + + virtual std::shared_ptrRead(rmscrypto::api::SharedStream stream) = 0; + +public: + + static std::shared_ptrCreate(); +}; +} // namespace pfile +} // namespace rmscore +#endif // _RMS_LIB_IPFILEHEADERREADER_H_ diff --git a/sdk/rms_sdk/PFile/IPfileHeaderWriter.h b/sdk/rms_sdk/PFile/IPfileHeaderWriter.h new file mode 100644 index 00000000..662f8ae6 --- /dev/null +++ b/sdk/rms_sdk/PFile/IPfileHeaderWriter.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_IPFILEHEADERWRITER_H_ +#define _RMS_LIB_IPFILEHEADERWRITER_H_ + +#include +#include +#include "../Common/FrameworkSpecificTypes.h" +namespace rmscore { +namespace pfile { +class PfileHeader; + +class IPfileHeaderWriter { +public: + + virtual ~IPfileHeaderWriter() {} + + virtual size_t Write(rmscrypto::api::SharedStream stream, + const std::shared_ptr header) = 0; + +public: + + static std::shared_ptrCreate(); +}; +} // namespace pfile +} // namespace rmscore + +#endif // _RMS_LIB_IPFILEHEADERWRITER_H_ diff --git a/sdk/rms_sdk/PFile/PFile.pro b/sdk/rms_sdk/PFile/PFile.pro new file mode 100644 index 00000000..86b4a82a --- /dev/null +++ b/sdk/rms_sdk/PFile/PFile.pro @@ -0,0 +1,28 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/rms +TARGET = modprotectedfile + +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release + + +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI +QT += core +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += PfileHeader.cpp \ + PfileHeaderReader.cpp \ + PfileHeaderWriter.cpp + +HEADERS += IPfileHeaderReader.h \ + IPfileHeaderWriter.h \ + PfileHeader.h \ + PfileHeaderReader.h \ + PfileHeaderWriter.h + +QMAKE_CFLAGS_WARN_ON -= -W3 +QMAKE_CFLAGS_WARN_ON += -W4 diff --git a/sdk/rms_sdk/PFile/PfileHeader.cpp b/sdk/rms_sdk/PFile/PfileHeader.cpp new file mode 100644 index 00000000..857143b7 --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeader.cpp @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "PfileHeader.h" + +using namespace std; +using namespace rmscore::common; + +namespace rmscore { +namespace pfile { +PfileHeader::PfileHeader(ByteArray && publishingLicense, + const string & fileExtension, + const uint32_t contentStartPosition, + const uint64_t originalFileSize, + ByteArray && metadata, + const uint32_t majorVersion, + const uint32_t minorVersion, + const string & cleartextRedirectionHeader) : + m_PublishingLicense(publishingLicense), + m_FileExtension(fileExtension), m_ContentStartPosition(contentStartPosition), + m_OriginalFileSize(originalFileSize), m_Metadata(metadata), m_MajorVersion( + majorVersion), m_MinorVersion(minorVersion), m_CleartextRedirectionHeader( + cleartextRedirectionHeader) {} + +const ByteArray& PfileHeader::GetPublishingLicense() const { + return m_PublishingLicense; +} + +const ByteArray& PfileHeader::GetMetadata() const { + return m_Metadata; +} + +const string& PfileHeader::GetFileExtension() const { + return m_FileExtension; +} + +uint32_t PfileHeader::GetContentStartPosition() const { + return m_ContentStartPosition; +} + +uint64_t PfileHeader::GetOriginalFileSize() const { + return m_OriginalFileSize; +} + +uint32_t PfileHeader::GetMajorVersion() const { + return m_MajorVersion; +} + +uint32_t PfileHeader::GetMinorVersion() const { + return m_MinorVersion; +} + +const string& PfileHeader::GetCleartextRedirectionHeader() const { + return m_CleartextRedirectionHeader; +} +} // namespace pfile +} // namespace rmscore diff --git a/sdk/rms_sdk/PFile/PfileHeader.h b/sdk/rms_sdk/PFile/PfileHeader.h new file mode 100644 index 00000000..b0811c63 --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeader.h @@ -0,0 +1,52 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PFILEHEADER_H_ +#define _RMS_LIB_PFILEHEADER_H_ + +#include +#include +#include "../Common/CommonTypes.h" + +namespace rmscore { +namespace pfile { +class PfileHeader { +public: + + PfileHeader(common::ByteArray&& publishingLicense, + const std::string & fileExtension, + const uint32_t contentStartPosition, + const uint64_t originalFileSize, + common::ByteArray&& metadata, + const uint32_t majorVersion, + const uint32_t minorVersion, + const std::string & cleartextRedirectionHeader); + + const common::ByteArray& GetPublishingLicense() const; + const common::ByteArray& GetMetadata() const; + const std::string & GetFileExtension() const; + uint32_t GetContentStartPosition() const; + uint64_t GetOriginalFileSize() const; + uint32_t GetMajorVersion() const; + uint32_t GetMinorVersion() const; + const std::string & GetCleartextRedirectionHeader() const; + +private: + + common::ByteArray m_PublishingLicense; + std::string m_FileExtension; + const uint32_t m_ContentStartPosition; + const uint64_t m_OriginalFileSize; + common::ByteArray m_Metadata; + const uint32_t m_MajorVersion; + const uint32_t m_MinorVersion; + std::string m_CleartextRedirectionHeader; +}; +} // namespace pfile +} // namespace rmscore +#endif // _RMS_LIB_PFILEHEADER_H_ diff --git a/sdk/rms_sdk/PFile/PfileHeaderReader.cpp b/sdk/rms_sdk/PFile/PfileHeaderReader.cpp new file mode 100644 index 00000000..3a384352 --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeaderReader.cpp @@ -0,0 +1,228 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../ModernAPI/RMSExceptions.h" +#include "PfileHeaderReader.h" +#include + +using namespace std; +using namespace rmscore::common; + +namespace rmscore { +namespace pfile { +const ByteArray ExpectedPreamble = { 0x2E, 0x70, 0x66, 0x69, 0x6C, 0x65 }; // byte + // representation + // of + // ".pfile" + +PfileHeaderReader::~PfileHeaderReader() +{} + +shared_ptrPfileHeaderReader::Read(rmscrypto::api::SharedStream stream) +{ + qDebug() << "PfileHeaderReader: Reading pfile header."; + + CheckPreamble(stream); + auto version = ReadVersionNumber(stream); + auto cleartextRedirectionHeader = ReadCleartextRedirectionHeader(stream); + + return ReadHeader(stream, std::get<0>(version), std::get<1>( + version), cleartextRedirectionHeader); +} + +void PfileHeaderReader::CheckPreamble(rmscrypto::api::SharedStream stream) +{ + ByteArray pr; + + qDebug() << L"PfileHeaderReader: Checking preamble"; + + auto expectedLength = static_cast(ExpectedPreamble.size()); + ReadBytes(pr, stream, expectedLength); + + if (pr.size() != expectedLength) + { + throw exceptions::RMSPFileException("Invalid pfile preambule", + exceptions::RMSPFileException::NotPFile); + } + + for (uint32_t i = 0; i < pr.size(); ++i) + { + if (pr[i] != ExpectedPreamble[i]) { + throw exceptions::RMSPFileException("Invalid pfile preambule", + exceptions::RMSPFileException::NotPFile); + } + } +} + +tuplePfileHeaderReader::ReadVersionNumber( + rmscrypto::api::SharedStream stream) +{ + const uint32_t MaxValidVersionNumber = 256; + uint32_t majorVersion, minorVersion; + + stream->Read(reinterpret_cast(&majorVersion), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&minorVersion), sizeof(uint32_t)); + + qDebug() << "PfileHeaderReader: Major version:" << majorVersion << + ", Minor version: " << minorVersion; + + if ((majorVersion >= MaxValidVersionNumber) || + (minorVersion >= MaxValidVersionNumber)) { + throw exceptions::RMSPFileException("Invalid pfile version", + exceptions::RMSPFileException::NotPFile); + } + + if (majorVersion != 2) { + throw exceptions::RMSPFileException("This version is not supported", + exceptions::RMSPFileException::NotSupportedVersion); + } + + return make_tuple(majorVersion, minorVersion); +} + +string PfileHeaderReader::ReadCleartextRedirectionHeader( + rmscrypto::api::SharedStream stream) +{ + ByteArray redirectHeader; + uint32_t redirectHeaderLength; + + stream->Read(reinterpret_cast(&redirectHeaderLength), + sizeof(uint32_t)); + ReadBytes(redirectHeader, stream, redirectHeaderLength); + + if (redirectHeader.size() != redirectHeaderLength) { + throw exceptions::RMSPFileException("Bad redirect header", + exceptions::RMSPFileException::BadArguments); + } + + string redirectHeaderStr(redirectHeader.begin(), redirectHeader.end()); + qDebug() << "PfileHeaderReader: Cleartext redirect header: " << + redirectHeaderStr.c_str(); + + return redirectHeaderStr; +} + +string PfileHeaderReader::ReadExtension(rmscrypto::api::SharedStream stream, + uint32_t offset, + uint32_t length) +{ + ByteArray ext; + + if (offset >= stream->Size()) { + throw exceptions::RMSPFileException("Bad extension", + exceptions::RMSPFileException::BadArguments); + } + + ReadAtOffset(ext, stream, offset, length); + string extStr(ext.begin(), ext.end()); + + qDebug() << "PfileHeaderReader: Extension: " << extStr.c_str(); + + return extStr; +} + +shared_ptrPfileHeaderReader::ReadHeader( + rmscrypto::api::SharedStream stream, + uint32_t majorVersion, + uint32_t minorVersion, + string cleartextRedirectionHeader) +{ + uint32_t headerSize; + uint32_t extensionOffset = 0; + uint32_t extensionLength = 0; + uint32_t plOffset = 0; + uint32_t plLength = 0; + uint32_t contentOffset = 0; + + stream->Read(reinterpret_cast(&headerSize), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&extensionOffset), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&extensionLength), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&plOffset), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&plLength), sizeof(uint32_t)); + stream->Read(reinterpret_cast(&contentOffset), sizeof(uint32_t)); + + uint32_t endOfHeader = plOffset + plLength; + uint64_t originalFileSize = 0; + uint32_t metadataOffset = 0; + uint32_t metadataLength = 0; + + ByteArray metadata; + ByteArray publishingLicense; + + if ((majorVersion >= 2) && (minorVersion >= 1)) + { + stream->Read(reinterpret_cast(&originalFileSize), + sizeof(uint64_t)); + stream->Read(reinterpret_cast(&metadataOffset), + sizeof(uint32_t)); + stream->Read(reinterpret_cast(&metadataLength), + sizeof(uint32_t)); + endOfHeader = metadataOffset + metadataLength; + } + + if (contentOffset < endOfHeader) { + throw exceptions::RMSPFileException("Bad content offset", + exceptions::RMSPFileException::BadArguments); + } + + string extension = ReadExtension(stream, extensionOffset, extensionLength); + + ReadAtOffset(publishingLicense, stream, plOffset, plLength); + + // remove UTF-8 BOM + if ((publishingLicense.size() > 3) && + (memcmp(publishingLicense.data(), "\xEF\xBB\xBF", 3) == 0)) { + publishingLicense.erase(publishingLicense.begin(), + publishingLicense.begin() + 3); + } + + if ((majorVersion == 2) && (minorVersion == 1)) + { + ReadAtOffset(metadata, stream, metadataOffset, metadataLength); + } + return make_shared(move(publishingLicense), extension, + contentOffset, originalFileSize, + move(metadata), majorVersion, minorVersion, + cleartextRedirectionHeader); +} + +void PfileHeaderReader::ReadAtOffset(ByteArray & dst, + rmscrypto::api::SharedStream stream, + const uint32_t offset, + const uint32_t length) +{ + stream->Seek(offset); + ReadBytes(dst, stream, length); +} + +void PfileHeaderReader::ReadBytes(ByteArray & dst, + rmscrypto::api::SharedStream stream, + const uint32_t length) +{ + // check for size + if (length == 0) return; + + if (length > stream->Size()) { + throw exceptions::RMSPFileException("Bad block length", + exceptions::RMSPFileException::BadArguments); + } + + auto pos = dst.size(); + dst.resize(pos + length); + + stream->Read((uint8_t *)&dst[pos], length); +} + +shared_ptrIPfileHeaderReader::Create() +{ + return std::dynamic_pointer_cast( + std::make_shared()); +} +} // namespace pfile +} // namespace rmscore diff --git a/sdk/rms_sdk/PFile/PfileHeaderReader.h b/sdk/rms_sdk/PFile/PfileHeaderReader.h new file mode 100644 index 00000000..c74b981f --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeaderReader.h @@ -0,0 +1,60 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PFILEHEADERREADER_H_ +#define _RMS_LIB_PFILEHEADERREADER_H_ + +#include "IPfileHeaderReader.h" +#include "PfileHeader.h" +#include "../Common/FrameworkSpecificTypes.h" + +#include + +namespace rmscore { +namespace pfile { +class PfileHeaderReader : public IPfileHeaderReader { +public: + + PfileHeaderReader() {} + + virtual ~PfileHeaderReader() override; + + virtual std::shared_ptrRead(rmscrypto::api::SharedStream stream) + override; + const static int NOT_PFILE = 0x800401ffL; + const static int NOT_SUPPORTED = 0x80070032L; + const static int BAD_ARGUMENTS = 0x000000a0L; + +private: + + std::shared_ptrReadHeader(rmscrypto::api::SharedStream stream, + uint32_t majorVersion, + uint32_t minorVersion, + std::string cleartextRedirectionHeader); + + void ReadAtOffset(common::ByteArray & dst, + rmscrypto::api::SharedStream stream, + const uint32_t offset, + const uint32_t length); + + void ReadBytes(common::ByteArray & dst, + rmscrypto::api::SharedStream stream, + const uint32_t length); + + void CheckPreamble(rmscrypto::api::SharedStream stream); + + std::tupleReadVersionNumber(rmscrypto::api::SharedStream stream); + std::string ReadCleartextRedirectionHeader( + rmscrypto::api::SharedStream stream); + std::string ReadExtension(rmscrypto::api::SharedStream stream, + uint32_t offset, + uint32_t length); +}; +} // namespace pfile +} // namespace rmscore +#endif // _RMS_LIB_PFILEHEADERREADER_H_ diff --git a/sdk/rms_sdk/PFile/PfileHeaderWriter.cpp b/sdk/rms_sdk/PFile/PfileHeaderWriter.cpp new file mode 100644 index 00000000..eeedc748 --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeaderWriter.cpp @@ -0,0 +1,164 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "PfileHeaderWriter.h" +#include "PfileHeader.h" +#include + +using namespace std; +using namespace rmscore::common; + +namespace rmscore { +namespace pfile { +PfileHeaderWriter::~PfileHeaderWriter() +{} + +size_t PfileHeaderWriter::Write(rmscrypto::api::SharedStream stream, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::Write"; + + auto fe = header->GetFileExtension(); + qDebug() << "Writing pfile header. " + << "Major version: " << header->GetMajorVersion() + << ", minor version: " << header->GetMinorVersion() + << ", file extension: " << fe.c_str() + << ", content start position: " << header->GetContentStartPosition() + << ", original file size: " << header->GetOriginalFileSize(); + + auto extension = header->GetFileExtension(); + + if (extension.empty()) { + extension = ".pfile"; + } + + uint32_t position = WritePreamble(stream); + + position += WriteVersionNumber(stream, header); + position += WriteCleartextRedirection(stream, header); + + WriteHeader(stream, header, position); + WriteExtension(stream, header); + WritePublishingLicense(stream, header); + WriteMetadata(stream, header); + + return stream->Size(); +} + +uint32_t PfileHeaderWriter::WritePreamble(rmscrypto::api::SharedStream writer) +{ + qDebug() << "PfileHeaderWriter::WritePreamble"; + common::ByteArray preamble = { 0x2E, 0x70, 0x66, 0x69, 0x6C, 0x65 }; // byte + // representation + // of + // ".pfile" + writer->Write(reinterpret_cast(preamble.data()), + static_cast(preamble.size())); + + return static_cast(preamble.size()); +} + +uint32_t PfileHeaderWriter::WriteVersionNumber( + rmscrypto::api::SharedStream writer, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::WriteVersionNumber"; + uint32_t mjv = header->GetMajorVersion(); + uint32_t mnv = header->GetMinorVersion(); + writer->Write(reinterpret_cast(&mjv), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&mnv), sizeof(uint32_t)); + + return 2 * sizeof(uint32_t); +} + +uint32_t PfileHeaderWriter::WriteCleartextRedirection( + rmscrypto::api::SharedStream writer, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::WriteCleartextRedirection"; + auto cleartextRedirectionHeader = header->GetCleartextRedirectionHeader(); + uint32_t cts = + static_cast(cleartextRedirectionHeader.size()); + writer->Write(reinterpret_cast(&cts), sizeof(uint32_t)); + writer->Write(reinterpret_cast(cleartextRedirectionHeader. + data()), + static_cast(cleartextRedirectionHeader.size())); + + return static_cast(cleartextRedirectionHeader.size()) + + sizeof(uint32_t); +} + +void PfileHeaderWriter::WriteHeader(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader, + size_t headerOffset) +{ + qDebug() << "PfileHeaderWriter::WriteHeader"; + uint32_t headerSize = 8 * sizeof(uint32_t) + sizeof(uint64_t); + uint32_t extensionOffset = static_cast(headerOffset) + + headerSize; + uint32_t extensionLength = + static_cast(header->GetFileExtension().size()); + uint32_t plOffset = extensionOffset + extensionLength; + uint32_t plLength = + static_cast(header->GetPublishingLicense().size()); + uint64_t originalFileSize = header->GetOriginalFileSize(); + uint32_t metadataOffset = plOffset + plLength; + uint32_t metadataLength = static_cast(header->GetMetadata().size()); + uint32_t contentOffset = metadataOffset + metadataLength; + + writer->Write(reinterpret_cast(&headerSize), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&extensionOffset), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&extensionLength), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&plOffset), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&plLength), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&contentOffset), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&originalFileSize), sizeof(uint64_t)); + writer->Write(reinterpret_cast(&metadataOffset), sizeof(uint32_t)); + writer->Write(reinterpret_cast(&metadataLength), sizeof(uint32_t)); +} + +void PfileHeaderWriter::WriteExtension(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::WriteExtension"; + auto extension = header->GetFileExtension(); + + if (extension.empty()) { + extension = ".pfile"; + } + writer->Write(reinterpret_cast(extension.data()), + static_cast(extension.length())); +} + +void PfileHeaderWriter::WritePublishingLicense( + rmscrypto::api::SharedStream writer, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::WritePublishingLicense"; + auto publishingLicense = header->GetPublishingLicense(); + writer->Write(reinterpret_cast(publishingLicense.data()), + static_cast(publishingLicense.size())); +} + +void PfileHeaderWriter::WriteMetadata(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader) +{ + qDebug() << "PfileHeaderWriter::WriteMetadata"; + auto metadata = header->GetMetadata(); + writer->Write(reinterpret_cast(metadata.data()), + static_cast(metadata.size())); +} + +shared_ptrIPfileHeaderWriter::Create() +{ + qDebug() << "PfileHeaderWriter::Create"; + return make_shared(); +} +} // namespace pfile +} // namespace rmscore diff --git a/sdk/rms_sdk/PFile/PfileHeaderWriter.h b/sdk/rms_sdk/PFile/PfileHeaderWriter.h new file mode 100644 index 00000000..58c192d6 --- /dev/null +++ b/sdk/rms_sdk/PFile/PfileHeaderWriter.h @@ -0,0 +1,51 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _MICROSOFT_PROTECTION_PFILEHEADERWRITER_H_ +#define _MICROSOFT_PROTECTION_PFILEHEADERWRITER_H_ + +#include "IPfileHeaderWriter.h" +#include "../Common/CommonTypes.h" +#include "../Common/FrameworkSpecificTypes.h" +#include + +namespace rmscore { +namespace pfile { +const std::string CleartextRedirectHeader( + "\r\n\r\n\r\nThis file uses Microsoft Information Protection solutions.\r\nOpen it using an application that supports protected files.\r\n\r\nYou can download Microsoft's protected file viewer from: http://go.microsoft.com/fwlink/?LinkId=280381 \r\nLearn more about Information Protection solutions at http://www.microsoft.com/rms \r\n\r\nDo not change this file in any way -- doing so will result in data loss.\r\n\r\n"); + +class PfileHeader; +class PfileHeaderWriter : public IPfileHeaderWriter { +public: + + virtual ~PfileHeaderWriter(); + + virtual size_t Write(rmscrypto::api::SharedStream stream, + const std::shared_ptrheader) override; + +private: + + uint32_t WritePreamble(rmscrypto::api::SharedStream writer); + uint32_t WriteVersionNumber(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader); + uint32_t WriteCleartextRedirection(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader); + void WriteHeader(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader, + size_t headerOffset); + void WriteExtension(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader); + void WritePublishingLicense(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader); + void WriteMetadata(rmscrypto::api::SharedStream writer, + const std::shared_ptrheader); +}; +} // namespace pfile +} // namespace rmscore + +#endif // _MICROSOFT_PROTECTION_PFILEHEADERWRITER_H_ diff --git a/sdk/rms_sdk/PFile/basetypes.h b/sdk/rms_sdk/PFile/basetypes.h new file mode 100644 index 00000000..6d6a6002 --- /dev/null +++ b/sdk/rms_sdk/PFile/basetypes.h @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef BASETYPES_H +#define BASETYPES_H + +typedef char BYTE; +typedef char BYTE; + + + +#endif // BASETYPES_H + + + diff --git a/sdk/rms_sdk/Platform/Common/Common.pro b/sdk/rms_sdk/Platform/Common/Common.pro new file mode 100644 index 00000000..96710850 --- /dev/null +++ b/sdk/rms_sdk/Platform/Common/Common.pro @@ -0,0 +1 @@ +TEMPLATE = subdirs diff --git a/sdk/rms_sdk/Platform/Filesystem/FileQt.cpp b/sdk/rms_sdk/Platform/Filesystem/FileQt.cpp new file mode 100644 index 00000000..11bc7596 --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/FileQt.cpp @@ -0,0 +1,116 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include +#include +#include +#include "FileQt.h" +#include "../Logger/Logger.h" +using namespace std; + +namespace rmscore { +namespace platform { +namespace filesystem { +shared_ptrIFile::Create(const string& path, FileOpenModes mode) +{ + // first check if directory exists + QString directory = QString::fromStdString(path); + auto idx = directory.lastIndexOf(QChar('/')); + + if ((idx > 0) && (idx < directory.size())) { + directory.resize(idx + 1); + + if (!QFile::exists(directory)) { + QDir dir; + dir.mkpath(directory); + } + } + + auto p_file = make_shared(path); + + if (!p_file->open(mode)) + { + return nullptr; + } + + return p_file; +} + +FileQt::FileQt(const string& path) + : + impl_(path.c_str()) +{} + +bool FileQt::open(FileOpenModes mode) +{ + // FIXME.shch: added QIODevice::Text + bool ok = this->impl_.open(FileQt::toQtMode(mode) | QIODevice::Text); + + if (!ok) + { + Logger::Error("Cant't open file '%s'", + this->impl_.fileName().toStdString().data()); + } + return ok; +} + +size_t FileQt::Read(common::CharArray& data, size_t len) +{ + data.resize(len); + QDataStream out(&this->impl_); + auto readBytes = (size_t)out.readRawData(&data[0], (int)len); + + if (readBytes < len) data.resize(readBytes); + return readBytes; +} + +size_t FileQt::Write(const char *data, size_t len) +{ + QDataStream out(&this->impl_); + + return (size_t)out.writeRawData(data, (int)len); +} + +void FileQt::Clear() +{ + auto openmode = this->impl_.openMode(); + + this->impl_.close(); + this->impl_.open(openmode | QIODevice::Truncate); +} + +void FileQt::Close() +{ + this->impl_.close(); +} + +string FileQt::ReadAllAsText() +{ + auto data = this->impl_.readAll(); + + return string(data); +} + +void FileQt::AppendText(const common::ByteArray& text) +{ + QTextStream out(&this->impl_); + + out << QByteArray(reinterpret_cast(text.data()), + static_cast(text.size())); +} + +size_t FileQt::GetSize() +{ + return (size_t) this->impl_.size(); +} + +} +} +} // namespace rmscore { namespace platform { namespace filesystem { +#endif // ifdef QTFRAMEWORK diff --git a/sdk/rms_sdk/Platform/Filesystem/FileQt.h b/sdk/rms_sdk/Platform/Filesystem/FileQt.h new file mode 100644 index 00000000..66b26896 --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/FileQt.h @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef FILEQT +#define FILEQT +#include "IFile.h" +#include +#include "../../ModernAPI/RMSExceptions.h" + +namespace rmscore { +namespace platform { +namespace filesystem { +class FileQt : public IFile { +public: + + virtual size_t Read(common::CharArray& data, + size_t len) override; + virtual size_t Write(const char *data, + size_t len) override; + + virtual void Clear() override; + virtual void Close() override; + virtual std::string ReadAllAsText() override; + virtual void AppendText(const common::ByteArray& text) override; + + virtual size_t GetSize() override; + +private: + + QFile impl_; + + static QIODevice::OpenModeFlag toQtMode(FileOpenModes mode) + { + switch (mode) + { + case FILE_OPEN_WRITE: return QIODevice::WriteOnly; + + case FILE_OPEN_READ: return QIODevice::ReadOnly; + + default: throw exceptions::RMSInvalidArgumentException("unknown FileOpenMode"); + } + } + +public: + + FileQt(const std::string& path); + bool open(FileOpenModes mode); +}; +} +} +} // namespace rmscore { namespace platform { namespace filesystem { + +#endif // FILEQT diff --git a/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.cpp b/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.cpp new file mode 100644 index 00000000..c62a875a --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.cpp @@ -0,0 +1,64 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include +#include"FileSystemQt.h" +#include"FileQt.h" +#include + +namespace rmscore { namespace platform { namespace filesystem { + +std::shared_ptr IFileSystem::Create() +{ + return std::make_shared(); +} + +std::shared_ptr FileSystemQt::OpenLocalStorageFile(const std::string& filePath, FileOpenModes mode) +{ + return IFile::Create(filePath, mode); +} + +std::shared_ptr FileSystemQt::OpenProtectedLocalStorageFile(const std::string& filePath, FileOpenModes mode) +{ + return IFile::Create(filePath, mode); +} + +void FileSystemQt::DeleteLocalStorageFile(const std::string& filePath) +{ + bool ok = QFile::remove(filePath.c_str()); + if(!ok) + { + qDebug() << "Failed to delete a file: " << filePath.c_str(); + } +} + +void IFileSystem::CreateDirectory(const std::string& dirPath) { + auto directory = QString::fromStdString(dirPath); + if (!QFile::exists(directory)) { + QDir dir; + dir.mkpath(directory); + } +} + +std::vector FileSystemQt::QueryLocalStorageFiles(const std::string& folder, const std::string& pattern) +{ + QStringList filters; + filters << pattern.c_str(); + QDir dir(folder.c_str()); + dir.setNameFilters(filters); + std::vector res; + for( QString f : dir.entryList(filters)) + { + res.push_back(f.toStdString()); + } + return res; +} + +}}} // namespace rmscore { namespace platform { namespace filesystem { +#endif diff --git a/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.h b/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.h new file mode 100644 index 00000000..4b06d276 --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/FileSystemQt.h @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IFILESYSTEMQTIMPL +#define IFILESYSTEMQTIMPL +#include "IFileSystem.h" +#include "../../Common/CommonTypes.h" + +namespace rmscore { namespace platform { namespace filesystem { + +class FileSystemQt : public IFileSystem +{ +private: + virtual std::shared_ptr OpenLocalStorageFile(const std::string& filePath, FileOpenModes mode) override; + virtual std::shared_ptr OpenProtectedLocalStorageFile(const std::string& filePath, FileOpenModes mode) override; + + virtual void DeleteLocalStorageFile(const std::string& filePath) override; + + virtual common::StringArray QueryLocalStorageFiles(const std::string& folder, const std::string& pattern) override; +}; + +}}} // namespace rmscore { namespace platform { namespace filesystem { + +#endif // IFILESYSTEMQTIMPL + diff --git a/sdk/rms_sdk/Platform/Filesystem/Filesystem.pro b/sdk/rms_sdk/Platform/Filesystem/Filesystem.pro new file mode 100644 index 00000000..38f084e1 --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/Filesystem.pro @@ -0,0 +1,29 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformfilesystem + +TEMPLATE = lib + +DEFINES += QTFRAMEWORK + +CONFIG += staticlib warn_on c++11 debug_and_release + +QT += core +QT -= gui + + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI + +SOURCES += \ + FileQt.cpp \ + FileSystemQt.cpp + +HEADERS += \ + IFile.h \ + IFileSystem.h \ + FileQt.h \ + FileSystemQt.h diff --git a/sdk/rms_sdk/Platform/Filesystem/IFile.h b/sdk/rms_sdk/Platform/Filesystem/IFile.h new file mode 100644 index 00000000..3d479047 --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/IFile.h @@ -0,0 +1,43 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IFILE +#define IFILE +#include +#include +#include +#include"../../Common/CommonTypes.h" + +namespace rmscore { namespace platform { namespace filesystem { + +enum FileOpenModes +{ + FILE_OPEN_WRITE, + FILE_OPEN_READ +}; + +class IFile +{ +public: + virtual size_t Read(common::CharArray& data, size_t len) = 0; + virtual size_t Write(const char* data, size_t len) = 0; + + virtual void Clear() = 0; + virtual void Close() = 0; + virtual std::string ReadAllAsText() = 0; + virtual void AppendText(const common::ByteArray& text) = 0; + + virtual size_t GetSize() = 0; + +public: + static std::shared_ptr Create(const std::string& path, FileOpenModes mode); +}; + +}}} // namespace rmscore { namespace platform { namespace filesystem { +#endif // IFILE + diff --git a/sdk/rms_sdk/Platform/Filesystem/IFileSystem.h b/sdk/rms_sdk/Platform/Filesystem/IFileSystem.h new file mode 100644 index 00000000..03766bdf --- /dev/null +++ b/sdk/rms_sdk/Platform/Filesystem/IFileSystem.h @@ -0,0 +1,38 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IFILESYSTEM +#define IFILESYSTEM + +#include +#include +#include +#include"../../Common/CommonTypes.h" +#include"IFile.h" + +namespace rmscore { namespace platform { namespace filesystem { + +class IFileSystem +{ +public: + virtual std::shared_ptr OpenLocalStorageFile(const std::string& filePath, FileOpenModes mode) = 0; + virtual std::shared_ptr OpenProtectedLocalStorageFile(const std::string& filePath, FileOpenModes mode) = 0; + + virtual void DeleteLocalStorageFile(const std::string& filePath) = 0; + + virtual std::vector QueryLocalStorageFiles(const std::string& folder, const std::string& pattern) = 0; + +public: + static std::shared_ptr Create(); + static void CreateDirectory(const std::string& dirPath); +}; + +}}} // namespace rmscore { namespace platform { namespace filesystem { + +#endif // IFILESYSTEM + diff --git a/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.cpp b/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.cpp new file mode 100644 index 00000000..9512d7f4 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.cpp @@ -0,0 +1,54 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include +#include +#include "DnsServerResolverQt.h" +#include +#include +#include + +using namespace std; +using namespace rmscore::common; + +namespace rmscore { +namespace platform { +namespace http { + +shared_ptrIDnsServerResolver::Create() +{ + return make_shared(); +} + +std::string DnsServerResolverQt::lookup(const std::string& dnsRequest) +{ + QDnsLookup dns; + dns.setType(QDnsLookup::SRV); + qDebug() << "dnsRequest: " << dnsRequest.c_str(); + dns.setName(dnsRequest.c_str()); + dns.lookup(); + QEventLoop loop; + QObject::connect(&dns, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + if (dns.error() != QDnsLookup::NoError) + { + qWarning("DNS lookup failed"); + } + foreach (const QDnsServiceRecord &record, dns.serviceRecords()) + { + qDebug() << "QDnsServiceRecord record: " << record.name() << " --> " << record.target(); + return record.target().toStdString(); + } + return ""; +} + +} // namespace http +} // namespace platform +} // namespace rmscore +#endif diff --git a/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.h b/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.h new file mode 100644 index 00000000..a5216e7b --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/DnsServerResolverQt.h @@ -0,0 +1,27 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DNSSERVERRESOLVERQT +#define DNSSERVERRESOLVERQT +#include "IDnsServerResolver.h" + +class QUdpSocket; + +namespace rmscore { +namespace platform { +namespace http { +class DnsServerResolverQt : public IDnsServerResolver { +public: + std::string lookup(const std::string& dnsRequest) override; +}; +} // namespace http +} // namespace platform +} // namespace rmscore + +#endif // DNSSERVERRESOLVERQT + diff --git a/sdk/rms_sdk/Platform/Http/Http.pro b/sdk/rms_sdk/Platform/Http/Http.pro new file mode 100644 index 00000000..b2066767 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/Http.pro @@ -0,0 +1,30 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformhttp + +TEMPLATE = lib + +DEFINES += QTFRAMEWORK + +CONFIG += staticlib warn_on c++11 debug_and_release + +QT += core network +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += \ + HttpClientQt.cpp \ + UriQt.cpp \ + DnsServerResolverQt.cpp + +HEADERS += \ + IUri.h \ + IHttpClient.h \ + IDnsServerResolver.h \ + HttpClientQt.h \ + UriQt.h \ + DnsServerResolverQt.h \ + mscertificates.h diff --git a/sdk/rms_sdk/Platform/Http/HttpClientQt.cpp b/sdk/rms_sdk/Platform/Http/HttpClientQt.cpp new file mode 100644 index 00000000..058167cc --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/HttpClientQt.cpp @@ -0,0 +1,178 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK + +#include "HttpClientQt.h" +#include +#include +#include + +#include "../Logger/Logger.h" +#include "../../ModernAPI/RMSExceptions.h" +#include "mscertificates.h" +#include "HttpClientQt.h" + +using namespace std; + +namespace rmscore { +namespace platform { +namespace http { +common::ByteArray ReadAllBytes(QIODevice *from) { + common::ByteArray result; + auto bytesAvailable = from->bytesAvailable(); + + if (bytesAvailable > 0) { + result.resize(static_cast(bytesAvailable)); + char *buf = reinterpret_cast(&result[0]); + + while (bytesAvailable > 0) { + auto read = from->read(buf, bytesAvailable); + + if (read <= 0) break; + bytesAvailable -= read; + } + } + + return result; +} + +shared_ptr IHttpClient::Create() { + static bool initialized = false; + + // add Microsoft certificates to trust list + if (!initialized) { + QSslConfiguration SslConfiguration(QSslConfiguration::defaultConfiguration()); + + QList certificates = SslConfiguration.caCertificates(); + certificates.append(QSslCertificate::fromData(MicrosoftCertCA)); + certificates.append(QSslCertificate::fromData(MicrosoftCertSubCA)); + SslConfiguration.setCaCertificates(certificates); + QSslConfiguration::setDefaultConfiguration(SslConfiguration); + initialized = true; + } + return make_shared(); +} + +HttpClientQt::HttpClientQt() : lastReply_(nullptr) { + this->request_.setSslConfiguration(QSslConfiguration::defaultConfiguration()); +} + +HttpClientQt::~HttpClientQt() { } + +void HttpClientQt::AddAuthorizationHeader(const string& authToken) { + this->AddHeader("Authorization", authToken); +} + +void HttpClientQt::AddAcceptMediaTypeHeader(const string& mediaType) { + this->AddHeader("Accept", mediaType); +} + +void HttpClientQt::AddAcceptLanguageHeader(const string& language) { + this->AddHeader("Accept-Language", language); +} + +void HttpClientQt::AddHeader(const string& headerName, const string& headerValue) { + this->request_.setRawHeader(headerName.c_str(), headerValue.c_str()); +} + +StatusCode HttpClientQt::Post(const string & url, + const common::ByteArray & request, + const string & mediaType, + common::ByteArray & response) { + Logger::Info("==> HttpClientQt::POST %s", url.data()); + Logger::Debug("==> request: %s", request.data()); + + this->request_.setUrl(QUrl(url.c_str())); + this->AddAcceptMediaTypeHeader(mediaType); + + lastReply_ = + this->manager_.post(this->request_, + QByteArray(reinterpret_cast(request.data()), + static_cast(request.size()))); + QEventLoop loop; + QObject::connect(lastReply_, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + QVariant statusCode = lastReply_->attribute(QNetworkRequest::HttpStatusCodeAttribute); + Logger::Info("statusCode: %i", statusCode.toInt()); + + Logger::Debug("--> Header:", nullptr); + foreach(const QNetworkReply::RawHeaderPair & pair, lastReply_->rawHeaderPairs()) { + Logger::Debug("%s : %s", pair.first.data(), pair.second.data() ); + } + + response = ReadAllBytes(lastReply_); + Logger::Debug("--> Body:", nullptr); + Logger::Debug(string(response.begin(), response.end()), nullptr); + + QNetworkReply::NetworkError error_type = lastReply_->error(); + + if (error_type != QNetworkReply::NoError) { + Logger::Error(QString("error: %1").arg( + lastReply_->errorString()).toStdString(), nullptr); + } + + return StatusCode(statusCode.toInt()); +} + +StatusCode HttpClientQt::Get(const string& url, common::ByteArray& response) { + Logger::Debug("==> HttpClientQt::GET %s", url.data()); + + this->request_.setUrl(QUrl(url.c_str())); + + lastReply_ = this->manager_.get(this->request_); + QEventLoop loop; + QObject::connect(lastReply_, SIGNAL(finished()), &loop, SLOT(quit())); + QObject::connect(lastReply_, &QNetworkReply::sslErrors, + [ = ](QListerrorList) { + for (auto& error : errorList) { + Logger::Error("QSslError: %s", + error.errorString().toStdString().c_str()); + throw exceptions::RMSNetworkException( + error.errorString().toStdString(), + exceptions::RMSNetworkException::ServerError); + } + }); + loop.exec(); + + QVariant statusCode = lastReply_->attribute( + QNetworkRequest::HttpStatusCodeAttribute); + Logger::Debug("statusCode: %i", statusCode.toInt()); + + Logger::Debug("--> Header:", nullptr); + foreach(const QNetworkReply::RawHeaderPair & pair, lastReply_->rawHeaderPairs()) { + Logger::Debug("%s : %s", pair.first.data(), pair.second.data()); + } + + response = ReadAllBytes(lastReply_); + Logger::Debug("--> Body:", nullptr); + Logger::Debug(string(response.begin(), response.end()), nullptr); + + QNetworkReply::NetworkError error_type = lastReply_->error(); + + if (error_type != QNetworkReply::NoError) { + Logger::Error(QString("error: %1").arg( + lastReply_->errorString()).toStdString(), nullptr); + } + + return StatusCode(statusCode.toInt()); +} + +const string HttpClientQt::GetResponseHeader(const string& headerName) { + return string(this->lastReply_->rawHeader(headerName.c_str()).data()); +} + +void HttpClientQt::SetAllowUI(bool /* allow*/) +{ + throw exceptions::RMSNotFoundException("Not implemented"); +} +} +} +} // namespace rmscore { namespace platform { namespace http { +#endif // ifdef QTFRAMEWORK diff --git a/sdk/rms_sdk/Platform/Http/HttpClientQt.h b/sdk/rms_sdk/Platform/Http/HttpClientQt.h new file mode 100644 index 00000000..edbe98c7 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/HttpClientQt.h @@ -0,0 +1,59 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _HTTPCLIENTQT_H_ +#define _HTTPCLIENTQT_H_ + +#include +#include +#include +#include +#include +#include "IHttpClient.h" + +namespace rmscore { +namespace platform { +namespace http { +class HttpClientQt : public IHttpClient { + // Q_OBJECT + +public: + + HttpClientQt(); + ~HttpClientQt(); + + virtual void AddAuthorizationHeader(const std::string& authToken) override; + virtual void AddAcceptMediaTypeHeader(const std::string& mediaType) override; + virtual void AddAcceptLanguageHeader(const std::string& languages) override; + + virtual void AddHeader(const std::string& headerName, + const std::string& headerValue) override; + + virtual StatusCode Post(const std::string & url, + const common::ByteArray& request, + const std::string & mediaType, + common::ByteArray & response) override; + + virtual StatusCode Get(const std::string& url, + common::ByteArray& response) override; + + virtual const std::string GetResponseHeader(const std::string& headerName) override; + + virtual void SetAllowUI(bool allow) override; + +private: + + QNetworkAccessManager manager_; + QNetworkRequest request_; + QNetworkReply *lastReply_; +}; +} +} +} // namespace rmscore { namespace platform { namespace http { + +#endif // _HTTPCLIENTQT_H_ diff --git a/sdk/rms_sdk/Platform/Http/IDnsServerResolver.h b/sdk/rms_sdk/Platform/Http/IDnsServerResolver.h new file mode 100644 index 00000000..fc47f228 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/IDnsServerResolver.h @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_CORE_IDNSSERVERRESOLVER_H_ +#define _RMS_CORE_IDNSSERVERRESOLVER_H_ + +#include +#include +#include + +#include "../../Common/CommonTypes.h" + +namespace rmscore { +namespace platform { +namespace http { +class IDnsServerResolver { +public: + virtual std::string lookup(const std::string& dnsRequest) = 0; + +public: + static std::shared_ptr Create(); +}; +} // namespace http +} // namespace platform +} // namespace rmscore +#endif // _RMS_CORE_IDNSSERVERRESOLVER_H_ diff --git a/sdk/rms_sdk/Platform/Http/IHttpClient.h b/sdk/rms_sdk/Platform/Http/IHttpClient.h new file mode 100644 index 00000000..0bc3708a --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/IHttpClient.h @@ -0,0 +1,59 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _IHTTPCLIENT_H_ +#define _IHTTPCLIENT_H_ + +#include +#include + +#include "../../Common/FrameworkSpecificTypes.h" + +namespace rmscore { +namespace platform { +namespace http { + +enum class StatusCode { + OK = 200, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + NOT_FOUND = 404, + INTERNAL_SERVER_ERROR = 500, + BAD_GATEWAY = 502, +}; + +class IHttpClient { +public: + virtual void AddAuthorizationHeader(const std::string& authToken) = 0; + virtual void AddAcceptMediaTypeHeader(const std::string& mediaType) = 0; + virtual void AddAcceptLanguageHeader(const std::string& language) = 0; + + virtual void AddHeader(const std::string& headerName, + const std::string& headerValue) = 0; + + virtual StatusCode Post(const std::string & url, + const common::ByteArray & request, + const std::string & mediaType, + common::ByteArray & response) = 0; + + virtual StatusCode Get(const std::string& url, + common::ByteArray& response) = 0; + + virtual const std::string GetResponseHeader(const std::string& headerName) = 0; + + virtual void SetAllowUI(bool allow) = 0; + virtual ~IHttpClient() {} + +public: + static std::shared_ptr Create(); +}; +} +} +} // namespace rmscore { namespace platform { namespace http { + +#endif // _IHTTPCLIENT_H_ diff --git a/sdk/rms_sdk/Platform/Http/IUri.cpp.autosave b/sdk/rms_sdk/Platform/Http/IUri.cpp.autosave new file mode 100644 index 00000000..56e856f2 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/IUri.cpp.autosave @@ -0,0 +1,3 @@ +#include "IUri.h" + + diff --git a/sdk/rms_sdk/Platform/Http/IUri.h b/sdk/rms_sdk/Platform/Http/IUri.h new file mode 100644 index 00000000..eaae7f58 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/IUri.h @@ -0,0 +1,32 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _IURI_H_ +#define _IURI_H_ + +#include +#include + +namespace rmscore { namespace platform { namespace http { + +class IUri { +public: + virtual const std::string GetScheme() const = 0; + virtual const std::string GetHost() const = 0; + virtual int GetPort() const = 0; + virtual const std::string ToString() const = 0; + virtual ~IUri() { } + +public: + static std::shared_ptr Create(const std::string& uri); +}; + +}}} // namespace rmscore { namespace platform { namespace http { + +#endif // _IURI_H_ + diff --git a/sdk/rms_sdk/Platform/Http/UriQt.cpp b/sdk/rms_sdk/Platform/Http/UriQt.cpp new file mode 100644 index 00000000..3e7f5027 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/UriQt.cpp @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "UriQt.h" +namespace rmscore { namespace platform { namespace http { + +std::shared_ptr IUri::Create(const std::string& uri) +{ + return std::make_shared(uri); +} +const std::string UriQt::GetScheme() const +{ + return this->pImpl_->scheme().toStdString(); +} +const std::string UriQt::GetHost() const +{ + return this->pImpl_->host().toStdString(); +} +int UriQt::GetPort() const +{ + return this->pImpl_->port(); +} +const std::string UriQt::ToString()const +{ + return this->pImpl_->toString().toStdString(); +} + +}}} // namespace rmscore { namespace platform { namespace http { +#endif + + diff --git a/sdk/rms_sdk/Platform/Http/UriQt.h b/sdk/rms_sdk/Platform/Http/UriQt.h new file mode 100644 index 00000000..d49761bb --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/UriQt.h @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IURIQTIMPL +#define IURIQTIMPL + +#include "IUri.h" +#include "QUrl" + +namespace rmscore { namespace platform { namespace http { + +class UriQt : public IUri +{ +public: + UriQt(const std::string& uri){this->pImpl_= new QUrl(uri.c_str());} + ~UriQt(){ if(nullptr != this->pImpl_) delete this->pImpl_;} + + virtual const std::string GetScheme() const override; + virtual const std::string GetHost() const override; + virtual int GetPort() const override; + virtual const std::string ToString()const override; + +private: + QUrl* pImpl_; +}; + +}}} // namespace rmscore { namespace platform { namespace http { + +#endif // IURIQTIMPL + diff --git a/sdk/rms_sdk/Platform/Http/mscertificates.h b/sdk/rms_sdk/Platform/Http/mscertificates.h new file mode 100644 index 00000000..bc8b85e9 --- /dev/null +++ b/sdk/rms_sdk/Platform/Http/mscertificates.h @@ -0,0 +1,90 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _MSCERTIFICATES_H_ +#define _MSCERTIFICATES_H_ + +#include + +const static QByteArray MicrosoftCertCA = { +"-----BEGIN CERTIFICATE-----\r\n\ +MIIF7TCCA9WgAwIBAgIQP4vItfyfspZDtWnWbELhRDANBgkqhkiG9w0BAQsFADCB\r\n\ +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl\r\n\ +ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp\r\n\ +TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEw\r\n\ +MzIyMjIwNTI4WhcNMzYwMzIyMjIxMzA0WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\r\n\ +BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv\r\n\ +c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm\r\n\ +aWNhdGUgQXV0aG9yaXR5IDIwMTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\r\n\ +AoICAQCygEGqNThNE3IyaCJNuLLx/9VSvGzH9dJKjDbu0cJcfoyKrq8TKG/Ac+M6\r\n\ +ztAlqFo6be+ouFmrEyNozQwph9FvgFyPRH9dkAFSWKxRxV8qh9zc2AodwQO5e7BW\r\n\ +6KPeZGHCnvjzfLnsDbVU/ky2ZU+I8JxImQxCCwl8MVkXeQZ4KI2JOkwDJb5xalwL\r\n\ +54RgpJki49KvhKSn+9GY7Qyp3pSJ4Q6g3MDOmT3qCFK7VnnkH4S6Hri0xElcTzFL\r\n\ +h93dBWcmmYDgcRGjuKVB4qRTufcyKYMME782XgSzS0NHL2vikR7TmE/dQgfI6B0S\r\n\ +/Jmpaz6SfsjWaTr8ZL22CZ3K/QwLopt3YEsDlKQwaRLWQi3BQUzK3Kr9j1uDRprZ\r\n\ +/LHR47PJf0h6zSTwQY9cdNCssBAgBkm3xy0hyFfj0IbzA2j70M5xwYmZSmQBbP3s\r\n\ +MJHPQTySx+W6hh1hhMdfgzlirrSSL0fzC/hV66AfWdC7dJse0Hbm8ukG1xDo+mTe\r\n\ +acY1logC8Ea4PyeZb8txiSk190gWAjWP1Xl8TQLPX+uKg09FcYj5qQ1OcunCnAfP\r\n\ +SRtOBA5jUYxe2ADBVSy2xuDCZU7JNDn1nLPEfuhhbhNfFcRf2X7tHc7uROzLLoax\r\n\ +7Dj2cO2rXBPB2Q8Nx4CyVe0096yb5MPa50c8prWPMd/FS6/r8QIDAQABo1EwTzAL\r\n\ +BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUci06AjGQQ7kU\r\n\ +BU7h6qfHMdEjiTQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQELBQADggIB\r\n\ +AH9yzw+3xRXbm8BJyiZb/p4T5tPw0tuXX/JLP02zrhmu7deXoKzvqTqjwkGw5biR\r\n\ +nhOBJAPmCf0/V0A5ISRW0RAvS0CpNoZLtFNXmvvxfomPEf4YbFGq6O0JlbXlccmh\r\n\ +6Yd1phV/yX43VF50k8XDZ8wNT2uoFwxtCJJ+i92Bqi1wIcM9BhS7vyRep4TXPw8h\r\n\ +Ir1LAAbblxzYXtTFC1yHblCk6MM4pPvLLMWSZpuFXst6bJN8gClYW1e1QGm6CHmm\r\n\ +ZGIVnYeWRbVmIyADixxzoNOieTPgUFmG2y/lAiXqcyqfABTINseSO+lOAOzYVgm5\r\n\ +M0kS0lQLAausR7aRKX1MtHWAUgHoyoL2n8ysnI8X6i8msKtyrAv+nlEex0NVZ09R\r\n\ +s1fWtuzuUrc66U7h14GIvE+OdbtLqPA1qibUZ2dJsnBMO5PcHd94kIZysjik0dyS\r\n\ +TclY6ysSXNQ7roxrsIPlAT/4CTL2kzU0Iq/dNw13CYArzUgA8YyZGUcFAenRv9FO\r\n\ +0OYoQzeZpApKCNmacXPSqs0xE2N2oTdvkjgefRI8ZjLny23h/FKJ3crWZgWalmG+\r\n\ +oijHHKOnNlA8OqTfSm7mhzvO6/DggTedEzxSjr25HTTGHdUKaj2YKXCMiSrRq4IQ\r\n\ +SB/c9O+lxbtVGjhjhE63bK2VVOxlIhBJF7jAHscPrFRH\r\n\ +-----END CERTIFICATE-----" +}; + +const static QByteArray MicrosoftCertSubCA = { +"-----BEGIN CERTIFICATE-----\r\n\ +MIIGaDCCBFCgAwIBAgITMwAAAJ0G5/l2xKJulgAAAAAAnTANBgkqhkiG9w0BAQsF\r\n\ +ADB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH\r\n\ +UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQD\r\n\ +Ex9NaWNyb3NvZnQgU2VjdXJlIFNlcnZlciBDQSAyMDExMB4XDTE0MDkxNjIwNTYy\r\n\ +M1oXDTE1MTIxNjIwNTYyM1owcDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAw\r\n\ +DgYDVQQHEwdSZWRtb25kMRIwEAYDVQQKEwlNaWNyb3NvZnQxEzARBgNVBAsTCkFB\r\n\ +RFJNLVBST0QxGTAXBgNVBAMTEHNzbC5ldS5hYWRybS5jb20wggEiMA0GCSqGSIb3\r\n\ +DQEBAQUAA4IBDwAwggEKAoIBAQC/UGECi48prbnEBaspm17l2pJo/abyg5SpOuwJ\r\n\ +EvwFfbfPkcAchLj+eK9nezVgbiaC7sVN+VBfErO5p1wltT+wsnen3t1CL7ZD7Cah\r\n\ +8AaUEH8AyevEZV0nKxJPrIpTc2dccyhYOxULkyJvENNYhmBzzq3lVfPXk6o6J75+\r\n\ +d07GeoEdU9W0rkYIoczBKwwbn96CtQxwIiC2nk/WMm/jdZzzi84O+nISTBcjQgC1\r\n\ +Wu0N+kkwUe3GygdT6lgTcD2aw8tj0uHtfyTMtM5pqPGU2ZOl6rXQIVV0cprJCulR\r\n\ +N8vUW1/xjR+TCyBMBfK2LZKS1ki5XJq+yMVb5393mGnFHFoTAgMBAAGjggHrMIIB\r\n\ +5zAOBgNVHQ8BAf8EBAMCBaAwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMB\r\n\ +BgorBgEEAYI3TAcDMB0GA1UdDgQWBBT+lHhBT62Fz7rS2ghUJvj/gnWHgDCBpAYD\r\n\ +VR0RBIGcMIGZgg4qLmV1LmFhZHJtLmNvbYILKi5hYWRybS5jb22CEioucm1zLmV1\r\n\ +LmFhZHJtLmNvbYIYKi5ybXMtYS1ORVUuZXUuYWFkcm0uY29tghgqLnJtcy1hLVdF\r\n\ +VS5ldS5hYWRybS5jb22CGCoucm1zLWItTkVVLmV1LmFhZHJtLmNvbYIYKi5ybXMt\r\n\ +Yi1XRVUuZXUuYWFkcm0uY29tMB8GA1UdIwQYMBaAFDZWiWVJy1ubLzysQhZQTZG5\r\n\ +M9eRMFMGA1UdHwRMMEowSKBGoESGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w\r\n\ +a2lvcHMvY3JsL01pY1NlY1NlckNBMjAxMV8yMDExLTEwLTE4LmNybDBgBggrBgEF\r\n\ +BQcBAQRUMFIwUAYIKwYBBQUHMAKGRGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w\r\n\ +a2lvcHMvY2VydHMvTWljU2VjU2VyQ0EyMDExXzIwMTEtMTAtMTguY3J0MAwGA1Ud\r\n\ +EwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAL9OpbAzAH6t7XtLHMfpSwOeu1MX\r\n\ +S+WnnpexO3yEEeq8mzVo1WdtoXL2oXay1c+xOrPECEQHVMCW9H8aayk7UzSuzzJg\r\n\ +cHiVQOAmmOdYCbKQDGn0RT8RhQ0H4tayXJpBGv3whU4c5uYzjiFuWkaF3hJFo3d8\r\n\ +EStKPBC3WIk+f804cMZjmcIDOR46jY4ckqbZsgXkhNXszMW9nMYnRYjaXKyh3qyT\r\n\ +GyhstM4BZON9l626GJTP2UrDVdX/a/6NQ7lNlPQ6e4lA8RTP5jlUgMqdQ47CfsCf\r\n\ +Kx6PC367ADN6iycl2MLjRh/DbgRTb37kWlTqCDoXumKR+LnA0JUhax5a+xzZprnc\r\n\ +QR0WDrG2SvVBu8GCBRlQ+oBjiEEKc9rD/b1PsQLJAG1zXwKv13i9FDCl5I8mFTi1\r\n\ +3mbiuRm+SUblbC8IeJoFkflv+7yCD64h0cN5jbSP/+NcqnuGWU4Zj39hVHyaO++W\r\n\ +5Gc+8k6kJjKCxckRLkCcmFaAQPGWmWJyd1jP2CwI4yhh3I+/ZqknuNx+DF58ASdd\r\n\ +RWp7+JDSV1+oseoJ195b7faI0or6kie1lGjYlv1YHkMdyqExkhe+0sbXwbZmUyPF\r\n\ +4WcEOODjqDt+qwfER6bgIVIxVeeljBZr6jdLUgFLTIk511Xs0CBGmsn7JIQhdm8U\r\n\ +5JIVRR8I5aveCXa2\r\n\ +-----END CERTIFICATE-----" +}; +#endif // _MSCERTIFICATES_H_ diff --git a/sdk/rms_sdk/Platform/Json/IJsonArray.h b/sdk/rms_sdk/Platform/Json/IJsonArray.h new file mode 100644 index 00000000..c1382b11 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/IJsonArray.h @@ -0,0 +1,45 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONARRAY +#define IJSONARRAY + +#include +#include +#include + +#include "../../Common/FrameworkSpecificTypes.h" + +namespace rmscore { namespace platform { namespace json { + +class IJsonObject; + +class IJsonArray +{ +public: + virtual uint32_t Size() = 0; + + virtual const std::string GetStringAt(uint32_t index) = 0; + virtual std::shared_ptr GetObjectAt(uint32_t index) = 0; + + virtual void Clear() = 0; + + virtual void Append(const IJsonObject& jsonObject) = 0; + virtual void Append(const std::string& name) = 0; + + virtual common::ByteArray Stringify() = 0; + +public: + static std::shared_ptr Create(); +}; + +}}} // namespace rmscore { namespace platform { namespace json { + + +#endif // IJSONARRAY + diff --git a/sdk/rms_sdk/Platform/Json/IJsonArrayQtImpl.h b/sdk/rms_sdk/Platform/Json/IJsonArrayQtImpl.h new file mode 100644 index 00000000..d64ae4dd --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/IJsonArrayQtImpl.h @@ -0,0 +1,47 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONARRAYQTIMPL +#define IJSONARRAYQTIMPL + +#include +#include + +#include "IJsonArray.h" +#include "IJsonObject.h" +#include "JsonObjectQt.h" + +namespace rmslib { namespace platform { namespace json { + +class JsonArrayQt : public IJsonArray +{ +private: + + virtual uint32_t Size() override; + + virtual const std::string GetStringAt(uint32_t index) override; + virtual std::shared_ptr GetObjectAt(uint32_t index) override; + + virtual void Clear() override; + + virtual void Append(const IJsonObject& jsonObject) override; + virtual void Append(const std::string& name) override; + +private: + QJsonArray impl_; + +public: + JsonArrayQt(){} + JsonArrayQt(const QJsonArray& impl):impl_(impl){} + const QJsonArray& impl(){return this->impl_;} + +}; + +}}} // namespace rmslib { namespace platform { namespace json { +#endif // IJSONARRAYQTIMPL + diff --git a/sdk/rms_sdk/Platform/Json/IJsonObject.h b/sdk/rms_sdk/Platform/Json/IJsonObject.h new file mode 100644 index 00000000..93d1d660 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/IJsonObject.h @@ -0,0 +1,63 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONOBJECT +#define IJSONOBJECT + +#include +#include +#include +#include "../../Common/CommonTypes.h" + +namespace rmscore { +namespace platform { +namespace json { +using StringDictionary = common::HashMapString; +using StringArray = std::vector; + +class IJsonArray; +class IJsonObject +{ +public: + virtual bool IsNull(const std::string &name) = 0; + + virtual std::shared_ptr GetArray() = 0; + + virtual bool HasName(const std::string &name) = 0; + + virtual std::string GetNamedString(const std::string &name, const std::string &defaultValue = std::string("")) = 0; + virtual void SetNamedString(const std::string &name, const std::string &value) = 0; + + virtual bool GetNamedBool(const std::string &name, bool bDefaultValue = false) = 0; + virtual void SetNamedBool(const std::string &name, bool bValue) = 0; + + virtual double GetNamedNumber(const std::string &name, double fDefaultValue = false) = 0; + virtual void SetNamedNumber(const std::string &name, double fValue) = 0; + + virtual std::shared_ptr GetNamedObject(const std::string &name) = 0; + virtual void SetNamedObject(const std::string &name, const IJsonObject &jsonObject) = 0; + + virtual std::shared_ptr GetNamedArray(const std::string &name) = 0; + virtual void SetNamedArray(const std::string &name, const IJsonArray &jsonArray) = 0; + + virtual void SetNamedValue(const std::string &name, const common::ByteArray &value) = 0; + virtual common::ByteArray GetNamedValue(const std::string &name) = 0; + + virtual StringArray GetNamedStringArray(const std::string &name) = 0; + + virtual StringDictionary ToStringDictionary() = 0; + + virtual common::ByteArray Stringify() = 0; + +public: + static std::shared_ptr Create(); +}; + +}}} // namespace rmscore { namespace platform { namespace json { + +#endif // IJSONOBJECT diff --git a/sdk/rms_sdk/Platform/Json/IJsonParser.h b/sdk/rms_sdk/Platform/Json/IJsonParser.h new file mode 100644 index 00000000..c85c5af7 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/IJsonParser.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONPARSER +#define IJSONPARSER + +#include +#include + +#include "../../Common/FrameworkSpecificTypes.h" +namespace rmscore { namespace platform { namespace json { + +class IJsonObject; +class IJsonArray; + +class IJsonParser +{ +public: + virtual std::shared_ptr Parse(const common::ByteArray& json) = 0; + virtual std::shared_ptr ParseArray(const common::ByteArray& jsonArray) = 0; + +public: + static std::shared_ptr Create(); +}; + +}}} // namespace rmscore { namespace platform { namespace json { + +#endif // IJSONPARSER + diff --git a/sdk/rms_sdk/Platform/Json/Json.pro b/sdk/rms_sdk/Platform/Json/Json.pro new file mode 100644 index 00000000..27c5cf76 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/Json.pro @@ -0,0 +1,29 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformjson + +TEMPLATE = lib + +DEFINES += QTFRAMEWORK + +CONFIG += staticlib warn_on c++11 debug_and_release + +QT += core +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += \ + JsonArrayQt.cpp \ + JsonObjectQt.cpp \ + JsonParserQt.cpp + +HEADERS += \ + IJsonArray.h \ + IJsonObject.h \ + JsonArrayQt.h \ + JsonObjectQt.h \ + JsonParserQt.h \ + IJsonParser.h diff --git a/sdk/rms_sdk/Platform/Json/JsonArrayQt.cpp b/sdk/rms_sdk/Platform/Json/JsonArrayQt.cpp new file mode 100644 index 00000000..a3f72fd7 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonArrayQt.cpp @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "JsonArrayQt.h" +#include "JsonObjectQt.h" +#include + +namespace rmscore { namespace platform { namespace json { + +std::shared_ptr IJsonArray::Create() +{ + return std::make_shared(); +} + +uint32_t JsonArrayQt::Size() +{ + return static_cast(this->impl_.size()); +} + +const std::string JsonArrayQt::GetStringAt(uint32_t index) +{ + QJsonValue val = this->impl_[index]; + return val.toString().toStdString(); +} + +std::shared_ptr JsonArrayQt::GetObjectAt(uint32_t index) +{ + QJsonValue val = this->impl_[index]; + return std::make_shared(val); +} + +void JsonArrayQt::Clear() +{ + QJsonArray::iterator it = this->impl_.begin(); + while(it != this->impl_.end()) + it = this->impl_.erase(it); +} + +void JsonArrayQt::Append(const IJsonObject& jsonObject) +{ + auto joi = static_cast(jsonObject); + this->impl_.append(joi.impl()); +} + +void JsonArrayQt::Append(const std::string& name) +{ + QJsonValue val(QString::fromStdString(name)); + this->impl_.append(val); +} + +common::ByteArray JsonArrayQt::Stringify() +{ + QJsonDocument doc(this->impl_); + auto res = doc.toJson(QJsonDocument::Compact); + return common::ByteArray(res.begin(), res.end()); + +} + +}}} // namespace rmscore { namespace platform { namespace json { +#endif + diff --git a/sdk/rms_sdk/Platform/Json/JsonArrayQt.h b/sdk/rms_sdk/Platform/Json/JsonArrayQt.h new file mode 100644 index 00000000..292f6524 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonArrayQt.h @@ -0,0 +1,47 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONARRAYQTIMPL +#define IJSONARRAYQTIMPL + +#include +#include + +#include "IJsonArray.h" +namespace rmscore { namespace platform { namespace json { + +class IJsonObject; +class JsonArrayQt : public IJsonArray +{ +private: + + virtual uint32_t Size() override; + + virtual const std::string GetStringAt(uint32_t index) override; + virtual std::shared_ptr GetObjectAt(uint32_t index) override; + + virtual void Clear() override; + + virtual void Append(const IJsonObject& jsonObject) override; + virtual void Append(const std::string& name) override; + + virtual common::ByteArray Stringify() override; + +private: + QJsonArray impl_; + +public: + JsonArrayQt(){} + JsonArrayQt(const QJsonArray& impl):impl_(impl){} + const QJsonArray& impl(){return this->impl_;} + +}; + +}}} // namespace rmscore { namespace platform { namespace json { +#endif // IJSONARRAYQTIMPL + diff --git a/sdk/rms_sdk/Platform/Json/JsonObjectQt.cpp b/sdk/rms_sdk/Platform/Json/JsonObjectQt.cpp new file mode 100644 index 00000000..2cce31c4 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonObjectQt.cpp @@ -0,0 +1,267 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include +#include +#include +#include + +#include "JsonObjectQt.h" +#include "JsonArrayQt.h" +#include "JsonParserQt.h" + +#include "../../ModernAPI/RMSExceptions.h" +#include "../Logger/Logger.h" + +namespace rmscore { +namespace platform { +namespace json { +std::shared_ptrIJsonObject::Create() +{ + return std::make_shared(); +} + +bool JsonObjectQt::IsNull(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + + return jo.contains(name.c_str()) + ? jo[name.c_str()].isNull() + : throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::IsNull: Name doesn't exist"); +} + +std::shared_ptrJsonObjectQt::GetArray() +{ + if (!this->impl_.isArray()) + { + throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetArray: The object is not an array"); + } + + QJsonArray arr = this->impl_.toArray(); + + return std::shared_ptr(new JsonArrayQt(arr)); +} + +bool JsonObjectQt::HasName(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + + return jo.contains(name.c_str()); +} + +std::string JsonObjectQt::GetNamedString(const std::string& name, + const std::string& defaultValue) +{ + QJsonObject jo = this->impl_.toObject(); + + if (jo.contains(name.c_str()) && !jo[name.c_str()].isNull()) { + auto obj = jo[name.c_str()]; + + if (obj.isString()) { + return obj.toString().toStdString(); + } + + throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetNamedString: convertion error"); + } + return defaultValue; +} + +void JsonObjectQt::SetNamedString(const std::string& name, + const std::string& value) +{ + QJsonObject jo = this->impl_.toObject(); + + jo.insert(name.c_str(), QJsonValue(QString::fromStdString(value))); + this->impl_ = QJsonValue(jo); +} + +bool JsonObjectQt::GetNamedBool(const std::string& name, bool bDefaultValue) +{ + QJsonObject jo = this->impl_.toObject(); + + return jo.contains(name.c_str()) + ? jo[name.c_str()].isBool() + ? jo[name.c_str()].toBool() + : throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetNamedBool: convertion error") + : bDefaultValue; +} + +void JsonObjectQt::SetNamedBool(const std::string& name, bool bValue) +{ + QJsonObject jo = this->impl_.toObject(); + + jo.insert(name.c_str(), bValue); + this->impl_ = QJsonValue(jo); +} + +double JsonObjectQt::GetNamedNumber(const std::string& name, double fDefaultValue) +{ + QJsonObject jo = this->impl_.toObject(); + + return jo.contains(name.c_str()) + ? jo[name.c_str()].isDouble() + ? jo[name.c_str()].toDouble() + : throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetNamedNumber: convertion error") + : fDefaultValue; +} + +void JsonObjectQt::SetNamedNumber(const std::string& name, double fValue) +{ + QJsonObject jo = this->impl_.toObject(); + + jo.insert(name.c_str(), fValue); + this->impl_ = QJsonValue(jo); +} + +std::shared_ptrJsonObjectQt::GetNamedObject(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + + if (!jo.contains(name.c_str())) + { + return nullptr; + } + + QJsonValue val = jo.value(name.data()); + + if (!val.isObject()) + { + throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetNamedObject: convertion error"); + } + + return std::make_shared(val); +} + +void JsonObjectQt::SetNamedObject(const std::string& name, + const IJsonObject& jsonObject) +{ + QJsonObject jo = this->impl_.toObject(); + auto other = static_cast(jsonObject); + + jo.insert(name.c_str(), other.impl()); + this->impl_ = QJsonValue(jo); +} + +std::shared_ptrJsonObjectQt::GetNamedArray(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + + if (!jo.contains(name.c_str())) + { + return nullptr; + } + + QJsonValue val = jo.value(name.data()); + + if (!val.isArray()) + { + throw exceptions::RMSInvalidArgumentException("the value is not an array"); + } + + return std::shared_ptr(new JsonArrayQt(val.toArray())); +} + +void JsonObjectQt::SetNamedArray(const std::string& name, + const IJsonArray & jsonArray) +{ + QJsonObject jo = this->impl_.toObject(); + auto other = static_cast(jsonArray); + + jo.insert(name.c_str(), QJsonValue(other.impl())); + this->impl_ = QJsonValue(jo); +} + +void JsonObjectQt::SetNamedValue(const std::string & name, + const common::ByteArray& value) { + QJsonObject jo = this->impl_.toObject(); + + QVariant jsonVar(QByteArray(reinterpret_cast(value.data()), + static_cast(value.size()))); + + jo.insert(name.c_str(), QJsonValue::fromVariant(jsonVar)); + this->impl_ = QJsonValue(jo); +} + +common::ByteArray JsonObjectQt::GetNamedValue(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + auto nameStr = name.c_str(); + auto ret = jo.contains(nameStr) + ? jo[nameStr].isString() + ? jo[nameStr].toString().toUtf8() + : throw exceptions::RMSInvalidArgumentException( + "JsonObjectQt::GetNamedValue: convertion error") + : QByteArray(); + + return common::ByteArray(ret.begin(), ret.end()); +} + +StringArray JsonObjectQt::GetNamedStringArray(const std::string& name) +{ + QJsonObject jo = this->impl_.toObject(); + + if (!jo.contains(name.c_str())) + { + Logger::Warning( + "JsonObjectQt::GetNamedStringArray: Can't find the key named '%s'", + name.c_str()); + return std::vector(); + } + + QJsonValue val = jo[name.c_str()]; + + if (!val.isArray()) + { + throw exceptions::RMSInvalidArgumentException("the value is not an array"); + } + + StringArray list; + QJsonArray arr = val.toArray(); + + for (int i = 0; i < arr.size(); ++i) + { + QJsonValue val = arr[i]; + list.push_back(val.toString().toStdString()); + } + + return list; +} + +StringDictionary JsonObjectQt::ToStringDictionary() +{ + QVariantMap map = this->impl_.toObject().toVariantMap(); + + StringDictionary result; + + for (QString& key : map.keys()) + { + result.insert(std::make_pair(key.toStdString(), + map[key].toString().toStdString())); + } + return result; +} + +common::ByteArray JsonObjectQt::Stringify() +{ + QJsonDocument doc(this->impl_.toObject()); + + auto res = doc.toJson(QJsonDocument::Compact); + + return common::ByteArray(res.begin(), res.end()); +} +} +} +} // namespace rmscore { namespace platform { namespace json { +#endif // ifdef QTFRAMEWORK diff --git a/sdk/rms_sdk/Platform/Json/JsonObjectQt.h b/sdk/rms_sdk/Platform/Json/JsonObjectQt.h new file mode 100644 index 00000000..0c37bf96 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonObjectQt.h @@ -0,0 +1,70 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONOBJECTQTIMPL +#define IJSONOBJECTQTIMPL + +#include +#include +#include +#include + +#include "IJsonObject.h" + +namespace rmscore { namespace platform { namespace json { + +class IJsonArray; +class JsonObjectQt : public IJsonObject +{ +private: + + virtual bool IsNull(const std::string& name) override; + + virtual std::shared_ptr GetArray() override; + + virtual bool HasName(const std::string& name) override; + + virtual std::string GetNamedString(const std::string& name, const std::string& defaultValue ) override; + virtual void SetNamedString(const std::string& name, const std::string& value) override; + + virtual bool GetNamedBool(const std::string& name, bool bDefaultValue = false) override; + virtual void SetNamedBool(const std::string& name, bool bValue) override; + + virtual double GetNamedNumber(const std::string& name, double fDefaultValue = false) override; + virtual void SetNamedNumber(const std::string& name, double fValue) override; + + virtual std::shared_ptr GetNamedObject(const std::string& name) override; + virtual void SetNamedObject(const std::string& name, const IJsonObject& jsonObject) override; + + virtual std::shared_ptr GetNamedArray(const std::string& name) override; + virtual void SetNamedArray(const std::string& name, const IJsonArray& jsonArray) override; + + virtual void SetNamedValue(const std::string &name, const common::ByteArray &value) override; + virtual common::ByteArray GetNamedValue(const std::string &name) override; + + virtual StringArray GetNamedStringArray(const std::string& name) override; + + virtual StringDictionary ToStringDictionary() override; + + virtual common::ByteArray Stringify() override; + +private: + QJsonValue impl_; + +public: + JsonObjectQt(){} + JsonObjectQt(const QJsonValue& impl):impl_(impl){} + const QJsonValue& impl(){return this->impl_;} + +}; + + +}}} // namespace rmscore { namespace platform { namespace json { + +#endif // IJSONOBJECTQTIMPL + diff --git a/sdk/rms_sdk/Platform/Json/JsonParserQt.cpp b/sdk/rms_sdk/Platform/Json/JsonParserQt.cpp new file mode 100644 index 00000000..bafffb20 --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonParserQt.cpp @@ -0,0 +1,73 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "JsonParserQt.h" +#include "JsonObjectQt.h" +#include "JsonArrayQt.h" +#include "../Logger/Logger.h" + +namespace rmscore { +namespace platform { +namespace json { +std::shared_ptrIJsonParser::Create() +{ + return std::make_shared(); +} + +std::shared_ptrJsonParserQt::Parse( + const common::ByteArray& jsonObject) +{ + QJsonParseError error; + auto data = jsonObject.data(); + QByteArray inArray(reinterpret_cast(data), + static_cast(jsonObject.size())); + auto qdoc = QJsonDocument::fromJson(inArray, &error); + + if (error.error != QJsonParseError::NoError) + { + Logger::Error("JsonParserQt::Parse: %s", + error.errorString().toStdString().data()); + return nullptr; + } + + if (!qdoc.isObject()) + { + Logger::Error("JsonParserQt::Parse: %s", "given json is not a json object"); + return nullptr; + } + return std::make_shared(QJsonValue(qdoc.object())); +} + +std::shared_ptrJsonParserQt::ParseArray( + const common::ByteArray& jsonArray) +{ + QJsonParseError error; + auto qdoc = + QJsonDocument::fromJson( + QByteArray(reinterpret_cast(jsonArray.data()), + static_cast(jsonArray.size())), &error); + + if (error.error != QJsonParseError::NoError) + { + Logger::Error("JsonParserQt::Parse: %s", + error.errorString().toStdString().data()); + return nullptr; + } + + if (!qdoc.isArray()) + { + Logger::Error("JsonParserQt::Parse: %s", "given json is not a json array"); + return nullptr; + } + return std::make_shared(qdoc.array()); +} +} +} +} // namespace rmscore { namespace platform { namespace json { +#endif // ifdef QTFRAMEWORK diff --git a/sdk/rms_sdk/Platform/Json/JsonParserQt.h b/sdk/rms_sdk/Platform/Json/JsonParserQt.h new file mode 100644 index 00000000..3924e8bd --- /dev/null +++ b/sdk/rms_sdk/Platform/Json/JsonParserQt.h @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IJSONPARSERQTIMPL +#define IJSONPARSERQTIMPL + +#include +#include "IJsonParser.h" + +namespace rmscore { namespace platform { namespace json { + +class JsonParserQt : public IJsonParser +{ +private: + virtual std::shared_ptr Parse(const common::ByteArray& json) override; + virtual std::shared_ptr ParseArray(const common::ByteArray& jsonArray) override; + +}; + +}}} // namespace rmscore { namespace platform { namespace json { + +#endif // IJSONPARSERQTIMPL + diff --git a/sdk/rms_sdk/Platform/Logger/Logger.h b/sdk/rms_sdk/Platform/Logger/Logger.h new file mode 100644 index 00000000..1aa646e4 --- /dev/null +++ b/sdk/rms_sdk/Platform/Logger/Logger.h @@ -0,0 +1,98 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _LOGGER_H_ +#define _LOGGER_H_ + +#include +#include +#include + +class Logger +{ + static const int max_length = 1024000; +public: + template + static void Append(const std::string& prefix, const std::string& record, Arguments... arguments) { + auto cArgs = sizeof...(Arguments); + if (cArgs > 0) { + std::string buff(max_length, '-'); +#ifdef Q_OS_WIN32 + int num_bytes = sprintf_s (&buff[0], max_length, record.c_str(), arguments...); +#else + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-security" + #endif + #if defined(__GNUC__) + #pragma GCC diagnostic ignored "-Wformat-security" + #endif + int num_bytes = std::snprintf (&buff[0], max_length, record.c_str(), arguments...); + #if defined(__clang__) + #pragma clang diagnostic pop + #endif +#endif + if (num_bytes < max_length) { + buff.resize(num_bytes); + } + Logger::instance().append(prefix, buff); + } else { + Logger::instance().append(prefix, record); + } + } + + template + static void Info(const std::string& record, Arguments... arguments) { + Logger::Append("INF", record, arguments...); + } + + template + static void Warning(const std::string& record, Arguments... arguments) { + Logger::Append("WRN", record, arguments...); + } + + template + static void Error(const std::string& record, Arguments... arguments) { + Logger::Append("ERR", record, arguments...); + } + +#ifndef QT_DEBUG + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunused-parameter" + #endif + #if defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #endif +#endif + template + static void Debug(const std::string& record, Arguments... arguments) { +#ifdef QT_DEBUG + Logger::Append("DBG", record, arguments...); +#endif + } +#ifndef QT_DEBUG + #if defined(__GNUC__) + #pragma GCC diagnostic pop + #endif + #if defined(__clang__) + #pragma clang diagnostic pop + #endif +#endif + + virtual ~Logger(){} + +protected: + virtual void append(const std::string& prefix, const std::string& record) = 0; + +private: + static Logger& instance(); +}; + +#endif // _LOGGER_H_ diff --git a/sdk/rms_sdk/Platform/Logger/Logger.pro b/sdk/rms_sdk/Platform/Logger/Logger.pro new file mode 100644 index 00000000..62a0cc2a --- /dev/null +++ b/sdk/rms_sdk/Platform/Logger/Logger.pro @@ -0,0 +1,24 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformlogger + +QT -= gui +QT += core + + +DEFINES += QTFRAMEWORK + +TEMPLATE = lib + +CONFIG += staticlib warn_on c++11 debug_and_release + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += \ + LoggerImplQt.cpp + +HEADERS += \ + Logger.h \ + LoggerImplQt.h diff --git a/sdk/rms_sdk/Platform/Logger/LoggerImplQt.cpp b/sdk/rms_sdk/Platform/Logger/LoggerImplQt.cpp new file mode 100644 index 00000000..6661a186 --- /dev/null +++ b/sdk/rms_sdk/Platform/Logger/LoggerImplQt.cpp @@ -0,0 +1,55 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "LoggerImplQt.h" +#include +#include +#include +#include + +Logger& Logger::instance() { + static LoggerImplQt instance; + return instance; +} + +static std::string localTime(const char * format) { + const time_t rawtime = time(nullptr); +#ifdef Q_OS_WIN32 + tm timebuf; + localtime_s(&timebuf, &rawtime); +#else + tm timebuf = *localtime (&rawtime); +#endif + const int BUFF_LEN = 32; + std::string res(BUFF_LEN, '-'); + auto len = strftime (&res[0], BUFF_LEN, format, &timebuf); + res.resize(len); + return res; +} + +LoggerImplQt::LoggerImplQt() { + std::stringstream filename; + filename << "rms_log_" << localTime("%H%M%S-%d%m") << ".log"; + + this->stream_.open(filename.str(), std::ofstream::out | std::ofstream::trunc); + if (this->stream_.fail()) { + qDebug() << "Can't open file: " << filename.str().c_str(); + } +} + +LoggerImplQt::~LoggerImplQt() { + this->stream_.close(); +} + +void LoggerImplQt::append(const std::string& prefix, const std::string& record) { + std::stringstream ss; + ss << localTime("%H:%M:%S ") << prefix.c_str() << ": " << record; + this->stream_ << ss.str() << std::endl; +} +#endif // QTFRAMEWORK diff --git a/sdk/rms_sdk/Platform/Logger/LoggerImplQt.h b/sdk/rms_sdk/Platform/Logger/LoggerImplQt.h new file mode 100644 index 00000000..89b157f2 --- /dev/null +++ b/sdk/rms_sdk/Platform/Logger/LoggerImplQt.h @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _LOGGERQTIMPL_H_ +#define _LOGGERQTIMPL_H_ + +#include "Logger.h" +#include + +class LoggerImplQt : public Logger { +public: + ~LoggerImplQt(); + +protected: + virtual void append(const std::string& prefix, const std::string& record) override; + +private: + LoggerImplQt(); + friend class Logger; + std::ofstream stream_; +}; + +#endif // _LOGGERQTIMPL_H_ diff --git a/sdk/rms_sdk/Platform/Logger/logger_global.h b/sdk/rms_sdk/Platform/Logger/logger_global.h new file mode 100644 index 00000000..6ef0e4e9 --- /dev/null +++ b/sdk/rms_sdk/Platform/Logger/logger_global.h @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef LOGGER_GLOBAL_H +#define LOGGER_GLOBAL_H + +#include + +#if defined(LOGGER_LIBRARY) +# define LOGGERSHARED_EXPORT Q_DECL_EXPORT +#else +# define LOGGERSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // LOGGER_GLOBAL_H diff --git a/sdk/rms_sdk/Platform/Platform.pro b/sdk/rms_sdk/Platform/Platform.pro new file mode 100644 index 00000000..714f0de0 --- /dev/null +++ b/sdk/rms_sdk/Platform/Platform.pro @@ -0,0 +1,12 @@ +TEMPLATE = subdirs + +DEFINES += QTFRAMEWORK + +SUBDIRS += \ + Http \ + Common \ + Filesystem \ + Json \ + Settings \ + Xml \ + Logger diff --git a/sdk/rms_sdk/Platform/Settings/ILanguageSettings.h b/sdk/rms_sdk/Platform/Settings/ILanguageSettings.h new file mode 100644 index 00000000..8bd77f63 --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/ILanguageSettings.h @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ILANGUAGESETTINGS +#define ILANGUAGESETTINGS + +#include +#include +#include + +namespace rmscore { namespace platform { namespace settings { + +class ILanguageSettings +{ +public: + virtual std::vector GetAppLanguages() = 0; + +public: + static std::shared_ptr Create(); +}; + +}}} // namespace rmscore { namespace platform { namespace settings { + +#endif // ILANGUAGESETTINGS + diff --git a/sdk/rms_sdk/Platform/Settings/ILocalSettings.h b/sdk/rms_sdk/Platform/Settings/ILocalSettings.h new file mode 100644 index 00000000..b16e3b30 --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/ILocalSettings.h @@ -0,0 +1,33 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ILOCALSETTINGS +#define ILOCALSETTINGS + +#include +#include + +namespace rmscore { namespace platform { namespace settings { + +class ILocalSettings +{ +public: + virtual std::string GetString(const std::string& container, const std::string& name, const std::string& defaultValue) = 0; + virtual bool GetBool(const std::string& container, const std::string& name, bool bDefaultValue) = 0; + virtual void SetBool(const std::string& container, const std::string& name, bool bValue) = 0; + + virtual int GetInt(const std::string& container, const std::string& name, int nDefaultValue) = 0; + virtual void SetInt(const std::string& container, const std::string& name, int nValue) = 0; + +public: + static std::shared_ptr Create(const std::string& filename = "appConfig.cfg"); +}; + +}}} //namespace rmscore { namespace platform { namespace settings { +#endif // ILOCALSETTINGS + diff --git a/sdk/rms_sdk/Platform/Settings/LanguageSettings.cpp b/sdk/rms_sdk/Platform/Settings/LanguageSettings.cpp new file mode 100644 index 00000000..6da0095a --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/LanguageSettings.cpp @@ -0,0 +1,25 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include"LanguageSettings.h" + +namespace rmscore { namespace platform { namespace settings { + +std::vector LanguageSettings::GetAppLanguages() +{ + std::vector res; + res.push_back("En-en"); + return res; +} + +std::shared_ptr ILanguageSettings::Create() +{ + return std::make_shared(); +} + +}}} //namespace rmscore { namespace platform { namespace settings { diff --git a/sdk/rms_sdk/Platform/Settings/LanguageSettings.h b/sdk/rms_sdk/Platform/Settings/LanguageSettings.h new file mode 100644 index 00000000..937536f1 --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/LanguageSettings.h @@ -0,0 +1,21 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef LANGUAGESETTINGS +#define LANGUAGESETTINGS + +#include"ILanguageSettings.h" +namespace rmscore { namespace platform { namespace settings { +class LanguageSettings : public ILanguageSettings +{ +public: + virtual std::vector GetAppLanguages() override; +}; +}}} //namespace rmscore { namespace platform { namespace settings { +#endif // LANGUAGESETTINGS + diff --git a/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.cpp b/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.cpp new file mode 100644 index 00000000..f860c07e --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.cpp @@ -0,0 +1,74 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "LocalSettingsQt.h" + +namespace rmscore { +namespace platform { +namespace settings { + +std::shared_ptr ILocalSettings::Create(const std::string& filename) +{ + return std::make_shared(filename.c_str()); +} + +LocalSettingsQt::LocalSettingsQt(const QString& filename) : + impl_(filename) +{} + +std::string LocalSettingsQt::GetString(const std::string& container, + const std::string& name, + const std::string& defaultValue) +{ + std::string key(container.empty() ? name : container + "/" + name); + + return this->impl_.value(key.c_str(), + defaultValue.c_str()).toString().toStdString(); +} + +bool LocalSettingsQt::GetBool(const std::string& container, + const std::string& name, + bool bDefaultValue) +{ + std::string key(container.empty() ? name : container + "/" + name); + + return this->impl_.value(key.c_str(), bDefaultValue).toBool(); +} + +void LocalSettingsQt::SetBool(const std::string& container, + const std::string& name, + bool bValue) +{ + std::string key(container.empty() ? name : container + "/" + name); + + return this->impl_.setValue(key.c_str(), bValue); +} + +int LocalSettingsQt::GetInt(const std::string& container, + const std::string& name, + int nDefaultValue) +{ + std::string key(container.empty() ? name : container + "/" + name); + + return this->impl_.value(key.c_str(), nDefaultValue).toInt(); +} + +void LocalSettingsQt::SetInt(const std::string& container, + const std::string& name, + int nValue) +{ + std::string key(container.empty() ? name : container + "/" + name); + + return this->impl_.setValue(key.c_str(), nValue); +} +} +} +} // namespace rmscore { namespace platform { namespace settings { + +#endif diff --git a/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.h b/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.h new file mode 100644 index 00000000..f24a3260 --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/LocalSettingsQt.h @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef LOCALSETTINGSQTIMPL +#define LOCALSETTINGSQTIMPL + +#include"ILocalSettings.h" +#include + +namespace rmscore { namespace platform { namespace settings { + +class LocalSettingsQt : public ILocalSettings +{ +public: + LocalSettingsQt(const QString& filename); + virtual std::string GetString(const std::string& container, const std::string& name, const std::string& defaultValue) override; + virtual bool GetBool(const std::string& container, const std::string& name, bool bDefaultValue) override; + virtual void SetBool(const std::string& container, const std::string& name, bool bValue) override; + + virtual int GetInt(const std::string& container, const std::string& name, int nDefaultValue) override; + virtual void SetInt(const std::string& container, const std::string& name, int nValue) override; + +private: + QSettings impl_; +}; + +}}} // namespace rmscore { namespace platform { namespace settings { + +#endif // LOCALSETTINGSQTIMPL + diff --git a/sdk/rms_sdk/Platform/Settings/Settings.pro b/sdk/rms_sdk/Platform/Settings/Settings.pro new file mode 100644 index 00000000..1e099f46 --- /dev/null +++ b/sdk/rms_sdk/Platform/Settings/Settings.pro @@ -0,0 +1,27 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformsettings + +TEMPLATE = lib + +DEFINES += QTFRAMEWORK + +CONFIG += staticlib warn_on c++11 debug_and_release + +QT += core network +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += \ + LanguageSettings.cpp \ + LocalSettingsQt.cpp + +HEADERS += \ + ILocalSettings.h \ + ILanguageSettings.h \ + LanguageSettings.h \ + LocalSettingsQt.h + diff --git a/sdk/rms_sdk/Platform/Xml/DomAttributeQt.cpp b/sdk/rms_sdk/Platform/Xml/DomAttributeQt.cpp new file mode 100644 index 00000000..351b0f0c --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomAttributeQt.cpp @@ -0,0 +1,188 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "DomAttributeQt.h" +#include "DomElementQt.h" +#include "DomNodeQt.h" +#include "DomDocumentQt.h" + +std::string DomAttributeQt::name() const +{ + return this->impl_.name().toStdString(); +} +//IDomNode::NodeType DomAttributeQt::nodeType() const +//{ +// return (IDomNode::NodeType)this->impl_.nodeType(); +//} +sp DomAttributeQt::ownerElement() const +{ + QDomElement elem = this->impl_.ownerElement(); + return std::make_shared(elem); +} +std::string DomAttributeQt::value() const +{ + return this->impl_.value().toStdString(); +} + +// from IDomNode + +sp DomAttributeQt::attributes() const +{ + QDomNamedNodeMap map = this->impl_.attributes(); + DomNamedNodeMap* pRes = new DomNamedNodeMap(); + for(int i = 0; i < map.size(); ++i) + { + QDomNode node = map.item(i); + pRes->insert(std::make_pair(node.nodeName().toStdString(), std::make_shared(node))); + } + + return sp(pRes); +} +sp DomAttributeQt::childNodes() const +{ + QDomNodeList list = this->impl_.childNodes(); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +bool DomAttributeQt::hasAttributes() const +{ + return this->impl_.hasAttributes(); +} +bool DomAttributeQt::hasChildNodes() const +{ + return this->impl_.hasChildNodes(); +} +bool DomAttributeQt::isAttr() const +{ + return this->impl_.isAttr(); +} +bool DomAttributeQt::isDocument() const +{ + return this->impl_.isDocument(); +} +bool DomAttributeQt::isElement() const +{ + return this->impl_.isElement(); +} +bool DomAttributeQt::isNull() const +{ + return this->impl_.isNull(); +} +bool DomAttributeQt::isText() const +{ + return this->impl_.isText(); +} +std::string DomAttributeQt::localName() const +{ + return this->impl_.localName().toStdString(); +} +sp DomAttributeQt::namedItem(const std::string & name) const +{ + QDomNode node = this->impl_.namedItem(QString::fromStdString(name)); + return std::make_shared(node); +} +std::string DomAttributeQt::namespaceURI() const +{ + return this->impl_.namespaceURI().toStdString(); +} +std::string DomAttributeQt::nodeName() const +{ + return this->impl_.nodeName().toStdString(); +} +IDomNode::NodeType DomAttributeQt::nodeType() const +{ + return (IDomNode::NodeType)this->impl_.nodeType(); +} +std::string DomAttributeQt::nodeValue() const +{ + return this->impl_.nodeValue().toStdString(); +} +sp DomAttributeQt::ownerDocument() const +{ + QDomDocument doc = this->impl_.ownerDocument(); + return std::make_shared(doc); +} +sp DomAttributeQt::firstChild() const +{ + QDomNode node = this->impl_.firstChild(); + return std::make_shared(node); +} +sp DomAttributeQt::firstChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.firstChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomAttributeQt::lastChild() const +{ + QDomNode node = this->impl_.lastChild(); + return std::make_shared(node); +} +sp DomAttributeQt::lastChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.lastChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomAttributeQt::previousSibling() const +{ + QDomNode node = this->impl_.previousSibling(); + return std::make_shared(node); +} +sp DomAttributeQt::previousSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.previousSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomAttributeQt::nextSibling() const +{ + QDomNode node = this->impl_.nextSibling(); + return std::make_shared(node); +} +sp DomAttributeQt::nextSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.nextSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomAttributeQt::parentNode() const +{ + QDomNode node = this->impl_.parentNode(); + return std::make_shared(node); + +} +std::string DomAttributeQt::prefix() const +{ + return impl_.prefix().toStdString(); +} +sp DomAttributeQt::toAttr() const +{ + QDomAttr attr = this->impl_.toAttr(); + return std::make_shared(attr); +} +sp DomAttributeQt::toDocument() const +{ + QDomDocument doc = this->impl_.toDocument(); + return std::make_shared(doc); +} +sp DomAttributeQt::toElement() const +{ + QDomElement elem = this->impl_.toElement(); + return std::make_shared(elem); +} +std::string DomAttributeQt::toText() const +{ + return this->impl_.toText().data().toStdString(); +} + +#endif + diff --git a/sdk/rms_sdk/Platform/Xml/DomAttributeQt.h b/sdk/rms_sdk/Platform/Xml/DomAttributeQt.h new file mode 100644 index 00000000..ee2893ab --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomAttributeQt.h @@ -0,0 +1,68 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMATTRIBUTEQTIMPL_H +#define IDOMATTRIBUTEQTIMPL_H + +#include "IDomAttribute.h" +#include + +class DomAttributeQt : public IDomAttribute +{ +private: + std::string name() const override; + sp ownerElement() const override; + std::string value() const override; +// form IDomNode + sp attributes() const override; + sp childNodes() const override; + + bool hasAttributes() const override; + bool hasChildNodes() const override; + + bool isAttr() const override; + bool isDocument() const override; + bool isElement() const override; + bool isNull() const override; + bool isText() const override; + + std::string localName() const override; + sp namedItem(const std::string & name) const override; + std::string namespaceURI() const override; + std::string nodeName() const override; + NodeType nodeType() const override; + std::string nodeValue() const override; + sp ownerDocument() const override; + + sp firstChild() const override; + sp firstChildElement(const std::string & tagName = std::string()) const override; + sp lastChild() const override; + sp lastChildElement(const std::string & tagName = std::string()) const override; + sp previousSibling() const override; + sp previousSiblingElement(const std::string & tagName = std::string()) const override; + sp nextSibling() const override; + sp nextSiblingElement(const std::string & tagName = std::string()) const override; + sp parentNode() const override; + std::string prefix() const override; + + sp toAttr() const override; + sp toDocument() const override; + sp toElement() const override; + std::string toText() const override; + +public: + DomAttributeQt(const QDomAttr& other):impl_(other){} + +private: + QDomAttr impl_; +// friend class DomNodeQt; +// friend class DomDocumentQt; +// friend class DomElementQt; +}; + +#endif // IDOMATTRIBUTEQTIMPL_H diff --git a/sdk/rms_sdk/Platform/Xml/DomDocumentQt.cpp b/sdk/rms_sdk/Platform/Xml/DomDocumentQt.cpp new file mode 100644 index 00000000..5203ef39 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomDocumentQt.cpp @@ -0,0 +1,258 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "DomDocumentQt.h" +#include "DomNodeQt.h" +#include "DomAttributeQt.h" +#include "DomElementQt.h" +#include +#include +#include +#include +#include "../Logger/Logger.h" + +sp IDomDocument::create() +{ + return sp(new DomDocumentQt()); +} +bool DomDocumentQt::setContent(const std::string & text, bool namespaceProcessing, std::string & errorMsg, int & errorLine, int & errorColumn) +{ + QString str; + bool res = this->impl_.setContent(QString(text.c_str()), namespaceProcessing, &str, &errorLine, &errorColumn); + errorMsg = str.toStdString(); + return res; +} +bool DomDocumentQt::setContent(const std::string & text, std::string & errorMsg, int & errorLine, int & errorColumn) +{ + QString str; + bool res = this->impl_.setContent(QString(text.c_str()), &str, &errorLine, &errorColumn); + errorMsg = str.toStdString(); + return res; +} + +sp DomDocumentQt::documentElement() const +{ + QDomElement elem = this->impl_.documentElement(); + return std::make_shared(elem); + +} + +sp DomDocumentQt::elementById(const std::string & elementId) +{ + QDomElement elem = this->impl_.elementById(elementId.c_str()); + return std::make_shared(elem); +} + +sp DomDocumentQt::elementsByTagName(const std::string & tagname) const +{ + QDomNodeList list = this->impl_.elementsByTagName(tagname.c_str()); + DomNodeList *pRes = new DomNodeList(); + for(int i = 0; i< list.size(); ++i) + { + QDomNode node = list.at(i); + pRes->push_back(std::make_shared(node)); + } + return sp(pRes); +} + +sp DomDocumentQt::SelectSingleNode(const std::string &xPath) +{ + const QString defaultNsPattern = "declare default element namespace '%1'"; + const QString xpathReqPattern = "%1; %2/%3"; + + QBuffer device; + device.setData(this->impl_.toString().toUtf8()); + device.open(QIODevice::ReadOnly); + QXmlQuery query; + query.bindVariable("inputDocument", &device); + + auto defaultNs = this->impl_.documentElement().toElement().attribute("xmlns"); + Logger::Debug("DomDocumentQt::SelectSingleNode: defaultNs: %s", defaultNs.toStdString().data()); + + QString xpathReq = xpathReqPattern.arg(defaultNsPattern.arg(defaultNs)).arg("doc($inputDocument)").arg(xPath.data()); + query.setQuery(xpathReq); + Logger::Debug("DomDocumentQt::SelectSingleNode: xpathReq: %s", xpathReq.toStdString().data()); + + if ( !query.isValid()) + { + Logger::Error("Error: DomDocumentQt::SelectSingleNode: invalid query."); + return nullptr; + } + QString res; + query.evaluateTo(&res); + if(res.isEmpty()) + { + Logger::Warning("DomDocumentQt::SelectSingleNode: result is empty."); + return nullptr; + } + QDomDocument resDoc; + resDoc.setContent("" + res + ""); + + auto root = resDoc.documentElement(); + + Logger::Debug("DomDocumentQt::SelectSingleNode: resDoc: %s", res.toStdString().data()); + return std::make_shared(resDoc.documentElement()); +} + +// from IDomNode + +sp DomDocumentQt::attributes() const +{ + QDomNamedNodeMap map = this->impl_.attributes(); + DomNamedNodeMap* pRes = new DomNamedNodeMap(); + for(int i = 0; i < map.size(); ++i) + { + QDomNode node = map.item(i); + pRes->insert(std::make_pair(node.nodeName().toStdString(), std::make_shared(node))); + } + + return sp(pRes); +} +sp DomDocumentQt::childNodes() const +{ + QDomNodeList list = this->impl_.childNodes(); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +bool DomDocumentQt::hasAttributes() const +{ + return this->impl_.hasAttributes(); +} +bool DomDocumentQt::hasChildNodes() const +{ + return this->impl_.hasChildNodes(); +} +bool DomDocumentQt::isAttr() const +{ + return this->impl_.isAttr(); +} +bool DomDocumentQt::isDocument() const +{ + return this->impl_.isDocument(); +} +bool DomDocumentQt::isElement() const +{ + return this->impl_.isElement(); +} +bool DomDocumentQt::isNull() const +{ + return this->impl_.isNull(); +} +bool DomDocumentQt::isText() const +{ + return this->impl_.isText(); +} +std::string DomDocumentQt::localName() const +{ + return this->impl_.localName().toStdString(); +} +sp DomDocumentQt::namedItem(const std::string & name) const +{ + QDomNode node = this->impl_.namedItem(QString::fromStdString(name)); + return std::make_shared(node); +} +std::string DomDocumentQt::namespaceURI() const +{ + return this->impl_.namespaceURI().toStdString(); +} +std::string DomDocumentQt::nodeName() const +{ + return this->impl_.nodeName().toStdString(); +} +IDomNode::NodeType DomDocumentQt::nodeType() const +{ + return (IDomNode::NodeType)this->impl_.nodeType(); +} +std::string DomDocumentQt::nodeValue() const +{ + return this->impl_.nodeValue().toStdString(); +} +sp DomDocumentQt::ownerDocument() const +{ + QDomDocument doc = this->impl_.ownerDocument(); + return std::make_shared(doc); +} +sp DomDocumentQt::firstChild() const +{ + QDomNode node = this->impl_.firstChild(); + return std::make_shared(node); +} +sp DomDocumentQt::firstChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.firstChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomDocumentQt::lastChild() const +{ + QDomNode node = this->impl_.lastChild(); + return std::make_shared(node); +} +sp DomDocumentQt::lastChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.lastChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomDocumentQt::previousSibling() const +{ + QDomNode node = this->impl_.previousSibling(); + return std::make_shared(node); +} +sp DomDocumentQt::previousSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.previousSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomDocumentQt::nextSibling() const +{ + QDomNode node = this->impl_.nextSibling(); + return std::make_shared(node); +} +sp DomDocumentQt::nextSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.nextSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomDocumentQt::parentNode() const +{ + QDomNode node = this->impl_.parentNode(); + return std::make_shared(node); + +} +std::string DomDocumentQt::prefix() const +{ + return impl_.prefix().toStdString(); +} +sp DomDocumentQt::toAttr() const +{ + QDomAttr attr = this->impl_.toAttr(); + return std::make_shared(attr); +} +sp DomDocumentQt::toDocument() const +{ + QDomDocument doc = this->impl_.toDocument(); + return std::make_shared(doc); +} +sp DomDocumentQt::toElement() const +{ + QDomElement elem = this->impl_.toElement(); + return std::make_shared(elem); +} +std::string DomDocumentQt::toText() const +{ + return this->impl_.toText().data().toStdString(); +} + +#endif + diff --git a/sdk/rms_sdk/Platform/Xml/DomDocumentQt.h b/sdk/rms_sdk/Platform/Xml/DomDocumentQt.h new file mode 100644 index 00000000..a62adc08 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomDocumentQt.h @@ -0,0 +1,78 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMDOCUMENTQTIPL_H +#define IDOMDOCUMENTQTIPL_H + +#include "IDomDocument.h" +#include +#include + +class DomDocumentQt : public IDomDocument +{ +private: + sp documentElement() const; + sp elementById(const std::string & elementId); + sp elementsByTagName(const std::string & tagname) const; + + bool setContent(const std::string & text, bool namespaceProcessing, std::string & errorMsg, int & errorLine, int & errorColumn) override; + bool setContent(const std::string & text, std::string & errorMsg, int & errorLine, int & errorColumn) override; + + sp SelectSingleNode(const std::string &xPath) override; + +// form IDomNode + sp attributes() const override; + sp childNodes() const override; + + bool hasAttributes() const override; + bool hasChildNodes() const override; + + bool isAttr() const override; + bool isDocument() const override; + bool isElement() const override; + bool isNull() const override; + bool isText() const override; + + std::string localName() const override; + sp namedItem(const std::string & name) const override; + std::string namespaceURI() const override; + std::string nodeName() const override; + NodeType nodeType() const override; + std::string nodeValue() const override; + sp ownerDocument() const override; + + sp firstChild() const override; + sp firstChildElement(const std::string & tagName = std::string()) const override; + sp lastChild() const override; + sp lastChildElement(const std::string & tagName = std::string()) const override; + sp previousSibling() const override; + sp previousSiblingElement(const std::string & tagName = std::string()) const override; + sp nextSibling() const override; + sp nextSiblingElement(const std::string & tagName = std::string()) const override; + sp parentNode() const override; + std::string prefix() const override; + + sp toAttr() const override; + sp toDocument() const override; + sp toElement() const override; + std::string toText() const override; + +public: + DomDocumentQt(const QDomDocument& other):impl_(other){} + DomDocumentQt():impl_(){} + +public: + QDomDocument impl_; +// friend class IDomDocument; +// friend class DomNodeQt; +// friend class DomAttributeQt; +// friend class DomElementQt; + +}; + +#endif // IDOMDOCUMENTQTIPL_H diff --git a/sdk/rms_sdk/Platform/Xml/DomElementQt.cpp b/sdk/rms_sdk/Platform/Xml/DomElementQt.cpp new file mode 100644 index 00000000..ebfb8cfe --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomElementQt.cpp @@ -0,0 +1,248 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "DomElementQt.h" +#include "DomAttributeQt.h" +#include "DomNodeQt.h" +#include "DomDocumentQt.h" +#include +#include +#include +#include + +std::string DomElementQt::attribute(const std::string & name, const std::string & defValue/* = std::string()*/) const +{ + return this->impl_.attribute(QString::fromStdString(name), QString::fromStdString(defValue)).toStdString(); +} +std::string DomElementQt::attributeNS(const std::string nsURI, const std::string & localName, const std::string & defValue/* = std::string()*/) const +{ + return this->impl_.attributeNS(QString::fromStdString(nsURI), localName.c_str(), defValue.c_str()).toStdString(); +} +sp DomElementQt::attributeNode(const std::string & name) +{ + QDomAttr attr = this->impl_.attributeNode(name.c_str()); + return std::make_shared(attr); +} +sp DomElementQt::attributeNodeNS(const std::string & nsURI, const std::string & localName) +{ + QDomAttr attr = this->impl_.attributeNodeNS(nsURI.c_str(), localName.c_str()); + return std::make_shared(attr); +} +//sp DomElementQt::attributes() const +//{ +// QDomNamedNodeMap map = this->impl_.attributes(); +// DomNamedNodeMap* pRes = new DomNamedNodeMap(); +// for(int i = 0; i < map.size(); ++i) +// { +// QDomNode& node = map.item(i); +// pRes->insert(std::make_pair(node.nodeName().toStdString(), std::make_shared(node))); +// } + +// return sp(pRes); +//} +sp DomElementQt::elementsByTagName(const std::string & tagname) const +{ + QDomNodeList list = this->impl_.elementsByTagName(QString::fromStdString(tagname)); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +sp DomElementQt::elementsByTagNameNS(const std::string & nsURI, const std::string & localName) const +{ + QDomNodeList list = this->impl_.elementsByTagNameNS(QString::fromStdString(nsURI), QString::fromStdString(localName)); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +bool DomElementQt::hasAttribute(const std::string & name) const +{ + return this->impl_.hasAttribute(QString::fromStdString(name)); +} +bool DomElementQt::hasAttributeNS(const std::string & nsURI, const std::string & localName) const +{ + return this->impl_.hasAttributeNS(QString::fromStdString(nsURI), QString::fromStdString(localName)); +} +//IDomNode::NodeType DomElementQt::nodeType() const +//{ +// return (IDomNode::NodeType)this->impl_.nodeType(); +//} +std::string DomElementQt::tagName() const +{ + return this->impl_.tagName().toStdString(); +} +std::string DomElementQt::text() const +{ + return this->impl_.text().toStdString(); +} + +// from IDomNode + +sp DomElementQt::attributes() const +{ + QDomNamedNodeMap map = this->impl_.attributes(); + DomNamedNodeMap* pRes = new DomNamedNodeMap(); + for(int i = 0; i < map.size(); ++i) + { + QDomNode node = map.item(i); + pRes->insert(std::make_pair(node.nodeName().toStdString(), std::make_shared(node))); + } + + return sp(pRes); +} +sp DomElementQt::childNodes() const +{ + QDomNodeList list = this->impl_.childNodes(); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +bool DomElementQt::hasAttributes() const +{ + return this->impl_.hasAttributes(); +} +bool DomElementQt::hasChildNodes() const +{ + return this->impl_.hasChildNodes(); +} +bool DomElementQt::isAttr() const +{ + return this->impl_.isAttr(); +} +bool DomElementQt::isDocument() const +{ + return this->impl_.isDocument(); +} +bool DomElementQt::isElement() const +{ + return this->impl_.isElement(); +} +bool DomElementQt::isNull() const +{ + return this->impl_.isNull(); +} +bool DomElementQt::isText() const +{ + return this->impl_.isText(); +} +std::string DomElementQt::localName() const +{ + return this->impl_.localName().toStdString(); +} +sp DomElementQt::namedItem(const std::string & name) const +{ + QDomNode node = this->impl_.namedItem(QString::fromStdString(name)); + return std::make_shared(node); +} +std::string DomElementQt::namespaceURI() const +{ + return this->impl_.namespaceURI().toStdString(); +} +std::string DomElementQt::nodeName() const +{ + return this->impl_.nodeName().toStdString(); +} +IDomNode::NodeType DomElementQt::nodeType() const +{ + return (IDomNode::NodeType)this->impl_.nodeType(); +} +std::string DomElementQt::nodeValue() const +{ + return this->impl_.nodeValue().toStdString(); +} +sp DomElementQt::ownerDocument() const +{ + QDomDocument doc = this->impl_.ownerDocument(); + return std::make_shared(doc); +} +sp DomElementQt::firstChild() const +{ + QDomNode node = this->impl_.firstChild(); + return std::make_shared(node); +} +sp DomElementQt::firstChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.firstChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomElementQt::lastChild() const +{ + QDomNode node = this->impl_.lastChild(); + return std::make_shared(node); +} +sp DomElementQt::lastChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.lastChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomElementQt::previousSibling() const +{ + QDomNode node = this->impl_.previousSibling(); + return std::make_shared(node); +} +sp DomElementQt::previousSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.previousSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomElementQt::nextSibling() const +{ + QDomNode node = this->impl_.nextSibling(); + return std::make_shared(node); +} +sp DomElementQt::nextSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.nextSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomElementQt::parentNode() const +{ + QDomNode node = this->impl_.parentNode(); + return std::make_shared(node); + +} +std::string DomElementQt::prefix() const +{ + return impl_.prefix().toStdString(); +} +sp DomElementQt::toAttr() const +{ + QDomAttr attr = this->impl_.toAttr(); + return std::make_shared(attr); +} +sp DomElementQt::toDocument() const +{ + QDomDocument doc = this->impl_.toDocument(); + return std::make_shared(doc); +} +sp DomElementQt::toElement() const +{ + QDomElement elem = this->impl_.toElement(); + return std::make_shared(elem); +} +std::string DomElementQt::toText() const +{ + return this->impl_.toText().data().toStdString(); +} + +#endif diff --git a/sdk/rms_sdk/Platform/Xml/DomElementQt.h b/sdk/rms_sdk/Platform/Xml/DomElementQt.h new file mode 100644 index 00000000..f0e2b80a --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomElementQt.h @@ -0,0 +1,77 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMELEMENTQTIMPL_H +#define IDOMELEMENTQTIMPL_H + +#include "IDomElement.h" +#include + +class DomElementQt : public IDomElement +{ +private: + std::string attribute(const std::string & name, const std::string & defValue = std::string()) const override; + std::string attributeNS(const std::string nsURI, const std::string & localName, const std::string & defValue = std::string()) const override; + sp attributeNode(const std::string & name) override; + sp attributeNodeNS(const std::string & nsURI, const std::string & localName) override; + sp elementsByTagName(const std::string & tagname) const override; + sp elementsByTagNameNS(const std::string & nsURI, const std::string & localName) const override; + bool hasAttribute(const std::string & name) const override; + bool hasAttributeNS(const std::string & nsURI, const std::string & localName) const override; + std::string tagName() const override; + std::string text() const override; + +// form IDomNode + sp attributes() const override; + sp childNodes() const override; + + bool hasAttributes() const override; + bool hasChildNodes() const override; + + bool isAttr() const override; + bool isDocument() const override; + bool isElement() const override; + bool isNull() const override; + bool isText() const override; + + std::string localName() const override; + sp namedItem(const std::string & name) const override; + std::string namespaceURI() const override; + std::string nodeName() const override; + NodeType nodeType() const override; + std::string nodeValue() const override; + sp ownerDocument() const override; + + sp firstChild() const override; + sp firstChildElement(const std::string & tagName = std::string()) const override; + sp lastChild() const override; + sp lastChildElement(const std::string & tagName = std::string()) const override; + sp previousSibling() const override; + sp previousSiblingElement(const std::string & tagName = std::string()) const override; + sp nextSibling() const override; + sp nextSiblingElement(const std::string & tagName = std::string()) const override; + sp parentNode() const override; + std::string prefix() const override; + + sp toAttr() const override; + sp toDocument() const override; + sp toElement() const override; + std::string toText() const override; + +public: + DomElementQt(const QDomElement& other):impl_(other){} + +private: + QDomElement impl_; +// friend class DomNodeQt; +// friend class DomDocumentQt; +// friend class DomAttributeQt; + +}; + +#endif // IDOMELEMENTQTIMPL_H diff --git a/sdk/rms_sdk/Platform/Xml/DomNamedNodeMap.h b/sdk/rms_sdk/Platform/Xml/DomNamedNodeMap.h new file mode 100644 index 00000000..ce1b4c86 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomNamedNodeMap.h @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DOMNAMEDNODEMAP +#define DOMNAMEDNODEMAP + +#include +#include +#include "../../Common/CommonTypes.h" + +class IDomNode; +using DomNamedNodeMap = rmscore::common::HashMapString>; + +#endif // DOMNAMEDNODEMAP + diff --git a/sdk/rms_sdk/Platform/Xml/DomNodeList.h b/sdk/rms_sdk/Platform/Xml/DomNodeList.h new file mode 100644 index 00000000..1684eaff --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomNodeList.h @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DOMNODELIST +#define DOMNODELIST + +#include +#include + +class IDomNode; +using DomNodeList = std::list>; + +#endif // DOMNODELIST + diff --git a/sdk/rms_sdk/Platform/Xml/DomNodeQt.cpp b/sdk/rms_sdk/Platform/Xml/DomNodeQt.cpp new file mode 100644 index 00000000..f9d30d33 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomNodeQt.cpp @@ -0,0 +1,167 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifdef QTFRAMEWORK +#include "DomNodeQt.h" +#include "DomDocumentQt.h" +#include "DomAttributeQt.h" +#include "DomDocumentQt.h" +#include "DomElementQt.h" + +sp DomNodeQt::attributes() const +{ + QDomNamedNodeMap map = this->impl_.attributes(); + DomNamedNodeMap* pRes = new DomNamedNodeMap(); + for(int i = 0; i < map.size(); ++i) + { + QDomNode node = map.item(i); + pRes->insert(std::make_pair(node.nodeName().toStdString(), std::make_shared(node))); + } + + return sp(pRes); +} +sp DomNodeQt::childNodes() const +{ + QDomNodeList list = this->impl_.childNodes(); + DomNodeList* pRes = new DomNodeList(); + for(int i = 0; i < list.size(); ++i) + { + QDomNode node = list.item(i); + pRes->push_back( std::make_shared(node)); + } + + return sp(pRes); +} +bool DomNodeQt::hasAttributes() const +{ + return this->impl_.hasAttributes(); +} +bool DomNodeQt::hasChildNodes() const +{ + return this->impl_.hasChildNodes(); +} +bool DomNodeQt::isAttr() const +{ + return this->impl_.isAttr(); +} +bool DomNodeQt::isDocument() const +{ + return this->impl_.isDocument(); +} +bool DomNodeQt::isElement() const +{ + return this->impl_.isElement(); +} +bool DomNodeQt::isNull() const +{ + return this->impl_.isNull(); +} +bool DomNodeQt::isText() const +{ + return this->impl_.isText(); +} +std::string DomNodeQt::localName() const +{ + return this->impl_.localName().toStdString(); +} +sp DomNodeQt::namedItem(const std::string & name) const +{ + QDomNode node = this->impl_.namedItem(QString::fromStdString(name)); + return std::make_shared(node); +} +std::string DomNodeQt::namespaceURI() const +{ + return this->impl_.namespaceURI().toStdString(); +} +std::string DomNodeQt::nodeName() const +{ + return this->impl_.nodeName().toStdString(); +} +IDomNode::NodeType DomNodeQt::nodeType() const +{ + return (IDomNode::NodeType)this->impl_.nodeType(); +} +std::string DomNodeQt::nodeValue() const +{ + return this->impl_.nodeValue().toStdString(); +} +sp DomNodeQt::ownerDocument() const +{ + QDomDocument doc = this->impl_.ownerDocument(); + return std::make_shared(doc); +} +sp DomNodeQt::firstChild() const +{ + QDomNode node = this->impl_.firstChild(); + return std::make_shared(node); +} +sp DomNodeQt::firstChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.firstChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomNodeQt::lastChild() const +{ + QDomNode node = this->impl_.lastChild(); + return std::make_shared(node); +} +sp DomNodeQt::lastChildElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.lastChildElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomNodeQt::previousSibling() const +{ + QDomNode node = this->impl_.previousSibling(); + return std::make_shared(node); +} +sp DomNodeQt::previousSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.previousSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomNodeQt::nextSibling() const +{ + QDomNode node = this->impl_.nextSibling(); + return std::make_shared(node); +} +sp DomNodeQt::nextSiblingElement(const std::string & tagName/* = std::string()*/) const +{ + QDomElement elem = this->impl_.nextSiblingElement(QString::fromStdString(tagName)); + return std::make_shared(elem); +} +sp DomNodeQt::parentNode() const +{ + QDomNode node = this->impl_.parentNode(); + return std::make_shared(node); + +} +std::string DomNodeQt::prefix() const +{ + return impl_.prefix().toStdString(); +} +sp DomNodeQt::toAttr() const +{ + QDomAttr attr = this->impl_.toAttr(); + return sp(new DomAttributeQt(attr)); +} +sp DomNodeQt::toDocument() const +{ + QDomDocument doc = this->impl_.toDocument(); + return std::make_shared(doc); +} +sp DomNodeQt::toElement() const +{ + QDomElement elem = this->impl_.toElement(); + return std::make_shared(elem); +} +std::string DomNodeQt::toText() const +{ + return this->impl_.toText().data().toStdString(); +} +#endif diff --git a/sdk/rms_sdk/Platform/Xml/DomNodeQt.h b/sdk/rms_sdk/Platform/Xml/DomNodeQt.h new file mode 100644 index 00000000..217b6356 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/DomNodeQt.h @@ -0,0 +1,64 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMNODEQTIMPL_H +#define IDOMNODEQTIMPL_H + +#include "IDomNode.h" +#include + +class DomNodeQt : public IDomNode +{ +private: + sp attributes() const override; + sp childNodes() const override; + + bool hasAttributes() const override; + bool hasChildNodes() const override; + + bool isAttr() const override; + bool isDocument() const override; + bool isElement() const override; + bool isNull() const override; + bool isText() const override; + + std::string localName() const override; + sp namedItem(const std::string & name) const override; + std::string namespaceURI() const override; + std::string nodeName() const override; + NodeType nodeType() const override; + std::string nodeValue() const override; + sp ownerDocument() const override; + + sp firstChild() const override; + sp firstChildElement(const std::string & tagName = std::string()) const override; + sp lastChild() const override; + sp lastChildElement(const std::string & tagName = std::string()) const override; + sp previousSibling() const override; + sp previousSiblingElement(const std::string & tagName = std::string()) const override; + sp nextSibling() const override; + sp nextSiblingElement(const std::string & tagName = std::string()) const override; + sp parentNode() const override; + std::string prefix() const override; + + sp toAttr() const override; + sp toDocument() const override; + sp toElement() const override; + std::string toText() const override; + +public: + DomNodeQt(const QDomNode& other):impl_(other){} + +private: + QDomNode impl_; +// friend class DomDocumentQt; +// friend class DomElementQt; +// friend class DomAttributeQt; +}; + +#endif // IDOMNODEQTIMPL_H diff --git a/sdk/rms_sdk/Platform/Xml/IDomAttribute.h b/sdk/rms_sdk/Platform/Xml/IDomAttribute.h new file mode 100644 index 00000000..5ffee8bb --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/IDomAttribute.h @@ -0,0 +1,25 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMATTRIBUTE_H +#define IDOMATTRIBUTE_H + +#include +#include "IDomNode.h" + +class IDomElement; + +class IDomAttribute : public IDomNode +{ +public: + virtual std::string name() const= 0; + virtual sp ownerElement() const= 0; + virtual std::string value() const= 0; +}; + +#endif // IDOMATTRIBUTE_H diff --git a/sdk/rms_sdk/Platform/Xml/IDomDocument.h b/sdk/rms_sdk/Platform/Xml/IDomDocument.h new file mode 100644 index 00000000..ad5fe415 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/IDomDocument.h @@ -0,0 +1,32 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMDOCUMENT_H +#define IDOMDOCUMENT_H + +#include +#include "IDomNode.h" + +class IDomElement; + +class IDomDocument : public IDomNode +{ +public: + virtual sp documentElement() const = 0; + virtual sp elementById(const std::string & elementId) = 0; + virtual sp elementsByTagName(const std::string & tagname) const = 0; + + virtual bool setContent(const std::string & text, bool namespaceProcessing, std::string & errorMsg, int & errorLine, int & errorColumn) = 0; + virtual bool setContent(const std::string & text, std::string & errorMsg, int & errorLine, int & errorColumn) = 0; + + virtual sp SelectSingleNode(const std::string &xPath) = 0; +public: + static sp create(); +}; + +#endif // IDOMDOCUMENT_H diff --git a/sdk/rms_sdk/Platform/Xml/IDomElement.h b/sdk/rms_sdk/Platform/Xml/IDomElement.h new file mode 100644 index 00000000..7af69f9e --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/IDomElement.h @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMELEMENT_H +#define IDOMELEMENT_H + +#include +#include "IDomNode.h" + +class IDomAttribute; + +class IDomElement : public IDomNode +{ +public: + virtual std::string attribute(const std::string & name, const std::string & defValue = std::string()) const = 0; + virtual std::string attributeNS(const std::string nsURI, const std::string & localName, const std::string & defValue = std::string()) const = 0; + virtual sp attributeNode(const std::string & name) = 0; + virtual sp attributeNodeNS(const std::string & nsURI, const std::string & localName) = 0; + virtual sp elementsByTagName(const std::string & tagname) const = 0; + virtual sp elementsByTagNameNS(const std::string & nsURI, const std::string & localName) const = 0; + virtual bool hasAttribute(const std::string & name) const = 0; + virtual bool hasAttributeNS(const std::string & nsURI, const std::string & localName) const = 0; + virtual std::string tagName() const = 0; + virtual std::string text() const = 0; +}; +#endif // IDOMELEMENT_H diff --git a/sdk/rms_sdk/Platform/Xml/IDomNode.h b/sdk/rms_sdk/Platform/Xml/IDomNode.h new file mode 100644 index 00000000..f19a9eb7 --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/IDomNode.h @@ -0,0 +1,78 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDOMNODE_H +#define IDOMNODE_H + +#include +#include +#include "../../Common/CommonTypes.h" +#include "DomNamedNodeMap.h" +#include "DomNodeList.h" + +template +using sp = std::shared_ptr; + +class IDomDocument; +class IDomAttribute; +class IDomElement; + +class IDomNode +{ +public: + enum class NodeType + { + ElementNode = 1, + AttributeNode = 2, + TextNode = 3, + DocumentNode = 10, + }; + +public: + virtual sp attributes() const= 0; + virtual sp childNodes() const= 0; + + virtual bool hasAttributes() const= 0; + virtual bool hasChildNodes() const= 0; + + virtual bool isAttr() const= 0; + virtual bool isDocument() const= 0; + virtual bool isElement() const= 0; + virtual bool isNull() const= 0; + virtual bool isText() const= 0; + + virtual std::string localName() const= 0; + virtual sp namedItem(const std::string & name) const= 0; + virtual std::string namespaceURI() const= 0; + virtual std::string nodeName() const = 0; + virtual NodeType nodeType() const = 0; + virtual std::string nodeValue() const = 0; + virtual sp ownerDocument() const = 0; + + virtual sp firstChild() const = 0; + virtual sp firstChildElement(const std::string & tagName = std::string()) const = 0; + virtual sp lastChild() const = 0; + virtual sp lastChildElement(const std::string & tagName = std::string()) const = 0; + virtual sp previousSibling() const= 0; + virtual sp previousSiblingElement(const std::string & tagName = std::string()) const = 0; + virtual sp nextSibling() const= 0; + virtual sp nextSiblingElement(const std::string & tagName = std::string()) const = 0; + virtual sp parentNode() const = 0; + virtual std::string prefix() const = 0; + + virtual sp toAttr() const = 0; + virtual sp toDocument() const = 0; + virtual sp toElement() const = 0; + virtual std::string toText() const = 0; +}; + +using DomNamedNodeMap = rmscore::common::HashMapString>; +#include +using DomNodeList = std::list>; + +#endif // IDOMNODE_H diff --git a/sdk/rms_sdk/Platform/Xml/Xml.pro b/sdk/rms_sdk/Platform/Xml/Xml.pro new file mode 100644 index 00000000..9fd41f7f --- /dev/null +++ b/sdk/rms_sdk/Platform/Xml/Xml.pro @@ -0,0 +1,33 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/rms/platform +TARGET = platformxml + +QT += xml xmlpatterns +QT -= gui + +TEMPLATE = lib +CONFIG += staticlib c++11 debug_and_release + +DEFINES += QTFRAMEWORK + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES += \ + DomAttributeQt.cpp \ + DomDocumentQt.cpp \ + DomElementQt.cpp \ + DomNodeQt.cpp + +HEADERS += \ + IDomDocument.h \ + IDomNode.h \ + IDomElement.h \ + IDomAttribute.h \ + DomNamedNodeMap.h \ + DomNodeList.h \ + DomAttributeQt.h \ + DomDocumentQt.h \ + DomElementQt.h \ + DomNodeQt.h diff --git a/sdk/rms_sdk/RestClients/AuthenticationHandler.cpp b/sdk/rms_sdk/RestClients/AuthenticationHandler.cpp new file mode 100644 index 00000000..efda2905 --- /dev/null +++ b/sdk/rms_sdk/RestClients/AuthenticationHandler.cpp @@ -0,0 +1,265 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include "AuthenticationHandler.h" +#include "../ModernAPI/RMSExceptions.h" +#include "../Platform/Http/IHttpClient.h" +#include "../Platform/Http/IUri.h" +#include "../Common/CommonTypes.h" + +using namespace rmscore::modernapi; +using namespace rmscore::platform::http; +using namespace std; + +namespace rmscore { +namespace restclients { +string AuthenticationHandler::GetAccessTokenForUrl( + const string & sUrl, + IAuthenticationCallbackImpl& callback) +{ + AuthenticationChallenge challenge; + + // get the challenge only if needed (e.g., it's not needed in Office case + // for now) + if (callback.NeedsChallenge()) + { + challenge = GetChallengeForUrl(sUrl); + } + + return callback.GetAccessToken(static_cast( + challenge)); +} + +AuthenticationChallenge AuthenticationHandler::GetChallengeForUrl( + const string& sUrl) +{ + // do a dummy get to the url to get the auth challenge + + auto pHttpClient = IHttpClient::Create(); + + common::ByteArray response; + StatusCode nStatusCode = pHttpClient->Get(sUrl, response); + + // this must be an authenticated endpoint and we must get a 401 + // (unauthorized). + // Otherwise, there is something wrong with the server + if (StatusCode::UNAUTHORIZED != nStatusCode) { + throw exceptions::RMSNetworkException("Server error", + exceptions::RMSNetworkException::ServerError); + } + + try + { + // the challenge must be in WWW-Authenticate header + auto header = pHttpClient->GetResponseHeader("WWW-Authenticate"); + return ParseChallengeHeader(header, sUrl); + } + catch (exceptions::RMSException) + { + // if couldn't find the header or couldn't parse it, that means the server + // returned an invalid response. + throw exceptions::RMSNetworkException("Server error", + exceptions::RMSNetworkException::ServerError); + } +} + +// trims the specified characters +static string TrimString(const string& str, const char *sCharacters) +{ + auto iFirst = str.find_first_not_of(sCharacters); + + if (string::npos == iFirst) + { + return string(); + } + + auto iLast = str.find_last_not_of(sCharacters); + + if (string::npos == iLast) + { + return string(); + } + + return str.substr(iFirst, iLast - iFirst + 1); +} + +// trims whitespace +static string TrimWhiteSpace(const string& str) +{ + const char sWhiteSpaceCharacters[] = " \t\r\n"; + + return TrimString(str, sWhiteSpaceCharacters); +} + +// splits the string by the specified delimiter +static vectorSplitString(const string& str, char wDelimiter) +{ + vector result; + + size_t nPosition = 0; + + while (nPosition < str.size()) + { + auto nDelimiterPosition = str.find(wDelimiter, nPosition); + + if (string::npos == nDelimiterPosition) + { + result.push_back(str.substr(nPosition)); + break; + } + else + { + result.push_back(str.substr(nPosition, nDelimiterPosition - nPosition)); + nPosition = nDelimiterPosition + 1; + } + } + + return result; +} + +// parses a name=value pair +static pairParseNameValuePair(const string& str) +{ + auto split = SplitString(str, L'='); + + if (2 == split.size()) + { + // trim whitespace and double quotes from both name and value + return make_pair( + TrimString(TrimWhiteSpace(split[0]), "\""), + TrimString(TrimWhiteSpace(split[1]), "\"")); + } + else + { + // not a valid name and value pair so return empty + return make_pair(string(), string()); + } +} + +// parses name=value pairs delimited by ',' +static vector >ParseNameValuePairList(const string& str) +{ + auto split = SplitString(str, L','); + + vector > pairs; + + for_each(begin(split), end(split), + [&pairs](const string& str) + { + auto pair = ParseNameValuePair(str); + + if (!pair.first.empty()) + { + pairs.push_back(move(pair)); + } + }); + + return move(pairs); +} + +// validates that the string starts with the prefix and trims the prefix +static string ValidateAndTrimStringPrefix(const string& str, + const string& prefix) +{ + if (0 == _strnicmp(prefix.c_str(), str.c_str(), prefix.size())) + { + return str.substr(prefix.size()); + } + else + { + return string(); + } +} + +AuthenticationChallenge AuthenticationHandler::ParseChallengeHeader( + const string& header, + const string& url) +{ + // verify that this is a bearer challenge (i.e., starts with "Bearer ") + auto trimmed = ValidateAndTrimStringPrefix(header, "Bearer "); + + if (trimmed.empty()) + { + throw exceptions::RMSNetworkException("Challenge is not bearer", + exceptions::RMSNetworkException::ServerError); + } + + + // parse name value pairs + auto pairs = ParseNameValuePairList(trimmed); + + AuthenticationChallenge challenge; + + // find the values of authorization_uri (authorization), realm and scope and + // fill out the challenge struct + for_each(begin(pairs), end(pairs), + [&challenge](const pair& p) + { + if ((0 == + _strcmpi("authorization_uri", + p.first.c_str())) || + (0 == _strcmpi("authorization", p.first.c_str()))) + { + challenge.authority = p.second; + } + else if (0 == _strcmpi("realm", p.first.c_str())) + { + challenge.resource = p.second; + } + else if (0 == _strcmpi("scope", p.first.c_str())) + { + challenge.scope = p.second; + } + }); + + if (challenge.authority.empty()) { + throw exceptions::RMSNetworkException( + "Invalid challenge returned by the server.", + exceptions::RMSNetworkException::ServerError); + } + + // if the resource (realm) is not in the header, use the source url's hostname + // with the port + if (challenge.resource.empty()) + { + auto uri = IUri::Create(url); + + // validate the scheme (should be either http or https) + auto scheme = uri->GetScheme(); + + if ((scheme.compare("http") != 0) && (scheme.compare("https") != 0)) + { + throw exceptions::RMSNetworkException("Invalid scheme", + exceptions::RMSNetworkException::ServerError); + } + + challenge.resource = uri->GetHost(); + + // if the port number is not in the hostname add it + if (string::npos == challenge.resource.find(L':')) + { + char sPort[20]; + #ifdef __GNUC__ + snprintf(sPort, sizeof(sPort), "%d", uri->GetPort()); +#else // ifdef __GNUC__ + _snprintf_s(sPort, sizeof(sPort), "%d", uri->GetPort()); +#endif // ifdef __GNUC__ + challenge.resource += ":"; + challenge.resource += sPort; + } + } + + return challenge; +} +} // namespace restclients +} // namespace rmscore diff --git a/sdk/rms_sdk/RestClients/AuthenticationHandler.h b/sdk/rms_sdk/RestClients/AuthenticationHandler.h new file mode 100644 index 00000000..a6b44f5f --- /dev/null +++ b/sdk/rms_sdk/RestClients/AuthenticationHandler.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_AUTHENTICATIONHANDLER_H_ +#define _RMS_LIB_AUTHENTICATIONHANDLER_H_ + +#include "../ModernAPI/IAuthenticationCallbackImpl.h" +#include + +namespace rmscore { +namespace restclients { +class AuthenticationHandler { +public: + + static std::string GetAccessTokenForUrl( + const std::string & sUrl, + modernapi::IAuthenticationCallbackImpl & callback); + +private: + + static modernapi::AuthenticationChallenge GetChallengeForUrl( + const std::string& sUrl); + static modernapi::AuthenticationChallenge ParseChallengeHeader( + const std::string& header, + const std::string& url); +}; +} // namespace restclients +} // namespace rmscore +#endif // _RMS_LIB_AUTHENTICATIONHANDLER_H_ diff --git a/sdk/rms_sdk/RestClients/CXMLUtils.cpp b/sdk/rms_sdk/RestClients/CXMLUtils.cpp new file mode 100644 index 00000000..e4fbaf53 --- /dev/null +++ b/sdk/rms_sdk/RestClients/CXMLUtils.cpp @@ -0,0 +1,199 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "../ModernAPI/RMSExceptions.h" +#include "../Common/CommonTypes.h" +#include "CXMLUtils.h" + +using namespace std; + +namespace rmscore { +namespace restclients { +static bool DoesTagMatch(const char *szTag, const string& strName) +{ + return !_strnicmp(szTag, strName.c_str(), strName.size()) && + !isalnum(*(szTag + strName.size())); // check that the character after + // the name is not a letter or + // digit +} + +bool CXMLUtils::FindTag(const char *szXML, + const string& strTagName, + const char *& szStart, + const char *& szEnd) +{ + bool found = false; + bool inQuote = false; + bool inTag = false; + bool inComment = false; + char quoteChar = '\0'; + + static const char szCommentStart[] = ""; + + static const int nCommentStartLen = sizeof(szCommentStart) - 1; // -1 for + // null + // terminator + static const int nCommentEndLen = sizeof(szCommentEnd) - 1; // -1 for + + // null + // terminator + + while (*szXML) + { + if (inComment) + { + if (!_strnicmp(szXML, szCommentEnd, nCommentEndLen)) + { + // reached to the end of the comment, so set inComment to true, + // skip the "-->" and continue with the loop + inComment = false; + szXML += nCommentEndLen; + continue; + } + } + else if (!_strnicmp(szXML, szCommentStart, nCommentStartLen)) + { + // encountered a start of a comment so set inComment to true, + // skip the Header:"); + foreach (const QNetworkReply::RawHeaderPair& pair, pReply->rawHeaderPairs()) + { + StringStream ss; ss << pair.first.toStdString() << ": " << pair.second.toStdString(); + Logger::info(Tag().toStdString(), ss.str()); + } + } + + QByteArray body = pReply->readAll(); + if (body.length() > 0) + { + Logger::info(Tag().toStdString(), "==> Body:"); + Logger::info(Tag().toStdString(), String(body.begin(), body.end())); + } +*/ + QNetworkReply::NetworkError error_type = pReply->error(); + if (error_type == QNetworkReply::NoError) + { + this->processAuthReply(pReply); + } + else + { + const QString ERROR("error"); + const QString ACCESS_DENIED("access_denied"); + const QString ERROR_SUBCODE("error_subcode"); + const QString CANCELED("cancel"); + + QUrl replyUri = QUrl(pReply->url()); +// Logger::info(Tag().toStdString(), replyUri.toString().toStdString()); + qDebug() << Tag() << ": " << replyUri.toString(); + + const QString redirectUri = replyUri.scheme() + "://" + replyUri.host(); + if (redirectUri.compare(redirectUrl_, Qt::CaseInsensitive) == 0) + { + QUrlQuery query(replyUri); + if(query.hasQueryItem(ERROR) + && query.queryItemValue(ERROR).compare(ACCESS_DENIED, Qt::CaseInsensitive) == 0 + && query.hasQueryItem(ERROR_SUBCODE) + && query.queryItemValue(ERROR_SUBCODE).compare(CANCELED, Qt::CaseInsensitive) == 0) + { + this->reject(); + } + } + else + { + QString errMsg = QString("WebAuthenticationDialog error: %1").arg(pReply->errorString()); + qDebug() << Tag() << ": " << errMsg; +// Logger::info(Tag().toStdString(), errMsg.toStdString()); + this->reject(); + throw RmsauthException(String(errMsg.toStdString())); + } + } + + pReply->deleteLater(); +} + +void Dialog::processAuthReply(QNetworkReply* pReply) +{ + if (pReply->rawHeaderPairs().length() > 0) + { + QByteArray location = pReply->rawHeader("Location"); + if(!location.isEmpty()) + { + QUrl locationUri = QUrl(location); + const QString redirectUri = locationUri.scheme() + "://" + locationUri.host(); + if(redirectUri.compare(redirectUrl_, Qt::CaseInsensitive) == 0) + { +// Logger::info(Tag().toStdString(), "==> pReply->url: %", pReply->url().toString().toStdString()); +// Logger::info(Tag().toStdString(), "==> locationUri: %", location.toStdString()); + + respondUrl_ = locationUri.toString(); + this->accept(); + } + } + } +} diff --git a/sdk/rmsauth_sdk/WebAuthDialog/Dialog.h b/sdk/rmsauth_sdk/WebAuthDialog/Dialog.h new file mode 100644 index 00000000..1b9a8391 --- /dev/null +++ b/sdk/rmsauth_sdk/WebAuthDialog/Dialog.h @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DIALOG_H +#define DIALOG_H + +#include +#include +#include + +#if defined(RMSAUTH_WEB_AUTH_DIALOG_LIBRARY) +# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT +#else +# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT +#endif + +namespace Ui { +class Dialog; +} + +class QNetworkReply; + +class MYSHAREDLIB_EXPORT Dialog : public QDialog +{ + Q_OBJECT + static const QString& Tag() {static const QString tag="Dialog"; return tag;} +public: + explicit Dialog(const QString& requestUrl, const QString& redirectUrl, bool useCookie = false, QWidget *parent = 0); + ~Dialog(); + + const QString& respondUrl() const {return respondUrl_;} + void clearCookie(); + +protected: + void showEvent(QShowEvent * event) override; + +private: + Ui::Dialog *ui; + QString requestUrl_; + QString redirectUrl_; + QString respondUrl_; + bool useCookie_; + +private slots: + void slot_webView_loadFinished(bool); + void slot_authManager_finished(QNetworkReply *); + +private: + void processAuthReply(QNetworkReply *reply); + +}; + +#endif // DIALOG_H diff --git a/sdk/rmsauth_sdk/WebAuthDialog/Dialog.ui b/sdk/rmsauth_sdk/WebAuthDialog/Dialog.ui new file mode 100644 index 00000000..2eeff130 --- /dev/null +++ b/sdk/rmsauth_sdk/WebAuthDialog/Dialog.ui @@ -0,0 +1,128 @@ + + + Dialog + + + + 0 + 0 + 509 + 787 + + + + WebAuthenticationDialog + + + background-color:white; + + + + + + background-color:white; + + + + about:blank + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 128 + 20 + + + + + + + + Qt::LeftToRight + + + background-color:yellow; + + + + + + :/images/loading.gif + + + false + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QWebView + QWidget +
QtWebKitWidgets/QWebView
+
+
+ + + + +
diff --git a/sdk/rmsauth_sdk/WebAuthDialog/WebAuthDialog.pro b/sdk/rmsauth_sdk/WebAuthDialog/WebAuthDialog.pro new file mode 100644 index 00000000..25c821b5 --- /dev/null +++ b/sdk/rmsauth_sdk/WebAuthDialog/WebAuthDialog.pro @@ -0,0 +1,40 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin +TARGET = rmsauthWebAuthDialog + +QT += core widgets webkitwidgets network + +TEMPLATE = lib + +DEFINES += RMSAUTH_WEB_AUTH_DIALOG_LIBRARY + +CONFIG += plugin c++11 debug_and_release warn_on + +INCLUDEPATH = ../rmsauth/rmsauth + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +SOURCES +=\ + Dialog.cpp \ + Autosaver.cpp \ + CookieJar.cpp + +HEADERS += Dialog.h \ + Autosaver.h \ + CookieJar.h + +FORMS += Dialog.ui + +RESOURCES = res.qrc + +unix { + contains(QMAKE_HOST.arch, x86_64) { + target.path = /usr/lib64 + INSTALLS += target + } else { + target.path += /usr/lib + INSTALLS += target + } +} diff --git a/sdk/rmsauth_sdk/WebAuthDialog/images/loading.gif b/sdk/rmsauth_sdk/WebAuthDialog/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..3070e2e97f7bcb7f8d420313c61cd5ffb6843042 GIT binary patch literal 4400 zcmdT{=U)`(+MZz+Sx1!7pcxhCT@)iM7#Uko6NRxrY$1p-niw0gq9KaiWY_Hl*oCDm zWnp2dOOf7{r3#4Br1vH(y@`N`XZ4)lIiB+$ywB(PFju?p>$d)WpT)K_#XvFeYBzBH z{Q29rZ`0{?9*-v!3PmE3SS?d|Q|-Q7JsJ$-$BLqkKu!^0yZBcr3E zV`F3EiqNp|h{z~qbWCjAqxgixq~w&;wDgS3tn9~6a#Xo_`2~eVPm4=R zpOrm-QC?A5RsFK2wywURv8lPGwXMCQv#Y!3Rj>MWU;n`1(D2CU*!aYo$+uI}Gw){K z&wT(O*uW-Up35YELH)HjJ~*F?tl1x6lMqrUL^oY-E>2K96;XBz48BhcEs+=>QT|#o zW~ZxX{#^mDa-*Ft8JwqU3xG_4@0L|ofaPY(!`hfV>8k!3pfUouLp_;k!>*37iQ0a7 z#u+#i>lU|9``tz3AIT1BXAha`(<>j%Iexi(A${vmNcg^p#zU+#L#=!Nx}E93m&C1= zn;NR^ozOo^RX0tZvxHU57oe+2kjtOPABC2fZ8#@3=vsF`cgNC;w?aF6FG~WJ8lzW} zQZ9I*4&@yC%r{p&5$Edj6IGK{Xy*Nmc3@IUt^c=%mf}m1&Sjwv=eoVWUX_1SxBXme zZQsKkoWS<#r?ZFV9?ZP0|FEd9CE)SwyQ%U1w(?!}3k-bPD;S8D(nv-3PNvWicm?nD z+J%YErwuJEC;+HWW-v)4@@W;B;baML7UWgX5sIzlLoNlj%Hqy(W8Jl(*lXSJpC}c7Tv0&0o;SQDdv1J()9WuE} zPC6Yz4%@fcFXKFOJxZ~J5VLwf=h{Y#aF>Oxz85@MwwKn538dm7Wu2LtPT~nn_PE^r zyTRD{Dtva0+xBJmF1jt)YGUMmZ)fR+h{KFh3VoC6^jCCbe!DVy-A{MUa0nMl1ZaK2 zWHmpSSfLcIxn)wodh!#zjLhAbVMMdvPdO``eXas^l#>?*Q|ix052iNX>K{yN=a>$q zcY9wM%20<#4`mLd_77!^6qycZPt;x+emwOmdicrgWdCpupkp?oB7NyNl1p9}Gm@wK z&A>=LVr@2Bpg;eZ<7gqeatZmfXq*7{1FHZ`6ODE{O%n|Uioy_=%64^Q0`49FD8NNh znndCSW4;WC2C|@V$ODAYAdwFk3L-9S99E*#WLGF&DaSE9-|cZcA}>K73rb4LUX(^u z$|KO1z7an4ZWzRG7PZ2~9V~(YN55hcYF_^UZHU17>c%Fheel@$5N+z}ChK86()HN9 z%H6#nW4Ch$2h{J3|Fr-`K5TZDnm3xeu*@xg-ZR*xvRbWo(>biOOR?MhsDqLI?qkm+ zZl|%Cb4S?R!1aIzN5yvu(+)TFFWKJ6ckXc3C;w+2oB$4JK(Eq(Zu$tCi9#Tc z#{fWtB@&|`mk-jsX@H-bSfrsM7*@biKNnoa2$DmnjEY1=%3`1ZB?F28qgX*fk1}%n zB!P&b%7S197FsF80T`vykm3dzic#C(j;;(GPiXHiL6C}3_wmULY-&1w z;=NK`0~wQLWaJ@Pb?mAJ9|V2T!K-?L4!&kns{qxYbeJ`UQU}$; zP*v|#%bJM|^wkd`?btk4)T!-95c>iPAF&wLOZ@g?j0L%VwJT-OOD=RHHJ34tKa(%>>kKku&rSW89e4i?|XjJDoGT~@IeAZgXX z;;%UcPOFa=sDE~)Z1pxhzDziJ#XeZN@op3yaYbHS8@?`ZG3j2tA($ngp1iynI}+xu zzcY5(e_4A!fCI#*RrfK^Oe%&^sqBxdj!i`+5(Gu07$FXj(L6kZr3x4ej9?MrSTK)< zDQGZ^L`Ep%P@xMRpOlmukj~2zqd9P{h+7a@T$;@b&n z@kadw0%SoRGj-HoEYZ2@m3@1xdkX-pNOk7JS_c96_=|6U|Kint+4^mTsMB~vncVH{ z#Kg9^j;IG9P=iQSyZuGOXxHv4kfm3w(jVib@YY zKiRjwph;9+6Gc32=n}Ow!NdKW>Ylw-zf3_$z5Q_pHUc&2%9x-6@;Mju=nV<8eopTYjYiES5F~u#fb- zI0fIE3kZu1r`*^*zff%f(2qoXpAn@(+M|vFixtb14henL!10vCtimf_*d<)7R-Sy8 zs$ut70BE!!v2KaO*UaB@WT;7>4g4zp5PynFQIbwGs-|N5WYOg<;ISZN7%fVebXN#kb z*wT0H{A=sPZHY16%Gzi9gQ6eAmfW9{F1M7XL?5&MW`O$R3cA1jhdASOC({R#MrAG~zu)Fh%YhLM@n4a(r+7T!e%`<7E#Q7u-kcBk>OqczOHcR0S>zmjw}FG^rwv8j&E5;wm4- zCuXp{+!Yw6xm!dMJSQiwB;aZ3^T%Z`D!IkERkiUbR@=ltTbr9&(e_%bwWd8f^HoDP z)33j^aVSQS*ETQvrMpQi$eOe56N6VkQlo|&4DiI z&)d>|OMx)*xQLPRv~g~ws%6QxubqPtgfgF91Xtx-i=&9c$i2y@{PF$e@hdMo-o z&><*<+WT_c6$XK~M9+>QJr6Aa7?rI#X1;hH3;d?%UDBhDU@qDEyCk)ZHUWf~^A0{8 zt=I)1Mgp_fWTNQM>ZAlm(wK;G5Ig(A(R1tvdSL(Ajm?*;P8#Xe|Fq<&{j-yFe*tPG z6`V0Kx=&ML#P+5BM{NeRbkQBa%2cP0$iH3fMP|p7-7hV@^RsY1vk7!EyhHi^OFNev zCcQrm97vDv$me|=!OBAFQwxLY-|_t$yPmn3Eyz2gE(%`Apz6a?kl$3O-rFb8i*lcEYdT*4pZ{MaxNT+-7 zlwmo?!61-++)hmC5gP7t{;gu#@-z4UsHuS4fDQix z)2i8EL1|?Z=Q-BK>tLbJtEs%k-uxzaqHomHL#R#JiBT_EgeH z`x91{*2u~pD?5S>-s@1>=$!>sH;ZFDO}c$UkDm;;`Re_C|pbhb#TyGp~cfcWUqbPCNL@G2NrMbJ^ucJ9~0u zcBhg5c==bXi;n-^ljD6YS+0f6EA`+G+X5>@doMRF#autvma&()VCgL@bpeGme@&9j zfcnqi1rE#6nFIzRUdUOY@4a$LPj3n9&PC+VvKxlw%**x5oHId(X6E^+?y@x7#Lk_+ KJcLQWj(-5_1MLR@ literal 0 HcmV?d00001 diff --git a/sdk/rmsauth_sdk/WebAuthDialog/res.qrc b/sdk/rmsauth_sdk/WebAuthDialog/res.qrc new file mode 100644 index 00000000..9ad0bca5 --- /dev/null +++ b/sdk/rmsauth_sdk/WebAuthDialog/res.qrc @@ -0,0 +1,5 @@ + + + images/loading.gif + + \ No newline at end of file diff --git a/sdk/rmsauth_sdk/rmsauth/AcquireTokenForClientHandler.cpp b/sdk/rmsauth_sdk/rmsauth/AcquireTokenForClientHandler.cpp new file mode 100644 index 00000000..5ffebbb6 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AcquireTokenForClientHandler.cpp @@ -0,0 +1,24 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "AcquireTokenForClientHandler.h" + +namespace rmsauth { + +AcquireTokenForClientHandler::AcquireTokenForClientHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String &resource, ClientKeyPtr clientKey, bool callSync) + : AcquireTokenHandlerBase(authenticator, tokenCache, resource, clientKey, TokenSubjectType::Client, callSync) +{ + supportADFS_ = true; +} + +void AcquireTokenForClientHandler::addAditionalRequestParameters(RequestParameters& requestParameters) +{ + requestParameters.addParam(OAuthConstants::oAuthParameter().GrantType, OAuthConstants::oAuthGrantType().ClientCredentials); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AcquireTokenHandlerBase.cpp b/sdk/rmsauth_sdk/rmsauth/AcquireTokenHandlerBase.cpp new file mode 100644 index 00000000..09d8b57d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AcquireTokenHandlerBase.cpp @@ -0,0 +1,273 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include + +namespace rmsauth { + +AcquireTokenHandlerBase::AcquireTokenHandlerBase(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String &resource, ClientKeyPtr clientKey, TokenSubjectType subjectType, bool callSync) + : authenticator_(authenticator) + , tokenCache_(tokenCache) + , resource_(resource) + , clientKey_(clientKey) + , tokenSubjectType_(subjectType) + , loadFromCache_(tokenCache != nullptr) + , storeToCache_(tokenCache != nullptr) + , supportADFS_(false) +{ + Logger::info(Tag(), "AcquireTokenHandlerBase"); + + callState_ = createCallState(authenticator->correlationId(), callSync); + + StringStream chacheInfo; + tokenCache != nullptr + ? chacheInfo << tokenCache->getCacheName() << " (" << tokenCache->count() << " items)" + : chacheInfo << "nullptr"; + + Logger::info(Tag(), "=== Token Acquisition started:\n\tAuthority: %\n\tResource: %\n\tClientId: %\n\tCacheType: %\n\tAuthentication Target: %\n\t", + authenticator->authority(), resource, clientKey->clientId(), chacheInfo.str(), static_cast(subjectType)); + + if (resource.empty()) + { + Logger::error(Tag(), "AcquireTokenHandlerBase: resource is empty"); + throw IllegalArgumentException("resource"); + } +} + +AuthenticationResultPtr AcquireTokenHandlerBase::runAsync() +{ + Logger::info(Tag(), "runAsync"); + bool notifiedBeforeAccessCache = false; + + try + { + preRunAsync(); + + AuthenticationResultPtr result = nullptr; + if (loadFromCache_) + { + notifyBeforeAccessCache(); + notifiedBeforeAccessCache = true; + + result = tokenCache_->loadFromCache(authenticator_->authority(), resource_, clientKey_->clientId(), tokenSubjectType_, uniqueId_, displayableId_, callState_); + + if (result != nullptr && result->accessToken().empty() && !result->refreshToken().empty()) + { + result = refreshAccessTokenAsync(result); + if (result != nullptr) + { + tokenCache_->storeToCache(result, authenticator_->authority(), resource_, clientKey_->clientId(), tokenSubjectType_, callState_); + } + } + } + + if (result == nullptr) + { + preTokenRequest(); + result = sendTokenRequestAsync(); + postTokenRequest(result); + + if (this->storeToCache_) + { + if (!notifiedBeforeAccessCache) + { + notifyBeforeAccessCache(); + notifiedBeforeAccessCache = true; + } + + tokenCache_->storeToCache(result, authenticator_->authority(), resource_, clientKey_->clientId(), tokenSubjectType_, callState_); + } + } + + postRunAsync(result); + + if (notifiedBeforeAccessCache) + { + notifyAfterAccessCache(); + } + + return result; + } + catch (const Exception& ex) + { + if (notifiedBeforeAccessCache) + { + this->notifyAfterAccessCache(); + } + Logger::error(Tag(), "runAsync(): exception: %", ex.error()); + throw; + } +} + +CallStatePtr AcquireTokenHandlerBase::createCallState(const Guid& correlationId, bool callSync) +{ + Logger::info(Tag(), "createCallState"); + auto id = (!correlationId.empty()) ? correlationId : Guid::newGuid(); + + return std::make_shared(id, callSync); +} + +void AcquireTokenHandlerBase::preRunAsync() +{ + Logger::info(Tag(), "preRunAsync"); + authenticator_-> updateFromTemplateAsync(callState_); + validateAuthorityType(); +} + +void AcquireTokenHandlerBase::postRunAsync(AuthenticationResultPtr result) +{ + Logger::info(Tag(), "postRunAsync"); + logReturnedToken(result); +} + +void AcquireTokenHandlerBase::preTokenRequest() +{ + Logger::info(Tag(), "preTokenRequest"); +} + +void AcquireTokenHandlerBase::postTokenRequest(AuthenticationResultPtr result) +{ + Logger::info(Tag(), "postTokenRequest"); + authenticator_->updateTenantId(result->tenantId()); +} + +AuthenticationResultPtr AcquireTokenHandlerBase::sendTokenRequestAsync() +{ + Logger::info(Tag(), "sendTokenRequestAsync"); + RequestParameters requestParameters(resource_, clientKey_); + addAditionalRequestParameters(requestParameters); + + return sendHttpMessageAsync(requestParameters); +} + +AuthenticationResultPtr AcquireTokenHandlerBase::sendTokenRequestByRefreshTokenAsync(const String& refreshToken) +{ + Logger::info(Tag(), "sendTokenRequestByRefreshTokenAsync"); + RequestParameters requestParameters(resource_, clientKey_); + requestParameters.addParam(OAuthConstants::oAuthParameter().GrantType, OAuthConstants::oAuthGrantType().RefreshToken); + requestParameters.addParam(OAuthConstants::oAuthParameter().RefreshToken, refreshToken); + AuthenticationResultPtr result = sendHttpMessageAsync(requestParameters); + + if (result->refreshToken().empty()) + { + result->refreshToken(refreshToken); + } + + return result; +} + +AuthenticationResultPtr AcquireTokenHandlerBase::refreshAccessTokenAsync(AuthenticationResultPtr result) +{ + Logger::info(Tag(), "refreshAccessTokenAsync"); + AuthenticationResultPtr newResult = nullptr; + if (!resource_.empty()) + { + try + { + newResult = sendTokenRequestByRefreshTokenAsync(result->refreshToken()); + authenticator_->updateTenantId(result->tenantId()); + + if (newResult->idToken().empty()) + { + // If Id token is not returned by token endpoint when refresh token is redeemed, we should copy tenant and user information from the cached token. + newResult->updateTenantAndUserInfo(result->tenantId(), result->idToken(), result->userInfo()); + } + } + catch (const RmsauthServiceException& ex) + { + if(StringUtils::equalsIC(ex.error(), "invalid_request")) + { + throw RmsauthServiceException( + Constants::rmsauthError().FailedToRefreshToken, + Constants::rmsauthErrorMessage().FailedToRefreshToken + ". " + ex.message()); + } + } + catch (const RmsauthException&) + { + newResult = nullptr; + } + } + + return newResult; +} + +AuthenticationResultPtr AcquireTokenHandlerBase::sendHttpMessageAsync(const RequestParameters& requestParameters) +{ + Logger::info(Tag(), "sendHttpMessageAsync"); + +// String uri = HttpHelper::CheckForExtraQueryParameter(authenticator_->tokenUri()); + auto uri = authenticator_->tokenUri(); + + TokenResponsePtr tokenResponse = HttpHelper::sendPostRequestAndDeserializeJsonResponseAsync(uri, requestParameters, callState_); + + return OAuth2Response::parseTokenResponse(tokenResponse, callState_); +} + +void AcquireTokenHandlerBase::notifyBeforeAccessCache() +{ + Logger::info(Tag(), "notifyBeforeAccessCache"); + TokenCacheNotificationArgs args( + tokenCache_.get(), + resource_, + clientKey_->clientId(), + uniqueId_, + displayableId_); + + tokenCache_->onBeforeAccess(args); +} + +void AcquireTokenHandlerBase::notifyAfterAccessCache() +{ + Logger::info(Tag(), "notifyAfterAccessCache"); + TokenCacheNotificationArgs args( + tokenCache_.get(), + resource_, + clientKey_->clientId(), + uniqueId_, + displayableId_); + + tokenCache_->onAfterAccess(args); +} + +void AcquireTokenHandlerBase::logReturnedToken(AuthenticationResultPtr result) +{ + if (!result->accessToken().empty()) + { + String accessTokenHash = HashUtils::createSha256Hash(result->accessToken()); + String refreshTokenHash; + if (!result->refreshToken().empty()) + { + refreshTokenHash = HashUtils::createSha256Hash(result->refreshToken()); + } + else + { + refreshTokenHash = "[No Refresh Token]"; + } + + Logger::info(Tag(), "=== Token Acquisition finished successfully. An access token was retuned:\n\tAccess Token Hash: %\n\tRefresh Token Hash: %\n\tExpiration Time: % (%)\n\tUser Hash: %\n\t", + accessTokenHash, refreshTokenHash, DateTime(result->expiresOn()).toString("HH:mm:ss MM.dd.yy"), result->expiresOn(), + result->userInfo() != nullptr ? HashUtils::createSha256Hash(result->userInfo()->uniqueId()) : "nullptr"); + } +} + +void AcquireTokenHandlerBase::validateAuthorityType() +{ + Logger::info(Tag(), "validateAuthorityType"); + if (!supportADFS_ && authenticator_->authorityType() == AuthorityType::ADFS) + { + StringStream ds; + ds << Constants::rmsauthError().InvalidAuthorityType + << ", " << Constants::rmsauthErrorMessage().InvalidAuthorityTypeTemplate + << authenticator_->authority(); + throw RmsauthException(ds.str()); + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AcquireTokenInteractiveHandler.cpp b/sdk/rmsauth_sdk/rmsauth/AcquireTokenInteractiveHandler.cpp new file mode 100644 index 00000000..375f8040 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AcquireTokenInteractiveHandler.cpp @@ -0,0 +1,244 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +AcquireTokenInteractiveHandler::AcquireTokenInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior, UserIdentifierPtr userId, const String& extraQueryParameters, IWebUIPtr webUI, bool callSync) + : AcquireTokenHandlerBase(authenticator, tokenCache, resource, std::make_shared(clientId), TokenSubjectType::User, callSync) +{ + Logger::info(Tag(), "AcquireTokenInteractiveHandler"); + + if (redirectUri.empty()) + { + throw new IllegalArgumentException("redirectUri"); + } + + redirectUri_ = redirectUri; + + if (!Url(redirectUri).fragment().empty()) + { + throw new IllegalArgumentException(Constants::rmsauthErrorMessage().RedirectUriContainsFragment, "redirectUri"); + } + + setRedirectUriRequestParameter(); + + if (userId == nullptr) + { + throw new IllegalArgumentException("userId", Constants::rmsauthErrorMessage().SpecifyAnyUser); + } + + userId_ = userId; + + promptBehavior_ = promptBehavior; + + if (!extraQueryParameters.empty() && extraQueryParameters[0] == '&') + { + extraQueryParameters_ = extraQueryParameters.substr(1); + } + + extraQueryParameters_ = extraQueryParameters; + + webUi_ = webUI; + + uniqueId_ = userId->uniqueId(); + displayableId_ = userId->displayableId(); + userIdentifierType_ = userId->type(); + + loadFromCache_ = (tokenCache_ != nullptr && promptBehavior_ != PromptBehavior::Always && promptBehavior_ != PromptBehavior::RefreshSession); + + supportADFS_ = true; +} + +void AcquireTokenInteractiveHandler::addAditionalRequestParameters(RequestParameters& requestParameters) +{ + requestParameters.addParam(OAuthConstants::oAuthParameter().GrantType, OAuthConstants::oAuthGrantType().AuthorizationCode); + requestParameters.addParam(OAuthConstants::oAuthParameter().Code, authorizationResult_->code()); + requestParameters.addParam(OAuthConstants::oAuthParameter().RedirectUri, redirectUriRequestParameter_); +} + +void AcquireTokenInteractiveHandler::postTokenRequest(AuthenticationResultPtr result) +{ + Logger::info(Tag(), "postTokenRequest"); + + AcquireTokenHandlerBase::postTokenRequest(result); + if ((displayableId_.empty() && uniqueId_.empty()) || userIdentifierType_ == UserIdentifierType::OptionalDisplayableId) + { + return; + } + + String uniqueId = (result->userInfo() != nullptr && !result->userInfo()->uniqueId().empty()) ? result->userInfo()->uniqueId() : "NULL"; + String displayableId = (result->userInfo() != nullptr) ? result->userInfo()->displayableId() : "NULL"; + + if (userIdentifierType_ == UserIdentifierType::UniqueId && uniqueId_.compare(uniqueId_) != 0) + { + throw RmsauthUserMismatchException(uniqueId_, uniqueId); + } + + if (userIdentifierType_ == UserIdentifierType::RequiredDisplayableId && displayableId.compare(displayableId_) != 0) + { + throw RmsauthUserMismatchException(displayableId_, displayableId); + } +} + +String AcquireTokenInteractiveHandler::createAuthorizationUri(bool includeFormsAuthParam) +{ + Logger::info(Tag(), "createAuthorizationUri"); + + String loginHint; + + if (!userId_->isAnyUser() + && (userId_->type() == UserIdentifierType::OptionalDisplayableId + || userId_->type() == UserIdentifierType::RequiredDisplayableId)) + { + loginHint = userId_->id(); + } + + RequestParameters requestParameters = createAuthorizationRequest(loginHint, includeFormsAuthParam); + + String urlString = authenticator_->authorizationUri() + "?" + requestParameters.toString(); +// auto authorizationUri = std::make_shared(urlString); +// authorizationUri = new Uri(HttpHelper.CheckForExtraQueryParameter(authorizationUri.AbsoluteUri)); + + return urlString; +} + +RequestParameters AcquireTokenInteractiveHandler::createAuthorizationRequest(const String& loginHint, bool includeFormsAuthParam) +{ + Logger::info(Tag(), "createAuthorizationRequest"); + + RequestParameters authorizationRequestParameters(resource_, clientKey_); + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().ResponseType, OAuthConstants::oAuthResponseType().Code); + + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().RedirectUri, redirectUriRequestParameter_); + + if (!loginHint.empty()) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().LoginHint, loginHint); + } + + if (callState_ != nullptr && !callState_->correlationId().empty()) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().CorrelationId, callState_->correlationId().toString()); + } + + // ADFS currently ignores the parameter for now. + if (promptBehavior_ == PromptBehavior::Always) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().Prompt, OAuthConstants::promptValue().Login); + } + else if (promptBehavior_ == PromptBehavior::RefreshSession) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().Prompt, OAuthConstants::promptValue().RefreshSession); + } + else if (promptBehavior_ == PromptBehavior::Never) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().Prompt, OAuthConstants::promptValue().AttemptNone); + } + + if (includeFormsAuthParam) + { + authorizationRequestParameters.addParam(OAuthConstants::oAuthParameter().FormsAuth, OAuthConstants::oAuthValue().FormsAuth); + } + + AcquireTokenInteractiveHandler::addHeadersToRequestParameters(authorizationRequestParameters, RmsauthIdHelper::getProductHeaders()); + AcquireTokenInteractiveHandler::addHeadersToRequestParameters(authorizationRequestParameters, RmsauthIdHelper::getPlatformHeaders()); + + if (!extraQueryParameters_.empty()) + { +// TODO.shch: Checks for extraQueryParameters duplicating standard parameters + authorizationRequestParameters.extraQueryParameter(extraQueryParameters_); + } + + return authorizationRequestParameters; +} + +void AcquireTokenInteractiveHandler::addHeadersToRequestParameters(RequestParameters& requestParameters, Headers headers) +{ + for(auto& header : headers) + { + requestParameters.addParam(header.first, header.second); + } +} + +void AcquireTokenInteractiveHandler::verifyAuthorizationResult() +{ + Logger::info(Tag(), "verifyAuthorizationResult"); + + if (promptBehavior_ == PromptBehavior::Never && authorizationResult_->error() == OAuthConstants::oAuthError().LoginRequired) + { + throw RmsauthException(Constants::rmsauthError().UserInteractionRequired); + } + + if (authorizationResult_->status() != AuthorizationStatus::Success) + { + throw RmsauthServiceException(authorizationResult_->error(), authorizationResult_->errorDescription()); + } +} + +void AcquireTokenInteractiveHandler::preTokenRequest() +{ + Logger::info(Tag(), "preTokenRequest"); + + AcquireTokenHandlerBase::preTokenRequest(); + + acquireAuthorization(); + verifyAuthorizationResult(); +} + +void AcquireTokenInteractiveHandler::acquireAuthorization() +{ + Logger::info(Tag(), "acquireAuthorization"); + sendAuthorizeRequest(); +} + +void AcquireTokenInteractiveHandler::sendAuthorizeRequest() +{ + Logger::info(Tag(), "sendAuthorizeRequest"); + String authorizationUri = createAuthorizationUri(includeFormsAuthParams()); + String resultUri = webUi_->authenticate(authorizationUri, redirectUri_); + authorizationResult_ = OAuth2Response::parseAuthorizeResponse(resultUri, callState_); +} + +bool AcquireTokenInteractiveHandler::includeFormsAuthParams() +{ + Logger::info(Tag(), "includeFormsAuthParams"); + return isUserLocal() && isDomainJoined(); +} + +String AcquireTokenInteractiveHandler::createAuthorizationUriAsync(const Guid& correlationId) +{ + Logger::info(Tag(), "createAuthorizationUriAsync"); + callState_->correlationId(correlationId); + authenticator_->updateFromTemplateAsync(callState_); + return createAuthorizationUri(false); +} + +bool AcquireTokenInteractiveHandler::isDomainJoined() +{ +// TODO.shch: figure out what it is. + bool returnValue = false; + return returnValue; +} + +bool AcquireTokenInteractiveHandler::isUserLocal() +{ +// TODO.shch: figure out what it is. +// string prefix = WindowsIdentity.GetCurrent().Name.Split('\\')[0].ToUpperInvariant(); +// return prefix.Equals(Environment.MachineName.ToUpperInvariant()); + return true; +} + +void AcquireTokenInteractiveHandler::setRedirectUriRequestParameter() +{ + redirectUriRequestParameter_ = redirectUri_; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandler.cpp b/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandler.cpp new file mode 100644 index 00000000..e7f27b7f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandler.cpp @@ -0,0 +1,100 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include + +namespace rmsauth { + +AcquireTokenNonInteractiveHandler::AcquireTokenNonInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, UserCredentialPtr userCredential, bool callSync) + : AcquireTokenHandlerBase(authenticator, tokenCache, resource, std::make_shared(clientId), TokenSubjectType::User, callSync) +{ + if (userCredential == nullptr) + { + throw RmsauthException("userCredential", "the value is null"); + } + + userCredential_ = userCredential; +} + +AcquireTokenNonInteractiveHandler::AcquireTokenNonInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, UserAssertionPtr userAssertion, bool callSync) + : AcquireTokenHandlerBase(authenticator, tokenCache, resource, std::make_shared(clientId), TokenSubjectType::User, callSync) +{ + if (userAssertion == nullptr) + { + throw RmsauthException("userAssertion", "the value is null"); + } + + userAssertion_ = userAssertion; +} + +void AcquireTokenNonInteractiveHandler::preRunAsync() +{ + AcquireTokenHandlerBase::preRunAsync(); + + if (userCredential_ != nullptr) + { + if (userCredential_->userName().empty()) + { + Logger::info(Tag(), "User name is empty"); + throw RmsauthException("userCredential_->userName()", "the value is empty"); + } + + displayableId_ = userCredential_->userName(); + } + else if (userAssertion_ != nullptr) + { + displayableId_ = userAssertion_->userName(); + } +} + +void AcquireTokenNonInteractiveHandler::preTokenRequest() +{ + AcquireTokenHandlerBase::preTokenRequest(); + + if (userAssertion_ == nullptr) + { + auto userRealmResponse = UserRealmDiscoveryResponse::createByDiscoveryAsync(authenticator_->userRealmUri(), userCredential_->userName(), callState_); + Logger::info(Tag(), "User '%' detected as '{%}'", userCredential_->userName(), userRealmResponse.accountType()); + + if (StringUtils::compareIC(userRealmResponse.accountType(), "federated") == 0) + { + if (userRealmResponse.federationMetadataUrl().empty()) + { + throw RmsauthException(Constants::rmsauthError().MissingFederationMetadataUrl); + } + + throw RmsauthException("Not implemented"); + +// Url wsTrustUrl = MexParser::fetchWsTrustAddressFromMexAsync(userRealmResponse.federationMetadataUrl(), userCredential_->userAuthType(), callState_); +// Logger::info(Tag(), "WS-Trust endpoint '{%}' fetched from MEX at '{%}'", wsTrustUrl.toString(), userRealmResponse.federationMetadataUrl()); + +// WsTrustResponse wsTrustResponse = WsTrustRequest::sendRequestAsync(wsTrustUrl, userCredential_, callState_); +// Logger::info(Tag(), "Token of type '{%}' acquired from WS-Trust endpoint", wsTrustResponse.tokenType()); + +// // We assume that if the response token type is not SAML 1.1, it is SAML 2 +// userAssertion_ = new UserAssertion(wsTrustResponse.token(), (wsTrustResponse.tokenType() == WsTrustResponse::Saml1Assertion) ? OAuthConstants::oAuthGrantType().Saml11Bearer : OAuthConstants::oAuthGrantType().Saml20Bearer); + } + else if (StringUtils::compareIC(userRealmResponse.accountType(), "managed") == 0) + { + // handle password grant flow for the managed user + if (userCredential_->password().empty()) + { + throw RmsauthException(Constants::rmsauthError().PasswordRequiredForManagedUserError); + } + } + else + { + throw RmsauthException(Constants::rmsauthError().UnknownUserType); + } + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandlerQt.cpp b/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandlerQt.cpp new file mode 100644 index 00000000..a9e92d6d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AcquireTokenNonInteractiveHandlerQt.cpp @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include + +namespace rmsauth { + +void AcquireTokenNonInteractiveHandler::addAditionalRequestParameters(RequestParameters& requestParameters) +{ + if (userAssertion_ != nullptr) + { + requestParameters.addParam(OAuthConstants::oAuthParameter().GrantType, userAssertion_->assertionType()); + QByteArray qbaBase64Assertion = QByteArray(userAssertion_->assertion().data(), (int)userAssertion_->assertion().size()).toBase64(); + requestParameters.addParam(OAuthConstants::oAuthParameter().Assertion, String(qbaBase64Assertion.begin(), qbaBase64Assertion.end())); + } + else + { + requestParameters.addParam(OAuthConstants::oAuthParameter().GrantType, OAuthConstants::oAuthGrantType().Password); + requestParameters.addParam(OAuthConstants::oAuthParameter().Username, userCredential_->userName()); + requestParameters.addParam(OAuthConstants::oAuthParameter().Password, userCredential_->password()); + } + + // To request id_token in response + requestParameters.addParam(OAuthConstants::oAuthParameter().Scope, OAuthConstants::oAuthValue().ScopeOpenId); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticationContext.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticationContext.cpp new file mode 100644 index 00000000..d111e01b --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticationContext.cpp @@ -0,0 +1,89 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +AuthenticationContext::AuthenticationContext(const String& authority, TokenCachePtr tokenCache) + : AuthenticationContext{authority, AuthorityValidationType::NotProvided, tokenCache} +{ +} + +AuthenticationContext::AuthenticationContext(const String& authority, AuthorityValidationType validateAuthority, TokenCachePtr tokenCache) + : tokenCache_(tokenCache) +{ + Logger::info(Tag(), "AuthenticationContext"); + // If authorityType is not provided (via first constructor), we validate by default (except for ASG and Office tenants). + authenticator_ = std::make_shared(authority, (validateAuthority != AuthorityValidationType::False)); +} + +AuthenticationResultPtr AuthenticationContext::acquireToken(const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior) +{ + Logger::info(Tag(), "acquireToken"); + String extraQueryParameters = ""; + bool callSync = true; + return acquireTokenCommonAsync(resource, clientId, redirectUri, promptBehavior, UserIdentifier::anyUser(), extraQueryParameters, callSync); +} + +AuthenticationResultPtr AuthenticationContext::acquireToken(const String& resource, const String& clientId, UserCredentialPtr userCredentiar) +{ + Logger::info(Tag(), "acquireToken"); + bool callSync = true; + return acquireTokenCommonAsync(resource, clientId, userCredentiar, callSync); +} + +AuthenticationResultPtr AuthenticationContext::acquireToken(const String& resource, const String& clientId, UserAssertionPtr userAssertion) +{ + Logger::info(Tag(), "acquireToken"); + bool callSync = true; + return acquireTokenCommonAsync(resource, clientId, userAssertion, callSync); +} + +AuthenticationResultPtr AuthenticationContext::acquireToken(const String& resource, ClientCredentialPtr clientCredential) +{ + Logger::info(Tag(), "acquireToken"); + bool callSync = true; + return acquireTokenCommonAsync(resource, clientCredential, callSync); +} + +AuthenticationResultPtr AuthenticationContext::acquireTokenCommonAsync(const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior, UserIdentifierPtr userId, const String& extraQueryParameters, bool callSync/* = false*/) +{ + Logger::info(Tag(), "acquireTokenCommonAsync"); + AcquireTokenInteractiveHandler handler(authenticator_, tokenCache_, resource, clientId, redirectUri, promptBehavior, userId, extraQueryParameters, createWebAuthenticationDialog(promptBehavior), callSync); + return handler.runAsync(); +} + +AuthenticationResultPtr AuthenticationContext::acquireTokenCommonAsync(const String& resource, const String& clientId, UserCredentialPtr userCredential, bool callSync/* = false*/) +{ + Logger::info(Tag(), "acquireTokenCommonAsync"); + AcquireTokenNonInteractiveHandler handler(authenticator_, tokenCache_, resource, clientId, userCredential, callSync); + return handler.runAsync(); +} + +AuthenticationResultPtr AuthenticationContext::acquireTokenCommonAsync(const String& resource, const String& clientId, UserAssertionPtr userAssertionl, bool callSync/* = false*/) +{ + Logger::info(Tag(), "acquireTokenCommonAsync"); + AcquireTokenNonInteractiveHandler handler(authenticator_, tokenCache_, resource, clientId, userAssertionl, callSync); + return handler.runAsync(); +} + +AuthenticationResultPtr AuthenticationContext::acquireTokenCommonAsync(const String& resource, ClientCredentialPtr clientCredential, bool callSync/* = false*/) +{ + Logger::info(Tag(), "acquireTokenCommonAsync"); + AcquireTokenForClientHandler handler(authenticator_, tokenCache_, resource, std::make_shared(clientCredential), callSync); + return handler.runAsync(); +} + +IWebUIPtr AuthenticationContext::createWebAuthenticationDialog(PromptBehavior promptBehavior) +{ + Logger::info(Tag(), "createWebAuthenticationDialog"); + return std::make_shared(promptBehavior); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticationRequest.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticationRequest.cpp new file mode 100644 index 00000000..fcf5057d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticationRequest.cpp @@ -0,0 +1,11 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "AuthenticationRequest.h" + + diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticationResult.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticationResult.cpp new file mode 100644 index 00000000..4412dbe6 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticationResult.cpp @@ -0,0 +1,40 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +AuthenticationResult::_JsonNames AuthenticationResult::JsonNames; + +AuthenticationResult::AuthenticationResult(const String& accessTokenType, const String& accessToken, const String& refreshToken, DateTimeOffset expiresOn) + : accessTokenType_(accessTokenType) + , accessToken_(accessToken) + , refreshToken_(refreshToken) + , expiresOn_(expiresOn) +{ +} + +String AuthenticationResult::createAuthorizationHeader() +{ + return oAuth2AuthorizationHeader_ + accessToken_; +} + +void AuthenticationResult::updateTenantAndUserInfo(const String& tenantId, const String& idToken, UserInfoPtr userInfo) +{ + Logger::info(Tag(), "updateTenantAndUserInfo"); + tenantId_ = tenantId; + idToken_ = idToken; + if (userInfo != nullptr) + { + userInfo_ = userInfo; + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticationResultQt.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticationResultQt.cpp new file mode 100644 index 00000000..da6c1c5b --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticationResultQt.cpp @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include "JsonUtilsQt.h" +#include +#include + +namespace rmsauth { + +AuthenticationResultPtr AuthenticationResult::deserialize(const String& jsonString) +{ + Logger::info(Tag(), "deserialize"); + AuthenticationResultPtr result = nullptr; + + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(jsonString.c_str(), &error); + if( error.error != QJsonParseError::NoError ) + { + throw RmsauthException(String("AuthenticationResult::deserialize: ") + error.errorString().toStdString()); + } + QJsonObject qobj = qdoc.object(); + + result.reset(new AuthenticationResult()); + + result->accessTokenType_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.accessTokenType); + result->accessToken_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.accessToken); + result->resource_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.resource); + result->refreshToken_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.refreshToken); + result->expiresOn_ = JsonUtilsQt::getIntOrDefault(qobj, AuthenticationResult::JsonNames.expiresOn); + result->tenantId_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.tenantId); + + result->userInfo_ = JsonUtilsQt::parseObject(qobj, AuthenticationResult::JsonNames.userInfo, &UserInfo::deserialize); + + result->idToken_ = JsonUtilsQt::getStringOrDefault(qobj, AuthenticationResult::JsonNames.idToken); + result->isMultipleResourceRefreshToken_ = JsonUtilsQt::getBoolOrDefault(qobj, AuthenticationResult::JsonNames.isMultipleResourceRefreshToken); + + return result; +} +String AuthenticationResult::serialize() +{ + Logger::info(Tag(), "serialize"); + QJsonObject qobj; + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.accessTokenType, accessTokenType_); + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.accessToken, accessToken_); + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.resource, resource_); + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.refreshToken, refreshToken_); + qobj.insert(AuthenticationResult::JsonNames.expiresOn.c_str(), (int)expiresOn_); + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.tenantId, tenantId_); + if(userInfo_ != nullptr) + JsonUtilsQt::insertObject(qobj, AuthenticationResult::JsonNames.userInfo, userInfo_->serialize()); + JsonUtilsQt::insertString(qobj, AuthenticationResult::JsonNames.idToken, idToken_); + qobj.insert(AuthenticationResult::JsonNames.isMultipleResourceRefreshToken.c_str(), isMultipleResourceRefreshToken_); + + QJsonDocument doc(qobj); + auto res = doc.toJson(QJsonDocument::Compact); + return String(res.begin(), res.end()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/Authenticator.cpp b/sdk/rmsauth_sdk/rmsauth/Authenticator.cpp new file mode 100644 index 00000000..d894e05e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/Authenticator.cpp @@ -0,0 +1,130 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include + +namespace rmsauth { + +AuthenticatorTemplateList Authenticator::authenticatorTemplateList; + +const String Authenticator::tenantlessTenantName() +{ + static const String str = "Common"; + return str; +} + +Authenticator::Authenticator(const String& authority, bool validateAuthority) + : validateAuthority_(validateAuthority) + , default_(false) +{ + authority_ = canonicalizeUri(authority); + authorityType_ = detectAuthorityType(authority_); + if (authorityType_ != AuthorityType::AAD && validateAuthority) + { + Logger::error(Tag(), Constants::rmsauthErrorMessage().UnsupportedAuthorityValidation); + throw IllegalArgumentException(Constants::rmsauthErrorMessage().UnsupportedAuthorityValidation, "validateAuthority"); + } +} + +void Authenticator::updateFromTemplateAsync(CallStatePtr callState) +{ + Logger::info(Tag(), "updateFromTemplateAsync"); + + if (!updatedFromTemplate_) + { + Url authorityUri(authority_); + String host = authorityUri.authority(); + String path = authorityUri.path().substr(1); + String tenant = path.substr(0, path.find("/")); + auto matchingTemplate = Authenticator::authenticatorTemplateList.findMatchingItemAsync(validateAuthority_, host, tenant, callState); + authorizationUri_ = StringUtils::replace(matchingTemplate->authorizeEndpoint(), "{tenant}", tenant); + tokenUri_ = StringUtils::replace(matchingTemplate->tokenEndpoint(), "{tenant}", tenant); + userRealmUri_ = canonicalizeUri(matchingTemplate->userRealmEndpoint()); + isTenantless_ = tenant.compare(tenantlessTenantName()) == 0; + selfSignedJwtAudience_ = StringUtils::replace(matchingTemplate->issuer(), "{tenant}", tenant); + updatedFromTemplate_ = true; + default_ = false; + } +} +void Authenticator::updateTenantId(const String& tenantId) +{ + Logger::info(Tag(), "updateTenantId"); + + if (isTenantless_ && !tenantId.empty()) + { + authority_ = replaceTenantlessTenant(authority_, tenantId); + updatedFromTemplate_ = false; + } +} + +AuthorityType Authenticator::detectAuthorityType(const String& authority) +{ + Logger::info(Tag(), "detectAuthorityType"); + + if (authority.empty()) + { + throw IllegalArgumentException("authority"); + } + + if (!Url(authority).isValid()) + { + Logger::error(Tag(), Constants::rmsauthErrorMessage().AuthorityInvalidUriFormat); + throw IllegalArgumentException(Constants::rmsauthErrorMessage().AuthorityInvalidUriFormat, authority); + } + + Url authorityUri(authority); + if (authorityUri.scheme() != "https") + { + Logger::error(Tag(), Constants::rmsauthErrorMessage().AuthorityUriInsecure); + throw IllegalArgumentException(Constants::rmsauthErrorMessage().AuthorityUriInsecure, authority); + } + + String path = authorityUri.path().substr(1); + if (path.empty()) + { + Logger::error(Tag(), Constants::rmsauthErrorMessage().AuthorityUriInvalidPath); + throw IllegalArgumentException(Constants::rmsauthErrorMessage().AuthorityUriInvalidPath, authority); + } + + String firstPath = path.substr(0, path.find("/")); + AuthorityType authorityType = Authenticator::isAdfsAuthority(firstPath) ? AuthorityType::ADFS : AuthorityType::AAD; + + return authorityType; +} + +String Authenticator::canonicalizeUri(const String& uri) +{ + if (!uri.empty() && !StringUtils::endsWith(uri, "/")) + { + return uri + "/"; + } + + return uri; +} + +String Authenticator::replaceTenantlessTenant(const String& authority, const String& tenantId) +{ + Logger::info(Tag(), "replaceTenantlessTenant"); + + // TODO.shch: porting +// auto regex = new Regex(Regex.Escape(TenantlessTenantName), RegexOptions.IgnoreCase); +// return regex.Replace(authority, tenantId, 1); + return StringUtils::replace(authority, tenantlessTenantName(), tenantId); +} + +bool Authenticator::isAdfsAuthority(const String& firstPath) +{ + bool res = StringUtils::compareIC(firstPath, "adfs") == 0; + Logger::info(Tag(), "isAdfsAuthority: '%'", res); + return res; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplate.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplate.cpp new file mode 100644 index 00000000..92b75379 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplate.cpp @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +using SELF = AuthenticatorTemplate; + +//const String AuthenticatorTemplate::instanceDiscoveryEndpointTemplate() +//{ +// static const String str = "https://{host}/Common/discovery/instance"; +// return str; +//} + +const String AuthenticatorTemplate::authorizeEndpointTemplate() +{ + static const String str = "https://{host}/{tenant}/oauth2/authorize"; + return str; + +} +const String AuthenticatorTemplate::HOST() +{ + static const String str = "{host}"; + return str; + +} +const String AuthenticatorTemplate::TENANT() +{ + static const String str = "{tenant}"; + return str; + +} +AuthenticatorTemplatePtr AuthenticatorTemplate::createFromHost(const String& host) +{ + static const String tokenEndpointTemplate = "https://{host}/{tenant}/oauth2/token"; + static const String userRealmEndpointTemplate = "https://{host}/Common/UserRealm"; + static const String authorityTemplate = "https://{host}/{tenant}/"; + static const String instanceDiscoveryEndpointTemplate = "https://{host}/Common/discovery/instance"; + + auto res = std::make_shared(); + res->host_ = host; + res->authority_ = StringUtils::replace(authorityTemplate, SELF::HOST(), host); + res->instanceDiscoveryEndpoint_ = StringUtils::replace(instanceDiscoveryEndpointTemplate, SELF::HOST(), host); + res->authorizeEndpoint_ = StringUtils::replace(SELF::authorizeEndpointTemplate(), SELF::HOST(), host); + res->tokenEndpoint_ = StringUtils::replace(tokenEndpointTemplate, SELF::HOST(), host); + res->issuer_ = res->tokenEndpoint_; + res->userRealmEndpoint_ = StringUtils::replace(userRealmEndpointTemplate, SELF::HOST(), host); + return res; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateList.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateList.cpp new file mode 100644 index 00000000..71653250 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateList.cpp @@ -0,0 +1,52 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +AuthenticatorTemplateList::AuthenticatorTemplateList() +{ + StringArray trustedHostList = { "login.windows.net", "login.chinacloudapi.cn", "login.cloudgovapi.us", "login.microsoftonline.com" }; + +// TODO.shch: implement PlatformSpecificHelper.GetEnvironmentVariable("customTrustedHost") +// string customAuthorityHost = PlatformSpecificHelper.GetEnvironmentVariable("customTrustedHost"); + + String customAuthorityHost; + if (customAuthorityHost.empty()) + { + for (String host : trustedHostList) + { + this->push_back(AuthenticatorTemplate::createFromHost(host)); + } + } + else + { + this->push_back(AuthenticatorTemplate::createFromHost(customAuthorityHost)); + } +} +AuthenticatorTemplatePtr AuthenticatorTemplateList::findMatchingItemAsync(bool validateAuthority, const String& host, const String& tenant, CallStatePtr callState) +{ + if (validateAuthority) + { + for(ArrayList::size_type i = 0; i < this->size(); ++i) + { + auto authenticatorTemplate = this->at(i); + if(authenticatorTemplate->host() == host) + { + return authenticatorTemplate; + } + } + + this->at(0)->verifyAnotherHostByInstanceDiscoveryAsync(host, tenant, callState); + } + + return AuthenticatorTemplate::createFromHost(host); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateQt.cpp b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateQt.cpp new file mode 100644 index 00000000..6b84c9b3 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/AuthenticatorTemplateQt.cpp @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include "HttpHelperQt.h" +#include +#include +#include +#include + +namespace rmsauth { + +void AuthenticatorTemplate::verifyAnotherHostByInstanceDiscoveryAsync(const String& host, const String& tenant, CallStatePtr callState) +{ + Logger::info(Tag(), "verifyAnotherHostByInstanceDiscoveryAsync"); + + String instanceDiscoveryEndpoint = instanceDiscoveryEndpoint_; + instanceDiscoveryEndpoint += ("?api-version=1.0&authorization_endpoint=" + AuthenticatorTemplate::authorizeEndpointTemplate()); + instanceDiscoveryEndpoint = StringUtils::replace(instanceDiscoveryEndpoint, AuthenticatorTemplate::HOST(), host); + instanceDiscoveryEndpoint = StringUtils::replace(instanceDiscoveryEndpoint, AuthenticatorTemplate::TENANT(), tenant); + + QNetworkRequest request = HttpHelperQt::createRequest(); + request.setUrl(QUrl(instanceDiscoveryEndpoint.data())); + +// HttpHelperQt::addCorrelationIdHeadersToRequest(request, callState); + HttpHelperQt::addHeadersToRequest(request, RmsauthIdHelper::getPlatformHeaders()); + HttpHelperQt::addHeadersToRequest(request, RmsauthIdHelper::getProductHeaders()); + + InstanceDiscoveryResponsePtr discoveryResponsePtr = nullptr; + if(QCoreApplication::instance() == nullptr) + { + auto fut = std::async(&HttpHelperQt::jobGetRunner, std::ref(request), callState); + auto body = fut.get(); + discoveryResponsePtr = HttpHelperQt::deserializeInstanceDiscoveryResponse(body); + } + else + { + auto body = HttpHelperQt::jobGet(request, callState); + discoveryResponsePtr = HttpHelperQt::deserializeInstanceDiscoveryResponse(body); + } + + if (discoveryResponsePtr == nullptr || discoveryResponsePtr->tenantDiscoveryEndpoint.empty()) + { + throw RmsauthException(Constants::rmsauthError().AuthorityNotInValidList); + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/CallState.cpp b/sdk/rmsauth_sdk/rmsauth/CallState.cpp new file mode 100644 index 00000000..64007b62 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/CallState.cpp @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +CallState::CallState(Guid& correlationId, bool callSync) + : correlationId_(correlationId) + , callSync_(callSync) +{ +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/ClientAssertion.cpp b/sdk/rmsauth_sdk/rmsauth/ClientAssertion.cpp new file mode 100644 index 00000000..799f031e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/ClientAssertion.cpp @@ -0,0 +1,15 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +ClientAssertion::ClientAssertion(){} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/ClientAssertionCertificate.cpp b/sdk/rmsauth_sdk/rmsauth/ClientAssertionCertificate.cpp new file mode 100644 index 00000000..4550fd55 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/ClientAssertionCertificate.cpp @@ -0,0 +1,17 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + + +ClientAssertionCertificate::ClientAssertionCertificate() +{} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/ClientCredential.cpp b/sdk/rmsauth_sdk/rmsauth/ClientCredential.cpp new file mode 100644 index 00000000..69bc8cec --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/ClientCredential.cpp @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +ClientCredential::ClientCredential(const String& clientId, const String& clientSecret) + : clientId_ (clientId) + , clientSecret_(clientSecret) +{ + if (clientId.empty()) + { + throw new IllegalArgumentException("clientId"); + } + + if (clientSecret.empty()) + { + throw new IllegalArgumentException("clientSecret"); + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/ClientKey.cpp b/sdk/rmsauth_sdk/rmsauth/ClientKey.cpp new file mode 100644 index 00000000..4c1a5051 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/ClientKey.cpp @@ -0,0 +1,45 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +ClientKey::ClientKey(ClientCredentialPtr clientCredential) + : credential_(clientCredential) + , clientId_(clientCredential->clientId()) + , hasCredential_(true) +{ +} + +ClientKey::ClientKey(ClientAssertionCertificatePtr clientCertificate, AuthenticatorPtr authenticator) + : certificate_(clientCertificate) + , authenticator_(authenticator) + , clientId_(clientCertificate->clientId()) + , hasCredential_(true) +{ +} + +ClientKey::ClientKey(ClientAssertionPtr clientAssertion) + : assertion_(clientAssertion) + , clientId_(clientAssertion->clientId()) + , hasCredential_(true) +{ +} + +ClientKey::ClientKey(const String& clientId) + : clientId_(clientId) + , hasCredential_(false) +{ + if (clientId.empty()) + { + throw new IllegalArgumentException("clientId"); + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/DateTime.cpp b/sdk/rmsauth_sdk/rmsauth/DateTime.cpp new file mode 100644 index 00000000..c9a7d25b --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/DateTime.cpp @@ -0,0 +1,45 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +void DateTime::addDays(int64_t ndays) +{ + this->pImpl->addDays(ndays); +} +void DateTime::addMSecs(int64_t msecs) +{ + this->pImpl->addMSecs(msecs); +} + +void DateTime::addMonths(int nmonths) +{ + this->pImpl->addMonths(nmonths); +} + +void DateTime::addSecs(int64_t s) +{ + this->pImpl->addSecs(s); +} + +void DateTime::addYears(int nyears) +{ + this->pImpl->addYears(nyears); +} +int64_t DateTime::toTime() +{ + return this->pImpl->toTime(); +} +String DateTime::toString(const String& format) +{ + return this->pImpl->toString(format); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/DateTimeQt.cpp b/sdk/rmsauth_sdk/rmsauth/DateTimeQt.cpp new file mode 100644 index 00000000..3d68d658 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/DateTimeQt.cpp @@ -0,0 +1,65 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "DateTimeQt.h" + +namespace rmsauth { + +DateTime::DateTime() +{ + this->pImpl = std::make_shared(); +} +DateTime::DateTime(int64_t sec) +{ + this->pImpl = std::make_shared(sec); +} + +DateTimeQt::DateTimeQt() + : dateTime_(QDateTime::currentDateTimeUtc()) +{ +} +DateTimeQt::DateTimeQt(int64_t sec) + : dateTime_(QDateTime::fromTime_t(sec, Qt::UTC)) +{ +} + +void DateTimeQt::addDays(int64_t ndays) +{ + QDateTime dt = this->dateTime_.addDays((qint64)ndays); + this->dateTime_ = dt; +} +void DateTimeQt::addMSecs(int64_t msecs) +{ + this->dateTime_ = this->dateTime_.addMSecs((qint64)msecs); +} + +void DateTimeQt::addMonths(int nmonths) +{ + this->dateTime_ = this->dateTime_.addMonths(nmonths); +} + +void DateTimeQt::addSecs(int64_t s) +{ + this->dateTime_ = this->dateTime_.addSecs((qint64)s); +} + +void DateTimeQt::addYears(int nyears) +{ + this->dateTime_ = this->dateTime_.addYears(nyears); +} +int64_t DateTimeQt::toTime() +{ + return this->dateTime_.toTime_t(); +} + +String DateTimeQt::toString(const String& format) +{ + return this->dateTime_.toString(format.c_str()).toStdString(); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/DateTimeQt.h b/sdk/rmsauth_sdk/rmsauth/DateTimeQt.h new file mode 100644 index 00000000..f7f29d04 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/DateTimeQt.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DATEQT_H +#define DATEQT_H + +#include +#include + +namespace rmsauth { + +class DateTimeQt : public IDateTime +{ +public: + DateTimeQt(); + DateTimeQt(int64_t sec); + +private: + void addDays(int64_t ndays) override; + void addMSecs(int64_t msecs) override; + void addMonths(int nmonths) override; + void addSecs(int64_t s) override; + void addYears(int nyears) override; + int64_t toTime() override; + virtual String toString(const String& format) override; + +private: + QDateTime dateTime_; + friend class DateTime; +}; + +} //namespace rmsauth { + +#endif // DATEQT_H diff --git a/sdk/rmsauth_sdk/rmsauth/FileCacheEncrypted.cpp b/sdk/rmsauth_sdk/rmsauth/FileCacheEncrypted.cpp new file mode 100644 index 00000000..9e4aa6a5 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/FileCacheEncrypted.cpp @@ -0,0 +1,78 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include "../../rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.h" + +using namespace std; + +namespace rmsauth { + +FileCacheEncrypted::FileCacheEncrypted(const String& filePath) + : FileCache(filePath) +{ +} + +void FileCacheEncrypted::readCache() +{ + Logger::info(Tag(), "readCache"); + ifstream ifs(cacheFilePath_, ios::binary|ios::ate); + if (!ifs.is_open()) + { + Logger::info(Tag(), "Cache file doesn't exist! '%'", cacheFilePath_); + return; + } + ifstream::pos_type pos = ifs.tellg(); + + ByteArray cacheData(pos); + + ifs.seekg(0, ios::beg); + ifs.read(&cacheData[0], pos); + + // decrypt cacheData; + auto inputDataPtr = std::make_shared>(cacheData.begin(), cacheData.end()); + auto cacheDataDecryptedPtr = rmscrypto::api::DecryptWithAutoKey(inputDataPtr); + ByteArray cacheDataDecrypted(cacheDataDecryptedPtr->begin(), cacheDataDecryptedPtr->end()); + + deserialize(cacheDataDecrypted); + ifs.close(); +} + +void FileCacheEncrypted::writeCache() +{ + Logger::info(Tag(), "writeCache"); + ofstream ofs(cacheFilePath_, ios::binary|ios::app); + if (!ofs.is_open()) + { + Logger::info(Tag(), "Can't open cache file for writing! '%'", cacheFilePath_); + return; + } + + auto cacheData = serialize(); + + // encrypt cacheData + Logger::info(Tag(), "encrypting cacheData"); + auto inputDataPtr = std::make_shared>(cacheData.begin(), cacheData.end()); + auto cacheDataEncryptedPtr = rmscrypto::api::EncryptWithAutoKey(inputDataPtr); + ByteArray cacheDataEncrypted(cacheDataEncryptedPtr->begin(), cacheDataEncryptedPtr->end()); + + Logger::info(Tag(), "writing to the file stream"); + ofs.write(&cacheDataEncrypted[0], cacheDataEncrypted.size()); + + if(-1 == ofs.tellp()) + { + throw RmsauthParsingException("writeCache", "write data error"); + } + ofs.close(); +} + + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/FileCacheQt.cpp b/sdk/rmsauth_sdk/rmsauth/FileCacheQt.cpp new file mode 100644 index 00000000..adf84718 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/FileCacheQt.cpp @@ -0,0 +1,120 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace rmsauth { + +Mutex FileCache::fileLock_; + +FileCache::FileCache(const String& filePath) +{ + if (filePath.empty()) // using default settings + { + const QString fileName = "token_cache.dat"; + auto path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.ms-ad"; + if(!QDir().mkpath(path)) + { + throw RmsauthException("Can't create cache directory"); + } + QFileInfo fi(QDir(path), fileName); + cacheFilePath_ = fi.absoluteFilePath().toStdString(); + } + else + { + QFileInfo fi(QString::fromStdString(filePath)); + auto userDefinedCacheDir = fi.path(); + if(!QDir().exists(userDefinedCacheDir)) + { + throw RmsauthException("Can't find user defined cache directory", userDefinedCacheDir.toStdString()); + } + cacheFilePath_ = fi.absoluteFilePath().toStdString(); + } + + Logger::info(Tag(), "path: %", cacheFilePath_); +} + +void FileCache::readCache() +{ + Logger::info(Tag(), "readCache"); + ifstream ifs(cacheFilePath_, ios::binary|ios::ate); + if (!ifs.is_open()) + { + Logger::info(Tag(), "Cache file doesn't exist! '%'", cacheFilePath_); + return; + } + ifstream::pos_type pos = ifs.tellg(); + + ByteArray cacheData(pos); + + ifs.seekg(0, ios::beg); + ifs.read(&cacheData[0], pos); + deserialize(cacheData); + ifs.close(); +} + +void FileCache::writeCache() +{ + Logger::info(Tag(), "writeCache"); + ofstream ofs(cacheFilePath_, ios::binary|ios::app); + if (!ofs.is_open()) + { + Logger::info(Tag(), "Can't open cache file for writing! '%'", cacheFilePath_); + return; + } + + auto cacheData = serialize(); + ofs.write(&cacheData[0], cacheData.size()); + + if(-1 == ofs.tellp()) + { + throw RmsauthParsingException("writeCache", "write data error"); + } + ofs.close(); +} + +void FileCache::clear() +{ + Logger::info(Tag(), "clear"); + TokenCache::clear(); + Lock l(fileLock_); + bool ok = QFile::remove(cacheFilePath_.c_str()); + if(!ok) + { + Logger::error(Tag(), "clear: Failed to delete a file: "); + } +} + +void FileCache::onBeforeAccess(const TokenCacheNotificationArgs&/* args*/) +{ + Logger::info(Tag(), "onBeforeAccess"); + Lock l(fileLock_); + readCache(); +} + +void FileCache::onAfterAccess(const TokenCacheNotificationArgs&/* args*/) +{ + Logger::info(Tag(), "onAfterAccess"); + Lock l(fileLock_); + // if the access operation resulted in a cache update + if (hasStateChanged_) + { + writeCache(); + hasStateChanged_ = false; + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/Guid.cpp b/sdk/rmsauth_sdk/rmsauth/Guid.cpp new file mode 100644 index 00000000..6456b9e6 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/Guid.cpp @@ -0,0 +1,22 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +String Guid::toString() const +{ + return this->pImpl->toString(); +} +bool Guid::empty() const +{ + return this->pImpl->empty(); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/GuidQt.cpp b/sdk/rmsauth_sdk/rmsauth/GuidQt.cpp new file mode 100644 index 00000000..19986635 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/GuidQt.cpp @@ -0,0 +1,55 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "GuidQt.h" + +namespace rmsauth { + +Guid::Guid() +{ + this->pImpl = std::make_shared(); +} + +Guid::Guid(const String& str) +{ + this->pImpl = std::make_shared(QString::fromStdString(str)); +} + +Guid::Guid(ptr guid) +{ + this->pImpl = guid; +} + +Guid Guid::newGuid() +{ + auto pImpl = std::make_shared(QUuid::createUuid()); + return Guid(pImpl); +} + +GuidQt::GuidQt() +{ +} + +GuidQt::GuidQt(const QUuid& uuid):uuid_(uuid) +{ +} +GuidQt::GuidQt(const QString& str):uuid_(str) +{ +} + +String GuidQt::toString() const +{ + return this->uuid_.toString().toStdString(); +} + + bool GuidQt::empty() const + { + return this->uuid_.isNull(); + } + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/GuidQt.h b/sdk/rmsauth_sdk/rmsauth/GuidQt.h new file mode 100644 index 00000000..3979d215 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/GuidQt.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef GUIDQT_H +#define GUIDQT_H + +#include +#include + +namespace rmsauth { + +class GuidQt : public IGuid +{ +public: + GuidQt(); + explicit GuidQt(const QString& str); + explicit GuidQt(const QUuid&); + +private: + QUuid uuid_; + + virtual String toString() const override; + virtual bool empty() const override; + +}; + +} // namespace rmsauth { + +#endif // GUIDQT_H diff --git a/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.cpp b/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.cpp new file mode 100644 index 00000000..7eb31d48 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.cpp @@ -0,0 +1,400 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "JsonUtilsQt.h" +#include "HttpHelperQt.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rmsauth { + +QByteArray HttpHelperQt::jobGet(QNetworkRequest& request, CallStatePtr callState) +{ + Logger::info(Tag(), "jobGet"); + + HttpHelperQt::addCorrelationIdHeadersToRequest(request, callState); + HttpHelperQt::logRequestHeaders(request); + + QNetworkAccessManager nam; + QNetworkReply* pReply = nam.get(request); + QEventLoop loop; + QObject::connect(pReply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + HttpHelperQt::logResponseHeaders(pReply); + + QNetworkReply::NetworkError networkError = pReply->error(); + if (networkError != QNetworkReply::NoError) + { + auto errMessage = pReply->errorString(); + qDebug() << QString("error: %1").arg(errMessage); + ErrorResponsePtr errorResponse = HttpHelperQt::parseResponseError(pReply); + + if (QString::fromStdString(errorResponse->error).compare("invalid_instance", Qt::CaseInsensitive) == 0) + { + throw RmsauthServiceException(Constants::rmsauthError().AuthorityNotInValidList, errMessage.toStdString()); + } + else + { + StringStream ss; + ss << Constants::rmsauthErrorMessage().AuthorityValidationFailed << ". " + << errorResponse->error << ": " + << errorResponse->errorDescription << ". " + << errMessage.toStdString(); + + throw RmsauthServiceException( + Constants::rmsauthError().AuthorityValidationFailed, + ss.str()); + } + } + + HttpHelperQt::verifyCorrelationIdHeaderInReponse(pReply, callState); + + auto body = pReply->readAll(); + HttpHelperQt::logResponseBody(body); + return std::move(body); +} + +QByteArray HttpHelperQt::jobGetRunner(QNetworkRequest& request, CallStatePtr callState) +{ + Logger::info(Tag(), "jobGetRunner"); + + int argc = 1; + char name[] = "jobGetRunner"; + char ** argv = new char*[argc]; + argv[0] = name; + QCoreApplication a(argc, argv); + + auto body = jobGet(request, callState); + + QTimer::singleShot(0, &a, SLOT(quit())); + a.exec(); + + return std::move(body); +} + +QByteArray HttpHelperQt::jobPost(QNetworkRequest& request, const RequestParameters& requestParameters, CallStatePtr callState) +{ + Logger::info(Tag(), "jobPost"); + + if ((callState != nullptr) && !callState->correlationId().empty()) + { + HttpHelperQt::addCorrelationIdHeadersToRequest(request, callState); + } + HttpHelperQt::logRequestHeaders(request); + Logger::info(Tag(), "request url: %", request.url().toString().toStdString()); + Logger::info(Tag(), "request body: %", requestParameters.toString()); + + QNetworkAccessManager nam; + QNetworkReply *pReply = nam.post(request, requestParameters.toString().data()); + QEventLoop loop; + QObject::connect(pReply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + HttpHelperQt::logResponseHeaders(pReply); + + QNetworkReply::NetworkError error_type = pReply->error(); + + if (error_type != QNetworkReply::NoError) + { + String errString = QString("error: %1").arg(pReply->errorString()).toStdString(); + Logger::error(Tag(), errString); + throw RmsauthServiceException(errString); + } + + HttpHelperQt::verifyCorrelationIdHeaderInReponse(pReply, callState); + + auto body = pReply->readAll(); + HttpHelperQt::logResponseBody(body); + return std::move(body); +} + +QByteArray HttpHelperQt::jobPostRunner(QNetworkRequest& request, const RequestParameters& requestParameters, CallStatePtr callState) +{ + Logger::info(Tag(), "jobPostRunner"); + + int argc = 1; + char name[] = "jobPostRunner"; + char **argv = new char *[argc]; + + argv[0] = name; + QCoreApplication a(argc, argv); + + auto body = jobPost(request, requestParameters, callState); + + + QTimer::singleShot(0, &a, SLOT(quit())); + a.exec(); + + return std::move(body); +} + +TokenResponsePtr HttpHelper::sendPostRequestAndDeserializeJsonResponseAsync(const String& url, const RequestParameters& requestParameters, CallStatePtr callState) +{ + Logger::info(Tag(), "sendPostRequestAndDeserializeJsonResponseAsync"); + + QNetworkRequest request = HttpHelperQt::createRequest(); + + request.setUrl(QUrl(url.data())); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + HttpHelperQt::addHeadersToRequest(request, RmsauthIdHelper::getProductHeaders()); + + if (QCoreApplication::instance() == nullptr) + { + auto fut = std::async(&HttpHelperQt::jobPostRunner, std::ref(request), requestParameters, callState); + auto body = fut.get(); + return HttpHelperQt::deserializeTokenResponse(body); + } + + auto body = HttpHelperQt::jobPost(request, requestParameters, callState); + return HttpHelperQt::deserializeTokenResponse(body); +} + +static bool addCACertificate(const std::vector& certificate, QSsl::EncodingFormat format) +{ + Logger::info("local", "addCACertificate"); + + QSslConfiguration SslConfiguration(QSslConfiguration::defaultConfiguration()); + + QList certificates = SslConfiguration.caCertificates(); + + QList cert = QSslCertificate::fromData(QByteArray( + reinterpret_cast(certificate.data()), static_cast(certificate.size())), format); + + if (cert.length() == 0) return false; + + certificates.append(cert); + + SslConfiguration.setCaCertificates(certificates); + QSslConfiguration::setDefaultConfiguration(SslConfiguration); + + return true; +} + +bool HttpHelper::addCACertificateBase64(const std::vector& certificate) +{ + Logger::info(Tag(), "addCACertificateBase64"); + return addCACertificate(certificate, QSsl::Pem); +} + +bool HttpHelper::addCACertificateDer(const std::vector& certificate) +{ + Logger::info(Tag(), "addCACertificateDer"); + return addCACertificate(certificate, QSsl::Der); +} + +QNetworkRequest HttpHelperQt::createRequest() +{ + Logger::info(Tag(), "createRequest"); + + QNetworkRequest request; + + request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); + request.setRawHeader("User-Agent", Constants::rmsauthIdParameter().UserAgent.data()); + return std::move(request); +} + +void HttpHelperQt::addCorrelationIdHeadersToRequest(QNetworkRequest& request, CallStatePtr callState) +{ + Logger::info(Tag(), "deserializeTokenResponse"); + + request.setRawHeader(OAuthConstants::oAuthHeader().CorrelationId.data(), callState->correlationId().toString().data()); + request.setRawHeader(OAuthConstants::oAuthHeader().RequestCorrelationIdInResponse.data(), "true"); +} + +void HttpHelperQt::verifyCorrelationIdHeaderInReponse(QNetworkReply* pReply, CallStatePtr callState) +{ + Logger::info(Tag(), "verifyCorrelationIdHeaderInReponse"); + + if ((callState == nullptr) || callState->correlationId().empty()) + { + return; + } + + QUuid correlationIdInRequest(QString::fromStdString(callState->correlationId().toString())); + + auto headers = pReply->rawHeaderPairs(); + + for (auto header : headers) + { + if (QString(header.first).compare(OAuthConstants::oAuthHeader().CorrelationId.data(), Qt::CaseInsensitive) == 0) + { + QString correlationIdStr(header.second); + + QUuid correlationIdInResponse(correlationIdStr); + + if (correlationIdInResponse.isNull()) + { + Logger::warning(Tag(), "Returned correlation id '%' is not in GUID format.", correlationIdStr.toStdString()); + } + else if (correlationIdInResponse != correlationIdInRequest) + { + Logger::warning(Tag(), "Returned correlation id '%' does not match the sent correlation id '%'", + correlationIdInResponse.toString().toStdString(), + correlationIdInRequest.toString().toStdString()); + } + + break; + } + } +} + +TokenResponsePtr HttpHelperQt::deserializeTokenResponse(const QByteArray& body) +{ + Logger::info(Tag(), "deserializeTokenResponse"); + auto pTokenResponse = std::make_shared(); + + Logger::info(Tag(), "jsonObject: %", String(body.begin(), body.end())); + + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(body, &error); + + if (error.error != QJsonParseError::NoError) + { + throw RmsauthException(String("deserializeTokenResponse: ") + error.errorString().toStdString()); + } + + QJsonObject qobj = qdoc.object(); + + pTokenResponse->tokenType = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().tokenType); + pTokenResponse->accessToken = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().accessToken); + pTokenResponse->refreshToken = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().refreshToken); + pTokenResponse->resource = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().resource); + pTokenResponse->idToken = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().idToken); + pTokenResponse->createdOn = JsonUtilsQt::getStringAsIntOrDefault(qobj, TokenResponse::jsonNames().createdOn); + pTokenResponse->expiresOn = JsonUtilsQt::getStringAsIntOrDefault(qobj, TokenResponse::jsonNames().expiresOn); + pTokenResponse->expiresIn = JsonUtilsQt::getStringAsIntOrDefault(qobj, TokenResponse::jsonNames().expiresIn); + pTokenResponse->correlationId = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().correlationId); + + pTokenResponse->error = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().error); + pTokenResponse->errorDescription = JsonUtilsQt::getStringOrDefault(qobj, TokenResponse::jsonNames().errorDescription); + pTokenResponse->errorCodes = JsonUtilsQt::getIntArrayOrEmpty(qobj, TokenResponse::jsonNames().errorCodes); + + return pTokenResponse; +} + +InstanceDiscoveryResponsePtr HttpHelperQt::deserializeInstanceDiscoveryResponse(const QByteArray& body) +{ + Logger::info(Tag(), "deserializeInstanceDiscoveryResponse"); + + auto pInstanceDiscoveryResponse = std::make_shared(); + + Logger::info(Tag(), "jsonObject: %", String(body.begin(), body.end())); + + QJsonParseError parseError; + auto qdoc = QJsonDocument::fromJson(body, &parseError); + + if (parseError.error != QJsonParseError::NoError) + { + throw RmsauthException(String("deserializeInstanceDiscoveryResponse QJsonDocument::fromJson: ") + parseError.errorString().toStdString()); + } + + QJsonObject qobj = qdoc.object(); + + pInstanceDiscoveryResponse->tenantDiscoveryEndpoint = JsonUtilsQt::getStringOrDefault(qobj, InstanceDiscoveryResponse::jsonNames().tenantDiscoveryEndpoint); + + return pInstanceDiscoveryResponse; +} + +ErrorResponsePtr HttpHelperQt::parseResponseError(QNetworkReply* pReply) +{ + Logger::info(Tag(), "parseResponseError"); + + auto pErrorResponse = std::make_shared(); + + auto jsonObject = pReply->readAll(); + + Logger::info(Tag(), "jsonObject: %", String(jsonObject.begin(), jsonObject.end())); + + if (jsonObject.isEmpty()) + { + pErrorResponse->error = Constants::rmsauthError().ServiceReturnedError; + pErrorResponse->errorDescription = Constants::rmsauthErrorMessage().ServiceReturnedError; + } + else + { + QJsonParseError parseError; + auto qdoc = QJsonDocument::fromJson(jsonObject, &parseError); + + if (parseError.error != QJsonParseError::NoError) + { + } + + QJsonObject qobj = qdoc.object(); + + pErrorResponse->error = JsonUtilsQt::getStringOrDefault(qobj, ErrorResponse::jsonNames().error); + pErrorResponse->errorDescription = JsonUtilsQt::getStringOrDefault(qobj, ErrorResponse::jsonNames().errorDescription); + pErrorResponse->errorCodes = JsonUtilsQt::getIntArrayOrEmpty(qobj, ErrorResponse::jsonNames().errorCodes); + } + + return pErrorResponse; +} + +void HttpHelperQt::addHeadersToRequest(QNetworkRequest& request, const Headers& headers) +{ + for (auto& header : headers) + { + request.setRawHeader(header.first.data(), header.second.data()); + } +} +void HttpHelperQt::logRequestHeaders(const QNetworkRequest& req) +{ + Logger::info(Tag(), "logRequestHeaders"); + QList headerList = req.rawHeaderList(); + if(headerList.length() > 0) + { + Logger::info(Tag(), "--> Headers:"); + for(auto& header : headerList) + { + const QByteArray& headerVal = req.rawHeader(header); + StringStream ss; ss << String(header.data(), header.size()) << ": " << String(headerVal.data(), headerVal.size()); + Logger::info(Tag(), ss.str()); + } + } +} + +void HttpHelperQt::logResponseHeaders(QNetworkReply *pReply) +{ + Logger::info(Tag(), "logResponseHeaders"); + if (pReply->rawHeaderPairs().length() > 0) + { + Logger::info(Tag(), "--> Headers:"); + foreach (const QNetworkReply::RawHeaderPair& pair, pReply->rawHeaderPairs()) + { + StringStream ss; ss << String(pair.first.data(), pair.first.size()) << ": " << String(pair.second.data(), pair.second.size()); + Logger::info(Tag(), ss.str()); + } + } +} +void HttpHelperQt::logResponseBody(const QByteArray& body) +{ + Logger::info(Tag(), "logResponseBody"); + if (body.length() > 0) + { + Logger::info(Tag(), "==> Body:"); + Logger::info(Tag(), String(body.begin(), body.end())); + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.h b/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.h new file mode 100644 index 00000000..2390eaa7 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/HttpHelperQt.h @@ -0,0 +1,49 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef HTTPHELPERQT +#define HTTPHELPERQT + +#include +#include +#include +#include +#include + +namespace rmsauth { + +class HttpHelperQt +{ + static const String& Tag() {static const String tag="HttpHelperQt"; return tag;} + +public: + static QNetworkRequest createRequest(); + static void addHeadersToRequest(QNetworkRequest& request, const Headers& headers); + + static TokenResponsePtr deserializeTokenResponse(const QByteArray& body); + static InstanceDiscoveryResponsePtr deserializeInstanceDiscoveryResponse(const QByteArray& body); + static ErrorResponsePtr parseResponseError(QNetworkReply* pReply); + static void verifyCorrelationIdHeaderInReponse(QNetworkReply* pReply, CallStatePtr callState); + + static void addCorrelationIdHeadersToRequest(QNetworkRequest& request, CallStatePtr callState); + + static QByteArray jobPost(QNetworkRequest& request, const RequestParameters& requestParameters, CallStatePtr callState); + static QByteArray jobPostRunner(QNetworkRequest& request, const RequestParameters& requestParameters, CallStatePtr callState); + + static QByteArray jobGet(QNetworkRequest& request, CallStatePtr callState); + static QByteArray jobGetRunner(QNetworkRequest& request, CallStatePtr callState); + + static void logRequestHeaders(const QNetworkRequest& req); + static void logResponseHeaders(QNetworkReply *pReply); + static void logResponseBody(const QByteArray& body); +}; + +} //namespace rmsauth { + +#endif // HTTPHELPERQT + diff --git a/sdk/rmsauth_sdk/rmsauth/IWebUI.cpp b/sdk/rmsauth_sdk/rmsauth/IWebUI.cpp new file mode 100644 index 00000000..7b64fed1 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/IWebUI.cpp @@ -0,0 +1,16 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +WebUI::WebUI(PromptBehavior promptBehavior):promptBehavior_(promptBehavior) +{} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.cpp b/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.cpp new file mode 100644 index 00000000..8c2ad925 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.cpp @@ -0,0 +1,154 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "JsonUtilsQt.h" +#include +#include +#include +#include +#include +#include + +namespace rmsauth { + +String JsonUtilsQt::getStringOrDefault(const QJsonObject& qobj, const String& key, const String defval) +{ + if (qobj.contains(key.data())) + { + auto res = qobj.value(key.data()); + if(!res.isString()) + { + Logger::error(Tag(), "getStringOrDefault: The value for the key '%' is not a string", key); + throw RmsauthJsonParsingException("JsonUtilsQt::getStringOrDefault", "value is not a string"); + } + + return res.toString().toStdString(); + } + return defval; +} + +int JsonUtilsQt::getIntOrDefault(const QJsonObject& qobj, const String& key, int defval) +{ + if (qobj.contains(key.data())) + { + auto res = qobj.value(key.data()); + if(!res.isDouble()) + { + Logger::error(Tag(), "getIntOrDefault: The value for the key '%' is not int", key); + throw RmsauthJsonParsingException("JsonUtilsQt::getIntOrDefault", "value is not int"); + } + + return res.toInt(); + } + return defval; +} + +int JsonUtilsQt::getStringAsIntOrDefault(const QJsonObject& qobj, const String& key, int defval) +{ + if (qobj.contains(key.data())) + { + auto res = qobj.value(key.data()); + + if(res.isDouble()) + { + return res.toDouble(defval); + } + + if(!res.isString()) + { + Logger::error(Tag(), "getStringAsIntOrDefault: The value for the key '%' is not a string", key); + throw RmsauthJsonParsingException("JsonUtilsQt::getStringAsIntOrDefault", "value is not a string"); + } + + auto strRes = res.toString(); + bool ok; + auto intRes = strRes.toInt(&ok); + + if(!ok) + { + Logger::error(Tag(), "The value '%' for the key '%' can't be converted to int", strRes.toStdString(), key); + throw RmsauthJsonParsingException("JsonUtilsQt::getStringAsIntOrZero", "value can't be converted to int"); + } + + return intRes; + } + return defval; +} + +bool JsonUtilsQt::getBoolOrDefault(const QJsonObject& qobj, const String& key, bool defval) +{ + if (qobj.contains(key.data())) + { + auto res = qobj.value(key.data()); + if(!res.isBool()) + { + Logger::error(Tag(), "getBoolOrDefault: The value for the key '%' is not bool", key); + throw RmsauthJsonParsingException("JsonUtilsQt::getBoolOrDefault", "value is not bool"); + } + + return res.toBool(); + } + + return defval; +} + +IntArray JsonUtilsQt::getIntArrayOrEmpty(const QJsonObject& qobj, const String& key) +{ + IntArray sa; + if (qobj.contains(key.data())) + { + QJsonValue val = qobj.value(key.data()); + if(val.isArray()) + { + QJsonArray arr = val.toArray(); + for( QJsonValue elem : arr) + { + if(elem.isDouble()) + { + sa.push_back( elem.toInt()); + } + else + { + StringStream ss; + ss << "getIntArrayOrEmpty: the array element for the key '" << key << "' in not an int"; + throw RmsauthException(ss.str()); + } + } + } + else if(val.isNull()) + { + return std::move(sa); + } + else + { + StringStream ss; + ss << "getIntArrayOrEmpty: the value for the key '" << key << "' in not an array"; + throw RmsauthException(ss.str()); + } + } + return std::move(sa); +} + +void JsonUtilsQt::insertObject(QJsonObject& qobj, const String& key, const String& jsonString) +{ + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(jsonString.data(), &error); + if( error.error != QJsonParseError::NoError ) + { + throw RmsauthException(String("AuthenticationResult::deserialize: ") + error.errorString().toStdString()); + } + QJsonObject qobjToInsert = qdoc.object(); + qobj.insert(key.data(), qobjToInsert); +} + +void JsonUtilsQt::insertString(QJsonObject& qobj, const String& key, const String& str) +{ + qobj.insert(QString::fromStdString(key), QString::fromStdString(str)); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.h b/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.h new file mode 100644 index 00000000..dd5c34b4 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/JsonUtilsQt.h @@ -0,0 +1,55 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef JSONUTILSQT_H +#define JSONUTILSQT_H + +#include +#include +#include +#include + +namespace rmsauth { + +class JsonUtilsQt +{ + static const String Tag(){static const String tag = "JsonUtilsQt"; return tag;} + template + using Deserializer = P (*)(const String& jsonString); + +public: + static String getStringOrDefault(const QJsonObject& qobj, const String& key, const String defval = ""); + static int getIntOrDefault(const QJsonObject& qobj, const String& key, int defval = 0 ); + static int getStringAsIntOrDefault(const QJsonObject& qobj, const String& key, int defval = 0); + static bool getBoolOrDefault(const QJsonObject& qobj, const String& key, bool defval = false); + static IntArray getIntArrayOrEmpty(const QJsonObject& qobj, const String& key); + template + static T parseObject(const QJsonObject& qobj, const String& key, Deserializer d); + static void insertObject(QJsonObject& qobj, const String& key, const String& jsonString); + static void insertString(QJsonObject& qobj, const String& key, const String& str); +}; + +template +P JsonUtilsQt::parseObject(const QJsonObject& qobj, const String& key, Deserializer

deserialize) +{ + if (!qobj.contains(key.data())) + { + return nullptr; + } + + auto qjo = qobj.value(key.data()); + QJsonDocument doc(qjo.toObject()); + + auto jsonData = doc.toJson(QJsonDocument::Compact); + + return deserialize(String(jsonData.begin(), jsonData.end())); +} + +} // namespace rmsauth { + +#endif // JSONUTILSQT_H diff --git a/sdk/rmsauth_sdk/rmsauth/Logger.cpp b/sdk/rmsauth_sdk/rmsauth/Logger.cpp new file mode 100644 index 00000000..5bfe24e8 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/Logger.cpp @@ -0,0 +1,81 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +Logger& Logger::instance() +{ + static LoggerImpl instance; + return instance; +} + +void Logger::printf(StringStream& ss, const char *s) +{ + while (*s) + { + if (*s == '%') + { + if (*(s + 1) == '%') + { + ++s; + } + else + { + throw Exception("Logger: invalid format string: missing arguments"); + } + } + ss << *s++; + } +} + +void Logger::record(const String& category, const String& tag, const String& record) +{ + Logger::instance().append(category, tag, record); +} + +void Logger::info(const String& tag, const String& record) +{ + Logger::record("INF", tag, record); +} +void Logger::warning(const String& tag, const String& record) +{ + Logger::record("WRN", tag, record); +} +void Logger::error(const String& tag, const String& record) +{ + Logger::record("ERR", tag, record); +} + +LoggerImpl::LoggerImpl() +{ + StringStream filename; + filename << "rmsauth_" << LoggerImpl::getLocalTime("HHmmss-MMdd") << ".log"; + + this->stream_.open (filename.str(), std::ofstream::out | std::ofstream::trunc); + if( this->stream_.fail()) + { + StringStream info; + info << "Can't open file: " << filename.str(); + throw std::runtime_error(info.str()); + } +} +LoggerImpl::~LoggerImpl() +{ + this->stream_.close(); +} +void LoggerImpl::append(const String& category, const String& tag, const std::string& record) +{ + std::stringstream ss; + ss << LoggerImpl::getLocalTime("HH:mm:ss ") << category << ": " << tag << ": " << record; + this->stream_ << ss.str() << std::endl; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/LoggerImplQt.cpp b/sdk/rmsauth_sdk/rmsauth/LoggerImplQt.cpp new file mode 100644 index 00000000..22b5e8da --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/LoggerImplQt.cpp @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +String LoggerImpl::getLocalTime(const String& format) +{ + auto now = QDateTime::currentDateTime(); + return std::move(now.toString(QString::fromStdString(format)).toStdString()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/OAuth2ResponseQt.cpp b/sdk/rmsauth_sdk/rmsauth/OAuth2ResponseQt.cpp new file mode 100644 index 00000000..db381420 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/OAuth2ResponseQt.cpp @@ -0,0 +1,194 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "JsonUtilsQt.h" +#include +#include +#include +#include +#include +#include + +namespace rmsauth { + +AuthenticationResultPtr OAuth2Response::parseTokenResponse(TokenResponsePtr tokenResponse, CallStatePtr/* callState*/) +{ + Logger::info(Tag(), "parseTokenResponse"); + AuthenticationResultPtr result = nullptr; + + if (!tokenResponse->accessToken.empty()) + { + auto curTimeUts = QDateTime::currentDateTimeUtc(); + Logger::info(Tag(), "curTimeUTC: %; expiresIn: %", curTimeUts.toString("HH:mm:ss MM.dd.yy").toStdString(), tokenResponse->expiresIn); + + auto expiresUtc = curTimeUts.addSecs(tokenResponse->expiresIn); + DateTimeOffset expiresOn = expiresUtc.toTime_t(); + + Logger::info(Tag(), "tonken expiresOn: % (%)", expiresUtc.toString("HH:mm:ss MM.dd.yy").toStdString(), expiresOn); + + result = std::make_shared(tokenResponse->tokenType, tokenResponse->accessToken, tokenResponse->refreshToken, expiresOn); + // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need + // to get it from the STS response. + result->resource(tokenResponse->resource); + result->isMultipleResourceRefreshToken(!tokenResponse->refreshToken.empty() && !tokenResponse->resource.empty()); + + IdTokenPtr idToken = OAuth2Response::parseIdToken(tokenResponse->idToken); + if (idToken != nullptr) + { + String tenantId = idToken->tenantId; + String uniqueId; + String displayableId; + + if (!idToken->objectId.empty()) + { + uniqueId = idToken->objectId; + } + else if (!idToken->subject.empty()) + { + uniqueId = idToken->subject; + } + + if (!idToken->UPN.empty()) + { + displayableId = idToken->UPN; + } + else if (!idToken->email.empty()) + { + displayableId = idToken->email; + } + + String givenName = idToken->givenName; + String familyName = idToken->familyName; + String identityProvider = idToken->identityProvider.empty() ? idToken->issuer : idToken->identityProvider; + DateTimeOffset passwordExpiresOn = 0; + if (idToken->passwordExpiration > 0) + { + passwordExpiresOn = QDateTime::currentDateTimeUtc().addSecs(idToken->passwordExpiration).toTime_t(); + } + + String changePasswordUri; + if (!idToken->passwordChangeUrl.empty()) + { + changePasswordUri = idToken->passwordChangeUrl; + } + + auto userInfo = std::make_shared(); + userInfo->uniqueId(uniqueId); + userInfo->displayableId(displayableId); + userInfo->givenName(givenName); + userInfo->familyName(familyName); + userInfo->identityProvider(identityProvider); + userInfo->passwordExpiresOn(passwordExpiresOn); + userInfo->passwordChangeUrl(changePasswordUri); + + result->updateTenantAndUserInfo(tenantId, tokenResponse->idToken, userInfo ); + } + } + else if (!tokenResponse->error.empty()) + { + Logger::error(Tag(), "error: %, description: %", tokenResponse->error, tokenResponse->errorDescription); + throw RmsauthException(tokenResponse->error, tokenResponse->errorDescription); + } + else + { + throw RmsauthException(Constants::rmsauthError().Unknown); + } + + return result; +} + +IdTokenPtr OAuth2Response::parseIdToken(const String& idToken) +{ + Logger::info(Tag(), "parseIdToken"); + Logger::info(Tag(), "idToken: %", idToken); + IdTokenPtr parseResult = nullptr; + if (!idToken.empty()) + { + StringArray idTokenSegments = StringUtils::split(idToken, '.'); + + // If Id token format is invalid, we silently ignore the id token + if (idTokenSegments.size() != 3) + { + throw RmsauthException("idTokenSegments.size() != 3"); + } + + QByteArray ba; + ba.append(idTokenSegments[1].data()); + String jsonString = QByteArray::fromBase64(ba).data(); + + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(jsonString.data(), &error); + if( error.error != QJsonParseError::NoError ) + { + throw RmsauthException(String("deserializeTokenResponse: ") + error.errorString().toStdString()); + } + + QJsonObject qobj = qdoc.object(); + parseResult.reset(new IdToken()); + + parseResult->objectId = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().objectId); + parseResult->subject = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().subject); + parseResult->tenantId = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().tenantId); + parseResult->UPN = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().UPN); + parseResult->givenName = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().givenName); + parseResult->familyName = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().familyName); + parseResult->email = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().email); + parseResult->passwordChangeUrl = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().passwordChangeUrl); + parseResult->identityProvider = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().identityProvider); + parseResult->issuer = JsonUtilsQt::getStringOrDefault(qobj, IdToken::jsonNames().issuer); + parseResult->passwordExpiration = JsonUtilsQt::getStringAsIntOrDefault(qobj, IdToken::jsonNames().passwordExpiration); + } + + return parseResult; +} + +AuthorizationResultPtr OAuth2Response::parseAuthorizeResponse(const String& webAuthenticationResult, CallStatePtr/* callState*/) +{ + Logger::info(Tag(), "parseAuthorizeResponse"); + Logger::info(Tag(), "webAuthenticationResult: %", webAuthenticationResult); + + AuthorizationResultPtr parseResult = nullptr; + + QUrl url(webAuthenticationResult.data()); + if (url.hasQuery()) + { + QUrlQuery query = QUrlQuery(url); + if( query.hasQueryItem(OAuthConstants::oAuthReservedClaim().Code.data()) ) + { + parseResult = std::make_shared(query.queryItemValue(OAuthConstants::oAuthReservedClaim().Code.data()).toStdString()); + } + else if( query.hasQueryItem(OAuthConstants::oAuthReservedClaim().Error.data()) ) + { + String error = query.queryItemValue(OAuthConstants::oAuthReservedClaim().Error.data()).toStdString(); + String errorDesc = query.hasQueryItem(OAuthConstants::oAuthReservedClaim().ErrorDescription.data()) + ? query.queryItemValue(OAuthConstants::oAuthReservedClaim().ErrorDescription.data(), QUrl::FullyDecoded).toStdString() + : ""; + parseResult = std::make_shared( + error, + StringUtils::replaceAll(errorDesc, '+', ' ')); + } + else + { + parseResult = std::make_shared( + Constants::rmsauthError().AuthenticationFailed, + Constants::rmsauthErrorMessage().AuthorizationServerInvalidResponse); + } + } + + return parseResult; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/RequestParameters.cpp b/sdk/rmsauth_sdk/rmsauth/RequestParameters.cpp new file mode 100644 index 00000000..b5e1aa27 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/RequestParameters.cpp @@ -0,0 +1,71 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +RequestParameters::RequestParameters(const String& resource, ClientKeyPtr clientKeyPtr) +{ + addParam(OAuthConstants::oAuthParameter().Resource, resource); + if(clientKeyPtr != nullptr) + addClientKey(*clientKeyPtr); +} + +String& RequestParameters::operator[](const String & key) +{ + return params_[key]; +} + +const String& RequestParameters::operator[](const String & key) const +{ + auto it = params_.find(key); + if(it == params_.end()) + throw IllegalArgumentException("operator[]"); + return it->second; +} + +void RequestParameters::addParam(const String & key, const String & value) +{ + params_.insert(make_pair(key, value)); +} + +String RequestParameters::toString() const +{ + StringStream ss; + for(auto& pair : params_) + { + ss << "&" << pair.first << "=" << pair.second; + } + return ss.str(); +} + +void RequestParameters::addClientKey(const ClientKey& clientKey) +{ + addParam(OAuthConstants::oAuthParameter().ClientId, clientKey.clientId()); + + if (clientKey.credential() != nullptr) + { + addParam(OAuthConstants::oAuthParameter().ClientSecret, RequestParameters::uriEncode(clientKey.credential()->clientSecret())); + } + else if (clientKey.certificate() != nullptr) + { +// TODO.shch: complete +// addParam(OAuthConstants::oAuthParameter().ClientAssertionType, clientKey.assertion().assertionType()); +// addParam(OAuthConstants::oAuthParameter().ClientAssertion, clientKey.assertion().assertion()); + } + else if (clientKey.assertion() != nullptr) + { +// JsonWebToken jwtToken = new JsonWebToken(clientKey.Certificate, clientKey.Authenticator.SelfSignedJwtAudience); +// ClientAssertion clientAssertion = jwtToken.Sign(clientKey.Certificate); +// this[OAuthParameter.ClientAssertionType] = clientAssertion.AssertionType; +// this[OAuthParameter.ClientAssertion] = clientAssertion.Assertion; + } +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/RequestParametersQt.cpp b/sdk/rmsauth_sdk/rmsauth/RequestParametersQt.cpp new file mode 100644 index 00000000..7552691e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/RequestParametersQt.cpp @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +String RequestParameters::uriEncode(const String& value) +{ + auto encodedData = QUrl::toPercentEncoding(QString::fromStdString(value)); + return String(encodedData.data(), encodedData.size()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelper.cpp b/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelper.cpp new file mode 100644 index 00000000..a091c651 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelper.cpp @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +const Headers RmsauthIdHelper::getProductHeaders() +{ + Headers headers; + headers.insert(std::make_pair(Constants::rmsauthIdParameter().Product, Constants::rmsauthIdParameter().ProductVal)); + headers.insert(std::make_pair(Constants::rmsauthIdParameter().Version, Constants::rmsauthIdParameter().VersionVal)); + return move(headers); +} + +const Headers RmsauthIdHelper::getPlatformHeaders() +{ + Headers headers; + headers.insert(std::make_pair(Constants::rmsauthIdParameter().CpuPlatform, RmsauthIdHelper::getProcessorArchitecture())); + headers.insert(std::make_pair(Constants::rmsauthIdParameter().OS, RmsauthIdHelper::getOSVersion())); + return move(headers); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelperQt.cpp b/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelperQt.cpp new file mode 100644 index 00000000..1a44b70e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/RmsauthIdHelperQt.cpp @@ -0,0 +1,32 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include + +namespace rmsauth { + +const String RmsauthIdHelper::getProcessorArchitecture() +{ +#ifdef QT_VER_LESS_THEN_54 + return "unk"; +#else + return QSysInfo::currentCpuArchitecture().toStdString(); +#endif +} +const String RmsauthIdHelper::getOSVersion() +{ +#ifdef QT_VER_LESS_THEN_54 + return "unk"; +#else + return QSysInfo::kernelType().toStdString(); +#endif +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/TokenCache.cpp b/sdk/rmsauth_sdk/rmsauth/TokenCache.cpp new file mode 100644 index 00000000..3da7599f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/TokenCache.cpp @@ -0,0 +1,228 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +TokenCache::TokenCache() +{ +} + +TokenCache::TokenCache(const ByteArray& state) +{ + deserialize(state); +} + + +TokenCache& TokenCache::defaultShared() +{ + static TokenCache tokenCache; + return tokenCache; +} + +int TokenCache::count() const +{ + return (int)tokenCacheDictionary_.size(); +} + + +List TokenCache::readItems() +{ + TokenCacheNotificationArgs args{this}; + onBeforeAccess(args); + + List items; + for (auto kvp : tokenCacheDictionary_) + { + items.push_back(std::make_shared(kvp.first, kvp.second)); + } + + onAfterAccess(args); + + return move(items); +} + +void TokenCache::deleteItem(TokenCacheItemPtr item) +{ + Logger::info(Tag(), "deleteItem"); + + TokenCacheNotificationArgs args(this, item->resource(), item->clientId(), item->uniqueId(), item->displayableId()); + + onBeforeAccess(args); + onBeforeWrite(args); + + tokenCacheDictionary_.erase(item->tokenCacheKey()); + + hasStateChanged_ = true; + onAfterAccess(args); +} + +void TokenCache::clear() +{ + Logger::info(Tag(), "clear"); + + TokenCacheNotificationArgs args{ this }; + onBeforeAccess(args); + onBeforeWrite(args); + tokenCacheDictionary_.clear(); + hasStateChanged_ = true; + onAfterAccess(args); +} + +AuthenticationResultPtr TokenCache::loadFromCache(const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId, CallStatePtr callState) +{ + Logger::info(Tag(), "loadFromCache"); + + AuthenticationResultPtr result = nullptr; + + auto item = loadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId, callState); + + if (item != nullptr) + { + TokenCacheKey& cacheKey = item->tokenCacheKey(); + result = item->authenticationResult(); + + DateTime nowUtc; + nowUtc.addSecs(expirationMarginInSeconds_); + + Logger::info(Tag(), "Local time UTC: '%', token expiresOn: % (%)", DateTime().toString("HH:mm:ss MM.dd.yy"), DateTime(result->expiresOn()).toString("HH:mm:ss MM.dd.yy"), result->expiresOn() ); + + bool tokenNearExpiry = (result->expiresOn() <= nowUtc.toTime()); + + if (tokenNearExpiry || !StringUtils::equalsIC(cacheKey.resource(), resource) ) + { + result->accessToken(""); + if (tokenNearExpiry) + { + Logger::info(Tag(), "An expired or near expiry token was found in the cache"); + } + } + + if (result->accessToken().empty() && result->refreshToken().empty()) + { + tokenCacheDictionary_.erase(cacheKey); + Logger::info(Tag(), "An old item was removed from the cache"); + hasStateChanged_ = true; + result = nullptr; + } + + if (result != nullptr) + { + Logger::info(Tag(), "A matching token was found in the cache"); + } + } + else + { + Logger::info(Tag(), "No matching token was found in the cache"); + } + + return result; +} + +void TokenCache::storeToCache(AuthenticationResultPtr result, const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, CallStatePtr/* callState*/) +{ + Logger::info(Tag(), "storeToCache"); + + String uniqueId = (result->userInfo() != nullptr) ? result->userInfo()->uniqueId() : ""; + String displayableId = (result->userInfo() != nullptr) ? result->userInfo()->displayableId() : ""; + + TokenCacheNotificationArgs args(this, clientId, resource, uniqueId, displayableId); + onBeforeWrite(args); + + TokenCacheKey tokenCacheKey(authority, resource, clientId, subjectType, result->userInfo()); + auto it = tokenCacheDictionary_.find(tokenCacheKey); + if(it != tokenCacheDictionary_.end()) + { + it->second = result; + Logger::info(Tag(), "An item was updated in the cache"); + } + else + { + Logger::info(Tag(), "An item was added to the cache"); + tokenCacheDictionary_.insert(KeyValuePair(std::move(tokenCacheKey), result)); + } + + updateCachedMrrtRefreshTokens(result, authority, clientId, subjectType); + + hasStateChanged_ = true; +} + +void TokenCache::updateCachedMrrtRefreshTokens(AuthenticationResultPtr result, const String& authority, const String& clientId, TokenSubjectType subjectType) +{ + if (result->userInfo() != nullptr && result->isMultipleResourceRefreshToken()) + { + auto list = queryCache(authority, clientId, subjectType, result->userInfo()->uniqueId(), result->userInfo()->displayableId()); + for(TokenCacheItemPtr itemPtr : list) + { + if(itemPtr->isMultipleResourceRefreshToken()) + { + itemPtr->refreshToken(result->refreshToken()); + } + } + } +} + +TokenCacheItemPtr TokenCache::loadSingleItemFromCache(const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId, CallStatePtr/* callState*/) +{ + auto list = queryCache(authority, clientId, subjectType, uniqueId, displayableId); + auto qnty = std::count_if( + std::begin(list), std::end(list), + [&resource](TokenCacheItemPtr itemPtr) + { + return StringUtils::equalsIC(itemPtr->resource(), resource); + }); + + if (qnty > 1) + { + RmsauthException(Constants::rmsauthError().MultipleTokensMatched); + } + + if(qnty == 1) + { + Logger::info(Tag(), "An item matching the requested resource was found in the cache"); + return list.front(); + } + + if(qnty == 0) + { + auto mrrt = std::find_if( + std::begin(list), std::end(list), + [&](TokenCacheItemPtr itemPtr) + { + return itemPtr->isMultipleResourceRefreshToken(); + }); + if(mrrt != std::end(list)) + { + return *mrrt; + } + } + + return nullptr; +} + +List TokenCache::queryCache(const String& authority, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId) +{ + List list; + for (auto kvp : tokenCacheDictionary_) + { + TokenCacheKey key = kvp.first; + if (StringUtils::equalsIC(key.authority(), authority) + && (clientId.empty() || StringUtils::equalsIC(key.clientId(), clientId)) + && (uniqueId.empty() || StringUtils::equalsIC(key.uniqueId(), uniqueId)) + && (displayableId.empty() || StringUtils::equalsIC(key.displayableId(), displayableId)) + && (key.tokenSubjectType() == subjectType)) + { + list.push_back(std::make_shared(kvp.first, kvp.second)); + } + } + + return std::move(list); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/TokenCacheItem.cpp b/sdk/rmsauth_sdk/rmsauth/TokenCacheItem.cpp new file mode 100644 index 00000000..0ee9809b --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/TokenCacheItem.cpp @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +TokenCacheItem::TokenCacheItem(const TokenCacheKey& tokenCacheKey, AuthenticationResultPtr result) + : tokenCacheKey_(tokenCacheKey) + , resultPtr_(result) +{ +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/TokenCacheKey.cpp b/sdk/rmsauth_sdk/rmsauth/TokenCacheKey.cpp new file mode 100644 index 00000000..c2ba952f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/TokenCacheKey.cpp @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +TokenCacheKey::TokenCacheKey(const String& authority, const String& resource, const String& clientId, const TokenSubjectType tokenSubjectType, const UserInfoPtr userInfo) + : TokenCacheKey{authority, resource, clientId, tokenSubjectType, (userInfo != nullptr) ? userInfo->uniqueId() : "", (userInfo != nullptr) ? userInfo->displayableId() : ""} + { + } + + TokenCacheKey::TokenCacheKey(const String& authority, const String& resource, const String& clientId, const TokenSubjectType tokenSubjectType, const String& uniqueId, const String& displayableId) + : authority_(authority) + , resource_(resource) + , clientId_(clientId) + , uniqueId_(uniqueId) + , displayableId_(displayableId) + , tokenSubjectType_(tokenSubjectType) + { + } + + bool TokenCacheKey::equals(const TokenCacheKey& other) const + { + return StringUtils::equalsIC(other.authority_, authority_) + && StringUtils::equalsIC(other.resource_, resource_) + && StringUtils::equalsIC(other.clientId_, clientId_) + && StringUtils::equalsIC(other.uniqueId_, uniqueId_) + && StringUtils::equalsIC(other.displayableId_, displayableId_) + && (other.tokenSubjectType_ == tokenSubjectType_); + } + +bool TokenCacheKey::operator==(const TokenCacheKey &other) const +{ + return equals(other); +} + +size_t TokenCacheKey::getHashCode() const +{ + const String DELIM = ":::"; + StringStream ss; + ss << StringUtils::toLower(authority_) << DELIM + << StringUtils::toLower(resource_) << DELIM + << StringUtils::toLower(clientId_) << DELIM + << StringUtils::toLower(uniqueId_) << DELIM + << StringUtils::toLower(displayableId_) << DELIM + << static_cast(tokenSubjectType_); + + auto hashcode = std::hash()(ss.str()); + Logger::info(Tag(), + "TokenCacheKey::getHashCode(): authority: %; resource: %; clientId: % uniqueId: %; displayableId_: %; tokenSubjectType_: %; hashcode: %;", + authority_, resource_, clientId_, uniqueId_, displayableId_, (int)tokenSubjectType_, hashcode); + + return hashcode; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/TokenCacheQt.cpp b/sdk/rmsauth_sdk/rmsauth/TokenCacheQt.cpp new file mode 100644 index 00000000..08e2b597 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/TokenCacheQt.cpp @@ -0,0 +1,103 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include + +namespace rmsauth { + +ByteArray TokenCache::serialize() +{ + Logger::info(Tag(), "serialize"); + + QByteArray qba; + + QDataStream qds(&qba, QIODevice::WriteOnly); + + Logger::info(Tag(), "Serializing token cache with % items.", tokenCacheDictionary_.size()); + + qds << SchemaVersion_; + qds << count(); + for( auto kvp : tokenCacheDictionary_) + { + auto tokenCacheKey = kvp.first; + AuthenticationResultPtr authenticationResultPtr = kvp.second; + + qds << QString::fromStdString(tokenCacheKey.authority()); + qds << QString::fromStdString(tokenCacheKey.resource()); + qds << QString::fromStdString(tokenCacheKey.clientId()); + qds << static_cast(tokenCacheKey.tokenSubjectType()); + + qds << QString::fromStdString(authenticationResultPtr->serialize()); + } + + ByteArray ba(qba.begin(), qba.end()); + return std::move(ba); +} + +void TokenCache::deserialize(const ByteArray& state) +{ + Logger::info(Tag(), "deserialize"); + + if (state.empty()) + { + tokenCacheDictionary_.clear(); + return; + } + + QByteArray qba(state.data(), (int)state.size()); + QDataStream qds(&qba, QIODevice::ReadOnly); + + int schemaVersion; + qds >> schemaVersion; + if (schemaVersion != SchemaVersion_) + { + Logger::warning(Tag(), "The version of the persistent state of the cache does not match the current schema, so skipping deserialization."); + return; + } + + int count; + qds >> count; + + for(int i=0; i> authority; + qds >> resource; + qds >> clientId; + qds >> tokenSubjectType; + + QString authenticationResultString; + qds >> authenticationResultString; + AuthenticationResultPtr result = AuthenticationResult::deserialize(authenticationResultString.toStdString()); + + if(result == nullptr) + { + throw RmsauthParsingException("AuthenticationResult::deserialize returned nullptr"); + } + + TokenCacheKey tokenCacheKey( + authority.toStdString() + ,resource.toStdString() + ,clientId.toStdString() + ,TokenSubjectType(tokenSubjectType) + ,result->userInfo()); + + + tokenCacheDictionary_.insert(std::make_pair(std::move(tokenCacheKey), result)); + } + + Logger::info(Tag(), "Deserialized % items to token cache.", this->count()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/Url.cpp b/sdk/rmsauth_sdk/rmsauth/Url.cpp new file mode 100644 index 00000000..42e1829d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/Url.cpp @@ -0,0 +1,47 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +void Url::setUrl(const String& url) +{ + this->pImpl->setUrl(url); +} +String Url::toString() const +{ + return this->pImpl->toString(); +} + +String Url::scheme() const +{ + return this->pImpl->scheme(); +} +String Url::authority() const +{ + return this->pImpl->authority(); +} +String Url::fragment() const +{ + return this->pImpl->fragment(); +} +String Url::host() const +{ + return this->pImpl->host(); +} +String Url::path() const +{ + return this->pImpl->path(); +} +bool Url::isValid() const +{ + return this->pImpl->isValid(); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UrlQt.cpp b/sdk/rmsauth_sdk/rmsauth/UrlQt.cpp new file mode 100644 index 00000000..3a00ffbe --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UrlQt.cpp @@ -0,0 +1,65 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "UrlQt.h" +#include + +namespace rmsauth { + +Url::Url() : pImpl(std::make_shared()) +{ +} + +Url::Url(const String& url) : pImpl(std::make_shared(url.data())) +{ +} + +UrlQt::UrlQt() +{ +} + +UrlQt::UrlQt(const String& url) : url_(url.data()) +{ +} + +void UrlQt::setUrl(const String& url) +{ + this->url_.setUrl(url.data()); +} + +String UrlQt::toString() const +{ + return this->url_.toString().toStdString(); +} + +String UrlQt::scheme() const +{ + return this->url_.scheme().toStdString(); +} +String UrlQt::authority() const +{ + return this->url_.authority().toStdString(); +} +String UrlQt::host() const +{ + return this->url_.host().toStdString(); +} +String UrlQt::fragment() const +{ + return this->url_.fragment().toStdString(); +} +String UrlQt::path() const +{ + return this->url_.path().toStdString(); +} +bool UrlQt::isValid() const +{ + return this->url_.isValid(); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UrlQt.h b/sdk/rmsauth_sdk/rmsauth/UrlQt.h new file mode 100644 index 00000000..ec697e1d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UrlQt.h @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef URLQT_H +#define URLQT_H + +#include +#include + +namespace rmsauth { + +class UrlQt : public IUrl +{ +public: + UrlQt(); + UrlQt(const String& url); + void setUrl(const String& url) override; + String toString() const override; + String scheme() const override; + String authority() const override; + String host() const override; + String fragment() const override; + String path() const override; + bool isValid() const override; + +private: + QUrl url_; +}; + +} // namespace rmsauth { + +#endif // URLQT_H diff --git a/sdk/rmsauth_sdk/rmsauth/UserAssertion.cpp b/sdk/rmsauth_sdk/rmsauth/UserAssertion.cpp new file mode 100644 index 00000000..8d4a95ef --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UserAssertion.cpp @@ -0,0 +1,45 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include + +namespace rmsauth { + +UserAssertion::UserAssertion(const String& assertion) +{ + if (assertion.empty()) + { + throw RmsauthException("assertion", "the value is empty"); + } + + assertion_ = assertion; +} + +UserAssertion::UserAssertion(const String& assertion, const String& assertionType) + : UserAssertion(assertion, assertionType, "") +{} + +UserAssertion::UserAssertion(const String& assertion, const String& assertionType, const String& userName) +{ + if (assertion.empty()) + { + throw RmsauthException("assertion", "the value is empty"); + } + + if (assertionType.empty()) + { + throw RmsauthException("assertionType", "the value is empty"); + } + + assertion_ = assertion; + assertionType_ = assertionType; + userName_ = userName; +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UserCredential.cpp b/sdk/rmsauth_sdk/rmsauth/UserCredential.cpp new file mode 100644 index 00000000..2738b6b4 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UserCredential.cpp @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +UserCredential::UserCredential() + : userAuthType_(UserAuthType::IntegratedAuth) +{ +} + +UserCredential::UserCredential(const String& userName) + : userAuthType_(UserAuthType::IntegratedAuth) + , userName_(userName) +{ +} + +UserCredential::UserCredential(const String& userName, const String& password) + : userAuthType_(UserAuthType::UsernamePassword) + , userName_(userName) + , password_(password) +{ +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UserIdentifier.cpp b/sdk/rmsauth_sdk/rmsauth/UserIdentifier.cpp new file mode 100644 index 00000000..f4dc2748 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UserIdentifier.cpp @@ -0,0 +1,54 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include + +namespace rmsauth { + +UserIdentifierPtr UserIdentifier::anyUserSingleton() +{ + static const UserIdentifierPtr uid = std::make_shared("AnyUser", UserIdentifierType::UniqueId); + return uid; +} + +UserIdentifier::UserIdentifier(const String& id, UserIdentifierType type) +{ + if (id.empty()) + { + throw IllegalArgumentException("id"); + } + + id_ = id; + type_ = type; +} + +UserIdentifierPtr UserIdentifier::anyUser() +{ + return anyUserSingleton(); +} + +bool UserIdentifier::isAnyUser() const +{ + return (type_ == anyUser()->type() && id_ == anyUser()->id()); +} + +const String UserIdentifier::uniqueId() const +{ + return (!isAnyUser() && type_ == UserIdentifierType::UniqueId) + ? id_ + : ""; +} + +const String UserIdentifier::displayableId() const +{ + return (!isAnyUser() && (type_ == UserIdentifierType::OptionalDisplayableId || type_ == UserIdentifierType::RequiredDisplayableId) + ? id_ + : ""); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UserInfoQt.cpp b/sdk/rmsauth_sdk/rmsauth/UserInfoQt.cpp new file mode 100644 index 00000000..50c02d66 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UserInfoQt.cpp @@ -0,0 +1,56 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "JsonUtilsQt.h" +#include +#include + +namespace rmsauth { + +UserInfoPtr UserInfo::deserialize(const String& jsonString) +{ + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(jsonString.c_str(), &error); + if( error.error != QJsonParseError::NoError ) + { + throw RmsauthJsonParsingException("UserInfo::deserialize: ", error.errorString().toStdString()); + } + QJsonObject qobj = qdoc.object(); + + auto userInfo = std::make_shared(); + userInfo->uniqueId_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().uniqueId); + userInfo->displayableId_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().displayableId); + userInfo->givenName_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().givenName); + userInfo->familyName_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().familyName); + userInfo->identityProvider_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().identityProvider); + userInfo->passwordChangeUrl_ = JsonUtilsQt::getStringOrDefault(qobj, UserInfo::jsonNames().passwordChangeUrl); + userInfo->passwordExpiresOn_ = (DateTimeOffset)JsonUtilsQt::getIntOrDefault(qobj, UserInfo::jsonNames().passwordExpiresOn); + userInfo->forcePrompt_ = JsonUtilsQt::getBoolOrDefault(qobj, UserInfo::jsonNames().forcePrompt); + + return userInfo; +} + +String UserInfo::serialize() +{ + QJsonObject qobj; + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().uniqueId, uniqueId_); + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().displayableId, displayableId_); + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().givenName, givenName_); + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().familyName, familyName_); + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().identityProvider, identityProvider_); + JsonUtilsQt::insertString(qobj, UserInfo::jsonNames().passwordChangeUrl, passwordChangeUrl_); + qobj.insert(UserInfo::jsonNames().passwordExpiresOn.c_str(), (int)passwordExpiresOn_); + qobj.insert(UserInfo::jsonNames().forcePrompt.c_str(), forcePrompt_); + + QJsonDocument doc(qobj); + auto res = doc.toJson(QJsonDocument::Compact); + return String(res.begin(), res.end()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/UserRealmDiscoveryResponseQt.cpp b/sdk/rmsauth_sdk/rmsauth/UserRealmDiscoveryResponseQt.cpp new file mode 100644 index 00000000..e9a0f800 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/UserRealmDiscoveryResponseQt.cpp @@ -0,0 +1,72 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "HttpHelperQt.h" +#include "JsonUtilsQt.h" + +namespace rmsauth { + +static UserRealmDiscoveryResponse deserializeUserRealmDiscoveryResponse(const QByteArray& body) +{ + Logger::info("deserializeUserRealmDiscoveryResponse", "jsonObject: %", String(body.begin(), body.end())); + + QJsonParseError error; + auto qdoc = QJsonDocument::fromJson(body, &error); + + if (error.error != QJsonParseError::NoError) + { + throw RmsauthException(String("deserializeUserRealmDiscoveryResponse: ") + error.errorString().toStdString()); + } + + QJsonObject qobj = qdoc.object(); + + UserRealmDiscoveryResponse userRealmResponse; + + userRealmResponse.version(JsonUtilsQt::getStringOrDefault(qobj, UserRealmDiscoveryResponse::jsonNames().version)); + userRealmResponse.accountType(JsonUtilsQt::getStringOrDefault(qobj, UserRealmDiscoveryResponse::jsonNames().accountType)); + userRealmResponse.federationProtocol(JsonUtilsQt::getStringOrDefault(qobj, UserRealmDiscoveryResponse::jsonNames().federationProtocol)); + userRealmResponse.federationMetadataUrl(JsonUtilsQt::getStringOrDefault(qobj, UserRealmDiscoveryResponse::jsonNames().federationMetadataUrl)); + userRealmResponse.federationActiveAuthUrl(JsonUtilsQt::getStringOrDefault(qobj, UserRealmDiscoveryResponse::jsonNames().federationActiveAuthUrl)); + + return std::move(userRealmResponse); +} + +UserRealmDiscoveryResponse UserRealmDiscoveryResponse::createByDiscoveryAsync(const String& userRealmUri, const String& userName, CallStatePtr callState) +{ + String userRealmEndpoint = userRealmUri + userName + "?api-version=1.0"; + +// userRealmEndpoint = HttpHelper.CheckForExtraQueryParameter(userRealmEndpoint); + Logger::info(Tag(), "Sending user realm discovery request to '%'", userRealmEndpoint); + + QNetworkRequest request = HttpHelperQt::createRequest(); + request.setUrl(QUrl(userRealmEndpoint.data())); + HttpHelperQt::addHeadersToRequest(request, RmsauthIdHelper::getPlatformHeaders()); + HttpHelperQt::addHeadersToRequest(request, RmsauthIdHelper::getProductHeaders()); + request.setRawHeader("Accept", "application/json"); + + if(QCoreApplication::instance() == nullptr) + { + auto fut = std::async(&HttpHelperQt::jobGetRunner, std::ref(request), callState); + auto body = fut.get(); + auto userRealmResponse = deserializeUserRealmDiscoveryResponse(body); + return std::move(userRealmResponse); + } + + auto body = HttpHelperQt::jobGet(request, callState); + auto userRealmResponse = deserializeUserRealmDiscoveryResponse(body); + return std::move(userRealmResponse); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/WebUIQt.cpp b/sdk/rmsauth_sdk/rmsauth/WebUIQt.cpp new file mode 100644 index 00000000..04df4d96 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/WebUIQt.cpp @@ -0,0 +1,111 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include "../WebAuthDialog/Dialog.h" +#include +#include +#include +#include + +namespace rmsauth { + +static String jobAuthenticate(const String& requestUri, const String& callbackUri, bool useCookie) +{ + Dialog d(requestUri.data(), callbackUri.data(), useCookie); + + d.exec(); + if(d.result() == QDialog::Accepted) + { + return d.respondUrl().toStdString(); + } + + throw RmsauthException("Canceled by user"); +} + +#ifdef QT_VER_LESS_THEN_54 +static void messageInterceptor(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + QByteArray localMsg = msg.toLocal8Bit(); + switch (type) { + case QtDebugMsg: + fprintf(stderr, "%s\n", localMsg.constData()); + break; + case QtWarningMsg: + Logger::warning("WebUIQT", "Warning: %", localMsg.constData()); + break; + case QtCriticalMsg: + fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + break; + case QtFatalMsg: + fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + abort(); + } +} + +static String jobRunnerAuthenticate(const String& requestUri, const String& callbackUri, bool useCookie) +{ + Logger::info("WebUIQT", "jobRunnerAuthenticate"); + int argc = 1; + char name[] = "jobRunnerAuthenticate"; + char ** argv = new char*[argc]; + argv[0] = name; + + // To suppress "WARNING: QApplication was not created in the main() thread" on the console + // we redirect it to the Logger. + Logger::info("WebUIQT", "Redirecting all the warnings to the Logger"); + auto oldMH = qInstallMessageHandler(messageInterceptor); + + QApplication a(argc, argv); + + auto result = jobAuthenticate(requestUri, callbackUri, useCookie); + QTimer::singleShot(0, &a, SLOT(quit())); + a.exec(); + + Logger::info("WebUIQT", "Warnings redirection stoped"); + qInstallMessageHandler(oldMH); + + return std::move(result); +} +#endif + +String WebUI::authenticate(const String& requestUri, const String& callbackUri) +{ + bool useCookie = promptBehavior_ != PromptBehavior::Always; + + if(qApp == nullptr) + { +#ifdef QT_VER_LESS_THEN_54 + // To avoid issue #17 (https://github.com/MSOpenTech/rms-sdk-cpp/issues/17) + // for QT versions less then 5.4 + // we need to create QApplication instance in a separate thread. + auto fut = std::async(std::launch::async, &jobRunnerAuthenticate, requestUri, callbackUri, useCookie); + auto result = fut.get(); + return std::move(result); +#else + int argc = 1; + char name[] = "authenticate"; + char ** argv = new char*[argc]; + argv[0] = name; + + QApplication a(argc, argv); + + auto result = jobAuthenticate(requestUri, callbackUri, useCookie); + QTimer::singleShot(0, &a, SLOT(quit())); + a.exec(); + return std::move(result); +#endif + } + + auto result = jobAuthenticate(requestUri, callbackUri, useCookie); + return std::move(result); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth.pro b/sdk/rmsauth_sdk/rmsauth/rmsauth.pro new file mode 100644 index 00000000..169238d0 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth.pro @@ -0,0 +1,144 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin +TARGET = rmsauth + +# QT 5.4 has useful features +QT_CUR_VER = "v$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}" +message(Qt current version: $$QT_CUR_VER) + +lessThan(QT_CUR_VER, v5.4) { + message(QT_VER_LESS_THEN_54) + DEFINES += QT_VER_LESS_THEN_54 +} + +TEMPLATE = lib + +DEFINES += RMSAUTH_LIBRARY + +QT += core widgets network +CONFIG += plugin c++11 debug_and_release warn_on + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -L$$DESTDIR -lrmsauthWebAuthDialogd -lrmscryptod +} else { + LIBS += -L$$DESTDIR -lrmsauthWebAuthDialog -lrmscrypto +} + +INCLUDEPATH = ./rmsauth + +SOURCES += \ + AuthenticationContext.cpp \ + Url.cpp \ + DateTime.cpp \ + Guid.cpp \ + utils.cpp \ + Authenticator.cpp \ + AuthenticatorTemplate.cpp \ + AuthenticatorTemplateList.cpp \ + CallState.cpp \ + AcquireTokenHandlerBase.cpp \ + AcquireTokenInteractiveHandler.cpp \ + AcquireTokenNonInteractiveHandler.cpp \ + ClientKey.cpp \ + TokenCache.cpp \ + AuthenticationResult.cpp \ + RequestParameters.cpp \ + ClientAssertionCertificate.cpp \ + ClientCredential.cpp \ + ClientAssertion.cpp \ + IWebUI.cpp \ + UserIdentifier.cpp \ + RmsauthIdHelper.cpp \ + Logger.cpp \ + TokenCacheKey.cpp \ + TokenCacheItem.cpp \ + UserCredential.cpp \ + UserAssertion.cpp \ + UserRealmDiscoveryResponseQt.cpp\ + AcquireTokenForClientHandler.cpp \ + FileCacheEncrypted.cpp + +HEADERS += \ + rmsauth/AuthenticationContext.h \ + rmsauth/types.h \ + rmsauth/Exceptions.h \ + rmsauth/Url.h \ + rmsauth/DateTime.h \ + rmsauth/Guid.h \ + rmsauth/utils.h \ + rmsauth/Authenticator.h \ + rmsauth/AuthenticatorTemplate.h \ + rmsauth/AuthenticatorTemplateList.h \ + rmsauth/AuthorityType.h \ + rmsauth/CallState.h \ + rmsauth/Constants.h \ + rmsauth/AcquireTokenHandlerBase.h \ + rmsauth/AcquireTokenInteractiveHandler.h \ + rmsauth/AcquireTokenNonInteractiveHandler.h \ + rmsauth/ClientKey.h \ + rmsauth/TokenCache.h \ + rmsauth/TokenSubjectType.h \ + rmsauth/AuthenticationResult.h \ + rmsauth/RequestParameters.h \ + rmsauth/OAuthConstants.h \ + rmsauth/OAuth2Response.h\ + rmsauth/ClientAssertionCertificate.h \ + rmsauth/ClientCredential.h \ + rmsauth/ClientAssertion.h \ + rmsauth/HttpHelper.h \ + rmsauth/Entities.h \ + rmsauth/AuthorizationResult.h \ + rmsauth/IWebUI.h \ + rmsauth/UserIdentifier.h \ + rmsauth/RmsauthIdHelper.h \ + rmsauth/Logger.h \ + rmsauth/TokenCacheKey.h \ + rmsauth/TokenCacheNotificationArgs.h \ + rmsauth/TokenCacheItem.h \ + rmsauth/UserInfo.h \ + rmsauth/FileCache.h \ + rmsauth/rmsauthExport.h \ + rmsauth/UserCredential.h \ + rmsauth/UserAssertion.h \ + rmsauth/UserRealmDiscoveryResponse.h \ + rmsauth/AcquireTokenForClientHandler.h \ + rmsauth/FileCacheEncrypted.h + +# Framework specific (qt based) + +HEADERS += \ + GuidQt.h \ + UrlQt.h \ + DateTimeQt.h \ + JsonUtilsQt.h \ + HttpHelperQt.h + +SOURCES += \ + GuidQt.cpp \ + UrlQt.cpp \ + DateTimeQt.cpp \ + HttpHelperQt.cpp \ + OAuth2ResponseQt.cpp \ + JsonUtilsQt.cpp \ + RmsauthIdHelperQt.cpp \ + WebUIQt.cpp \ + AuthenticatorTemplateQt.cpp \ + LoggerImplQt.cpp \ + AuthenticationResultQt.cpp \ + UserInfoQt.cpp \ + FileCacheQt.cpp \ + utilsQt.cpp \ + TokenCacheQt.cpp\ + AcquireTokenNonInteractiveHandlerQt.cpp \ + RequestParametersQt.cpp + +unix { + contains(QMAKE_HOST.arch, x86_64) { + target.path = /usr/lib64 + INSTALLS += target + } else { + target.path += /usr/lib + INSTALLS += target + } +} diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenForClientHandler.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenForClientHandler.h new file mode 100644 index 00000000..b735d8a2 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenForClientHandler.h @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ACQUIRETOKENFORCLIENTHANDLER_H +#define ACQUIRETOKENFORCLIENTHANDLER_H + +#include "AcquireTokenHandlerBase.h" + +namespace rmsauth { + +class AcquireTokenForClientHandler : public AcquireTokenHandlerBase +{ + static const String& Tag() {static const String tag="AcquireTokenForClientHandler"; return tag;} + +public: + AcquireTokenForClientHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, ClientKeyPtr clientKey, bool callSync); + +protected: + void addAditionalRequestParameters(RequestParameters& requestParameters) override; +}; + +} // namespace rmsauth { + +#endif // ACQUIRETOKENFORCLIENTHANDLER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenHandlerBase.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenHandlerBase.h new file mode 100644 index 00000000..1c8b9ea9 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenHandlerBase.h @@ -0,0 +1,74 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ACQUIRETOKENHANDLERBASE_H +#define ACQUIRETOKENHANDLERBASE_H + +#include "types.h" +#include "Authenticator.h" +#include "ClientKey.h" +#include "TokenCache.h" +#include "TokenSubjectType.h" +#include "Exceptions.h" +#include "AuthenticationResult.h" +#include "RequestParameters.h" +#include "Entities.h" +#include "OAuthConstants.h" +#include "Constants.h" +#include "TokenSubjectType.h" +#include "HttpHelper.h" +#include "UserIdentifier.h" + +namespace rmsauth { + +class AcquireTokenHandlerBase +{ + static const String& Tag() {static const String tag="AcquireTokenHandlerBase"; return tag;} + +protected: + AuthenticatorPtr authenticator_ = nullptr; + TokenCachePtr tokenCache_ = nullptr; + String resource_; + ClientKeyPtr clientKey_ = nullptr; + TokenSubjectType tokenSubjectType_; + bool loadFromCache_; + bool storeToCache_; + bool supportADFS_; + CallStatePtr callState_ = nullptr; + + UserIdentifierType userIdentifierType_; + + String uniqueId_; + String displayableId_; + +public: + AuthenticationResultPtr runAsync(); + static CallStatePtr createCallState(const Guid& correlationId, bool callSync); + +protected: + AcquireTokenHandlerBase(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, ClientKeyPtr clientKey, TokenSubjectType subjectType, bool callSync); + virtual void preRunAsync(); + virtual void postRunAsync(AuthenticationResultPtr result); + virtual void preTokenRequest(); + virtual void postTokenRequest(AuthenticationResultPtr result); + virtual void addAditionalRequestParameters(RequestParameters& requestParameters) = 0; + virtual AuthenticationResultPtr sendTokenRequestAsync(); + AuthenticationResultPtr sendTokenRequestByRefreshTokenAsync(const String& refreshToken); + +private: + AuthenticationResultPtr refreshAccessTokenAsync(AuthenticationResultPtr result); + AuthenticationResultPtr sendHttpMessageAsync(const RequestParameters& requestParameters); + void notifyBeforeAccessCache(); + void notifyAfterAccessCache(); + void logReturnedToken(AuthenticationResultPtr result); + void validateAuthorityType(); +}; + +} // namespace rmsauth { + +#endif // ACQUIRETOKENHANDLERBASE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenInteractiveHandler.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenInteractiveHandler.h new file mode 100644 index 00000000..15fda4ff --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenInteractiveHandler.h @@ -0,0 +1,60 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ACQUIRETOKENINTERACTIVEHANDLER_H +#define ACQUIRETOKENINTERACTIVEHANDLER_H + +#include "AcquireTokenHandlerBase.h" +#include "PromptBehavior.h" +#include "IWebUI.h" +#include "UserIdentifier.h" +#include "Exceptions.h" +#include "Constants.h" +#include "RmsauthIdHelper.h" +#include "AuthorizationResult.h" +#include "Url.h" + +namespace rmsauth { + +class AcquireTokenInteractiveHandler : public AcquireTokenHandlerBase +{ + static const String& Tag() {static const String tag="AcquireTokenInteractiveHandler"; return tag;} + + AuthorizationResultPtr authorizationResult_ = nullptr; + String redirectUri_; + String redirectUriRequestParameter_; + PromptBehavior promptBehavior_; + String extraQueryParameters_; + IWebUIPtr webUi_ = nullptr; + UserIdentifierPtr userId_ = nullptr; + +public: + AcquireTokenInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior, UserIdentifierPtr userId, const String& extraQueryParameters, IWebUIPtr webUI, bool callSync); + +protected: + void addAditionalRequestParameters(RequestParameters& requestParameters) override; + void preTokenRequest() override; + void postTokenRequest(AuthenticationResultPtr result) override; + void acquireAuthorization(); + void sendAuthorizeRequest(); + static bool includeFormsAuthParams(); + String createAuthorizationUriAsync(const Guid& correlationId); + +private: + String createAuthorizationUri(bool includeFormsAuthParam); + RequestParameters createAuthorizationRequest(const String& loginHint, bool includeFormsAuthParam); + void verifyAuthorizationResult(); + static bool isDomainJoined(); + static bool isUserLocal(); + void setRedirectUriRequestParameter(); + static void addHeadersToRequestParameters(RequestParameters& requestParameters, Headers headers); +}; + +} // namespace rmsauth { + +#endif // ACQUIRETOKENINTERACTIVEHANDLER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenNonInteractiveHandler.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenNonInteractiveHandler.h new file mode 100644 index 00000000..3395b46a --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AcquireTokenNonInteractiveHandler.h @@ -0,0 +1,41 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ACQUIRETOKENNONINTERACTIVEHANDLER_H +#define ACQUIRETOKENNONINTERACTIVEHANDLER_H + +#include "AcquireTokenHandlerBase.h" +#include "UserCredential.h" +#include "UserAssertion.h" +#include "UserIdentifier.h" +#include "Exceptions.h" +#include "Constants.h" +#include "AuthorizationResult.h" + +namespace rmsauth { + +class AcquireTokenNonInteractiveHandler : public AcquireTokenHandlerBase +{ + static const String& Tag() {static const String tag="AcquireTokenNonInteractiveHandler"; return tag;} + + UserCredentialPtr userCredential_ = nullptr; + UserAssertionPtr userAssertion_ = nullptr; + +public: + AcquireTokenNonInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, UserCredentialPtr userCredential, bool callSync); + AcquireTokenNonInteractiveHandler(AuthenticatorPtr authenticator, TokenCachePtr tokenCache, const String& resource, const String& clientId, UserAssertionPtr userAssertion, bool callSync); + +protected: + void addAditionalRequestParameters(RequestParameters& requestParameters) override; + void preRunAsync() override; + void preTokenRequest() override; +}; + +} // namespace rmsauth { + +#endif // ACQUIRETOKENNONINTERACTIVEHANDLER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationContext.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationContext.h new file mode 100644 index 00000000..61f948be --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationContext.h @@ -0,0 +1,61 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATIONCONTEXT_H +#define AUTHENTICATIONCONTEXT_H + +#include "types.h" +#include "AuthenticationResult.h" +#include "Authenticator.h" +#include "PromptBehavior.h" +#include "UserIdentifier.h" +#include "TokenCache.h" +#include "Guid.h" +#include "AcquireTokenInteractiveHandler.h" +#include "AcquireTokenNonInteractiveHandler.h" +#include "AcquireTokenForClientHandler.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +enum class AuthorityValidationType +{ + True, + False, + NotProvided +}; + + +class RMSAUTH_EXPORT AuthenticationContext +{ + static const String& Tag() {static const String tag="AuthenticationContext"; return tag;} + + AuthenticatorPtr authenticator_; + TokenCachePtr tokenCache_; + +public: + AuthenticationContext(const String& authority, TokenCachePtr tokenCache); + AuthenticationContext(const String& authority, AuthorityValidationType validateAuthority, TokenCachePtr tokenCache); + + AuthenticationResultPtr acquireToken(const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior); + AuthenticationResultPtr acquireToken(const String& resource, const String& clientId, UserCredentialPtr userCredentiar); + AuthenticationResultPtr acquireToken(const String& resource, const String& clientId, UserAssertionPtr userAssertion); + AuthenticationResultPtr acquireToken(const String& resource, ClientCredentialPtr clientCredential); + +private: + AuthenticationResultPtr acquireTokenCommonAsync(const String& resource, const String& clientId, const String& redirectUri, PromptBehavior promptBehavior, UserIdentifierPtr userId, const String& extraQueryParameters, bool callSync = false); + AuthenticationResultPtr acquireTokenCommonAsync(const String& resource, const String& clientId, UserCredentialPtr userCredential, bool callSync = false); + AuthenticationResultPtr acquireTokenCommonAsync(const String& resource, const String& clientId, UserAssertionPtr userAssertionl, bool callSync = false); + AuthenticationResultPtr acquireTokenCommonAsync(const String& resource, ClientCredentialPtr clientCredential, bool callSync = false); + + static IWebUIPtr createWebAuthenticationDialog(PromptBehavior promptBehavior); +}; + +} // namespace rmsauth { + +#endif // AUTHENTICATIONCONTEXT_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationRequest.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationRequest.h new file mode 100644 index 00000000..b476e347 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationRequest.h @@ -0,0 +1,258 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATIONREQUEST_H +#define AUTHENTICATIONREQUEST_H + +#include "types.h" +#include "PromptBehavior.h" + +enum class UserIdentifierType +{ + UniqueId, + LoginHint, + NoUser +}; + +/** + * Represent request and keeps authorization code and similar info. + */ +class AuthenticationRequest +{ +public: +// /** +// * Developer can use acquiretoken(with loginhint) or acquireTokenSilent(with +// * userid), so this sets the type of the request. +// */ + +// AuthenticationRequest() +// : mIdentifierType (UserIdentifierType::NoUser) +// {} + +// AuthenticationRequest(const String& authority, String resource, const String& client, const String& redirect, +// const String& loginhint, PromptBehavior prompt, const String& extraQueryParams, UUID correlationId) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (client) +// , mRedirectUri (redirect) +// , mLoginHint (loginhint) +// , mPrompt (prompt) +// , mExtraQueryParamsAuthentication (extraQueryParams) +// , mCorrelationId (correlationId) +// , mIdentifierType (UserIdentifierType::NoUser) +// {} + +// AuthenticationRequest(const String& authority, const String& resource, const String& client, const String& redirect, const String& loginhint, UUID correlationId) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (client) +// , mRedirectUri (redirect) +// , mLoginHint (loginhint) +// , mCorrelationId (correlationId) +// {} + +// AuthenticationRequest(const String& authority, const String& resource, const String& client, const String& redirect, const String& loginhint) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (client) +// , mRedirectUri (redirect) +// , mLoginHint (loginhint) +// {} + +// AuthenticationRequest(const String& authority, const String& resource, const String& clientid) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (clientid) +// {} + +// /** +// * Cache usage and refresh token requests. +// * +// * @param authority +// * @param resource +// * @param clientid +// * @param userid +// * @param correlationId +// */ +// AuthenticationRequest(const String& authority, const String& resource, const String& clientid, const String& userid, const UUID& correlationId) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (clientid) +// , mUserId (userid) +// , mCorrelationId (correlationId) + +// {} + +// AuthenticationRequest(const String& authority, const String& resource, const String& clientId, const UUID& correlationId) +// : mAuthority (authority) +// , mResource (resource) +// , mClientId (clientId) +// , mCorrelationId (correlationId) + +// {} + +// const String& getAuthority() const +// { +// return mAuthority; +// } + +// void setAuthority(const String& authority) +// { +// mAuthority = authority; +// } + +// const String& getRedirectUri() const +// { +// return mRedirectUri; +// } + +// const String& getResource() const +// { +// return mResource; +// } + +// const String& getClientId() const +// { +// return mClientId; +// } + +// const String& getLoginHint() const +// { +// return mLoginHint; +// } + +// const UUID& getCorrelationId() const +// { +// return this->mCorrelationId; +// } + +// const String& getExtraQueryParamsAuthentication() const +// { +// return mExtraQueryParamsAuthentication; +// } + +// String getLogInfo() const +// { +// StringStream ss; +// ss << "Request authority: " << mAuthority +// << " resource: " << mResource +// << " clientid: " << mClientId; +// return ss.str(); +// } + +// const PromptBehavior& getPrompt() const +// { +// return mPrompt; +// } + +// void setPrompt(const PromptBehavior& prompt) +// { +// this->mPrompt = prompt; +// } + +// /** +// * @return the mRequestId related to the delegate +// */ +// int getRequestId() const +// { +// return mRequestId; +// } + +// /** +// * @param requestId the requestId to set +// */ +// void setRequestId(int requestId) +// { +// this->mRequestId = requestId; +// } + +// const String& getBrokerAccountName() const +// { +// return mBrokerAccountName; +// } + +// void setBrokerAccountName(const String& brokerAccountName) +// { +// this->mBrokerAccountName = brokerAccountName; +// } + +// void setLoginHint(const String& name) +// { +// mLoginHint = name; +// } + +// const String& getUserId() const +// { +// return mUserId; +// } + +// void setUserId(const String& userId) +// { +// this->mUserId = userId; +// } + +// bool isSilent() const +// { +// return mSilent; +// } + +// void setSilent(bool silent) +// { +// this->mSilent = silent; +// } + +// const String& getVersion() const +// { +// return mVersion; +// } + +// void setVersion(const String& version) +// { +// this->mVersion = version; +// } + +// const UserIdentifierType& getUserIdentifierType() const +// { +// return mIdentifierType; +// } + +// void setUserIdentifierType(const UserIdentifierType& user) +// { +// mIdentifierType = user; +// } + +//private: +// int mRequestId = 0; + +// String mAuthority; + +// String mRedirectUri; + +// String mResource; + +// String mClientId; + +// String mLoginHint; + +// String mUserId; + +// String mBrokerAccountName; + +// UUID mCorrelationId; + +// String mExtraQueryParamsAuthentication; + +// PromptBehavior mPrompt; + +// bool mSilent = false; + +// String mVersion; + +// UserIdentifierType mIdentifierType; +}; +#endif // AUTHENTICATIONREQUEST_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationResult.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationResult.h new file mode 100644 index 00000000..6318ba5f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticationResult.h @@ -0,0 +1,90 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATIONRESULT_H +#define AUTHENTICATIONRESULT_H + +#include "types.h" +#include "UserInfo.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class AuthenticationResult; +using AuthenticationResultPtr = ptr; + +class RMSAUTH_EXPORT AuthenticationResult +{ + static const String& Tag() {static const String tag="AuthenticationResult"; return tag;} + + const String oAuth2AuthorizationHeader_ = "Bearer "; + + String accessTokenType_; + String accessToken_; + String resource_; + String refreshToken_; + DateTimeOffset expiresOn_; + String tenantId_; + UserInfoPtr userInfo_; + String idToken_; + bool isMultipleResourceRefreshToken_; + +public: + AuthenticationResult(const String& accessTokenType, const String& accessToken, const String& refreshToken, DateTimeOffset expiresOn); + + const String& accessTokenType() const { return accessTokenType_; } + + const String& accessToken() const { return accessToken_; } + void accessToken(const String& val){ accessToken_ = val; } + + const String& resource() const { return resource_; } + void resource(const String& val){ resource_ = val; } + + const String& refreshToken() const { return refreshToken_; } + void refreshToken(const String& val){ refreshToken_ = val; } + + DateTimeOffset expiresOn() const { return expiresOn_; } + + const String& tenantId() const { return tenantId_; } + + const UserInfoPtr userInfo() const { return userInfo_; } + + const String& idToken() const { return idToken_; } + + bool isMultipleResourceRefreshToken() const { return isMultipleResourceRefreshToken_; } + void isMultipleResourceRefreshToken(const bool val) { isMultipleResourceRefreshToken_ = val; } + + + String createAuthorizationHeader(); + static AuthenticationResultPtr deserialize(const String& /*serializedObject*/); + String serialize(); + + void updateTenantAndUserInfo(const String& tenantId, const String& idToken, UserInfoPtr userInfo); + +private: + friend class OAuth2Response; + AuthenticationResult() = default; + +private: + static struct _JsonNames { + const String accessTokenType = "accessTokenType"; + const String accessToken = "accessToken"; + const String resource = "resource"; + const String refreshToken = "refreshToken"; + const String expiresOn = "expiresOn"; + const String tenantId = "tenantId_"; + const String userInfo = "userInfo"; + const String idToken = "idToken"; + const String isMultipleResourceRefreshToken = "isMultipleResourceRefreshToken"; + } JsonNames; + +}; + +} // namespace rmsauth { + +#endif // AUTHENTICATIONRESULT_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Authenticator.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Authenticator.h new file mode 100644 index 00000000..123a2f48 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Authenticator.h @@ -0,0 +1,74 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATOR_H +#define AUTHENTICATOR_H + +#include "types.h" +#include "AuthorityType.h" +#include "Guid.h" +#include "CallState.h" +#include "Exceptions.h" +#include "AuthenticatorTemplateList.h" +#include "Constants.h" +#include "utils.h" +#include "Url.h" + +namespace rmsauth { + +class Authenticator +{ + static const String& Tag() {static const String tag="Authenticator"; return tag;} + + static const String tenantlessTenantName(); + + static AuthenticatorTemplateList authenticatorTemplateList; + bool updatedFromTemplate_ = false; + + bool validateAuthority_; + bool default_ = true; + String authority_; + AuthorityType authorityType_; + bool isTenantless_; + String authorizationUri_; + String tokenUri_; + String userRealmUri_; + String selfSignedJwtAudience_; + Guid correlationId_; + +public: + Authenticator():default_(true){} + Authenticator(const String& authority, bool validateAuthority); + + const String& authority() const {return authority_;} + const AuthorityType& authorityType() const {return authorityType_;} + bool validateAuthority() const {return validateAuthority_;} + bool isTenantless() const {return isTenantless_;} + const String& authorizationUri() const {return authorizationUri_;} + const String& tokenUri() const {return tokenUri_;} + const String& userRealmUri() const {return userRealmUri_;} + const String& selfSignedJwtAudience() const {return selfSignedJwtAudience_;} + const Guid& correlationId() const {return correlationId_;} + void correlationId(const Guid& val) {correlationId_ = val;} + + void updateFromTemplateAsync(CallStatePtr callState); + void updateTenantId(const String& tenantId); + +private: + static AuthorityType detectAuthorityType(const String& authority); + static String canonicalizeUri(const String& uri); + static String replaceTenantlessTenant(const String& authority, const String& tenantId); + static bool isAdfsAuthority(const String& firstPath); + +}; + +using AuthenticatorPtr = ptr; + +} // namespace rmsauth { + +#endif // AUTHENTICATOR_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplate.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplate.h new file mode 100644 index 00000000..76f158bd --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplate.h @@ -0,0 +1,51 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATORTEMPLATE_H +#define AUTHENTICATORTEMPLATE_H +#include +#include "CallState.h" +#include "types.h" + +namespace rmsauth { + +class AuthenticatorTemplate +{ + static const String& Tag() {static const String tag="AuthenticatorTemplate"; return tag;} + + String host_; + String issuer_; + String authority_; + String instanceDiscoveryEndpoint_; + String authorizeEndpoint_; + String tokenEndpoint_; + String userRealmEndpoint_; + + static const String authorizeEndpointTemplate(); + static const String HOST(); + static const String TENANT(); + +public: + const String& host() const {return host_;} + const String& issuer() const {return issuer_;} + const String& authority() const {return authority_;} + const String& instanceDiscoveryEndpoint() const {return instanceDiscoveryEndpoint_;} + const String& authorizeEndpoint() const {return authorizeEndpoint_;} + const String& tokenEndpoint() const {return tokenEndpoint_;} + const String& userRealmEndpoint() const {return userRealmEndpoint_;} + + static ptr createFromHost(const String& host); + void verifyAnotherHostByInstanceDiscoveryAsync(const String& host, const String& tenant, CallStatePtr callState); + +}; + +using AuthenticatorTemplatePtr = ptr; + +} // namespace rmsauth { + +#endif // AUTHENTICATORTEMPLATE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplateList.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplateList.h new file mode 100644 index 00000000..11b1226d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthenticatorTemplateList.h @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHENTICATORTEMPLATELIST_H +#define AUTHENTICATORTEMPLATELIST_H +#include "types.h" +#include "AuthenticatorTemplate.h" +#include "CallState.h" +#include + +namespace rmsauth { + +class AuthenticatorTemplateList : public ArrayList +{ +public: + AuthenticatorTemplateList(); + + AuthenticatorTemplatePtr findMatchingItemAsync(bool validateAuthority, const String& host, const String& tenant, CallStatePtr callState); + +}; + +} // namespace rmsauth { + +#endif // AUTHENTICATORTEMPLATELIST_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorityType.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorityType.h new file mode 100644 index 00000000..3b19ef1e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorityType.h @@ -0,0 +1,23 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHORITYTYPE +#define AUTHORITYTYPE + +namespace rmsauth { + +enum class AuthorityType +{ + AAD = 0, + ADFS +}; + +} // namespace rmsauth { + +#endif // AUTHORITYTYPE + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorizationResult.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorizationResult.h new file mode 100644 index 00000000..8ceb4d02 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/AuthorizationResult.h @@ -0,0 +1,56 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef AUTHORIZATIONRESULT_H +#define AUTHORIZATIONRESULT_H + +#include "types.h" + +namespace rmsauth { + +enum class AuthorizationStatus +{ + Failed = -1, + Success = 1, +}; + +class AuthorizationResult +{ + static const String& Tag() {static const String tag="AuthorizationResult"; return tag;} + + AuthorizationStatus status_; + String code_; + String error_; + String errorDescription_; + +public: +// AuthorizationResult(const String& code); +// AuthorizationResult(const String& error, const String& errorDescription); + AuthorizationResult(const String& code) + : status_(AuthorizationStatus::Success) + , code_(code) + { + } + AuthorizationResult(const String& error, const String& errorDescription) + : status_(AuthorizationStatus::Failed) + , error_(error) + , errorDescription_(errorDescription) + { + } + + const AuthorizationStatus& status() const { return status_; } + const String& code() const { return code_; } + const String& error() const { return error_; } + const String& errorDescription() const { return errorDescription_; } +}; + +using AuthorizationResultPtr = ptr; + +} // namespace rmsauth { + +#endif // AUTHORIZATIONRESULT_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/CallState.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/CallState.h new file mode 100644 index 00000000..bcddfba2 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/CallState.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CALLSTATE_H +#define CALLSTATE_H +#include "AuthorityType.h" +#include "Guid.h" + +namespace rmsauth { + +class CallState +{ + Guid correlationId_; + bool callSync_; + AuthorityType authorityType_; + +public: + CallState(Guid& correlationId, bool callSync); + + const Guid& correlationId() const { return correlationId_;} // getter + void correlationId(const Guid& val) { correlationId_ = val;} // setter + + bool callSync() const { return callSync_;} + void callSync(const bool val) { callSync_ = val;} + + const AuthorityType& authorityType() const { return authorityType_;} + void authorityType(const AuthorityType& val) { authorityType_ = val;} +}; + +using CallStatePtr = ptr; + +} // namespace rmsauth { + +#endif // CALLSTATE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertion.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertion.h new file mode 100644 index 00000000..551673ce --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertion.h @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CLIENTASSERTION_H +#define CLIENTASSERTION_H + +#include "types.h" + +namespace rmsauth { + +class ClientAssertion +{ +public: + ClientAssertion(); + const String& clientId() const { return clientId_; } + +private: + String clientId_; + +}; + +using ClientAssertionPtr = ptr; + +} // namespace rmsauth { + +#endif // CLIENTASSERTION_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertionCertificate.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertionCertificate.h new file mode 100644 index 00000000..dbac55a0 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientAssertionCertificate.h @@ -0,0 +1,30 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CLIENTASSERTIONCERTIFICATE_H +#define CLIENTASSERTIONCERTIFICATE_H + +#include "types.h" + +namespace rmsauth { + +class ClientAssertionCertificate +{ +public: + ClientAssertionCertificate(); + const String& clientId() const { return clientId_; } + +private: + String clientId_; +}; + +using ClientAssertionCertificatePtr = ptr; + +} // namespace rmsauth { + +#endif // CLIENTASSERTIONCERTIFICATE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientCredential.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientCredential.h new file mode 100644 index 00000000..4bd3a926 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientCredential.h @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CLIENTCREDENTIAL_H +#define CLIENTCREDENTIAL_H + +#include "types.h" +#include "Exceptions.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT ClientCredential +{ +public: + ClientCredential(const String& clientId, const String& clientSecret); + + const String& clientId() const { return clientId_; } + const String& clientSecret() const { return clientSecret_; } + +private: + String clientId_; + String clientSecret_; +}; + +using ClientCredentialPtr = ptr; + +} // namespace rmsauth { + +#endif // CLIENTCREDENTIAL_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientKey.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientKey.h new file mode 100644 index 00000000..41fade7a --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/ClientKey.h @@ -0,0 +1,48 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CLIENTKEY_H +#define CLIENTKEY_H + +#include "types.h" +#include "ClientCredential.h" +#include "ClientAssertionCertificate.h" +#include "ClientAssertion.h" +#include "Authenticator.h" + +namespace rmsauth { + +class ClientKey +{ +public: + ClientKey(ClientCredentialPtr clientCredential); + ClientKey(ClientAssertionCertificatePtr clientCertificate, AuthenticatorPtr authenticator); + ClientKey(ClientAssertionPtr clientAssertion); + ClientKey(const String& clientId); + + ClientCredentialPtr credential() const { return credential_; } + ClientAssertionCertificatePtr certificate() const { return certificate_; } + ClientAssertionPtr assertion() const { return assertion_; } + AuthenticatorPtr authenticator() const { return authenticator_; } + const String& clientId() const { return clientId_; } + bool hasCredential() const { return hasCredential_; } + +private: + ClientCredentialPtr credential_ = nullptr; + ClientAssertionCertificatePtr certificate_ = nullptr; + ClientAssertionPtr assertion_ = nullptr; + AuthenticatorPtr authenticator_ = nullptr; + String clientId_; + bool hasCredential_; +}; + +using ClientKeyPtr = ptr; + +} // namespace rmsauth { + +#endif // CLIENTKEY_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Constants.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Constants.h new file mode 100644 index 00000000..3a00358b --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Constants.h @@ -0,0 +1,352 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CONSTANTS +#define CONSTANTS +#include "types.h" + +namespace rmsauth { + +struct Constants +{ + struct RmsauthError { + ///

+ /// Unknown error. + /// + const String Unknown = "unknown_error"; + + /// + /// Invalid argument. + /// + const String InvalidArgument = "invalid_argument"; + + /// + /// Authentication failed. + /// + const String AuthenticationFailed = "authentication_failed"; + + /// + /// Authentication canceled. + /// + const String AuthenticationCanceled = "authentication_canceled"; + + /// + /// Unauthorized response expected from resource server. + /// + const String UnauthorizedResponseExpected = "unauthorized_response_expected"; + + /// + /// 'authority' is not in the list of valid addresses. + /// + const String AuthorityNotInValidList = "authority_not_in_valid_list"; + + /// + /// Authority validation failed. + /// + const String AuthorityValidationFailed = "authority_validation_failed"; + + /// + /// Loading required assembly failed. + /// + const String AssemblyLoadFailed = "assembly_load_failed"; + + /// + /// Loading required assembly failed. + /// + const String InvalidOwnerWindowType = "invalid_owner_window_type"; + + /// + /// MultipleTokensMatched were matched. + /// + const String MultipleTokensMatched = "multiple_matching_tokens_detected"; + + /// + /// Invalid authority type. + /// + const String InvalidAuthorityType = "invalid_authority_type"; + + /// + /// Invalid credential type. + /// + const String InvalidCredentialType = "invalid_credential_type"; + + /// + /// Invalid service URL. + /// + const String InvalidServiceUrl = "invalid_service_url"; + + /// + /// failed_to_acquire_token_silently. + /// + const String FailedToAcquireTokenSilently = "failed_to_acquire_token_silently"; + + /// + /// Certificate key size too small. + /// + const String CertificateKeySizeTooSmall = "certificate_key_size_too_small"; + + /// + /// Identity protocol login URL Null. + /// + const String IdentityProtocolLoginUrlNull = "identity_protocol_login_url_null"; + + /// + /// Identity protocol mismatch. + /// + const String IdentityProtocolMismatch = "identity_protocol_mismatch"; + + /// + /// Email address suffix mismatch. + /// + const String EmailAddressSuffixMismatch = "email_address_suffix_mismatch"; + + /// + /// Identity provider request failed. + /// + const String IdentityProviderRequestFailed = "identity_provider_request_failed"; + + /// + /// STS token request failed. + /// + const String StsTokenRequestFailed = "sts_token_request_failed"; + + /// + /// Encoded token too long. + /// + const String EncodedTokenTooLong = "encoded_token_too_long"; + + /// + /// Service unavailable. + /// + const String ServiceUnavailable = "service_unavailable"; + + /// + /// Service returned error. + /// + const String ServiceReturnedError = "service_returned_error"; + + /// + /// Federated service returned error. + /// + const String FederatedServiceReturnedError = "federated_service_returned_error"; + + /// + /// STS metadata request failed. + /// + const String StsMetadataRequestFailed = "sts_metadata_request_failed"; + + /// + /// No data from STS. + /// + const String NoDataFromSts = "no_data_from_sts"; + + /// + /// User Mismatch. + /// + const String UserMismatch = "user_mismatch"; + + /// + /// Unknown User Type. + /// + const String UnknownUserType = "unknown_user_type"; + + /// + /// Unknown User. + /// + const String UnknownUser = "unknown_user"; + + /// + /// User Realm Discovery Failed. + /// + const String UserRealmDiscoveryFailed = "user_realm_discovery_failed"; + + /// + /// Accessing WS Metadata Exchange Failed. + /// + const String AccessingWsMetadataExchangeFailed = "accessing_ws_metadata_exchange_failed"; + + /// + /// Parsing WS Metadata Exchange Failed. + /// + const String ParsingWsMetadataExchangeFailed = "parsing_ws_metadata_exchange_failed"; + + /// + /// WS-Trust Endpoint Not Found in Metadata Document. + /// + const String WsTrustEndpointNotFoundInMetadataDocument = "wstrust_endpoint_not_found"; + + /// + /// Parsing WS-Trust Response Failed. + /// + const String ParsingWsTrustResponseFailed = "parsing_wstrust_response_failed"; + + /// + /// The request could not be preformed because the network is down. + /// + const String NetworkNotAvailable = "network_not_available"; + + /// + /// The request could not be preformed because of an unknown failure in the UI flow. + /// + const String AuthenticationUiFailed = "authentication_ui_failed"; + + /// + /// One of two conditions was encountered. + /// 1. The PromptBehavior.Never flag was passed and but the constraint could not be honored + /// because user interaction was required. + /// 2. An error occurred during a silent web authentication that prevented the authentication + /// flow from completing in a short enough time frame. + /// + const String UserInteractionRequired = "user_interaction_required"; + + /// + /// Password is required for managed user. + /// + const String PasswordRequiredForManagedUserError = "password_required_for_managed_user"; + + /// + /// Failed to get user name. + /// + const String GetUserNameFailed = "get_user_name_failed"; + + /// + /// Federation Metadata Url is missing for federated user. + /// + const String MissingFederationMetadataUrl = "missing_federation_metadata_url"; + + /// + /// Failed to refresh token. + /// + const String FailedToRefreshToken = "failed_to_refresh_token"; + + /// + /// Integrated authentication failed. You may try an alternative authentication method. + /// + const String IntegratedAuthFailed = "integrated_authentication_failed"; + + /// + /// Duplicate query parameter in extraQueryParameters + /// + const String DuplicateQueryParameter = "duplicate_query_parameter"; + }; + + static const RmsauthError& rmsauthError() + { + static const RmsauthError rmsauthError{}; + return rmsauthError; + } + + struct RmsauthErrorMessage{ + const String AccessingMetadataDocumentFailed = "Accessing WS metadata exchange failed"; + const String AssemblyLoadFailedTemplate = "Loading an assembly required for interactive user authentication failed. Make sure assembly '%' exists"; + const String AuthenticationUiFailed = "The browser based authentication dialog failed to complete"; + const String AuthorityInvalidUriFormat = "'authority' should be in Uri format"; + const String AuthorityNotInValidList = "'authority' is not in the list of valid addresses"; + const String AuthorityValidationFailed = "Authority validation failed"; + const String AuthorityUriInsecure = "'authority' should use the 'https' scheme"; + const String AuthorityUriInvalidPath = "'authority' Uri should have at least one segment in the path (i.e. https:////...)"; + const String AuthorizationServerInvalidResponse = "The authorization server returned an invalid response"; + const String CertificateKeySizeTooSmallTemplate = "The certificate used must have a key size of at least % bits"; + const String EmailAddressSuffixMismatch = "No identity provider email address suffix matches the provided address"; + const String EncodedTokenTooLong = "Encoded token size is beyond the upper limit"; + const String FailedToAcquireTokenSilently = "Failed to acquire token silently. Call method AcquireToken"; + const String FailedToRefreshToken = "Failed to refresh token"; + const String FederatedServiceReturnedErrorTemplate = "Federated serviced at % returned error: %"; + const String IdentityProtocolLoginUrlNull = "The LoginUrl property in identityProvider cannot be null"; + const String IdentityProtocolMismatch = "No identity provider matches the requested protocol"; + const String IdentityProviderRequestFailed = "Token request to identity provider failed. Check InnerException for more details"; + const String InvalidArgumentLength = "Parameter has invalid length"; + const String InvalidAuthenticateHeaderFormat = "Invalid authenticate header format"; + const String InvalidAuthorityTypeTemplate = "This method overload is not supported by "; + const String InvalidCredentialType = "Invalid credential type"; + const String InvalidFormatParameterTemplate = "Parameter '%' has invalid format"; + const String InvalidTokenCacheKeyFormat = "Invalid token cache key format"; + const String MissingAuthenticateHeader = "WWW-Authenticate header was expected in the response"; + const String MultipleTokensMatched = "The cache contains multiple tokens satisfying the requirements. Call AcquireToken again providing more requirements (e.g. UserId)"; + const String NetworkIsNotAvailable = "The network is down so authentication cannot proceed"; + const String NoDataFromSTS = "No data received from security token service"; + const String NullParameterTemplate = "Parameter '%' cannot be null"; + const String ParsingMetadataDocumentFailed = "Parsing WS metadata exchange failed"; + const String ParsingWsTrustResponseFailed = "Parsing WS-Trust response failed"; + const String PasswordRequiredForManagedUserError = "Password is required for managed user"; + const String RedirectUriContainsFragment = "'redirectUri' must NOT include a fragment component"; + const String ServiceReturnedError = "Serviced returned error. Check InnerException for more details"; + const String StsMetadataRequestFailed = "Metadata request to Access Control service failed. Check InnerException for more details"; + const String StsTokenRequestFailed = "Token request to security token service failed. Check InnerException for more details"; + const String UnauthorizedHttpStatusCodeExpected = "Unauthorized Http Status Code (401) was expected in the response"; + const String UnauthorizedResponseExpected = "Unauthorized http response (status code 401) was expected"; + const String UnexpectedAuthorityValidList = "Unexpected list of valid addresses"; + const String Unknown = "Unknown error"; + const String UnknownUser = "Could not identify logged in user"; + const String UnknownUserType = "Unknown User Type"; + const String UnsupportedAuthorityValidation = "Authority validation is not supported for this type of authority"; + const String UnsupportedMultiRefreshToken = "This authority does not support refresh token for multiple resources. Pass null as a resource"; + const String AuthenticationCanceled = "User canceled authentication"; + const String UserMismatch = "User '%' returned by service does not match user '%' in the request"; + const String UserCredentialAssertionTypeEmpty = "credential.AssertionType cannot be empty"; + const String UserInteractionRequired = + "One of two conditions was encountered: "\ + "1. The PromptBehavior.Never flag was passed, but the constraint could not be honored, because user interaction was required. "\ + "2. An error occurred during a silent web authentication that prevented the http authentication flow from completing in a short enough time frame"; + const String UserRealmDiscoveryFailed = "User realm discovery failed"; + const String WsTrustEndpointNotFoundInMetadataDocument = "WS-Trust endpoint not found in metadata document"; + const String GetUserNameFailed = "Failed to get user name"; + const String MissingFederationMetadataUrl = "Federation Metadata Url is missing for federated user. This user type is unsupported."; + const String SpecifyAnyUser = "If you do not need access token for any specific user, pass userId=UserIdentifier::anyUser() instead of userId=null."; + const String IntegratedAuthFailed = "Integrated authentication failed. You may try an alternative authentication method"; + const String DuplicateQueryParameterTemplate = "Duplicate query parameter '%' in extraQueryParameters"; + }; + + static const RmsauthErrorMessage& rmsauthErrorMessage() + { + static const RmsauthErrorMessage rmsauthErrorMessage{}; + return rmsauthErrorMessage; + } + + struct RmsauthIdParameter { + /// + /// RMSAUTH Flavor + /// + const String Product = "x-client-SKU"; + const String ProductVal = "RMSAuth"; + + /// + /// RMSAUTH assembly version + /// + const String Version = "x-client-Ver"; + const String VersionVal = "0.1"; + + /// + /// CPU platform with x86, x64 or ARM as value + /// + const String CpuPlatform = "x-client-CPU"; + + /// + /// Version of the operating system. This will not be sent on WinRT + /// + const String OS = "x-client-OS"; + + /// + /// Device model. This will not be sent on .NET + /// + const String UserAgent = "x-client-DM"; + + const String DeviceModel = "RMSAuth"; + }; + + static const RmsauthIdParameter& rmsauthIdParameter() + { + static const RmsauthIdParameter rmsauthIdParameter{}; + return rmsauthIdParameter; + } +}; + +} // namespace rmsauth { + +#endif // CONSTANTS + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/DateTime.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/DateTime.h new file mode 100644 index 00000000..90dbfa6f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/DateTime.h @@ -0,0 +1,46 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef DATETIME_H +#define DATETIME_H + +#include "types.h" + +namespace rmsauth { + +class IDateTime +{ +public: + virtual void addDays(int64_t ndays) = 0; + virtual void addMonths(int nmonths) = 0; + virtual void addYears(int nyears) = 0; + virtual void addMSecs(int64_t msecs) = 0; + virtual void addSecs(int64_t s) = 0; + virtual int64_t toTime() = 0; + virtual String toString(const String& format) = 0; +}; + +class DateTime : public IDateTime +{ +public: + DateTime(); + DateTime(int64_t sec); + void addDays(int64_t ndays) override; + void addMSecs(int64_t msecs) override; + void addMonths(int nmonths) override; + void addSecs(int64_t s) override; + void addYears(int nyears) override; + int64_t toTime() override; + virtual String toString(const String& format) override; +private: + ptr pImpl; +}; + +} //namespace rmsauth { + +#endif // DATETIME_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Entities.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Entities.h new file mode 100644 index 00000000..20835c6e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Entities.h @@ -0,0 +1,135 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef ENTITIES_H +#define ENTITIES_H + +#include "types.h" +#include "OAuthConstants.h" + +namespace rmsauth { + +struct TokenResponse +{ + struct JsonNames { + + const String tokenType = OAuthConstants::oAuthReservedClaim().TokenType; + const String accessToken = OAuthConstants::oAuthReservedClaim().AccessToken; + const String refreshToken = OAuthConstants::oAuthReservedClaim().RefreshToken; + const String resource = OAuthConstants::oAuthReservedClaim().Resource; + const String idToken = OAuthConstants::oAuthReservedClaim().IdToken; + const String createdOn = OAuthConstants::oAuthReservedClaim().CreatedOn; + const String expiresOn = OAuthConstants::oAuthReservedClaim().ExpiresOn; + const String expiresIn = OAuthConstants::oAuthReservedClaim().ExpiresIn; + const String correlationId = "correlation_id"; + const String error = OAuthConstants::oAuthReservedClaim().Error; + const String errorDescription = OAuthConstants::oAuthReservedClaim().ErrorDescription; + const String errorCodes = OAuthConstants::oAuthReservedClaim().ErrorCodes; + + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } + + String tokenType; + String accessToken; + String refreshToken; + String resource; + String idToken; + long createdOn; + long expiresOn; + long expiresIn; + String correlationId; + + String error; + String errorDescription; + IntArray errorCodes; +}; +using TokenResponsePtr = ptr; + +struct IdToken +{ + struct JsonNames { + const String objectId= OAuthConstants::idTokenClaim().ObjectId; + const String subject = OAuthConstants::idTokenClaim().Subject; + const String tenantId = OAuthConstants::idTokenClaim().TenantId; + const String UPN = OAuthConstants::idTokenClaim().UPN; + const String givenName = OAuthConstants::idTokenClaim().GivenName; + const String familyName = OAuthConstants::idTokenClaim().FamilyName; + const String email = OAuthConstants::idTokenClaim().Email; + const String passwordExpiration = OAuthConstants::idTokenClaim().PasswordExpiration; + const String passwordChangeUrl = OAuthConstants::idTokenClaim().PasswordChangeUrl; + const String identityProvider = OAuthConstants::idTokenClaim().IdentityProvider; + const String issuer = OAuthConstants::idTokenClaim().Issuer; + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } + + + String objectId; + String subject; + String tenantId; + String UPN; + String givenName; + String familyName; + String email; + long passwordExpiration; + String passwordChangeUrl; + String identityProvider; + String issuer; +}; +using IdTokenPtr = ptr; + +struct InstanceDiscoveryResponse +{ + struct JsonNames { + const String tenantDiscoveryEndpoint= "tenant_discovery_endpoint"; + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } + + + String tenantDiscoveryEndpoint; +}; +using InstanceDiscoveryResponsePtr = ptr; + +struct ErrorResponse +{ + struct JsonNames { + const String error = OAuthConstants::oAuthReservedClaim().Error; + const String errorDescription = OAuthConstants::oAuthReservedClaim().ErrorDescription; + const String errorCodes = OAuthConstants::oAuthReservedClaim().ErrorCodes; + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } + + String error; + String errorDescription; + IntArray errorCodes; +}; + +using ErrorResponsePtr = ptr; + +} // namespace rmsauth { + +#endif // ENTITIES_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Exceptions.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Exceptions.h new file mode 100644 index 00000000..e82306f5 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Exceptions.h @@ -0,0 +1,89 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef EXCEPTIONS +#define EXCEPTIONS +#include "types.h" + +namespace rmsauth { + +class Exception +{ +public: + Exception(const String& error) + : error_(error) + {} + + Exception(const String& error, const String& message) + : error_(error) + , message_(message) + {} + + virtual const String& error() const {return error_;} + virtual const String& message() const {return message_;} + +private: + String error_; + String message_; +}; + +class RmsauthException : public Exception +{ +public: +// using Exception::Exception; + RmsauthException(const String& error, const String& message) : Exception(error, message){} + RmsauthException(const String& error) : RmsauthException(error, ""){} +}; + +class RmsauthServiceException: public RmsauthException +{ +public: +// using RmsauthException::RmsauthException; + RmsauthServiceException(const String& error, const String& message) : RmsauthException(error, message){} + RmsauthServiceException(const String& error) : RmsauthServiceException(error, ""){} + +}; + +class RmsauthUserMismatchException: public RmsauthException +{ +public: +// using RmsauthException::RmsauthException; + RmsauthUserMismatchException(const String& error, const String& message) : RmsauthException(error, message){} + RmsauthUserMismatchException(const String& error) : RmsauthUserMismatchException(error, ""){} + +}; + +class RmsauthParsingException: public RmsauthException +{ +public: +// using RmsauthException::RmsauthException; + RmsauthParsingException(const String& error, const String& message) : RmsauthException(error, message){} + RmsauthParsingException(const String& error) : RmsauthParsingException(error, ""){} + +}; + +class RmsauthJsonParsingException: public RmsauthParsingException +{ +public: +// using RmsauthParsingException::RmsauthParsingException; + RmsauthJsonParsingException(const String& error, const String& message) : RmsauthParsingException(error, message){} + RmsauthJsonParsingException(const String& error) : RmsauthJsonParsingException(error, ""){} +}; + +class IllegalArgumentException : public Exception +{ +public: +// using Exception::Exception; + IllegalArgumentException(const String& error, const String& message) : Exception(error, message){} + IllegalArgumentException(const String& error) : IllegalArgumentException(error, ""){} +}; + +} // namespace rmsauth { + +#endif // EXCEPTIONS + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCache.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCache.h new file mode 100644 index 00000000..29f745e5 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCache.h @@ -0,0 +1,41 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef FILECACHE_H +#define FILECACHE_H + +#include "types.h" +#include "TokenCache.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT FileCache : public TokenCache +{ +protected: + static const String Tag() { static const String tag = "FileCache"; return tag;} + String cacheFilePath_; + static Mutex fileLock_; + +public: + FileCache(const String& filePath = ""); + void clear() override; + +protected: + virtual void readCache(); + virtual void writeCache(); + +private: + virtual void onBeforeAccess(const TokenCacheNotificationArgs& args) override; + virtual void onAfterAccess(const TokenCacheNotificationArgs& args) override; + virtual const String getCacheName() const override {return FileCache::Tag();} +}; + +} // namespace rmsauth { + +#endif // FILECACHE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCacheEncrypted.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCacheEncrypted.h new file mode 100644 index 00000000..44eeee09 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/FileCacheEncrypted.h @@ -0,0 +1,35 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef FILECACHEENCRYPTED_H +#define FILECACHEENCRYPTED_H + +#include "types.h" +#include "FileCache.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT FileCacheEncrypted : public FileCache +{ + static const String Tag() { static const String tag = "FileCacheEncrypted"; return tag;} + +public: + FileCacheEncrypted(const String& filePath = ""); + +protected: + virtual void readCache() override; + virtual void writeCache() override; + +private: + virtual const String getCacheName() const override {return FileCacheEncrypted::Tag();} +}; + +} // namespace rmsauth { + +#endif // FILECACHEENCRYPTED_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Guid.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Guid.h new file mode 100644 index 00000000..3007f39a --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Guid.h @@ -0,0 +1,40 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef GUID_H +#define GUID_H + +#include "types.h" + +namespace rmsauth { + +class IGuid +{ +public: + virtual String toString() const = 0; + virtual bool empty() const = 0; +}; + +class Guid : public IGuid +{ +public: + Guid(); + Guid(const String& str); + virtual String toString() const override; + virtual bool empty() const override; + + static Guid newGuid(); + +private: + ptr pImpl; + Guid(ptr guid); +}; + +} // namespace rmsauth { + +#endif // GUID_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/HttpHelper.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/HttpHelper.h new file mode 100644 index 00000000..646e6577 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/HttpHelper.h @@ -0,0 +1,84 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef HTTPHELPER_H +#define HTTPHELPER_H + +#include "types.h" +#include "RequestParameters.h" +#include "CallState.h" +#include "Entities.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT HttpHelper +{ + static const String& Tag() {static const String tag="HttpHelperQt"; return tag;} + +public: + static TokenResponsePtr sendPostRequestAndDeserializeJsonResponseAsync(const String& uri, const RequestParameters& requestParameters, const CallStatePtr callState); + // to use trusted CA put certificates + static bool addCACertificateBase64(const std::vector &certificate); + static bool addCACertificateDer(const std::vector &certificate); + + enum class StatusCode + { + Continue = 100, + SwitchingProtocols = 101, + OK = 200, + Created = 201, + Accepted = 202, + NonAuthoritativeInformation = 203, + NoContent = 204, + ResetContent = 205, + PartialContent = 206, + MultipleChoices = 300, + Ambiguous = 300, + MovedPermanently = 301, + Moved = 301, + Found = 302, + Redirect = 302, + SeeOther = 303, + RedirectMethod = 303, + NotModified = 304, + UseProxy = 305, + Unused = 306, + RedirectKeepVerb = 307, + TemporaryRedirect = 307, + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + LengthRequired = 411, + PreconditionFailed = 412, + RequestEntityTooLarge = 413, + RequestUriTooLong = 414, + UnsupportedMediaType = 415, + RequestedRangeNotSatisfiable = 416, + ExpectationFailed = 417, + UpgradeRequired = 426, + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504, + HttpVersionNotSupported = 505, + }; +}; + +} // namespace rmsauth { + +#endif // HTTPHELPER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/IWebUI.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/IWebUI.h new file mode 100644 index 00000000..6dc4e95a --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/IWebUI.h @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IWEBUI_H +#define IWEBUI_H + +#include "types.h" +#include "Url.h" +#include "PromptBehavior.h" + +namespace rmsauth { + +class IWebUI +{ +public: + virtual String authenticate(const String& requestUri, const String& callbackUri) = 0; +}; +using IWebUIPtr = ptr; + +class WebUI : public IWebUI +{ + PromptBehavior promptBehavior_; + +public: + WebUI(PromptBehavior promptBehavior); + + String authenticate(const String& requestUri, const String& callbackUri) override; +}; + +} // namespace rmsauth { + +#endif // IWEBUI_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/IdToken.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/IdToken.h new file mode 100644 index 00000000..b661e463 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/IdToken.h @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IDTOKEN +#define IDTOKEN +#include "types.h" + +struct IdToken +{ + String mSubject; + String mTenantId; + String mUpn; + String mGivenName; + String mFamilyName; + String mEmail; + String mIdentityProvider; + String mObjectId; + int64_t mPasswordExpiration; + String mPasswordChangeUrl; +}; + +#endif // IDTOKEN + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Logger.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Logger.h new file mode 100644 index 00000000..e20dc542 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Logger.h @@ -0,0 +1,119 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include "types.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT Logger +{ +public: + template + static void record(const String& category, const String& tag, const String& record, T value, Args... args); + + template + static void info(const String& tag, const String& record, T value, Args... args); + + template + static void warning(const String& tag, const String& record, T value, Args... args); + + + template + static void error(const String& tag, const String& record, T value, Args... args); + + static void record(const String& category, const String& tag, const String& record); + static void info(const String& tag, const String& record); + static void warning(const String& tag, const String& record); + static void error(const String& tag, const String& record); + virtual ~Logger(){} + +protected: + virtual void append(const String& category, const String& tag, const String& record) = 0; + +private: + static Logger& instance(); + + static void printf(StringStream& ss, const char *s); + + template + static void printf(StringStream& ss, const char *s, T value, Args... args); +}; + +template +void Logger::record(const String& category, const String& tag, const String& record, T value, Args... args) +{ + StringStream ss; + Logger::printf(ss, record.c_str(), value, args...); + Logger::instance().append(category, tag, ss.str()); +} + +template +void Logger::info(const String& tag, const String& record, T value, Args... args) +{ + Logger::record("INF", tag, record, value, args...); +} + +template +void Logger::warning(const String& tag, const String& record, T value, Args... args) +{ + Logger::record("WRN", tag, record, value, args...); +} + +template +void Logger::error(const String& tag, const String& record, T value, Args... args) +{ + Logger::record("ERR", tag, record, value, args...); +} + +template +void Logger::printf(StringStream& ss, const char *s, T value, Args... args) +{ + while (*s) + { + if (*s == '%') + { + if (*(s + 1) == '%') + { + ++s; + } + else + { + ss << value; + s += 1; + Logger::printf(ss, s, args...); // call even when *s == 0 to detect extra arguments + return; + } + } + ss << *s++; + } +} + +class LoggerImpl : public Logger +{ +public: + ~LoggerImpl(); + +protected: + virtual void append(const String& category, const String& tag, const String& record) override; + static String getLocalTime(const String& format); + +private: + LoggerImpl(); + friend class Logger; + std::ofstream stream_; +}; + +} // namespace rmsauth { + +#endif // LOGGER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuth2Response.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuth2Response.h new file mode 100644 index 00000000..19f48a26 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuth2Response.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef OAUTH2RESPONSE_H +#define OAUTH2RESPONSE_H + +#include "types.h" +#include "Entities.h" +#include "CallState.h" +#include "AuthenticationResult.h" +#include "AuthorizationResult.h" + +namespace rmsauth { + +class OAuth2Response +{ + static const String& Tag() {static const String tag="OAuth2Response"; return tag;} + +public: + static AuthenticationResultPtr parseTokenResponse(TokenResponsePtr tokenResponse, CallStatePtr callState); + static AuthorizationResultPtr parseAuthorizeResponse(const String& webAuthenticationResult, CallStatePtr callState); + +private: + static IdTokenPtr parseIdToken(const String& idToken); +}; + +} // namespace rmsauth { + +#endif // OAUTH2RESPONSE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuthConstants.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuthConstants.h new file mode 100644 index 00000000..e82b8654 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/OAuthConstants.h @@ -0,0 +1,193 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef OAUTHCONSTANTS_H +#define OAUTHCONSTANTS_H + +#include "types.h" + +namespace rmsauth { + +struct OAuthConstants +{ + struct OAuthParameter { + const String ResponseType = "response_type"; + const String GrantType = "grant_type"; + const String ClientId = "client_id"; + const String ClientSecret = "client_secret"; + const String ClientAssertion = "client_assertion"; + const String ClientAssertionType = "client_assertion_type"; + const String RefreshToken = "refresh_token"; + const String RedirectUri = "redirect_uri"; + const String Resource = "resource"; + const String Code = "code"; + const String Scope = "scope"; + const String Assertion = "assertion"; + const String RequestedTokenUse = "requested_token_use"; + const String Username = "username"; + const String Password = "password"; + const String FormsAuth = "amr_values"; + const String LoginHint = "login_hint"; // login_hint is not standard oauth2 parameter + const String CorrelationId = "client-request-id"; // correlation id is not standard oauth2 parameter + const String Prompt = "prompt"; // prompt is not standard oauth2 parameter + }; + + static const OAuthParameter& oAuthParameter() + { + static const OAuthParameter oAuthParameter{}; + return oAuthParameter; + } + + struct OAuthGrantType { + const String AuthorizationCode = "authorization_code"; + const String RefreshToken = "refresh_token"; + const String ClientCredentials = "client_credentials"; + const String Saml11Bearer = "urn:ietf:params:oauth:grant-type:saml1_1-bearer"; + const String Saml20Bearer = "urn:ietf:params:oauth:grant-type:saml2-bearer"; + const String JwtBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + const String Password = "password"; + }; + + static const OAuthGrantType& oAuthGrantType() + { + static const OAuthGrantType oAuthGrantType{}; + return oAuthGrantType; + } + + struct OAuthResponseType + { + const String Code = "code"; + + }; + + static const OAuthResponseType& oAuthResponseType() + { + static const OAuthResponseType oAuthResponseType{}; + return oAuthResponseType; + } + + struct OAuthReservedClaim { + const String Code = "code"; + const String TokenType = "token_type"; + const String AccessToken = "access_token"; + const String RefreshToken = "refresh_token"; + const String Resource = "resource"; + const String IdToken = "id_token"; + const String CreatedOn = "created_on"; + const String ExpiresOn = "expires_on"; + const String ExpiresIn = "expires_in"; + const String Error = "error"; + const String ErrorDescription = "error_description"; + const String ErrorCodes = "error_codes"; + }; + + static const OAuthReservedClaim& oAuthReservedClaim() + { + static const OAuthReservedClaim oAuthReservedClaim{}; + return oAuthReservedClaim; + } + + + struct IdTokenClaim { + const String ObjectId = "oid"; + const String Subject = "sub"; + const String TenantId = "tid"; + const String UPN = "upn"; + const String Email = "email"; + const String GivenName = "given_name"; + const String FamilyName = "family_name"; + const String IdentityProvider = "idp"; + const String Issuer = "iss"; + const String PasswordExpiration = "pwd_exp"; + const String PasswordChangeUrl = "pwd_url"; + }; + + static const IdTokenClaim& idTokenClaim() + { + static const IdTokenClaim idTokenClaim{}; + return idTokenClaim; + } + + + struct OAuthAssertionType { + const String JwtBearer = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"; + }; + + static const OAuthAssertionType& oAuthAssertionType() + { + static const OAuthAssertionType oAuthAssertionType{}; + return oAuthAssertionType; + } + + + struct OAuthRequestedTokenUse { + const String OnBehalfOf = "on_behalf_of"; + }; + + static const OAuthRequestedTokenUse& oAuthRequestedTokenUse() + { + static const OAuthRequestedTokenUse oAuthRequestedTokenUse{}; + return oAuthRequestedTokenUse; + } + + + struct OAuthHeader { + const String CorrelationId = "client-request-id"; + const String RequestCorrelationIdInResponse = "return-client-request-id"; + }; + + static const OAuthHeader& oAuthHeader() + { + static const OAuthHeader oAuthHeader{}; + return oAuthHeader; + } + + + struct OAuthError { + const String LoginRequired = "login_required"; + const String InvalidGrant = "invalid_grant"; + } ; + + static const OAuthError& oAuthError() + { + static const OAuthError oAuthError{}; + return oAuthError; + } + + + struct OAuthValue { + const String FormsAuth = "pwd"; + const String ScopeOpenId = "openid"; + }; + + static const OAuthValue& oAuthValue() + { + static const OAuthValue oAuthValue{}; + return oAuthValue; + } + + + struct PromptValue { + const String Login = "login"; + const String RefreshSession = "refresh_session"; + + // The behavior of this value is identical to prompt=none for managed users; However, for federated users, AAD + // redirects to ADFS as it cannot determine in advance whether ADFS can login user silently (e.g. via WIA) or not. + const String AttemptNone = "attempt_none"; + }; + + static const PromptValue& promptValue() + { + static const PromptValue promptValue{}; + return promptValue; + } +}; + +} // namespace rmsauth { + +#endif // OAUTHCONSTANTS_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/PromptBehavior.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/PromptBehavior.h new file mode 100644 index 00000000..ea390e65 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/PromptBehavior.h @@ -0,0 +1,20 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef PROMPTBEHAVIOR_H +#define PROMPTBEHAVIOR_H + +enum class PromptBehavior +{ + Auto, + Always, + Never, + RefreshSession +}; + +#endif // PROMPTBEHAVIOR diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/RequestParameters.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/RequestParameters.h new file mode 100644 index 00000000..e2502a2f --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/RequestParameters.h @@ -0,0 +1,42 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef REQUESTPARAMETERS_H +#define REQUESTPARAMETERS_H + +#include "types.h" +#include "ClientKey.h" +#include "OAuthConstants.h" + +namespace rmsauth { + +class RequestParameters +{ +public: + RequestParameters(const String& resource, const ClientKeyPtr clientKey); + String& operator[](const String& key); + const String& operator[](const String& key) const; + void addParam(const String& key, const String& value); + String toString() const; + + const String& extraQueryParameter() const {return extraQueryParameter_;} + void extraQueryParameter(const String& val) {extraQueryParameter_ = val;} + + static String uriEncode(const String& value); + +private: + void addClientKey(const ClientKey& clientKey); + +private: + StringMap params_; + String extraQueryParameter_; +}; + +} // namespace rmsauth { + +#endif // REQUESTPARAMETERS_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/RmsauthIdHelper.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/RmsauthIdHelper.h new file mode 100644 index 00000000..4da410bb --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/RmsauthIdHelper.h @@ -0,0 +1,29 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef RMSAUTHIDHELPER +#define RMSAUTHIDHELPER + +#include "types.h" + +namespace rmsauth { + +class RmsauthIdHelper +{ +public: + static const Headers getProductHeaders(); + static const Headers getPlatformHeaders(); + +private: + static const String getProcessorArchitecture(); + static const String getOSVersion(); +}; + +} // namespace rmsauth { + +#endif // RMSAUTHIDHELPER diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCache.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCache.h new file mode 100644 index 00000000..a7a28bc0 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCache.h @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TOKENCACHE_H +#define TOKENCACHE_H + +#include "types.h" +#include "AuthenticationResult.h" +#include "ClientKey.h" +#include "CallState.h" +#include "TokenCacheNotificationArgs.h" +#include "TokenCacheKey.h" +#include "TokenCacheItem.h" +#include "Logger.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +class RMSAUTH_EXPORT TokenCache +{ + static const String Tag(){static const String tag = "TokenCache"; return tag;} + + const int SchemaVersion_ = 2; + const String LocalSettingsContainerName_ = "ActiveDirectoryAuthenticationLibrary"; + HashMap tokenCacheDictionary_; + // We do not want to return near expiry tokens, this is why we use this hard coded setting to refresh tokens which are close to expiration. + const int64_t expirationMarginInSeconds_ = 300; + +public: + TokenCache(const ByteArray& state); + static TokenCache& defaultShared(); + bool hasStateChanged() const { return hasStateChanged_; } + void hasStateChanged(const bool val) { hasStateChanged_ = val; } + + int count() const; + ByteArray serialize(); + void deserialize(const ByteArray& state); + virtual List readItems(); + virtual void deleteItem(TokenCacheItemPtr item); + virtual void clear(); + + virtual void onAfterAccess(const TokenCacheNotificationArgs&) {} + virtual void onBeforeAccess(const TokenCacheNotificationArgs&) {} + virtual void onBeforeWrite(const TokenCacheNotificationArgs&) {} + + AuthenticationResultPtr loadFromCache(const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId, CallStatePtr callState); + void storeToCache(AuthenticationResultPtr result, const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, CallStatePtr callState); + void updateCachedMrrtRefreshTokens(AuthenticationResultPtr result, const String& authority, const String& clientId, TokenSubjectType subjectType); + TokenCacheItemPtr loadSingleItemFromCache(const String& authority, const String& resource, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId, CallStatePtr callState); + List queryCache(const String& authority, const String& clientId, TokenSubjectType subjectType, const String& uniqueId, const String& displayableId); + virtual const String getCacheName() const {return TokenCache::Tag();} + +protected: + TokenCache(); + volatile bool hasStateChanged_ = false; +}; + +using TokenCachePtr = ptr; + +} // namespace rmsauth { + +#endif // TOKENCACHE_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheItem.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheItem.h new file mode 100644 index 00000000..4f550087 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheItem.h @@ -0,0 +1,53 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TOKENCACHEITEM_H +#define TOKENCACHEITEM_H + +#include "types.h" +#include "AuthenticationResult.h" +#include "TokenCacheKey.h" + +namespace rmsauth { + +class TokenCacheItem +{ + TokenCacheKey tokenCacheKey_; + AuthenticationResultPtr resultPtr_; + +public: + TokenCacheItem(const TokenCacheKey& key, AuthenticationResultPtr result); + + const TokenCacheKey& tokenCacheKey() const {return tokenCacheKey_;} + TokenCacheKey& tokenCacheKey() { return tokenCacheKey_; } + const AuthenticationResultPtr authenticationResult() const {return resultPtr_; } + AuthenticationResultPtr authenticationResult() { return resultPtr_;} + + const String& authority() const { return tokenCacheKey_.authority(); } + const String& clientId() const { return tokenCacheKey_.clientId(); } + DateTimeOffset expiresOn() const { return resultPtr_->expiresOn(); } + const String familyName() const { return resultPtr_->userInfo() != nullptr ? resultPtr_->userInfo()->familyName():""; } + const String givenName() const { return resultPtr_->userInfo() != nullptr ? resultPtr_->userInfo()->givenName():""; } + const String identityProvider() const { return resultPtr_->userInfo() != nullptr ? resultPtr_->userInfo()->identityProvider():""; } + bool isMultipleResourceRefreshToken() const { return resultPtr_->isMultipleResourceRefreshToken(); } + const String& resource() const { return tokenCacheKey_.resource(); } + const String& tenantId() const { return resultPtr_->tenantId(); } + const String& uniqueId() const { return tokenCacheKey_.uniqueId(); } + const String& displayableId() const { return tokenCacheKey_.displayableId(); } + const String& accessToken() const { return resultPtr_->accessToken(); } + const String& refreshToken() const { return resultPtr_->refreshToken(); } + void refreshToken(const String& val) { resultPtr_->refreshToken(val); } + const String& idToken() const { return resultPtr_->idToken(); } + TokenSubjectType tokenSubjectType() const { return tokenCacheKey_.tokenSubjectType(); } +}; + +using TokenCacheItemPtr = ptr; + +} // namespace rmsauth { + +#endif // TOKENCACHEITEM_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheKey.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheKey.h new file mode 100644 index 00000000..90bcefcc --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheKey.h @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TOKENCACHEKEY_H +#define TOKENCACHEKEY_H + +#include +#include "types.h" +#include "TokenSubjectType.h" +#include "utils.h" +#include "UserInfo.h" +#include "Logger.h" + +namespace rmsauth { + +class TokenCacheKey; +using TokenCacheKeyPtr = ptr; + +class TokenCacheKey +{ + static const String& Tag() {static const String tag="TokenCacheKey"; return tag;} + + String authority_; + String resource_; + String clientId_; + String uniqueId_; + String displayableId_; + TokenSubjectType tokenSubjectType_; + +public: + TokenCacheKey() = default; + TokenCacheKey(const String& authority, const String& resource, const String& clientId, const TokenSubjectType tokenSubjectType, const UserInfoPtr userInfo); + TokenCacheKey(const String& authority, const String& resource, const String& clientId, const TokenSubjectType tokenSubjectType, const String& uniqueId, const String& displayableId); + + const String& authority() const { return authority_; } + const String& resource() const { return resource_; } + const String& clientId() const { return clientId_; } + const String& uniqueId() const { return uniqueId_; } + const String& displayableId() const { return displayableId_; } + TokenSubjectType tokenSubjectType() const { return tokenSubjectType_; } + + bool equals(const TokenCacheKey& other) const; + bool operator==(const TokenCacheKey &other) const; + std::size_t getHashCode() const; +}; + +} // namespace rmsauth { + +namespace std { + +template <> +struct hash +{ + size_t operator()(const rmsauth::TokenCacheKey& k) const + { + return (k.getHashCode()); + } +}; + +} + +#endif // TOKENCACHEKEY_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheNotificationArgs.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheNotificationArgs.h new file mode 100644 index 00000000..dceb0af0 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenCacheNotificationArgs.h @@ -0,0 +1,48 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TOKENCACHENOTIFICATIONARGS_H +#define TOKENCACHENOTIFICATIONARGS_H + +#include "types.h" + +namespace rmsauth { + +class TokenCache; + +class TokenCacheNotificationArgs final +{ + TokenCache* tokenCache_; + String clientId_; + String resource_; + String uniqueId_; + String displayableId_; + +public: + TokenCacheNotificationArgs(TokenCache* tokenCache) + : tokenCache_{tokenCache} + {} + + TokenCacheNotificationArgs(TokenCache* tokenCache, const String& clientId, const String& resource, const String& uniqueId, const String& displayableId) + : tokenCache_(tokenCache) + , clientId_(clientId) + , resource_(resource) + , uniqueId_(uniqueId) + , displayableId_(displayableId) + {} + + TokenCache* tokenCache() const { return tokenCache_; } + const String& clientId() const { return clientId_; } + const String& resource() const { return resource_; } + const String& uniqueId() const { return uniqueId_; } + const String& displayableId() const { return displayableId_; } +}; + +} //namespace rmsauth { + +#endif // TOKENCACHENOTIFICATIONARGS_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenSubjectType.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenSubjectType.h new file mode 100644 index 00000000..930bbdc1 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/TokenSubjectType.h @@ -0,0 +1,26 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TOKENSUBJECTTYPE +#define TOKENSUBJECTTYPE + +#include "types.h" + +namespace rmsauth { + +enum class TokenSubjectType +{ + User = 0, + Client, + UserPlusClient +}; + +} // namespace rmsauth { + +#endif // TOKENSUBJECTTYPE + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/Url.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/Url.h new file mode 100644 index 00000000..cf0b4ae2 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/Url.h @@ -0,0 +1,52 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef IURL +#define IURL + +#include "types.h" + +namespace rmsauth { + +class IUrl +{ +public: + virtual void setUrl(const String&) = 0; + virtual String toString() const = 0; + virtual String scheme() const = 0; + virtual String authority() const = 0; + virtual String host() const = 0; + virtual String fragment() const = 0; + virtual String path() const = 0; + virtual bool isValid() const = 0; +}; + +class Url : public IUrl +{ +public: + Url(); + Url(const String& url); + void setUrl(const String& url) override; + String toString() const override; + String scheme() const override; + String authority() const override; + String host() const override; + String fragment() const override; + String path() const override; + bool isValid() const override; + +private: + ptr pImpl; +}; + +using UrlPtr = ptr; + +} // namespace rmsauth { + +#endif // IURL + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/UserAssertion.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserAssertion.h new file mode 100644 index 00000000..03fee767 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserAssertion.h @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERASSERTION +#define USERASSERTION + +#include "types.h" + +namespace rmsauth { + +class UserAssertion final +{ + String assertion_; + String assertionType_; + String userName_; + +public: + UserAssertion(const String& assertion); + UserAssertion(const String& assertion, const String& assertionType); + UserAssertion(const String& assertion, const String& assertionType, const String& userName); + + const String& assertion() const { return assertion_; } + const String& assertionType() const { return assertionType_; } + const String& userName() const { return userName_; } +}; + +using UserAssertionPtr = ptr; + +} // namespace rmsauth { + +#endif // USERASSERTION + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/UserCredential.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserCredential.h new file mode 100644 index 00000000..6dc826f1 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserCredential.h @@ -0,0 +1,46 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERCREDENTIAL +#define USERCREDENTIAL + +#include "types.h" +#include "rmsauthExport.h" + +namespace rmsauth { + +enum class UserAuthType +{ + IntegratedAuth, + UsernamePassword +}; + +class RMSAUTH_EXPORT UserCredential +{ + UserAuthType userAuthType_; + String userName_; + String password_; + +public: + UserCredential(); + UserCredential(const String& userName); + UserCredential(const String& userName, const String& password); + + const String& userName() const { return userName_; } + void userName(const String& val) { userName_= val; } + + UserAuthType userAuthType() const { return userAuthType_; } + + const String& password() const { return password_; } +}; + +using UserCredentialPtr = ptr; + +} // namespace rmsauth { + +#endif // USERCREDENTIAL diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/UserIdentifier.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserIdentifier.h new file mode 100644 index 00000000..dd376b5d --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserIdentifier.h @@ -0,0 +1,52 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERIDENTIFIER_H +#define USERIDENTIFIER_H + +#include "types.h" +#include "Exceptions.h" + +namespace rmsauth { + +enum class UserIdentifierType +{ + UniqueId, + OptionalDisplayableId, + RequiredDisplayableId +}; + +class UserIdentifier; +using UserIdentifierPtr = ptr; + +class UserIdentifier final +{ + UserIdentifierType type_; + String id_; + + static UserIdentifierPtr anyUserSingleton(); + +public: + UserIdentifier(const String& id, UserIdentifierType type); + + UserIdentifierType type() const { return type_; } + + const String& id() const { return id_; } + + static UserIdentifierPtr anyUser(); + + bool isAnyUser() const; + + const String uniqueId() const; + + const String displayableId() const; +}; + +} // namespace rmsauth { + +#endif // USERIDENTIFIER_H diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/UserInfo.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserInfo.h new file mode 100644 index 00000000..39774ef9 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserInfo.h @@ -0,0 +1,83 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERINFO +#define USERINFO + +#include "types.h" +#include "Entities.h" +#include "DateTime.h" +#include "Url.h" + +namespace rmsauth { + +class UserInfo; +using UserInfoPtr = ptr; + +class UserInfo +{ + String uniqueId_; + String displayableId_; + String givenName_; + String familyName_; + String identityProvider_; + String passwordChangeUrl_; + DateTimeOffset passwordExpiresOn_; + bool forcePrompt_; + +public: + const String& uniqueId() const { return uniqueId_; } + void uniqueId(const String& val) { uniqueId_ = val; } + + const String& displayableId() const { return displayableId_; } + void displayableId(const String& val) { displayableId_ = val; } + + const String& givenName() const { return givenName_; } + void givenName(const String& val) { givenName_ = val; } + + const String& familyName() const { return familyName_; } + void familyName(const String& val) { familyName_ = val; } + + const String& identityProvider() const { return identityProvider_; } + void identityProvider(const String& val) { identityProvider_ = val; } + + const String& passwordChangeUrl() const { return passwordChangeUrl_; } + void passwordChangeUrl(const String& val) { passwordChangeUrl_ = val; } + + const DateTimeOffset& passwordExpiresOn() const { return passwordExpiresOn_; } + void passwordExpiresOn(const DateTimeOffset& val) { passwordExpiresOn_ = val; } + + const bool& forcePrompt() const { return forcePrompt_; } + void forcePrompt(const bool& val) { forcePrompt_ = val; } + + String serialize(); + static UserInfoPtr deserialize(const String& jsonString); + +private: + struct JsonNames { + const String uniqueId = "uniqueId"; + const String displayableId = "displayableId"; + const String givenName = "givenName"; + const String familyName = "familyName"; + const String identityProvider = "identityProvider"; + const String passwordChangeUrl = "passwordChangeUrl"; + const String passwordExpiresOn = "passwordExpiresOn"; + const String forcePrompt = "forcePrompt"; + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } + +}; + +} // namespace rmsauth { + +#endif // USERINFO diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/UserRealmDiscoveryResponse.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserRealmDiscoveryResponse.h new file mode 100644 index 00000000..f6d56544 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/UserRealmDiscoveryResponse.h @@ -0,0 +1,60 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef USERREALMDISCOVERYRESPONSE +#define USERREALMDISCOVERYRESPONSE + +#include +#include + +namespace rmsauth { + +class UserRealmDiscoveryResponse final +{ + static const String& Tag() {static const String tag="UserRealmDiscoveryResponse"; return tag;} + + String version_; + String accountType_; + String federationProtocol_; + String federationMetadataUrl_; + String federationActiveAuthUrl_; + +public: + const String& version() const { return version_; } + const String& accountType() const { return accountType_; } + const String& federationProtocol() const { return federationProtocol_; } + const String& federationMetadataUrl() const { return federationMetadataUrl_; } + const String& federationActiveAuthUrl() const { return federationActiveAuthUrl_; } + + void version(const String& val) { version_ = val; } + void accountType(const String& val) { accountType_ = val; } + void federationProtocol(const String& val) { federationProtocol_ = val; } + void federationMetadataUrl(const String& val) { federationMetadataUrl_ = val; } + void federationActiveAuthUrl(const String& val) { federationActiveAuthUrl_ = val; } + + static UserRealmDiscoveryResponse createByDiscoveryAsync(const String& userRealmUri, const String& userName, CallStatePtr callState); + + struct JsonNames { + const String version = "ver"; + const String accountType = "account_type"; + const String federationProtocol = "federation_protocol"; + const String federationMetadataUrl = "federation_metadata_url"; + const String federationActiveAuthUrl = "federation_active_auth_url"; + }; + + static const JsonNames& jsonNames() + { + static const JsonNames jsonNames{}; + return jsonNames; + } +}; + +} // namespace rmsauth { + +#endif // USERREALMDISCOVERYRESPONSE + diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/rmsauthExport.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/rmsauthExport.h new file mode 100644 index 00000000..2d618a03 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/rmsauthExport.h @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef RMSAUTHEXPORT +#define RMSAUTHEXPORT + +#include +#if defined(RMSAUTH_LIBRARY) +# define RMSAUTH_EXPORT Q_DECL_EXPORT +#else +# define RMSAUTH_EXPORT Q_DECL_IMPORT +#endif + +#endif // RMSAUTHEXPORT diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/types.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/types.h new file mode 100644 index 00000000..b5417a29 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/types.h @@ -0,0 +1,73 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TYPES +#define TYPES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rmsauth { + +template +using ptr = std::shared_ptr; + +template +using ptrU = std::unique_ptr; + +using String = std::string; + +template +using List = std::list; + +template +using ArrayList = std::vector; + +template +using Iterator = typename ArrayList::iterator; + +template +using HashMap = std::unordered_map; + +template +using HashSet = std::unordered_set; + +template +using KeyValuePair = std::pair; + +template +using KeyValuePairPtr = ptr>; + +using Headers = HashMap; +using StringMap = Headers; + +using ByteArray = ArrayList; +using StringArray = ArrayList; +using IntArray = ArrayList; + +using StringStream = std::stringstream; + +using Mutex = std::mutex; + +using Lock = std::lock_guard; + +template +using Future = std::future; + +using DateTimeOffset = int64_t; + +} // namespace rmsauth { + +#endif // TYPES diff --git a/sdk/rmsauth_sdk/rmsauth/rmsauth/utils.h b/sdk/rmsauth_sdk/rmsauth/rmsauth/utils.h new file mode 100644 index 00000000..0ad07d25 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/rmsauth/utils.h @@ -0,0 +1,40 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef UTILS_H +#define UTILS_H + +#include "types.h" + +namespace rmsauth { + +class StringUtils +{ +public: + static bool startsWith(const String& src, const String& substr); + static bool endsWith(const String& src, const String& substr); + static int compareIC(const String& src, const String& str); + static bool equalsIC(const String& src, const String& str); + static String trim(const String& src); + static String removeQuoteInHeaderValue(const String& src); + static String toLower(const String& src); + static StringArray split(const String& src, const char delim); + static String replace(const String& src, const String& form, const String& to); + static String replaceAll(const String& src, const String& form, const String& to); + static String replaceAll(const String& src, const char form, const char to); +}; + +class HashUtils +{ +public: + static String createSha256Hash(const String& token); +}; + +} //namespace rmsauth { + +#endif // UTILS_H diff --git a/sdk/rmsauth_sdk/rmsauth/utils.cpp b/sdk/rmsauth_sdk/rmsauth/utils.cpp new file mode 100644 index 00000000..feaffd1e --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth/utils.cpp @@ -0,0 +1,122 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include +#include + +namespace rmsauth { + +bool StringUtils::startsWith(const String& src, const String& substr) +{ + return src.compare(0, substr.length(), substr) == 0; +} +bool StringUtils::endsWith(const String& src, const String& substr) +{ + return src.compare(src.length()-substr.length(), substr.length(), substr) == 0; +} +int StringUtils::compareIC(const String& src, const String& str) +{ + String srcLow = StringUtils::toLower(src); + String strLow = StringUtils::toLower(str); + return srcLow.compare(strLow); +} +bool StringUtils::equalsIC(const String& src, const String& str) +{ + return StringUtils::compareIC(src, str) == 0; +} +String StringUtils::trim(const String& src) +{ + if(src.empty())return src; + int s = 0; + while( src[s] == ' ' + || src[s] == '\t' + || src[s] == '\r' + || src[s] == '\n') + {s++;} + auto e = src.length()-1; + while( src[e] == ' ' + || src[e] == '\t' + || src[e] == '\r' + || src[e] == '\n') + {e--;} + return src.substr(s,e-s+1); +} +String StringUtils::removeQuoteInHeaderValue(const String& src) +{ + if(src.empty())return src; + auto tmp = StringUtils::trim(src); + int s = 0; + while( tmp[s] == '\''){s++;} + while( tmp[s] == '"'){s++;} + auto e = tmp.length()-1; + while( tmp[e] == '"'){e--;} + return tmp.substr(s,e-s+1); +} +String StringUtils::toLower(const String& src) +{ + std::setlocale(LC_ALL, "en_US.UTF-8"); + String result(src); + for(String::size_type i=0; i +#include + +namespace rmsauth { + +String HashUtils::createSha256Hash(const String& token) +{ + QCryptographicHash h(QCryptographicHash::Sha256); + h.addData(token.data()); + auto res = h.result(); + return String(res.begin(), res.end()); +} + +} // namespace rmsauth { diff --git a/sdk/rmsauth_sdk/rmsauth_sdk.pro b/sdk/rmsauth_sdk/rmsauth_sdk.pro new file mode 100644 index 00000000..5cc20753 --- /dev/null +++ b/sdk/rmsauth_sdk/rmsauth_sdk.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + WebAuthDialog\ + rmsauth\ + UnitTests + +rmsauth.depends = WebAuthDialog +UnitTests.depends = rmsauth diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.cpp new file mode 100644 index 00000000..09271de6 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.cpp @@ -0,0 +1,307 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "Cbc4kCryptoProvider.h" +#include "CryptoConstants.h" +#include "../CryptoAPI/CryptoAPI.h" +#include "../CryptoAPI/RMSCryptoExceptions.h" + +using namespace std; +using namespace rmscrypto::api; + +namespace rmscrypto { +namespace crypto { +Cbc4kCryptoProvider::Cbc4kCryptoProvider(const vector& key) +{ + if (key.size() < AES128_KEY_BYTE_LENGTH) + { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid key size"); + } + + m_key = key; + shared_ptr pCryptoEngine = api::ICryptoEngine::Create(); + + m_pEcbKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_ECB); + m_pCbcKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_CBC); + m_pCbcPaddingKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_CBC_PKCS7); +} + +void Cbc4kCryptoProvider::Encrypt(const uint8_t *pbIn, + uint32_t cbInUnsafe, + uint32_t dwStartingBlockNumberUnsafe, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOutUnsafe, + uint32_t *pcbOut) +{ + auto cbIn = cbInUnsafe, cbOut = cbOutUnsafe, + dwStartingBlockNumber = dwStartingBlockNumberUnsafe; + + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (!isFinal && (0 != cbIn % CBC4K_BLOCK_SIZE)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pcbOut exception"); + } + + // if it's the final block add padding, otherwise the output size is the same + uint32_t cbRequired = isFinal ? GetPaddedSize(cbIn) : cbIn; + + if (nullptr == pbOut) + { + // No need to do the encryption, just return the number of bytes required + *pcbOut = cbRequired; + return; + } + + if (cbOut < cbRequired) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid buffer size"); + } + + auto cbResult = 0; + + while (cbIn >= CBC4K_BLOCK_SIZE) + { + if (cbOut < CBC4K_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid buffer size"); + } + + // Encrypt the current block + EncryptBlock(pbIn, + CBC4K_BLOCK_SIZE, + dwStartingBlockNumber, + false, + pbOut, + cbOut); + + // Go to the next block + + pbIn += CBC4K_BLOCK_SIZE; + cbIn -= CBC4K_BLOCK_SIZE; + + pbOut += CBC4K_BLOCK_SIZE; + cbOut -= CBC4K_BLOCK_SIZE; + + ++dwStartingBlockNumber; + + cbResult += CBC4K_BLOCK_SIZE; + } + + if (!isFinal && (cbIn != 0)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + + if (isFinal) + { + // Note that cbIn might be 0 when isFinal == true and 0 == cbIn % + // CBC4K_BLOCK_SIZE. + // In that case we just encrypt an empty buffer as final and get a padding + // block of AES128_BLOCK_SIZE (16) bytes. + cbResult += + EncryptBlock(pbIn, cbIn, dwStartingBlockNumber, true, pbOut, cbOut); + } + + *pcbOut = cbResult; +} + +void Cbc4kCryptoProvider::Decrypt(const uint8_t *pbIn, + uint32_t cbInUnsafe, + uint32_t dwStartingBlockNumberUnsafe, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOutUnsafe, + uint32_t *pcbOut) +{ + auto cbIn = cbInUnsafe, cbOut = cbOutUnsafe, + dwStartingBlockNumber = dwStartingBlockNumberUnsafe; + + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (!isFinal && (0 != cbIn % CBC4K_BLOCK_SIZE)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (0 != cbIn % AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pcbOut exception"); + } + + if (nullptr == pbOut) + { + // No need to do the decryption, just return the number of bytes required + *pcbOut = cbIn; + return; + } + + if (cbOut < cbIn) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + auto cbResult = 0; + + // If this is the final chunk of the data, don't decrypt the final block in + // the loop (even if it's 4K). It needs a special + // treatment and will be decrypted separately. + while (isFinal + ? cbIn > CBC4K_BLOCK_SIZE + : cbIn >= CBC4K_BLOCK_SIZE) + { + if (cbOut < CBC4K_BLOCK_SIZE) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + DecryptBlock(pbIn, + CBC4K_BLOCK_SIZE, + dwStartingBlockNumber, + false, + pbOut, + cbOut); + + pbIn += CBC4K_BLOCK_SIZE; + cbIn -= CBC4K_BLOCK_SIZE; + + pbOut += CBC4K_BLOCK_SIZE; + cbOut -= CBC4K_BLOCK_SIZE; + + ++dwStartingBlockNumber; + + cbResult += CBC4K_BLOCK_SIZE; + } + + if (!isFinal && (cbIn != 0)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + + if (isFinal) + { + // Note that the cbIn can't be 0, the final block always should have at + // least AES128_BLOCK_SIZE (16) bytes + if (cbIn < AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + cbResult += + DecryptBlock(pbIn, cbIn, dwStartingBlockNumber, true, pbOut, cbOut); + } + + *pcbOut = cbResult; +} + +uint32_t Cbc4kCryptoProvider::EncryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (pbOut == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbOut exception"); + } + + if (!isFinalBlock && (CBC4K_BLOCK_SIZE != cbIn)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + + // Generate the IV + vector iv = GenerateIvForBlock(dwBlockNumber); + + if (!isFinalBlock) + { + m_pCbcKey->Encrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + } + else + { + m_pCbcPaddingKey->Encrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + } + + return cbOut; +} + +uint32_t Cbc4kCryptoProvider::DecryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (pbOut == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbOut exception"); + } + + if (!isFinalBlock && (CBC4K_BLOCK_SIZE != cbIn)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + // Generate the IV + vector iv = GenerateIvForBlock(dwBlockNumber); + + if (!isFinalBlock) + { + m_pCbcKey->Decrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + } + else + { + m_pCbcPaddingKey->Decrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + } + + return cbOut; +} + +uint32_t Cbc4kCryptoProvider::GetPaddedSize(uint32_t cbSizeUnsafe) +{ + auto cbSize = cbSizeUnsafe; + + return ((cbSize / AES128_BLOCK_SIZE) + 1) * AES128_BLOCK_SIZE; +} + +vectorCbc4kCryptoProvider::GenerateIvForBlock(uint32_t dwBlockNumber) +{ + vector ivInput(AES128_KEY_BYTE_LENGTH, 0); + + // Set the first 4 bytes to the block number + memcpy(&ivInput[0], &dwBlockNumber, sizeof(dwBlockNumber)); + + vector iv(AES128_KEY_BYTE_LENGTH); + + uint32_t cbIv = AES128_KEY_BYTE_LENGTH; + m_pEcbKey->Encrypt(&ivInput[0], + static_cast(ivInput.size()), &iv[0], cbIv, nullptr, + 0); + + return iv; +} +} // namespace crypto +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.h b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.h new file mode 100644 index 00000000..02cd4e66 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc4kCryptoProvider.h @@ -0,0 +1,78 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CBC4KCRYPTOPROVIDER_H_ +#define _CRYPTO_STREAMS_LIB_CBC4KCRYPTOPROVIDER_H_ + +#include "../CryptoAPI/CryptoAPI.h" +#include "CryptoConstants.h" + + +namespace rmscrypto { +namespace crypto { +class Cbc4kCryptoProvider : public api::ICryptoProvider { +public: + + Cbc4kCryptoProvider(const std::vector& key); + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + + virtual uint64_t GetCipherTextSize(uint64_t clearTextSize) override { + return ((clearTextSize / AES128_BLOCK_SIZE) + 1) * AES128_BLOCK_SIZE; + } + + virtual uint32_t GetBlockSize() override { + return CBC4K_BLOCK_SIZE; + } + + virtual std::vector GetKey() override { + return m_key; + } + +private: + + uint32_t EncryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut); + uint32_t DecryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut); + + std::vector GenerateIvForBlock(uint32_t dwBlockNumber); + + static uint32_t GetPaddedSize(uint32_t cbSize); + +private: + + std::shared_ptr m_pEcbKey; + std::shared_ptr m_pCbcKey; + std::shared_ptr m_pCbcPaddingKey; + std::vector m_key; +}; +} // namespace crypto +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CBC4KCRYPTOPROVIDER_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.cpp new file mode 100644 index 00000000..c1bfbe29 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.cpp @@ -0,0 +1,294 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "Cbc512NoPaddingCryptoProvider.h" +#include "CryptoConstants.h" +#include "../CryptoAPI/CryptoAPI.h" +#include "../CryptoAPI/RMSCryptoExceptions.h" + +using namespace std; +using namespace rmscrypto::api; + +namespace rmscrypto { +namespace crypto { +Cbc512NoPaddingCryptoProvider::Cbc512NoPaddingCryptoProvider( + const vector& key) +{ + if (key.size() < AES128_KEY_BYTE_LENGTH) + { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid key size"); + } + + m_key = key; + shared_ptr pCryptoEngine = api::ICryptoEngine::Create(); + + m_pEcbKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_ECB); + m_pCbcKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_CBC); +} + +void Cbc512NoPaddingCryptoProvider::Encrypt(const uint8_t *pbIn, + uint32_t cbInUnsafe, + uint32_t dwStartingBlockNumberUnsafe, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOutUnsafe, + uint32_t *pcbOut) +{ + auto cbIn = cbInUnsafe, cbOut = cbOutUnsafe, + dwStartingBlockNumber = dwStartingBlockNumberUnsafe; + + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (!isFinal && (0 != cbIn % CBC512_BLOCK_SIZE)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pcbOut exception"); + } + + if ((cbIn % AES128_BLOCK_SIZE) != 0) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + auto cbResult = 0; + + if (nullptr == pbOut) + { + // No need to do the encryption, just return the number of uint8_ts required + *pcbOut = (unsigned long)cbIn; + return; + } + + + while (cbIn > CBC512_BLOCK_SIZE) + { + if (cbOut < CBC512_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid buffer size"); + } + + // Encrypt the current block + EncryptBlock(pbIn, + CBC512_BLOCK_SIZE, + dwStartingBlockNumber, + false, + pbOut, + cbOut); + + // Go to the next block + pbIn += CBC512_BLOCK_SIZE; + cbIn -= CBC512_BLOCK_SIZE; + + pbOut += CBC512_BLOCK_SIZE; + cbOut -= CBC512_BLOCK_SIZE; + + ++dwStartingBlockNumber; + cbResult += CBC512_BLOCK_SIZE; + } + + if (!isFinal && (cbIn > CBC512_BLOCK_SIZE)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + cbResult += EncryptBlock(pbIn, cbIn, dwStartingBlockNumber, true, pbOut, cbOut); + *pcbOut = cbResult; +} + +void Cbc512NoPaddingCryptoProvider::Decrypt(const uint8_t *pbIn, + uint32_t cbInUnsafe, + uint32_t dwStartingBlockNumberUnsafe, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOutUnsafe, + uint32_t *pcbOut) +{ + auto cbIn = cbInUnsafe, cbOut = cbOutUnsafe, + dwStartingBlockNumber = dwStartingBlockNumberUnsafe; + + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (!isFinal && (0 != cbIn % CBC512_BLOCK_SIZE)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (0 != cbIn % AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pcbOut exception"); + } + + if (nullptr == pbOut) + { + // No need to do the decryption, just return the number of bytes required + *pcbOut = cbIn; + return; + } + + if ((cbIn % AES128_BLOCK_SIZE) != 0) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pbOut) + { + // No need to do the decryption, just return the number of uint8_ts required + *pcbOut = cbIn; + return; + } + + if (cbOut < cbIn) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + auto cbResult = 0; + + while (cbIn >= CBC512_BLOCK_SIZE) + { + if (cbOut < CBC512_BLOCK_SIZE) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + DecryptBlock(pbIn, + CBC512_BLOCK_SIZE, + dwStartingBlockNumber, + false, + pbOut, + cbOut); + + pbIn += CBC512_BLOCK_SIZE; + cbIn -= CBC512_BLOCK_SIZE; + + pbOut += CBC512_BLOCK_SIZE; + cbOut -= CBC512_BLOCK_SIZE; + + ++dwStartingBlockNumber; + + cbResult += CBC512_BLOCK_SIZE; + } + + if (!isFinal && (cbIn != 0)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + + if (isFinal && (cbIn > 0)) + { + // Note that the cbIn can't be 0, the final block always should have at + // least AES128_BLOCK_SIZE (16) uint8_ts + if (cbIn < AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + cbResult += + DecryptBlock(pbIn, cbIn, dwStartingBlockNumber, true, pbOut, cbOut); + } + + *pcbOut = cbResult; +} + +uint64_t Cbc512NoPaddingCryptoProvider::GetCipherTextSize(uint64_t clearTextSize) +{ + if ((clearTextSize <= 0) || ((clearTextSize % AES128_BLOCK_SIZE) != 0)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid argument"); + } + return clearTextSize; +} + +uint32_t Cbc512NoPaddingCryptoProvider::EncryptBlock( + const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (pbOut == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbOut exception"); + } + + if (!isFinalBlock && (CBC512_BLOCK_SIZE != cbIn)) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid aligment"); + } + + // Generate the IV + vector iv = GenerateIvForBlock(dwBlockNumber); + m_pCbcKey->Encrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + + return cbOut; +} + +uint32_t Cbc512NoPaddingCryptoProvider::DecryptBlock( + const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (pbOut == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbOut exception"); + } + + if (!isFinalBlock && (CBC512_BLOCK_SIZE != cbIn)) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + // Generate the IV + vector iv = GenerateIvForBlock(dwBlockNumber); + + m_pCbcKey->Decrypt(pbIn, cbIn, pbOut, cbOut, &iv[0], + static_cast(iv.size())); + + return cbOut; +} + +uint32_t Cbc512NoPaddingCryptoProvider::GetPaddedSize(uint32_t cbSizeUnsafe) +{ + auto cbSize = cbSizeUnsafe; + + if (cbSize <= 0) return 0; + + return (((cbSize - 1) / AES128_BLOCK_SIZE) + 1) * AES128_BLOCK_SIZE; +} + +vectorCbc512NoPaddingCryptoProvider::GenerateIvForBlock( + uint32_t dwBlockNumber) +{ + vector ivInput(AES128_KEY_BYTE_LENGTH, 0); + + // Set the first 8 uint8_ts to the number of uint8_ts + uint64_t cbuint8_tNumber = (uint64_t)dwBlockNumber * CBC512_BLOCK_SIZE; + memcpy(&ivInput[0], &cbuint8_tNumber, sizeof(cbuint8_tNumber)); + + vector iv(AES128_KEY_BYTE_LENGTH); + + uint32_t cbIv = AES128_KEY_BYTE_LENGTH; + m_pEcbKey->Encrypt(&ivInput[0], + static_cast(ivInput.size()), &iv[0], cbIv, nullptr, + 0); + + return iv; +} +} // namespace crypto +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.h b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.h new file mode 100644 index 00000000..30ff7428 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Cbc512NoPaddingCryptoProvider.h @@ -0,0 +1,75 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CBC512NOPADDINGCRYPTOPROVIDER_H_ +#define _CRYPTO_STREAMS_LIB_CBC512NOPADDINGCRYPTOPROVIDER_H_ + +#include "../CryptoAPI/CryptoAPI.h" +#include "CryptoConstants.h" + +namespace rmscrypto { +namespace crypto { +class Cbc512NoPaddingCryptoProvider : public api::ICryptoProvider { +public: + + Cbc512NoPaddingCryptoProvider(const std::vector& key); + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + + virtual uint64_t GetCipherTextSize(uint64_t clearTextSize) override; + + virtual uint32_t GetBlockSize() override { + return CBC512_BLOCK_SIZE; + } + + virtual std::vector GetKey() override { + return m_key; + } + +private: + + uint32_t EncryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut); + uint32_t DecryptBlock(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwBlockNumber, + bool isFinalBlock, + uint8_t *pbOut, + uint32_t cbOut); + + std::vector GenerateIvForBlock(uint32_t dwBlockNumber); + + static uint32_t GetPaddedSize(uint32_t cbSize); + +private: + + std::shared_ptr m_pEcbKey; + std::shared_ptr m_pCbcKey; + std::shared_ptr m_pCbcPaddingKey; + std::vector m_key; +}; +} // namespace crypto +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CBC512NOPADDINGCRYPTOPROVIDER_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Crypto.pro b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Crypto.pro new file mode 100644 index 00000000..7717693a --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/Crypto.pro @@ -0,0 +1,29 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin/crypto +TARGET = modcrypto + +QT -= gui +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release +QT += core + +win32:INCLUDEPATH += $$REPO_ROOT/third_party/include +LIBS += -L$$REPO_ROOT/bin/crypto/platform + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -lplatformcryptod +} else { + LIBS += -lplatformcrypto +} + + +SOURCES += Cbc4kCryptoProvider.cpp \ + Cbc512NoPaddingCryptoProvider.cpp \ + EcbCryptoProvider.cpp + +HEADERS += \ + Cbc4kCryptoProvider.h \ + Cbc512NoPaddingCryptoProvider.h \ + EcbCryptoProvider.h \ + CryptoConstants.h diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/CryptoConstants.h b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/CryptoConstants.h new file mode 100644 index 00000000..ee8fa341 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/CryptoConstants.h @@ -0,0 +1,19 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CRYPTODEFS_H_ +#define _CRYPTO_STREAMS_LIB_CRYPTODEFS_H_ +namespace rmscrypto { +namespace crypto { +const unsigned int AES128_KEY_BYTE_LENGTH = 16; +const unsigned int AES128_BLOCK_SIZE = 16; +const unsigned int CBC4K_BLOCK_SIZE = 4096; +const unsigned int CBC512_BLOCK_SIZE = 512; +} // namespace crypto +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CRYPTODEFS_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.cpp new file mode 100644 index 00000000..e8e3b3bb --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.cpp @@ -0,0 +1,98 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "EcbCryptoProvider.h" +#include "CryptoConstants.h" +#include "../CryptoAPI/CryptoAPI.h" +#include "../CryptoAPI/RMSCryptoExceptions.h" + +using namespace std; +using namespace rmscrypto::api; + +namespace rmscrypto { +namespace crypto { +EcbCryptoProvider::EcbCryptoProvider(const vector& key) +{ + m_key = key; + shared_ptr pCryptoEngine = api::ICryptoEngine::Create(); + m_pKey = pCryptoEngine->CreateKey(key.data(), + static_cast(key.size()), + CRYPTO_ALGORITHM_AES_ECB); +} + +void EcbCryptoProvider::Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t, + bool, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (0 != cbIn % AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException( + "Null pointer pcbOut exception"); + } + + *pcbOut = cbIn; + + if (nullptr == pbOut) + { + return; + } + + if (cbOut < cbIn) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + m_pKey->Encrypt(pbIn, cbIn, pbOut, cbOut, nullptr, 0); +} + +void EcbCryptoProvider::Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t, + bool, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (0 != cbIn % AES128_BLOCK_SIZE) { + throw exceptions::RMSCryptoInvalidArgumentException("Block is not aligned"); + } + + if (nullptr == pcbOut) { + throw exceptions::RMSCryptoNullPointerException( + "Null pointer pcbOut exception"); + } + + *pcbOut = cbIn; + + if (nullptr == pbOut) + { + return; + } + + if (cbOut < cbIn) { + throw exceptions::RMSCryptoInsufficientBufferException("Insufficient buffer"); + } + + m_pKey->Decrypt(pbIn, cbIn, pbOut, cbOut, nullptr, 0); +} +} // namespace crypto +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.h b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.h new file mode 100644 index 00000000..6f599b1d --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Crypto/EcbCryptoProvider.h @@ -0,0 +1,56 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_ECBCRYPTOPROVIDER_H_ +#define _CRYPTO_STREAMS_LIB_ECBCRYPTOPROVIDER_H_ + +#include "../CryptoAPI/CryptoAPI.h" +#include "CryptoConstants.h" + +namespace rmscrypto { +namespace crypto { +class EcbCryptoProvider : public api::ICryptoProvider { +public: + + EcbCryptoProvider(const std::vector& key); + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) override; + + virtual uint64_t GetCipherTextSize(uint64_t clearTextSize) override { + return clearTextSize; + } + + virtual uint32_t GetBlockSize() override { + return AES128_BLOCK_SIZE; + } + + virtual std::vectorGetKey() override { + return m_key; + } + +private: + + std::shared_ptr m_pKey; + std::vector m_key; +}; +} // namespace crypto +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_ECBCRYPTOPROVIDER_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.cpp b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.cpp new file mode 100644 index 00000000..cb8d862d --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.cpp @@ -0,0 +1,485 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "BlockBasedProtectedStream.h" +#include "RMSCryptoExceptions.h" +using namespace std; +namespace rmscrypto { +namespace api { +shared_ptrBlockBasedProtectedStream::Create( + shared_ptrpCryptoProvider, + shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize, + uint64_t u64BlockSize) { + return std::shared_ptr( + new BlockBasedProtectedStream(pCryptoProvider, + pBackingStream, + u64ContentStart, + u64ContentSize, + u64BlockSize)); +} + +BlockBasedProtectedStream::BlockBasedProtectedStream( + shared_ptrpCryptoProvider, + shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize, + uint64_t u64BlockSize) + : m_locker(new mutex) + , m_u64Position(0) + , m_bIsPositionValid(true) + , m_bSizeChangeRequested(false) + , m_u64NewSize(0) + , m_bIsPlainText(pCryptoProvider == nullptr) +{ + m_pSimple.reset(new SimpleProtectedStream(pCryptoProvider, pBackingStream, + u64ContentStart, u64ContentSize)); + m_pCachedBlock.reset(new CachedBlock(m_pSimple, u64BlockSize)); +} + +BlockBasedProtectedStream::BlockBasedProtectedStream( + const BlockBasedProtectedStream& rhs) + : enable_shared_from_this(rhs) + , m_locker(new mutex) + , m_u64Position(0) + , m_bIsPositionValid(true) + , m_bSizeChangeRequested(false) + , m_u64NewSize(0) + , m_bIsPlainText(rhs.m_bIsPlainText) +{ + m_pSimple = dynamic_pointer_cast(rhs.m_pSimple->Clone()); + + if (m_pSimple.get() == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Failed to clone stream"); + } + m_pCachedBlock.reset(new CachedBlock(m_pSimple, + rhs.m_pCachedBlock->GetBlockSize())); +} + +shared_futureBlockBasedProtectedStream::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + if (cbBuffer > 0) + { + if (pbBuffer == nullptr) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid argument"); + } + } + + if (!CanRead()) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid operation"); + } + + // lock resources + unique_lock lock(*m_locker); + + if (m_bIsPlainText) + { + return m_pSimple->ReadAsync(pbBuffer, cbBuffer, cbOffset, + fCreateBackingThread); + } + + if (!m_bIsPositionValid) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid operation"); + } + + + auto selfPtr = this->shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, + [](shared_ptrself, + uint8_t *buffer, + int64_t bSize, + const int64_t offset) -> int64_t + { + // lock resources + unique_locklock(*self->m_locker); + + // seek to offset + self->SeekInternal(offset); + + if (self->m_bSizeChangeRequested) + { + self->ProcessSizeChangeRequest(); + } + + int64_t u64Size = bSize; + + while (u64Size > 0 && self->m_u64Position < self->SizeInner()) + { + self->m_pCachedBlock->UpdateBlock(self->m_u64Position); + + uint64_t u64Read = self->m_pCachedBlock->ReadFromBlock(buffer, + self-> + m_u64Position, + u64Size); + + if (0 == u64Read) + { + // nothing to read anymore + break; + } + + // advance the buffer pointer + buffer += u64Read; + + // advance the current position + self->m_u64Position += u64Read; + + // decrease the number of uint8_ts to be read + u64Size -= u64Read; + } + + return static_cast((bSize) - u64Size); + }, move(selfPtr), pbBuffer, cbBuffer, cbOffset); +} + +shared_futureBlockBasedProtectedStream::WriteAsync( + const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + try { + return WriteInternalAsync(cpbBuffer, + cbBuffer, + cbOffset, + fCreateBackingThread, + true); + } + catch (exception& e) + { + m_locker->unlock(); + throw e; + } +} + +shared_futureBlockBasedProtectedStream::WriteInternalAsync( + const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + bool fLockResources) +{ + if (cbBuffer > 0) + { + if (cpbBuffer == nullptr) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid argument"); + } + } + + if ((fLockResources && !CanWrite()) || (!fLockResources && !CanWriteInner())) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid operation"); + } + + if (m_bIsPlainText) + { + // lock resources + if (fLockResources) m_locker->lock(); + auto ret = m_pSimple->WriteAsync(cpbBuffer, + cbBuffer, + cbOffset, + fCreateBackingThread); + + if (fLockResources) m_locker->unlock(); + + return ret; + } + + auto selfPtr = this->shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, + [](shared_ptrself, + const uint8_t *buffer, + int64_t bSize, + const int64_t offset, + bool fNeedLock) -> int64_t + { + // lock resources + if (fNeedLock) self->m_locker->lock(); + + if (!self->m_bIsPositionValid) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid operation"); + } + + if (self->m_bSizeChangeRequested) + { + self->ProcessSizeChangeRequest(); + } + + // seek to write + self->SeekInternal(offset); + + // the number of uint8_ts to write + uint64_t sizeRemaining = bSize; + + while (sizeRemaining > 0) + { + self->m_pCachedBlock->UpdateBlock(self->m_u64Position); + + uint64_t u64Written = self->m_pCachedBlock->WriteToBlock( + buffer, + self->m_u64Position, + sizeRemaining); + + if (0 == u64Written) + { + // nothing to write + break; + } + + // advance the buffer pointer + buffer += u64Written; + + // advance the current position + self->m_u64Position += u64Written; + + // decrease the number to be written + sizeRemaining -= u64Written; + } + + if (fNeedLock) self->m_locker->unlock(); + + // return total number of written + return static_cast(bSize - sizeRemaining); + }, move(selfPtr), cpbBuffer, cbBuffer, cbOffset, fLockResources); +} + +futureBlockBasedProtectedStream::FlushAsync(bool fCreateBackingThread) +{ + if (m_bIsPlainText) + { + // lock resources + unique_lock lock(*m_locker); + return m_pSimple->FlushAsync(fCreateBackingThread); + } + + auto selfPtr = this->shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, + [](shared_ptrself) -> bool + { + // lock resources + unique_locklock(*self->m_locker); + + if (self->m_bSizeChangeRequested) + { + self->ProcessSizeChangeRequest(); + } + + return self->m_pCachedBlock->Flush(); + }, move(selfPtr)); +} + +int64_t BlockBasedProtectedStream::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) { + return ReadAsync(pbBuffer, cbBuffer, Position(), false).get(); +} + +int64_t BlockBasedProtectedStream::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) { + return WriteAsync(cpbBuffer, cbBuffer, Position(), false).get(); +} + +bool BlockBasedProtectedStream::Flush() { + return FlushAsync(false).get(); +} + +shared_ptrBlockBasedProtectedStream::Clone() +{ + return static_pointer_cast( + shared_ptr(new BlockBasedProtectedStream(*this))); +} + +void BlockBasedProtectedStream::Seek(uint64_t u64Position) +{ + // lock resources + unique_lock lock(*m_locker); + SeekInternal(u64Position); +} + +bool BlockBasedProtectedStream::CanRead() +{ + // lock resources + unique_lock lock(*m_locker); + + return m_pSimple->CanRead(); +} + +bool BlockBasedProtectedStream::CanWrite() +{ + // lock resources + unique_lock lock(*m_locker); + + return CanWriteInner(); +} + +bool BlockBasedProtectedStream::CanWriteInner() +{ + return m_pSimple->CanWrite(); +} + +uint64_t BlockBasedProtectedStream::Position() +{ + // lock resources + unique_lock lock(*m_locker); + return PositionInner(); +} + +uint64_t BlockBasedProtectedStream::Size() +{ + // lock resources + unique_lock lock(*m_locker); + return SizeInner(); +} + +void BlockBasedProtectedStream::SeekInternal(uint64_t u64Position) { + if (m_bIsPlainText) + { + m_pSimple->Seek(u64Position); + return; + } + + if (u64Position > SizeInner()) + { + if (CanWriteInner()) + { + SizeInner(u64Position); + } + else + { + m_bIsPositionValid = false; + return; + } + } + + m_bIsPositionValid = true; + m_u64Position = u64Position; +} + +uint64_t BlockBasedProtectedStream::PositionInner() { + if (m_bIsPlainText) + { + return m_pSimple->Position(); + } + + return m_u64Position; +} + +uint64_t BlockBasedProtectedStream::SizeInner() +{ + if (m_bIsPlainText) + { + return m_pSimple->Size(); + } + + if (m_bSizeChangeRequested) + { + return m_u64NewSize; + } + + return m_pCachedBlock->GetSizeInternal(); +} + +void BlockBasedProtectedStream::SizeInner(uint64_t value) { + if (SizeInner() != value) + { + if (m_bIsPlainText) + { + m_pSimple->Size(value); + return; + } + + m_bSizeChangeRequested = true; + m_u64NewSize = value; + } +} + +void BlockBasedProtectedStream::Size(uint64_t value) { + if (!CanWrite()) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid operation"); + } + + // lock resources + unique_lock lock(*m_locker); + SizeInner(value); +} + +void BlockBasedProtectedStream::ProcessSizeChangeRequest() +{ + // Set this to false before writing, otherwise we will fall into an infinite + // recursion + // when doing the actual writing. + m_bSizeChangeRequested = false; + + uint64_t oldSize = m_pCachedBlock->GetSizeInternal(); + + // we need to remember the original position, because we are going to + // write to the stream, which will modify the current position. + uint64_t originalPosition = PositionInner(); + + if (m_u64NewSize > oldSize) + { + FillWithZeros(m_u64NewSize); + } + else if (m_u64NewSize < oldSize) + { + m_pCachedBlock->RewriteFinalBlock(m_u64NewSize); + SizeInternal(m_u64NewSize); + } + + // Seek to the original position, if the original position is within the new + // Size. + // Otherwise seek to the size. + SeekInternal(min(originalPosition, SizeInner())); +} + +void BlockBasedProtectedStream::FillWithZeros(uint64_t newSize) +{ + const uint64_t bufferSize = m_pCachedBlock->GetBlockSize(); + + vector zeros((unsigned int)bufferSize, 0x0); + + SeekInternal(m_pCachedBlock->GetSizeInternal()); + + // Note that we might end-up writing more zeros than newSize - oldSize, + // because of the CBC padding. + while (newSize > m_pCachedBlock->GetSizeInternal()) + { + uint64_t toWrite = + min(newSize - m_pCachedBlock->GetSizeInternal(), bufferSize); + + WriteInternalAsync(zeros.data(), toWrite, PositionInner(), false, + false).get(); + } + + SizeInternal(newSize); +} + +void BlockBasedProtectedStream::SizeInternal(uint64_t size) +{ + m_pSimple->Size(size); + + // Adjust the position if needed + if (m_u64Position > size) + { + m_u64Position = size - 1; + } + + // update the cached block if needed + m_pCachedBlock->SizeInternal(size); +} + +BlockBasedProtectedStream::~BlockBasedProtectedStream() +{} +} // namespace api +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.h new file mode 100644 index 00000000..47bb1a4e --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/BlockBasedProtectedStream.h @@ -0,0 +1,111 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_PROTECTION_BLOCKBASEDPROTECTEDSTREAM_H_ +#define _CRYPTO_STREAMS_LIB_PROTECTION_BLOCKBASEDPROTECTEDSTREAM_H_ + +#include +#include "CryptoAPIExport.h" +#include "IStream.h" +#include "ICryptoProvider.h" +#include "SimpleProtectedStream.h" +#include "CachedBlock.h" + +namespace rmscrypto { +namespace api { +class BlockBasedProtectedStream : public IStream, + public std::enable_shared_from_this< + BlockBasedProtectedStream>{ +public: + + static DLL_PUBLIC_CRYPTO std::shared_ptrCreate( + std::shared_ptrpCryptoProvider, + std::shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize, + uint64_t u64BlockSize); + + // IStream implementation + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::futureFlushAsync(bool fCreateBackingThread) + override; + + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + + virtual ~BlockBasedProtectedStream() override; + +private: + + BlockBasedProtectedStream( + std::shared_ptrpCryptoProvider, + std::shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize, + uint64_t u64BlockSize); + + void SeekInternal(uint64_t u64Position); + uint64_t PositionInner(); + uint64_t SizeInner(); + void SizeInner(uint64_t value); + bool CanWriteInner(); + std::shared_futureWriteInternalAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + bool fLockResources); + + void + ProcessSizeChangeRequest(); + void SizeInternal( + uint64_t size); + void + FillWithZeros( + uint64_t newSize); + + BlockBasedProtectedStream(const BlockBasedProtectedStream&); + BlockBasedProtectedStream& operator=( + const BlockBasedProtectedStream&) = delete; + +private: + + std::shared_ptr m_locker; + + std::shared_ptr m_pSimple; + std::shared_ptr m_pCachedBlock; + + uint64_t m_u64Position; + bool m_bIsPositionValid; + bool m_bSizeChangeRequested; + uint64_t m_u64NewSize; + bool m_bIsPlainText; +}; +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_PROTECTION_BLOCKBASEDPROTECTEDSTREAM_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.cpp b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.cpp new file mode 100644 index 00000000..0975c4e8 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.cpp @@ -0,0 +1,282 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "SimpleProtectedStream.h" +#include "CachedBlock.h" +#include "RMSCryptoExceptions.h" + +using namespace std; +namespace rmscrypto { +namespace api { +CachedBlock::CachedBlock(shared_ptrpSimple, + uint64_t u64BlockSize) + : m_pSimple(pSimple) + , m_u64BlockSize(u64BlockSize) + , m_u64CacheStart(numeric_limits::max()) + , m_u64CacheSize(0) + , m_cache(static_cast(u64BlockSize)) + , m_bFinalBlockHasBeenWritten(false) + , m_bWritePending(false) +{} + +uint64_t CachedBlock::GetBlockSize() +{ + return m_u64BlockSize; +} + +void CachedBlock::UpdateBlock(uint64_t u64Position) +{ + uint32_t u32BlockNumber = CalculateBlockNumber(u64Position); + + if ((numeric_limits::max() != m_u64CacheStart) && + (CalculateBlockNumber(m_u64CacheStart) == u32BlockNumber)) + { + // the current cache is up-to-date no need to overwrite it + return; + } + + if (m_bWritePending) + { + // we're going to overwrite the current cached block, so we need to write + // the current block to the backing stream + + // determine if this is the final block + bool bCurrentBlockIsLastBlock = + (m_u64CacheStart + m_u64BlockSize >= m_pSimple->Size()); + bool bCurrentBlockIsFinal = false; + + if (bCurrentBlockIsLastBlock) + { + if (u64Position < m_u64CacheStart + m_u64BlockSize) + { + // This is the last block, and the new position is not past this block, + // so we don't expect any more data coming and this block should be + // treated as final. + bCurrentBlockIsFinal = true; + } + } + + // Write the block + m_pSimple->WriteInternalAsync(m_cache.data(), + m_u64CacheSize, + m_u64CacheStart, + false, + CalculateBlockNumber(m_u64CacheStart), + bCurrentBlockIsFinal).get(); + + if (bCurrentBlockIsFinal) + { + m_bFinalBlockHasBeenWritten = true; + } + + m_bWritePending = false; + } + + // calculate the start of the block + m_u64CacheStart = static_cast(u32BlockNumber) * m_u64BlockSize; + + // determine if this is the final block + bool bNewBlockIsFinal = + (m_u64CacheStart + m_u64BlockSize >= m_pSimple->Size()); + + // go to the start of the block and read + m_u64CacheSize = m_pSimple->ReadInternalAsync(&m_cache[0], + m_u64BlockSize, + m_u64CacheStart, + false, + u32BlockNumber, + bNewBlockIsFinal).get(); +} + +uint64_t CachedBlock::ReadFromBlock(uint8_t *pbBuffer, + uint64_t u64Position, + uint64_t u64Size) +{ + // if the position is in the cache range (i.e. [cacheStart, cacheStart + + // cacheSize)) + if ((m_u64CacheStart <= u64Position) && + (u64Position < m_u64CacheStart + m_u64CacheSize)) + { + // calculate the position in the cache where we need to read from + uint64_t u64PositionInCache = u64Position - m_u64CacheStart; + + // calculate the number of uint8_ts available to read + uint64_t u64ToRead = + min(u64Size, m_u64CacheSize - u64PositionInCache); + + // copy the data + memcpy(pbBuffer, &m_cache[u64PositionInCache], u64ToRead); + + return u64ToRead; + } + else + { + // nothing in cache to read + return 0; + } +} + +uint64_t CachedBlock::WriteToBlock( + const uint8_t *pbBuffer, + uint64_t u64Position, + uint64_t u64Size) +{ + // if the position is in the cache range (i.e. [cacheStart, cacheStart + + // blockSize)) + if ((m_u64CacheStart <= u64Position) && + (u64Position < m_u64CacheStart + m_u64BlockSize)) + { + // calculate the position in the cache where we need to write to + uint64_t u64PositionInCache = u64Position - m_u64CacheStart; + + // calculate the number of uint8_ts we can write to the current block + uint64_t u64ToWrite = + min(u64Size, m_u64BlockSize - u64PositionInCache); + + if (u64ToWrite > 0) + { + m_bWritePending = true; + } + + // write the data + memcpy(&m_cache[u64PositionInCache], pbBuffer, u64ToWrite); + + // update cache size + m_u64CacheSize = max(m_u64CacheSize, u64PositionInCache + u64ToWrite); + + // determine if this is the final block + bool bCurrentBlockIsFinal = + (m_u64CacheStart + m_u64BlockSize >= m_pSimple->Size()); + + if (bCurrentBlockIsFinal) + { + m_bFinalBlockHasBeenWritten = false; + } + + return u64ToWrite; + } + else + { + // nothing to write to this cached position + return 0; + } +} + +uint32_t CachedBlock::CalculateBlockNumber(uint64_t u64Position) const +{ + uint64_t u64BlockNumber = u64Position / m_u64BlockSize; + + if (m_bFinalBlockHasBeenWritten && + (u64BlockNumber * m_u64BlockSize == GetSizeInternal()) && + (u64Position != GetSizeInternal())) + { + // This is the case when the (encrypted final block size) == (block size) + // and the u64Position is in the final block but not pointing to the end of + // the block. + // This means that there is still space left in the final block (the CBC + // padding). + if (u64BlockNumber > 0) + { + --u64BlockNumber; + } + } + + return static_cast(u64BlockNumber); +} + +void CachedBlock::RewriteFinalBlock(uint64_t newSize) +{ + // shrinking the backing stream + if (newSize != 0) + { + // The new size can be somewhere in the middle of the block. If we delete + // everything after new size + // we won't be able to decrypt it and finalize it. The idea is + // 1. to read the last uint8_t (which will cause decrypting the block + // into + // the cache), + // 2. to set the new size (to get rid of everything after the new size + // in the cache) + // 3. and finally to write the last uint8_t back (which will make it + // reencrypt the cached block, i.e., will set the _isEncryptPending flag) + + // Read the last byte as if the size has never been changed + UpdateBlock(newSize - 1); + + uint8_t byte; + + /*uint64_t bytesRead = */ ReadFromBlock(&byte, newSize - 1, 1); + + // There is no final block anymore + m_bFinalBlockHasBeenWritten = false; + + // Now write the uint8_t + WriteToBlock(&byte, newSize - 1, 1); + } +} + +bool CachedBlock::Flush() +{ + uint64_t cacheStart = m_u64CacheStart; + + if (m_u64CacheStart == numeric_limits::max()) + { + // nothing written to cache, still need to flush the padding + cacheStart = 0; + } + + // determine if this is the final block + bool bIsFinal = (cacheStart + m_u64BlockSize >= m_pSimple->Size()); + + m_pSimple->WriteInternalAsync(m_cache.data(), m_u64CacheSize, cacheStart, false, + CalculateBlockNumber(cacheStart), bIsFinal).get(); + + if (bIsFinal) + { + m_bFinalBlockHasBeenWritten = true; + } + + m_bWritePending = false; + + return m_pSimple->Flush(); +} + +uint64_t CachedBlock::GetSizeInternal() const +{ + // if we're pending write somewhere in the middle, then the backing stream + // size is still valid + // but if we're pending write on the final block, then we need to calculate + // the size from our own cache + if (m_bWritePending && !m_bFinalBlockHasBeenWritten) + { + return (CalculateBlockNumber(m_u64CacheStart) * + static_cast(m_u64BlockSize)) + + static_cast(m_u64CacheSize); + } + + return m_pSimple->Size(); +} + +void CachedBlock::SizeInternal(uint64_t u64Size) +{ + // Make sure that the current cached block doesn't go beyond the new size + uint64_t u64BlockPosition = CalculateBlockNumber(m_u64CacheStart) * + static_cast(m_u64BlockSize); + + // This method should only be called after the cache has been updated. + // Validate that the current block is the correct block in the cache (not + // beyond the new size) + if (u64BlockPosition > u64Size) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid argument"); + } + + m_u64CacheSize = min(m_u64CacheSize, u64Size - u64BlockPosition); +} +} // namespace api +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.h new file mode 100644 index 00000000..dd462214 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CachedBlock.h @@ -0,0 +1,59 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CACHEDBLOCK_H_ +#define _CRYPTO_STREAMS_LIB_CACHEDBLOCK_H_ + +#include +#include + +namespace rmscrypto { +namespace api { +class SimpleProtectedStream; + +class CachedBlock { +public: + + CachedBlock(std::shared_ptrpSimple, + uint64_t u64BlockSize); + + uint64_t GetBlockSize(); + + void UpdateBlock(uint64_t u64Position); + + uint64_t ReadFromBlock(uint8_t *pbBuffer, + uint64_t u64Position, + uint64_t u64Size); + + uint64_t WriteToBlock(const uint8_t *pbBuffer, + uint64_t u64Position, + uint64_t u64Size); + + void RewriteFinalBlock(uint64_t newSize); + bool Flush(); + uint64_t GetSizeInternal() const; + void SizeInternal(uint64_t u64Size); + +private: + + uint32_t CalculateBlockNumber(uint64_t u64Position) const; + +private: + + std::shared_ptr m_pSimple; + uint64_t m_u64BlockSize; + + uint64_t m_u64CacheStart; + uint64_t m_u64CacheSize; + std::vector m_cache; + bool m_bFinalBlockHasBeenWritten; + bool m_bWritePending; +}; +} // namespace api +} // namespace rmscrypto +#endif // ifndef _CRYPTO_STREAMS_LIB_CACHEDBLOCK_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.cpp b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.cpp new file mode 100644 index 00000000..cb0ad7fc --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.cpp @@ -0,0 +1,180 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include + +#include + +#include "../Platform/KeyStorage/IKeyStorage.h" +#include "../Platform/KeyStorage/base64.h" +#include "../Platform/Crypto/CryptoEngine.h" +#include "../Crypto/CryptoConstants.h" +#include "../Crypto/Cbc4kCryptoProvider.h" +#include "../Crypto/Cbc512NoPaddingCryptoProvider.h" +#include "../Crypto/EcbCryptoProvider.h" + +#include "CryptoAPI.h" +#include "BlockBasedProtectedStream.h" +#include "ICryptoStream.h" +#include "StdStreamAdapter.h" +#include "RMSCryptoExceptions.h" + +using namespace std; +using namespace rmscrypto::crypto; +namespace rmscrypto { +namespace api { +SharedStream CreateCryptoStream( + CipherMode cipherMode, + const vector& key, + SharedStream backingStream) +{ + shared_ptr pCryptoProvider = nullptr; + uint64_t nProtectedStreamBlockSize = 4096; + + pCryptoProvider = CreateCryptoProvider(cipherMode, key); + nProtectedStreamBlockSize = pCryptoProvider->GetBlockSize() == 512 ? 512 : 4096; + + auto pProtectedStreamImpl = BlockBasedProtectedStream::Create(pCryptoProvider, + backingStream, + 0, + -1, + nProtectedStreamBlockSize); + + return pProtectedStreamImpl; +} + +SharedStream CreateCryptoStreamWithAutoKey(CipherMode cipherMode, + const string& csKeyName, + SharedStream backingStream) +{ + vector key(16); // AES-128 crypto key + auto ks = platform::keystorage::IKeyStorage::Create(); + + // try to lookup key + auto ret = ks->LookupKey(csKeyName); + + if ((ret.get() == nullptr) || ret->empty()) { + // we should generate a new key + if (RAND_bytes(key.data(), static_cast(key.size())) != 0) { + // convert to BASE64 encoding + auto keyBase64 = platform::keystorage::base64_encode( + key.data(), static_cast(key.size())); + + // now store the new key + ks->StoreKey(csKeyName, keyBase64); + + // reload the new key + ret = ks->LookupKey(csKeyName); + } + } + + if ((ret.get() != nullptr) && !ret->empty()) { + auto keyDec = platform::keystorage::base64_decode(*ret); + key = vector(keyDec.begin(), keyDec.end()); + return CreateCryptoStream(cipherMode, key, backingStream); + } + + // fault + return nullptr; +} + +std::shared_ptr >EncryptWithAutoKey( + std::shared_ptr >pbIn, + CipherMode cipherMode, + const std::string & csKeyName /*= "default"*/) { + // create backing stream + auto backingStdStream = make_shared( + ios::in | ios::out | ios::binary); + + auto backingStream = + CreateStreamFromStdStream(static_pointer_cast(backingStdStream)); + + auto cryptoStream = CreateCryptoStreamWithAutoKey(cipherMode, + csKeyName, + backingStream); + + // encrypt + cryptoStream->Write(pbIn->data(), pbIn->size()); + cryptoStream->Flush(); + + // return result + auto resStr = backingStdStream->str(); + return make_shared >(resStr.begin(), resStr.end()); +} + +std::shared_ptr >DecryptWithAutoKey( + std::shared_ptr >cbIn, + CipherMode cipherMode, + const std::string & csKeyName /*= "default"*/) { + // create backing stream + auto backingStdStream = make_shared( + ios::in | ios::out | ios::binary); + + backingStdStream->write(reinterpret_cast(cbIn->data()), + cbIn->size()); + + backingStdStream->flush(); + + auto backingStream = + CreateStreamFromStdStream(static_pointer_cast(backingStdStream)); + + auto cryptoStream = CreateCryptoStreamWithAutoKey(cipherMode, + csKeyName, + backingStream); + + // encrypt + auto resVec = cryptoStream->Read(cbIn->size()); + + // return result + return make_shared >(resVec.begin(), resVec.end()); +} + +SharedStream CreateStreamFromStdStream( + std::shared_ptrstdIStream) { + return static_pointer_cast(make_shared(stdIStream)); +} + +SharedStream CreateStreamFromStdStream( + std::shared_ptrstdOStream) { + return static_pointer_cast(make_shared(stdOStream)); +} + +SharedStream CreateStreamFromStdStream( + std::shared_ptrstdIOStream) +{ + return static_pointer_cast(make_shared(stdIOStream)); +} + +std::shared_ptrCreateCryptoProvider( + CipherMode cipherMode, + const std::vector& key) +{ + switch (cipherMode) + { + case CIPHER_MODE_CBC4K: + return make_shared(key); + + case CIPHER_MODE_ECB: + return make_shared(key); + + case CIPHER_MODE_CBC512NOPADDING: + return make_shared(key); + + default: + throw exceptions::RMSCryptoInvalidArgumentException("Invalid cipher mod"); + } +} + +std::shared_ptrCreateCryptoEngine() +{ + return ICryptoEngine::Create(); +} +} // namespace api +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.h new file mode 100644 index 00000000..bb2d46ca --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.h @@ -0,0 +1,59 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_API_H_ +#define _CRYPTO_STREAMS_LIB_API_H_ +#include +#include +#include "CryptoAPIExport.h" +#include "IStream.h" +#include "ICryptoProvider.h" +#include "ICryptoEngine.h" + +namespace rmscrypto { +namespace api { +// Stream factory +SharedStream DLL_PUBLIC_CRYPTO CreateCryptoStream( + CipherMode cipherMode, + const std::vector& key, + SharedStream backingStream); + +// A random new key for current user will be generated at first time using +// keyInitializationData +// To reuse the same key you MUST put the same keyInitializationData as the +// first time +SharedStream DLL_PUBLIC_CRYPTO CreateCryptoStreamWithAutoKey( + CipherMode cipherMode, + const std::string& csKeyName, + SharedStream backingStream); + +std::shared_ptr >DLL_PUBLIC_CRYPTO EncryptWithAutoKey( + std::shared_ptr >pbIn, + CipherMode cipherMode = CIPHER_MODE_CBC4K, + const std::string & csKeyName = "default"); + +std::shared_ptr >DLL_PUBLIC_CRYPTO DecryptWithAutoKey( + std::shared_ptr >pbIn, + CipherMode cipherMode = CIPHER_MODE_CBC4K, + const std::string & csKeyName = "default"); + +SharedStream DLL_PUBLIC_CRYPTO CreateStreamFromStdStream( + std::shared_ptrstdIStream); +SharedStream DLL_PUBLIC_CRYPTO CreateStreamFromStdStream( + std::shared_ptrstdOStream); +SharedStream DLL_PUBLIC_CRYPTO CreateStreamFromStdStream( + std::shared_ptrstdIOStream); + +// create crypto primitives directly +std::shared_ptrDLL_PUBLIC_CRYPTO CreateCryptoProvider( + CipherMode cipherMode, + const std::vector& key); +std::shared_ptrDLL_PUBLIC_CRYPTO CreateCryptoEngine(); +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_API_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.pro b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.pro new file mode 100644 index 00000000..9ec758a7 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPI.pro @@ -0,0 +1,59 @@ +REPO_ROOT = $$PWD/../../../.. +DESTDIR = $$REPO_ROOT/bin +TARGET = rmscrypto + +QT -= gui + +TEMPLATE = lib +CONFIG += plugin warn_on c++11 debug_and_release +QT += core + +DEFINES += RMS_CRYPTO_LIBRARY + +win32:INCLUDEPATH += $$REPO_ROOT/third_party/include +unix:!mac:INCLUDEPATH += /usr/include/glib-2.0/ /usr/include/libsecret-1/ /usr/lib/x86_64-linux-gnu/glib-2.0/include/ + +LIBS += -L$$REPO_ROOT/bin/crypto -L$$REPO_ROOT/bin/crypto/platform + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -lmodcryptod -lplatformkeystoraged -lplatformcryptod +}else { + LIBS += -lmodcrypto -lplatformkeystorage -lplatformcrypto +} + +unix { + contains(QMAKE_HOST.arch, x86_64) { + target.path = /usr/lib64 + INSTALLS += target + } else { + target.path += /usr/lib + INSTALLS += target + } +} + +HEADERS += \ + BlockBasedProtectedStream.h \ + CachedBlock.h \ + IStream.h \ + SimpleProtectedStream.h \ + ICryptoStream.h \ + CryptoAPI.h \ + StdStreamAdapter.h \ + ICryptoProvider.h \ + ICryptoEngine.h \ + ICryptoHash.h \ + ICryptoKey.h \ + CryptoAPIExport.h \ + RMSCryptoExceptions.h + +SOURCES += \ + BlockBasedProtectedStream.cpp \ + CachedBlock.cpp \ + SimpleProtectedStream.cpp \ + CryptoAPI.cpp \ + StdStreamAdapter.cpp + +win32:LIBS += -L$$REPO_ROOT/third_party/lib/eay/ -lssleay32MDd -llibeay32MDd -lGdi32 -lUser32 -lAdvapi32 +unix:!mac:LIBS += -lssl -lcrypto -lsecret-1 -lglib-2.0 +mac:LIBS += -lssl -lcrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPIExport.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPIExport.h new file mode 100644 index 00000000..bcd810cf --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/CryptoAPIExport.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_EXPORT_H_ +#define _RMS_LIB_EXPORT_H_ + +// This code produces too many warnings + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RMS_CRYPTO_LIBRARY + #ifdef __GNUC__ + #define DLL_PUBLIC_CRYPTO __attribute__ ((dllexport)) + #else + #define DLL_PUBLIC_CRYPTO __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. + #endif + #else + #ifdef __GNUC__ + #define DLL_PUBLIC_CRYPTO __attribute__ ((dllimport)) + #else + #define DLL_PUBLIC_CRYPTO __declspec(dllimport) // Note: actually gcc seems to also supports this syntax. + #endif + #endif + #define DLL_LOCAL +#else + #if __GNUC__ >= 4 + #define DLL_PUBLIC_CRYPTO __attribute__ ((visibility ("default"))) + #define DLL_LOCAL_CRYPTO __attribute__ ((visibility ("hidden"))) + #else + #define DLL_PUBLIC_CRYPTO + #define DLL_LOCAL_CRYPTO + #endif +#endif + +#endif // _RMS_LIB_EXPORT_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoEngine.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoEngine.h new file mode 100644 index 00000000..6a3ccf42 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoEngine.h @@ -0,0 +1,39 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_ICRYPTOENGINE +#define _CRYPTO_STREAMS_LIB_ICRYPTOENGINE + +#include +#include "ICryptoHash.h" +#include "ICryptoKey.h" + +namespace rmscrypto { +namespace api { +enum CryptoAlgorithm +{ + CRYPTO_ALGORITHM_AES_ECB = 0, + CRYPTO_ALGORITHM_AES_CBC = 1, + CRYPTO_ALGORITHM_AES_CBC_PKCS7 = 2, +}; + +class ICryptoEngine { +public: + + virtual std::shared_ptrCreateKey(const uint8_t *pbKey, + uint32_t cbKey, + CryptoAlgorithm algorithm) = + 0; + virtual std::shared_ptr CreateHash(CryptoHashAlgorithm algorithm) = + 0; + static std::shared_ptrCreate(); +}; +} // namespace api +} // namespace rmscrypto + +#endif // _CRYPTO_STREAMS_LIB_ICRYPTOENGINE diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoHash.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoHash.h new file mode 100644 index 00000000..3c62ad7f --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoHash.h @@ -0,0 +1,32 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_ICRYPTOHASH +#define _CRYPTO_STREAMS_LIB_ICRYPTOHASH +#include +namespace rmscrypto { +namespace api { +enum CryptoHashAlgorithm +{ + CRYPTO_HASH_ALGORITHM_SHA1 = 0, + CRYPTO_HASH_ALGORITHM_SHA256 = 1, +}; + +class ICryptoHash { +public: + + virtual size_t GetOutputSize() = 0; + virtual void Hash(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut) = 0; +}; +} // namespace api +} // namespace rmscrypto + +#endif // _CRYPTO_STREAMS_LIB_ICRYPTOHASH diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoKey.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoKey.h new file mode 100644 index 00000000..df539926 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoKey.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_ICRYPTOKEY_ +#define _CRYPTO_STREAMS_LIB_ICRYPTOKEY_ +#include +#include +namespace rmscrypto { +namespace api { +class ICryptoKey { +public: + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) = 0; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) = 0; +}; +} // namespace api +} // namespace rmscrypto + +#endif // _CRYPTO_STREAMS_LIB_ICRYPTOKEY_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoProvider.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoProvider.h new file mode 100644 index 00000000..f8761836 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoProvider.h @@ -0,0 +1,53 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CRYPTOPROVIDER_H_ +#define _CRYPTO_STREAMS_LIB_CRYPTOPROVIDER_H_ +#include +#include +#include + +#include "CryptoAPIExport.h" + +namespace rmscrypto { +namespace api { +enum CipherMode +{ + CIPHER_MODE_CBC4K, + CIPHER_MODE_ECB, + CIPHER_MODE_CBC512NOPADDING +}; + +class ICryptoProvider { +public: + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) = 0; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint32_t dwStartingBlockNumber, + bool isFinal, + uint8_t *pbOut, + uint32_t cbOut, + uint32_t *pcbOut) = 0; + + + virtual uint64_t GetCipherTextSize(uint64_t clearTextSize) + = 0; + + virtual uint32_t GetBlockSize() = 0; + virtual std::vectorGetKey() = 0; +}; +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CRYPTOPROVIDER_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoStream.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoStream.h new file mode 100644 index 00000000..d1054ea4 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/ICryptoStream.h @@ -0,0 +1,50 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_SECRETSTREAM_H_ +#define _CRYPTO_STREAMS_LIB_SECRETSTREAM_H_ +#include +#include "IStream.h" +#include "CryptoAPI.h" + +namespace rmscrypto { +namespace api { +class ICryptoStream : public IStream { +public: + + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::futureFlushAsync(bool fCreateBackingThread) override; + + // Sync methods + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual SharedStream Clone() = 0; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; +}; +} // namespace api +} // namespace rmscrypto +#endif // ifndef _CRYPTO_STREAMS_LIB_SECRETSTREAM_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/IStream.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/IStream.h new file mode 100644 index 00000000..b900249b --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/IStream.h @@ -0,0 +1,76 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_ISTREAM_H_ +#define _CRYPTO_STREAMS_LIB_ISTREAM_H_ + +#include +#include +#include +#include +#include "CryptoAPIExport.h" + +namespace rmscrypto { +namespace api { +class IStream; +typedef std::shared_ptrSharedStream; + +class IStream { +public: + + // Async methods. Be sure buffer exists until result will be got from + // std::future + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + = 0; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + = 0; + virtual std::future FlushAsync(bool fCreateBackingThread) = 0; + + // Sync methods + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) = 0; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) = 0; + virtual bool Flush() = 0; + + virtual SharedStream Clone() = 0; + + virtual void Seek(uint64_t u64Position) = 0; + virtual bool CanRead() = 0; + virtual bool CanWrite() = 0; + virtual uint64_t Position() = 0; + virtual uint64_t Size() = 0; + virtual void Size(uint64_t u64Value) = 0; + + virtual std::vectorRead(uint64_t u64size) + { + std::vector plainText; + + if (u64size > 0) + { + plainText.resize(u64size); + int actualSize = + static_cast(Read(&plainText[0], static_cast(plainText.size()))); + plainText.resize(actualSize); + } + return plainText; + } + +protected: + + virtual ~IStream() {} +}; +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_ISTREAM_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/RMSCryptoExceptions.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/RMSCryptoExceptions.h new file mode 100644 index 00000000..0674ae19 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/RMSCryptoExceptions.h @@ -0,0 +1,157 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_EXCEPTIONS_H +#define _CRYPTO_STREAMS_LIB_EXCEPTIONS_H +#include +#include + +#ifndef _NOEXCEPT +#if __GNUC__ >= 4 +#define _NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#endif +#endif + +namespace rmscrypto { +namespace exceptions { +class RMSCryptoException : public std::exception { +public: + + enum ExceptionTypes { + LogicError = 0, + IOError + }; + enum ErrorTypes { + InvalidArgument = 0, + NullPointer, + OperationUnavailable, + Insufficientbuffer, + SecretKeyException, + UnknownError + }; + + RMSCryptoException(const ExceptionTypes type, + const int error, + const std::string & message) _NOEXCEPT + : type_(type), error_(error), message_(message.c_str()) + {} + + RMSCryptoException(const ExceptionTypes type, + const int error, + const char *const & message) _NOEXCEPT + : type_(type), error_(error), message_(message) + {} + + virtual ~RMSCryptoException() _NOEXCEPT {} + + virtual const char* what() const _NOEXCEPT override { + return message_; + } + + virtual ExceptionTypes type() const _NOEXCEPT { + return type_; + } + + virtual int error() const _NOEXCEPT { + return error_; + } + +private: + + ExceptionTypes type_; + int error_; + const char *message_; +}; + +class RMSCryptoLogicException : public RMSCryptoException { +public: + + RMSCryptoLogicException(const int error, + const std::string& message) _NOEXCEPT + : RMSCryptoException(LogicError, error, message) {} + + RMSCryptoLogicException(const int error, + const char *const& message) _NOEXCEPT + : RMSCryptoException(LogicError, error, message) {} + + virtual ~RMSCryptoLogicException() _NOEXCEPT {} +}; + +class RMSCryptoIOException : public RMSCryptoException { +public: + + RMSCryptoIOException(const int error, + const std::string& message) _NOEXCEPT + : RMSCryptoException(IOError, error, message) {} + + RMSCryptoIOException(const int error, + const char *const& message) _NOEXCEPT + : RMSCryptoException(IOError, error, message) {} + + virtual ~RMSCryptoIOException() _NOEXCEPT {} +}; + +class RMSCryptoIOKeyException : public RMSCryptoIOException { +public: + + RMSCryptoIOKeyException(const std::string& message, int code) _NOEXCEPT + : RMSCryptoIOException(SecretKeyException, message), code_(code) {} + + RMSCryptoIOKeyException(const char *const& message, int code) _NOEXCEPT + : RMSCryptoIOException(SecretKeyException, message), code_(code) {} + + virtual ~RMSCryptoIOKeyException() _NOEXCEPT {} + + virtual int code() const _NOEXCEPT { + return code_; + } + +private: + + int code_; // additional reason for this error +}; + + +class RMSCryptoInvalidArgumentException : public RMSCryptoLogicException { +public: + + RMSCryptoInvalidArgumentException(const std::string& message) _NOEXCEPT + : RMSCryptoLogicException(InvalidArgument, message) {} + + RMSCryptoInvalidArgumentException(const char *const& message) _NOEXCEPT + : RMSCryptoLogicException(InvalidArgument, message) {} + + virtual ~RMSCryptoInvalidArgumentException() _NOEXCEPT {} +}; + +class RMSCryptoNullPointerException : public RMSCryptoLogicException { +public: + + RMSCryptoNullPointerException(const std::string& message) _NOEXCEPT + : RMSCryptoLogicException(NullPointer, message) {} + + RMSCryptoNullPointerException(const char *const& message) _NOEXCEPT + : RMSCryptoLogicException(NullPointer, message) {} + + virtual ~RMSCryptoNullPointerException() _NOEXCEPT {} +}; + +class RMSCryptoInsufficientBufferException : public RMSCryptoLogicException { +public: + + RMSCryptoInsufficientBufferException(const std::string& message) _NOEXCEPT + : RMSCryptoLogicException(NullPointer, message) {} + + RMSCryptoInsufficientBufferException(const char *const& message) _NOEXCEPT + : RMSCryptoLogicException(NullPointer, message) {} + + virtual ~RMSCryptoInsufficientBufferException() _NOEXCEPT {} +}; +} // namespace exceptions +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_EXCEPTIONS_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.cpp b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.cpp new file mode 100644 index 00000000..4d69b563 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.cpp @@ -0,0 +1,348 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "SimpleProtectedStream.h" +#include "RMSCryptoExceptions.h" + +using namespace std; +namespace rmscrypto { +namespace api { +SimpleProtectedStream::SimpleProtectedStream( + shared_ptrpCryptoProvider, + shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize) + : m_locker(new mutex) + , m_pCryptoProvider(pCryptoProvider) + , m_pBackingStream(pBackingStream) + , m_u64ContentStart(u64ContentStart) + , m_u64ContentSize(u64ContentSize) + , m_bIsPlainText(pCryptoProvider == nullptr) +{ + if (pBackingStream.get() == nullptr) { + throw exceptions::RMSCryptoInvalidArgumentException("Bad parameter"); + } + + if (u64ContentStart > pBackingStream->Size()) { + throw exceptions::RMSCryptoInvalidArgumentException("Bad parameter"); + } + + // m_u64ContentSize can be std::numeric_limits::max(), which means + // "until the end of the stram". + // that's why we need to take a min of the actual stream size and the + // m_u64ContentSize + m_u64ContentSize = min(m_u64ContentSize, + m_pBackingStream->Size() - m_u64ContentStart); + + // seek to the start + Seek(0); +} + +shared_futureSimpleProtectedStream::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return ReadInternalAsync(pbBuffer, + cbBuffer, + cbOffset, + fCreateBackingThread, + 0, + false); +} + +shared_futureSimpleProtectedStream::ReadInternalAsync( + uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + uint32_t u32StartingBlockNumber, + bool bIsFinal) +{ + if (m_bIsPlainText) + { + // lock resources + unique_lock lock(*m_locker); + + // calculate the number of uint8_ts left in the stream + uint64_t u64ContentLeft = m_u64ContentSize - cbOffset; + uint64_t toReadSize = + min(static_cast(cbBuffer), u64ContentLeft); + + return m_pBackingStream->ReadAsync(pbBuffer, toReadSize, cbOffset, + fCreateBackingThread); + } + + auto selfPtr = this->shared_from_this(); + + return std::async(fCreateBackingThread ? launch::async : launch::deferred, + [](shared_ptrself, + uint8_t *buffer, + const int64_t bSize, + const int64_t offset, + uint32_t startingBlockNumber, + bool isFinal) -> int64_t + { + // lock resources + unique_locklock(*self->m_locker); + + // calculate the number of uint8_ts left in the stream + uint64_t u64ContentLeft = self->m_u64ContentSize - offset; + uint64_t toRead = min(static_cast(bSize), u64ContentLeft); + + // seek to Read + self->SeekInternal(offset); + + // read the cipherText from the backing stream (make sure we don't read + // more + // than u64ContentLeft) + vectorcipherText = self->m_pBackingStream->Read(toRead); + + // decrypt the ciphertext into the supplied buffer + uint32_t cbOut = 0; + + if (cipherText.size() > 0) + { + self->m_pCryptoProvider->Decrypt(&cipherText[0], + static_cast(cipherText.size()), + startingBlockNumber, isFinal, + buffer, static_cast(bSize), + &cbOut); + } + + return static_cast(cbOut); + }, selfPtr, pbBuffer, cbBuffer, cbOffset, u32StartingBlockNumber, + bIsFinal); +} + +shared_futureSimpleProtectedStream::WriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + return WriteInternalAsync(cpbBuffer, + cbBuffer, + cbOffset, + fCreateBackingThread, + 0, + false); +} + +shared_futureSimpleProtectedStream::WriteInternalAsync( + const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + uint32_t u32StartingBlockNumber, + bool bIsFinal) +{ + auto selfPtr = this->shared_from_this(); + + return std::async(fCreateBackingThread ? launch::async : launch::deferred, + [](shared_ptrself, + const uint8_t *buffer, + const int64_t bSize, + const int64_t offset, + uint32_t startingBlockNumber, + bool isFinal) -> int64_t + { + uint32_t cbOut = (uint32_t)(bSize); + vectorcipherText; + + // lock resources + unique_locklock(*self->m_locker); + + if (self->m_bIsPlainText) + { + cipherText = vector(buffer, buffer + bSize); + } + else + { + // get the encrypted size + auto encryptedSize = self->m_pCryptoProvider->GetCipherTextSize(bSize); + + cipherText.resize(encryptedSize); + + qDebug() << "writing block #" << startingBlockNumber; + + // encrypt the supplied buffer into cipherText + self->m_pCryptoProvider->Encrypt(buffer, static_cast(bSize), + startingBlockNumber, isFinal, + &cipherText[0], + static_cast(cipherText.size()), + &cbOut); + } + + // qDebug() << "encrypt to offset: " << offset << " size: " << + // cipherText.size(); + // write the cipherText to the buffer + int64_t u64Written = + self->m_pBackingStream->WriteAsync(&cipherText[0], + cbOut, + offset + self->m_u64ContentStart, + false).get(); + + // adjust the content size + self->m_u64ContentSize = + max(self->m_u64ContentSize, offset + static_cast(bSize)); + + return u64Written; + }, selfPtr, cpbBuffer, + cbBuffer, + cbOffset, + u32StartingBlockNumber, + bIsFinal); +} + +futureSimpleProtectedStream::FlushAsync(bool fCreateBackingThread) +{ + // lock resources + unique_lock lock(*m_locker); + + return m_pBackingStream->FlushAsync(fCreateBackingThread); +} + +int64_t SimpleProtectedStream::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) { + return ReadAsync(pbBuffer, cbBuffer, Position(), false).get(); +} + +int64_t SimpleProtectedStream::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) { + return WriteAsync(cpbBuffer, cbBuffer, Position(), false).get(); +} + +bool SimpleProtectedStream::Flush() { + return FlushAsync(false).get(); +} + +void SimpleProtectedStream::Seek(uint64_t u64Position) +{ + // lock resources + unique_lock lock(*m_locker); + + return SeekInternal(u64Position); +} + +void SimpleProtectedStream::SeekInternal(uint64_t u64Position) +{ + m_pBackingStream->Seek(m_u64ContentStart + u64Position); +} + +shared_ptrSimpleProtectedStream::Clone() +{ + // lock resources + unique_lock lock(*m_locker); + + return static_pointer_cast(shared_ptr( + new SimpleProtectedStream( + m_pCryptoProvider, + m_pBackingStream + ->Clone(), + m_u64ContentStart, + m_u64ContentSize))); +} + +bool SimpleProtectedStream::CanRead() +{ + // lock resources + unique_lock lock(*m_locker); + + return m_pBackingStream->CanRead(); +} + +bool SimpleProtectedStream::CanWrite() +{ + // lock resources + unique_lock lock(*m_locker); + + return m_pBackingStream->CanWrite(); +} + +uint64_t SimpleProtectedStream::Position() +{ + // lock resources + unique_lock lock(*m_locker); + + return m_pBackingStream->Position() - m_u64ContentStart; +} + +uint64_t SimpleProtectedStream::Size() +{ + // lock resources + unique_lock lock(*m_locker); + + return SizeInternal(); +} + +uint64_t SimpleProtectedStream::SizeInternal() +{ + return m_u64ContentSize; +} + +void SimpleProtectedStream::Size(uint64_t u64Value) +{ + // lock resources + unique_lock lock(*m_locker); + + if (m_u64ContentSize > u64Value) + { + m_u64ContentSize = u64Value; + m_pBackingStream->Size(m_u64ContentStart + m_u64ContentSize); + } + else if (m_u64ContentSize < u64Value) + { + AppendZeros(u64Value - m_u64ContentSize); + } +} + +void SimpleProtectedStream::AppendZeros(uint64_t u64Count) +{ + vector zeros(4096, static_cast(0)); + + uint64_t u64OriginalPosition = Position(); + try + { + SeekInternal(m_u64ContentSize); + + while (u64Count > 0) + { + uint64_t u64Written = + WriteInternalAsync(&zeros[0], + min(zeros.size(), u64Count), + Position(), + false, + 0, + false).get(); + + if (0 == u64Written) + { + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoException::UnknownError, + "Write error"); + } + + u64Count -= u64Written; + } + } + catch (exceptions::RMSCryptoException) + { + Seek(u64OriginalPosition); + throw; + } + Seek(u64OriginalPosition); +} + +SimpleProtectedStream::~SimpleProtectedStream() +{ + // NOT SURE (need detach) +} +} // namespace api +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.h new file mode 100644 index 00000000..d32dd874 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/SimpleProtectedStream.h @@ -0,0 +1,98 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_SIMPLEPROTECTEDSTREAM_H_ +#define _CRYPTO_STREAMS_LIB_SIMPLEPROTECTEDSTREAM_H_ + +#include "IStream.h" +#include "ICryptoProvider.h" + +namespace rmscrypto { +namespace api { +class SimpleProtectedStream : public IStream, + public std::enable_shared_from_this + { + friend class CachedBlock; + +public: + + SimpleProtectedStream(std::shared_ptrpCryptoProvider, + std::shared_ptr pBackingStream, + uint64_t u64ContentStart, + uint64_t u64ContentSize); + + // IStream implementation + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) + override; + virtual std::futureFlushAsync(bool fCreateBackingThread) + override; + + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + + virtual ~SimpleProtectedStream() override; + + std::shared_futureReadInternalAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + uint32_t u32StartingBlockNumber, + bool bIsFinal); + std::shared_futureWriteInternalAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread, + uint32_t u32StartingBlockNumber, + bool bIsFinal); + +private: + + uint64_t SizeInternal(); + void SeekInternal(uint64_t u64Position); + + SimpleProtectedStream(const SimpleProtectedStream&) = delete; + SimpleProtectedStream& operator=(const SimpleProtectedStream&) = delete; + +private: + + void AppendZeros(uint64_t u64Count); + +private: + + std::shared_ptr m_locker; + + std::shared_ptr m_pCryptoProvider; + std::shared_ptr m_pBackingStream; + + uint64_t m_u64ContentStart; + uint64_t m_u64ContentSize; + bool m_bIsPlainText; +}; +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_SIMPLEPROTECTEDSTREAM_H_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.cpp b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.cpp new file mode 100644 index 00000000..593a018a --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.cpp @@ -0,0 +1,248 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "StdStreamAdapter.h" +#include "RMSCryptoExceptions.h" + +using namespace std; +namespace rmscrypto { +namespace api { +StdStreamAdapter::StdStreamAdapter(shared_ptrbackingIOStream) + : m_locker(new mutex) + , m_iBackingStream(static_pointer_cast(backingIOStream)) + , m_oBackingStream(static_pointer_cast(backingIOStream)) +{} + +StdStreamAdapter::StdStreamAdapter(shared_ptrbackingOStream) + : m_locker(new mutex) + , m_oBackingStream(backingOStream) +{} + +StdStreamAdapter::StdStreamAdapter(shared_ptrbackingIStream) + : m_locker(new mutex) + , m_iBackingStream(backingIStream) +{} + +// copy all properties include mutex to support thread safety work! +StdStreamAdapter::StdStreamAdapter(std::shared_ptrfrom) + : m_locker(from->m_locker) + , m_iBackingStream(from->m_iBackingStream) + , m_oBackingStream(from->m_oBackingStream) +{} + +shared_futureStdStreamAdapter::ReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + auto selfPtr = shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, []( + shared_ptrself, + uint8_t *buffer, + const int64_t size, + int64_t offset) -> int64_t { + // first lock object + self->m_locker->lock(); + + if (self->m_iBackingStream.get() != nullptr) { + self->m_iBackingStream->seekg(offset); + } else { + self->m_locker->unlock(); + + // unavailable + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoIOException::OperationUnavailable, + "Operation unavailable!"); + } + auto ret = static_cast(self->ReadInternal(buffer, size)); + self->m_locker->unlock(); + + return ret; + }, selfPtr, pbBuffer, cbBuffer, cbOffset); +} + +shared_futureStdStreamAdapter::WriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) +{ + auto selfPtr = shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, []( + shared_ptrself, + const uint8_t *buffer, + const int64_t size, + int64_t offset) -> int64_t { + // first lock object + self->m_locker->lock(); + + // seek to position and write + if (self->m_oBackingStream.get() != nullptr) { + self->m_oBackingStream->seekp(offset); + } else { + self->m_locker->unlock(); + + // unavailable + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoIOException::OperationUnavailable, + "Operation unavailable!"); + } + int64_t ret = 0; + + try { + ret = static_cast(self->WriteInternal(buffer, size)); + } + catch (exception& e) { + self->m_locker->unlock(); + throw e; + } + self->m_locker->unlock(); + + return ret; + }, selfPtr, cpbBuffer, cbBuffer, cbOffset); +} + +futureStdStreamAdapter::FlushAsync(bool fCreateBackingThread) { + auto selfPtr = shared_from_this(); + + return async(fCreateBackingThread ? launch::async : launch::deferred, []( + shared_ptrself) -> bool { + return self->Flush(); + }, selfPtr); +} + +// Sync methods +int64_t StdStreamAdapter::Read(uint8_t *pbBuffer, + const int64_t cbBuffer) { + if (m_iBackingStream.get() == nullptr) { + // unavailable + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoIOException::OperationUnavailable, + "Operation unavailable!"); + } + + lock_guard locker(*m_locker); + return ReadInternal(pbBuffer, cbBuffer); +} + +int64_t StdStreamAdapter::ReadInternal(uint8_t *pbBuffer, + const int64_t cbBuffer) { + m_iBackingStream->read(reinterpret_cast(pbBuffer), cbBuffer); + return m_iBackingStream->gcount(); +} + +int64_t StdStreamAdapter::Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) { + if (m_oBackingStream.get() == nullptr) { + // unavailable + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoIOException::OperationUnavailable, + "Operation unavailable!"); + } + m_locker->lock(); + try { + WriteInternal(cpbBuffer, cbBuffer); + } + catch (exception& e) { + m_locker->unlock(); + throw e; + } + m_locker->unlock(); + + return cbBuffer; +} + +int64_t StdStreamAdapter::WriteInternal(const uint8_t *cpbBuffer, + const int64_t cbBuffer) { + assert(cpbBuffer != nullptr || cbBuffer == 0); + + m_oBackingStream->write(reinterpret_cast(cpbBuffer), cbBuffer); + + return cbBuffer; +} + +bool StdStreamAdapter::Flush() { + // first lock object + lock_guard lock(*m_locker); + + // seek to position and write + if (m_oBackingStream.get() != nullptr) { + m_oBackingStream->flush(); + } + return true; +} + +SharedStream StdStreamAdapter::Clone() { + lock_guard locker(*m_locker); + return static_pointer_cast(shared_ptr(new + StdStreamAdapter( + shared_from_this()))); +} + +void StdStreamAdapter::Seek(uint64_t u64Position) { + // first lock object + lock_guard lock(*m_locker); + + if (m_iBackingStream.get() != nullptr) { + m_iBackingStream->seekg(u64Position); + } + + if (m_oBackingStream.get() != nullptr) { + m_oBackingStream->seekp(u64Position); + } +} + +bool StdStreamAdapter::CanRead() { + return m_iBackingStream.get() != nullptr; +} + +bool StdStreamAdapter::CanWrite() { + return m_oBackingStream.get() != nullptr; +} + +uint64_t StdStreamAdapter::Position() { + int ret = 0; + + lock_guard locker(*m_locker); + + if (m_iBackingStream.get() != nullptr) { + ret = static_cast(m_iBackingStream->tellg()); + } + + if (m_oBackingStream.get() != nullptr) { + ret = static_cast(m_oBackingStream->tellp()); + } + return static_cast(ret); +} + +uint64_t StdStreamAdapter::Size() { + int ret = 0; + + lock_guard locker(*m_locker); + + if (m_iBackingStream.get() != nullptr) { + auto oldPos = m_iBackingStream->tellg(); + m_iBackingStream->seekg(0, ios_base::end); + ret = static_cast(m_iBackingStream->tellg()); + m_iBackingStream->seekg(oldPos); + } + + if (m_oBackingStream.get() != nullptr) { + auto oldPos = m_oBackingStream->tellp(); + m_oBackingStream->seekp(0, ios_base::end); + ret = static_cast(m_oBackingStream->tellp()); + m_oBackingStream->seekp(oldPos); + } + return static_cast(ret); +} + +void StdStreamAdapter::Size(uint64_t /*u64Value*/) {} +} // namespace api +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.h b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.h new file mode 100644 index 00000000..7de71057 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI/StdStreamAdapter.h @@ -0,0 +1,66 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_STDSTREAMADAPTER_H +#define _CRYPTO_STREAMS_LIB_STDSTREAMADAPTER_H + +#include +#include "IStream.h" + +namespace rmscrypto { +namespace api { +class StdStreamAdapter : public IStream, + public std::enable_shared_from_this +{ +public: + StdStreamAdapter(std::shared_ptr backingIOStream); + StdStreamAdapter(std::shared_ptr backingOStream); + StdStreamAdapter(std::shared_ptr backingIStream); + + virtual std::shared_futureReadAsync(uint8_t *pbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) override; + virtual std::shared_futureWriteAsync(const uint8_t *cpbBuffer, + const int64_t cbBuffer, + const int64_t cbOffset, + bool fCreateBackingThread) override; + virtual std::future FlushAsync(bool fCreateBackingThread) override; + + // Sync methods + virtual int64_t Read(uint8_t *pbBuffer, + const int64_t cbBuffer) override; + virtual int64_t Write(const uint8_t *cpbBuffer, + const int64_t cbBuffer) override; + virtual bool Flush() override; + + virtual SharedStream Clone() override; + + virtual void Seek(uint64_t u64Position) override; + virtual bool CanRead() override; + virtual bool CanWrite() override; + virtual uint64_t Position() override; + virtual uint64_t Size() override; + virtual void Size(uint64_t u64Value) override; + +private: + StdStreamAdapter(std::shared_ptr from); + + std::shared_ptr m_locker; + std::shared_ptr m_iBackingStream; + std::shared_ptr m_oBackingStream; + + int64_t ReadInternal(uint8_t *pbBuffer, + const int64_t cbBuffer); + int64_t WriteInternal(const uint8_t *cpbBuffer, + const int64_t cbBuffer); +}; + +} // namespace api +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_STDSTREAMADAPTER_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/CryptoStreams.pro b/sdk/rmscrypto_sdk/CryptoStreams/CryptoStreams.pro new file mode 100644 index 00000000..2578ef8d --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/CryptoStreams.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs + +DEFINES += QTFRAMEWORK + +SUBDIRS += \ + Crypto \ + CryptoAPI \ + Platform + +CryptoAPI.depends = Crypto +Crypto.depends = Platform diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.cpp new file mode 100644 index 00000000..5e1c0601 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.cpp @@ -0,0 +1,141 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "AESCryptoKey.h" +#include "../../CryptoAPI/RMSCryptoExceptions.h" + +using namespace std; + +namespace rmscrypto { +namespace platform { +namespace crypto { +AESCryptoKey::AESCryptoKey(const uint8_t *pbKey, uint32_t cbKey, + api::CryptoAlgorithm& algorithm) + : m_key(cbKey), m_algorithm(algorithm) +{ + if (cbKey == 0) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid key length"); + } + memcpy(&m_key[0], pbKey, cbKey); +} + +AESCryptoKey::~AESCryptoKey() {} + +void AESCryptoKey::Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) +{ + TransformBlock(true, pbIn, cbIn, pbOut, cbOut, pbIv, cbIv); +} + +void AESCryptoKey::Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) +{ + TransformBlock(false, pbIn, cbIn, pbOut, cbOut, pbIv, cbIv); +} + +void AESCryptoKey::TransformBlock(bool encrypt, + const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) +{ + if (pbIn == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbIn exception"); + } + + if (pbOut == nullptr) { + throw exceptions::RMSCryptoNullPointerException("Null pointer pbOut exception"); + } + + if (((cbIv == 0) && (pbIv != nullptr)) || ((cbIv != 0) && (pbIv == nullptr))) { + pbIv = nullptr; + cbIv = 0; + } + + int totalOut = static_cast(cbOut); + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + const EVP_CIPHER *cipher = nullptr; + + switch (m_algorithm) { + case api::CRYPTO_ALGORITHM_AES_ECB: + cipher = EVP_aes_128_ecb(); + break; + + case api::CRYPTO_ALGORITHM_AES_CBC: + case api::CRYPTO_ALGORITHM_AES_CBC_PKCS7: + cipher = EVP_aes_128_cbc(); + break; + + default: + throw exceptions::RMSCryptoInvalidArgumentException("Unsupported algorithm"); + } + + // check lengths + if ((pbIv != nullptr) && + (EVP_CIPHER_iv_length(cipher) != static_cast(cbIv))) { + throw exceptions::RMSCryptoInvalidArgumentException( + "Invalid initial vector length"); + } + + if (EVP_CIPHER_key_length(cipher) != static_cast(m_key.size())) { + throw exceptions::RMSCryptoInvalidArgumentException("Invalid key length"); + } + + EVP_CipherInit_ex(&ctx, cipher, NULL, m_key.data(), pbIv, encrypt ? 1 : 0); + + if (m_algorithm == api::CRYPTO_ALGORITHM_AES_CBC_PKCS7) { + EVP_CIPHER_CTX_set_padding(&ctx, 1); + } else { + EVP_CIPHER_CTX_set_padding(&ctx, 0); + } + + if (!EVP_CipherUpdate(&ctx, pbOut, &totalOut, pbIn, static_cast(cbIn))) { + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoException::UnknownError, + "Failed to transform data"); + } + + pbOut += totalOut; + + // add padding if necessary + if (m_algorithm == api::CRYPTO_ALGORITHM_AES_CBC_PKCS7) { + int remain = cbOut - totalOut; + + if (remain < EVP_CIPHER_block_size(cipher)) { + throw exceptions::RMSCryptoInsufficientBufferException( + "No enough buffer size"); + } + + if (!EVP_CipherFinal_ex(&ctx, pbOut, &remain)) { + throw exceptions::RMSCryptoIOException( + exceptions::RMSCryptoException::UnknownError, + "Failed to transform final block"); + } + totalOut += remain; + } + + EVP_CIPHER_CTX_cleanup(&ctx); + + // remember total size + cbOut = static_cast(totalOut); +} +} // namespace crypto +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.h new file mode 100644 index 00000000..996bd1d5 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/AESCryptoKey.h @@ -0,0 +1,58 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CRYPTOKEY_ +#define _CRYPTO_STREAMS_LIB_CRYPTOKEY_ +#include +#include +#include + +#include "../../CryptoAPI/ICryptoKey.h" +#include "../../CryptoAPI/ICryptoEngine.h" +namespace rmscrypto { +namespace platform { +namespace crypto { +class AESCryptoKey : public api::ICryptoKey { +public: + + AESCryptoKey(const uint8_t *pbKey, + uint32_t cbKey, + api::CryptoAlgorithm& algorithm); + ~AESCryptoKey(); + + virtual void Encrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) override; + virtual void Decrypt(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv) override; + +private: + + void TransformBlock(bool encrypt, + const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut, + const uint8_t *pbIv, + uint32_t cbIv); + + + std::vector m_key; + api::CryptoAlgorithm m_algorithm; +}; +} // namespace crypto +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CRYPTOKEY_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/Crypto.pro b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/Crypto.pro new file mode 100644 index 00000000..f24285da --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/Crypto.pro @@ -0,0 +1,27 @@ +REPO_ROOT = $$PWD/../../../../.. +DESTDIR = $$REPO_ROOT/bin/crypto/platform +TARGET = platformcrypto + +TEMPLATE = lib + +DEFINES += QTFRAMEWORK + +CONFIG += staticlib warn_on c++11 debug_and_release + +QT += core +QT -= gui + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} + +win32:INCLUDEPATH += $$REPO_ROOT/third_party/include + +HEADERS += CryptoEngine.h \ + CryptoHash.h \ + AESCryptoKey.h + +SOURCES += \ + CryptoEngine.cpp \ + CryptoHash.cpp \ + AESCryptoKey.cpp diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.cpp new file mode 100644 index 00000000..7cb44f62 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.cpp @@ -0,0 +1,62 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include +#include "CryptoEngine.h" +#include "../../CryptoAPI/RMSCryptoExceptions.h" +using namespace std; + +namespace rmscrypto { +namespace api { +shared_ptrICryptoEngine::Create() { + return make_shared(); +} +} +namespace platform { +namespace crypto { +static QCryptographicHash::Algorithm MapHashAlgorithm( + api::CryptoHashAlgorithm algorithm) +{ + switch (algorithm) + { + case api::CRYPTO_HASH_ALGORITHM_SHA1: + return QCryptographicHash::Sha1; + + case api::CRYPTO_HASH_ALGORITHM_SHA256: + return QCryptographicHash::Sha256; + + default: + throw exceptions::RMSCryptoInvalidArgumentException("Invalid algorithm"); + } +} + +shared_ptrCryptoEngine::CreateKey(const uint8_t *pbKey, + uint32_t cbKey, + api::CryptoAlgorithm algorithm) +{ + if ((algorithm == api::CRYPTO_ALGORITHM_AES_ECB) || + (algorithm == api::CRYPTO_ALGORITHM_AES_CBC) || + (algorithm == api::CRYPTO_ALGORITHM_AES_CBC_PKCS7)) { + return make_shared(pbKey, cbKey, algorithm); + } + + // no algorithm + throw exceptions::RMSCryptoInvalidArgumentException("Invalid algorithm"); +} + +shared_ptrCryptoEngine::CreateHash( + api::CryptoHashAlgorithm algorithm) +{ + auto hash = make_shared(MapHashAlgorithm(algorithm)); + + return make_shared(hash, algorithm); +} +} // namespace crypto +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.h new file mode 100644 index 00000000..8dcfaf3e --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoEngine.h @@ -0,0 +1,31 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CRYPTOENGINE_ +#define _CRYPTO_STREAMS_LIB_CRYPTOENGINE_ + +#include "../../CryptoAPI/ICryptoEngine.h" +#include "AESCryptoKey.h" +#include "CryptoHash.h" +namespace rmscrypto { +namespace platform { +namespace crypto { +class CryptoEngine : public api::ICryptoEngine { +public: + + virtual std::shared_ptrCreateKey(const uint8_t *pbKey, + uint32_t cbKey, + api::CryptoAlgorithm algorithm) + override; + virtual std::shared_ptrCreateHash(api::CryptoHashAlgorithm algorithm) + override; +}; +} // namespace crypto +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CRYPTOENGINE_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.cpp new file mode 100644 index 00000000..48ba9f3e --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.cpp @@ -0,0 +1,65 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "CryptoHash.h" +#include "../../CryptoAPI/RMSCryptoExceptions.h" +using namespace std; + +namespace rmscrypto { +namespace platform { +namespace crypto { +CryptoHash::CryptoHash(std::shared_ptr hash, + api::CryptoHashAlgorithm algorithm) + : m_hash(hash) + , m_algorithm(algorithm) +{} + +size_t CryptoHash::GetOutputSize() +{ + switch (m_algorithm) + { + case api::CRYPTO_HASH_ALGORITHM_SHA1: + return 20; + + case api::CRYPTO_HASH_ALGORITHM_SHA256: + return 32; + + default: + throw exceptions::RMSCryptoInvalidArgumentException("Invalid algorithm"); + } +} + +void CryptoHash::Hash(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut) +{ + m_hash->addData(reinterpret_cast(pbIn), cbIn); + + // get the hash valuew + auto valueBuffer = m_hash->result(); + m_hash->reset(); + + // check that the output buffer is big enough + if (static_cast(cbOut) < valueBuffer.length()) { + throw exceptions::RMSCryptoInvalidArgumentException("Bounds error"); + } + + // set the output size + cbOut = valueBuffer.length(); + + // copy +#ifdef Q_OS_WIN32 + memcpy_s(pbOut, cbOut, valueBuffer.data(), valueBuffer.size()); +#else + memcpy(pbOut, valueBuffer.data(), valueBuffer.size()); +#endif +} +} // namespace crypto +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.h new file mode 100644 index 00000000..2ef769d8 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Crypto/CryptoHash.h @@ -0,0 +1,37 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_CRYPTOHASH_ +#define _CRYPTO_STREAMS_LIB_CRYPTOHASH_ +#include +#include +#include "../../CryptoAPI/ICryptoHash.h" +namespace rmscrypto { +namespace platform { +namespace crypto { +class CryptoHash : public api::ICryptoHash { +public: + + CryptoHash(std::shared_ptrhash, + api::CryptoHashAlgorithm algorithm); + + virtual size_t GetOutputSize() override; + virtual void Hash(const uint8_t *pbIn, + uint32_t cbIn, + uint8_t *pbOut, + uint32_t & cbOut) override; + +private: + + std::shared_ptr m_hash; + api::CryptoHashAlgorithm m_algorithm; +}; +} // namespace crypto +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_CRYPTOHASH_ diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.cpp new file mode 100644 index 00000000..6e7e720d --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.cpp @@ -0,0 +1,33 @@ +#include "IKeyStorage.h" +#include + +#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) +#include "KeyStoragePosix.h" +namespace rmscrypto { namespace platform { namespace keystorage { +std::shared_ptrIKeyStorage::Create() { + return std::shared_ptr(new KeyStoragePosix); +} +}}} +#elif defined(Q_OS_WIN32) || defined(Q_OS_WIN64) +#include "KeyStorageWindows.h" +namespace rmscrypto { namespace platform { namespace keystorage { +std::shared_ptrIKeyStorage::Create() { + throw std::logic_error("not implemented"); + return std::shared_ptr(new KeyStorageWindows); +} +}}} +#elif defined(Q_OS_OSX) +#include "KeyStorageOSX.h" +namespace rmscrypto { namespace platform { namespace keystorage { +std::shared_ptrIKeyStorage::Create() { + throw std::logic_error("not implemented"); + return std::shared_ptr(new KeyStorageOSX); +} +}}} +#else +namespace rmscrypto { namespace platform { namespace keystorage { +std::shared_ptrIKeyStorage::Create() { + throw std::logic_error("Unexpected OS"); +} +}}} +#endif diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.h new file mode 100644 index 00000000..52272dff --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/IKeyStorage.h @@ -0,0 +1,33 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_IKEYSTORAGE_H +#define _CRYPTO_STREAMS_LIB_IKEYSTORAGE_H + +#include +#include + +namespace rmscrypto { +namespace platform { +namespace keystorage { +class IKeyStorage { +public: + + virtual void RemoveKey(const std::string& csKeyWrapper) = 0; + virtual void StoreKey(const std::string& csKeyWrapper, + const std::string& csKey) = 0; + virtual std::shared_ptrLookupKey(const std::string& csKeyWrapper) = 0; + + static std::shared_ptr Create(); + + virtual ~IKeyStorage() {} +}; +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_IKEYSTORAGE_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorage.pro b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorage.pro new file mode 100644 index 00000000..fbb31f99 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorage.pro @@ -0,0 +1,44 @@ +REPO_ROOT = $$PWD/../../../../.. +DESTDIR = $$REPO_ROOT/bin/crypto/platform +TARGET = platformkeystorage + +QT -= gui + +TEMPLATE = lib +CONFIG += staticlib warn_on c++11 debug_and_release +QT += core + +unix:!mac:INCLUDEPATH += /usr/include/glib-2.0/ /usr/include/libsecret-1/ /usr/lib/x86_64-linux-gnu/glib-2.0/include/ +# win32:INCLUDEPATH += DPAPI +# mac:INCLUDEPATH += osxkeychain + +LIBS += -L$$DESTDIR -L$$DESTDIR/Platform/ + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) +} +unix { + target.path = /usr/lib + INSTALLS += target +} + +HEADERS += \ + base64.h \ + IKeyStorage.h + +SOURCES += \ + base64.cpp \ + IKeyStorage.cpp + +#include different versions of keystorage +win32 { + HEADERS += KeyStorageWindows.h + SOURCES += KeyStorageWindows.cpp +} unix:!mac { + HEADERS += KeyStoragePosix.h + SOURCES += KeyStoragePosix.cpp +} mac { + HEADERS += KeyStorageOSX.h + SOURCES += KeyStorageOSX.cpp +} + diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.cpp new file mode 100644 index 00000000..308e9f7a --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.cpp @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "KeyStorageOSX.h" + +using namespace std; +namespace rmscrypto { +namespace platform { +namespace keystorage { +void KeyStorageOSX::RemoveKey(const string& /*csKeyWrapper*/) { +} + +void KeyStorageOSX::StoreKey(const string& /*csKeyWrapper*/, const string& /*csKey*/) { +} + +shared_ptr KeyStorageOSX::LookupKey(const string& /*csKeyWrapper*/) { + shared_ptr res = nullptr; + return res; +} + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.h new file mode 100644 index 00000000..cc977edc --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageOSX.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_KEYSTORAGE_H +#define _CRYPTO_STREAMS_LIB_KEYSTORAGE_H + +#include +#include +#include "IKeyStorage.h" + +namespace rmscrypto { +namespace platform { +namespace keystorage { + +class KeyStorageOSX : public IKeyStorage +{ +public: + virtual void RemoveKey(const std::string& csKeyWrapper) override; + virtual void StoreKey(const std::string& csKeyWrapper, + const std::string& csKey) override; + virtual std::shared_ptrLookupKey(const std::string& csKeyWrapper) override; + + KeyStorageOSX() {} +}; + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_KEYSTORAGE_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.cpp new file mode 100644 index 00000000..c73e3b64 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.cpp @@ -0,0 +1,98 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "KeyStoragePosix.h" +#include "../../CryptoAPI/RMSCryptoExceptions.h" + +using namespace std; +namespace rmscrypto { +namespace platform { +namespace keystorage { +const SecretSchema* str_key_schema(void) { + static const SecretSchema the_schema = { + "microsoft.Password", SECRET_SCHEMA_NONE, + { + { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "NULL", static_cast(0) }, + }, 0,0, 0, 0, 0, 0, 0, 0, + }; + + return &the_schema; +} + +#define KEY_SCHEMA str_key_schema() + +void ProcessError(GError *error) { + string msg(reinterpret_cast(error->message)); + int code = error->code; + + g_error_free(error); + throw exceptions::RMSCryptoIOKeyException(msg.c_str(), code); +} + +void KeyStoragePosix::RemoveKey(const string& csKeyWrapper) { + GError *error = NULL; + + /* + * The variable argument list is the attributes used to later + * lookup the password. These attributes must conform to the schema. + */ + gboolean removed = secret_password_clear_sync(KEY_SCHEMA, NULL, &error, + "string", csKeyWrapper.c_str(), + NULL); + + if (!removed && (error != NULL)) { + ProcessError(error); + } +} + +void KeyStoragePosix::StoreKey(const string& csKeyWrapper, const string& csKey) { + GError *error = NULL; + + /* + * The variable argument list is the attributes used to later + * lookup the password. These attributes must conform to the schema. + */ + gboolean stored = secret_password_store_sync(KEY_SCHEMA, + SECRET_COLLECTION_DEFAULT, + "Microsoft RMSCryptoSDK", + csKey.c_str(), + NULL, + &error, + "string", + csKeyWrapper.c_str(), + NULL); + + if (!stored && (error != NULL)) { + ProcessError(error); + } +} + +shared_ptrKeyStoragePosix::LookupKey(const string& csKeyWrapper) { + GError *error = NULL; + + shared_ptr res = nullptr; + + /* The attributes used to lookup the password should conform to the schema. */ + gchar *password = secret_password_lookup_sync(KEY_SCHEMA, NULL, &error, + "string", csKeyWrapper.c_str(), + NULL); + + if (error != NULL) { + ProcessError(error); + } else if (password != NULL) { + res = make_shared(reinterpret_cast(password)); + secret_password_free(password); + } + return res; +} + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.h new file mode 100644 index 00000000..0379034c --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStoragePosix.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_KEYSTORAGE_H +#define _CRYPTO_STREAMS_LIB_KEYSTORAGE_H + +#include +#include +#include "IKeyStorage.h" + +namespace rmscrypto { +namespace platform { +namespace keystorage { + +class KeyStoragePosix : public IKeyStorage +{ +public: + virtual void RemoveKey(const std::string& csKeyWrapper) override; + virtual void StoreKey(const std::string& csKeyWrapper, + const std::string& csKey) override; + virtual std::shared_ptrLookupKey(const std::string& csKeyWrapper) override; + + KeyStoragePosix() {} +}; + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_KEYSTORAGE_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.cpp new file mode 100644 index 00000000..5189a166 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.cpp @@ -0,0 +1,28 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include "KeyStorageWindows.h" + +using namespace std; +namespace rmscrypto { +namespace platform { +namespace keystorage { +void KeyStorageWindows::RemoveKey(const string& /*csKeyWrapper*/) { +} + +void KeyStorageWindows::StoreKey(const string& /*csKeyWrapper*/, const string& /*csKey*/) { +} + +shared_ptrKeyStorageWindows::LookupKey(const string& /*csKeyWrapper*/) { + shared_ptr res = nullptr; + return res; +} + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.h new file mode 100644 index 00000000..6d11e206 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/KeyStorageWindows.h @@ -0,0 +1,34 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_KEYSTORAGE_H +#define _CRYPTO_STREAMS_LIB_KEYSTORAGE_H + +#include +#include +#include "IKeyStorage.h" + +namespace rmscrypto { +namespace platform { +namespace keystorage { + +class KeyStorageWindows : public IKeyStorage +{ +public: + virtual void RemoveKey(const std::string& csKeyWrapper) override; + virtual void StoreKey(const std::string& csKeyWrapper, + const std::string& csKey) override; + virtual std::shared_ptrLookupKey(const std::string& csKeyWrapper) override; + + KeyStorageWindows() {} +}; + +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto +#endif // _CRYPTO_STREAMS_LIB_KEYSTORAGE_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.cpp b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.cpp new file mode 100644 index 00000000..e8cc85ff --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.cpp @@ -0,0 +1,130 @@ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + + */ + +#include "base64.h" +#include + +namespace rmscrypto { +namespace platform { +namespace keystorage { +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return isalnum(c) || (c == '+') || (c == '/'); +} + +std::string base64_encode(unsigned char const *bytes_to_encode, + unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for (j = i; j < 3; j++) char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; + + while ((i++ < 3)) ret += '='; + } + + return ret; +} + +std::string base64_decode(std::string const& encoded_string) { + int in_len = static_cast(encoded_string.size()); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && (encoded_string[in_] != '=') && + is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + + if (i == 4) { + for (i = 0; i < 4; + i++) char_array_4[i] = static_cast(base64_chars.find(char_array_4[i])); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) char_array_4[j] = 0; + + for (j = 0; j < 4; j++) char_array_4[j] = static_cast(base64_chars.find(char_array_4[j])); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.h b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.h new file mode 100644 index 00000000..33f5a3af --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/KeyStorage/base64.h @@ -0,0 +1,22 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _CRYPTO_STREAMS_LIB_BASE64_H +#define _CRYPTO_STREAMS_LIB_BASE64_H +#include + +namespace rmscrypto { +namespace platform { +namespace keystorage { +std::string base64_encode(unsigned char const *, + unsigned int len); +std::string base64_decode(std::string const& s); +} // namespace keystorage +} // namespace platform +} // namespace rmscrypto +#endif // ifndef _CRYPTO_STREAMS_LIB_BASE64_H diff --git a/sdk/rmscrypto_sdk/CryptoStreams/Platform/Platform.pro b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Platform.pro new file mode 100644 index 00000000..6a4d8941 --- /dev/null +++ b/sdk/rmscrypto_sdk/CryptoStreams/Platform/Platform.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +DEFINES += QTFRAMEWORK + +SUBDIRS += \ + Crypto \ + KeyStorage diff --git a/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.cpp b/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.cpp new file mode 100644 index 00000000..7ee4350f --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.cpp @@ -0,0 +1,67 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "CryptedStreamTests.h" +#include "../CryptoStreams/CryptoAPI/CryptoAPI.h" +using namespace std; +void CryptedStreamTests::CryptedStreamToMemory_data() { + QTest::addColumn("aesKey"); + QTest::addColumn("plainData"); + QTest::addColumn("iv"); + QTest::addColumn("encryptedData"); + QTest::addColumn("algorithm"); + + QTest::newRow("AES_CBC4K") << "7bddca3c7ff9bdc8eea7a8eb63d01f11" << "Plain Text" << "00000000000000000000000000000000" + << "ea21b48f530be23b6d654db9302dd1ff" << static_cast(rmscrypto::api::CIPHER_MODE_CBC4K); +} + +void CryptedStreamTests::CryptedStreamToMemory() { + shared_ptr backingBuffer = make_shared(ios::in | ios::out | ios::binary); + vector key(16); + + QFETCH(QString, aesKey); + QFETCH(QString, plainData); + QFETCH(QString, iv); + QFETCH(QString, encryptedData); + QFETCH(qint8, algorithm); + + try { + + QByteArray qKey = QByteArray::fromHex(aesKey.toUtf8()); + QByteArray qData(plainData.toUtf8()); + QByteArray qIV = QByteArray::fromHex(iv.toUtf8()); + QByteArray qEncryptedData = QByteArray::fromHex(encryptedData.toUtf8()); + rmscrypto::api::CipherMode algo = static_cast(algorithm); + + memcpy(key.data(), qKey.data(), key.size()); + + auto backingStream = rmscrypto::api::CreateStreamFromStdStream(static_pointer_cast(backingBuffer)); + + auto cryptoStream = rmscrypto::api::CreateCryptoStream(algo, key, backingStream); + + cryptoStream->Write(reinterpret_cast(qData.data()), qData.size()); + cryptoStream->Flush(); + + auto res = backingBuffer->str(); + QVERIFY2(static_cast(res.length()) == qEncryptedData.size(), "Invalid encrypted size!"); + QVERIFY2(memcmp(res.data(), qEncryptedData.data(), res.length()) == 0, + "Invalid encrypted data!"); + + cryptoStream->Seek(0); + QByteArray dst(qData.size(), 0); + auto read = cryptoStream->Read(reinterpret_cast(dst.data()), dst.size()); + QVERIFY2(read == dst.size(), "Invalid decrypted size!"); + QVERIFY2(memcmp(dst.data(),qData.data(), dst.size())==0, "Invalid decrypted data!"); + + } catch(const std::exception& e) { + qDebug() << "Exeption: " << e.what(); + } + + +} diff --git a/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.h b/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.h new file mode 100644 index 00000000..e3a4638c --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/CryptedStreamTests.h @@ -0,0 +1,24 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CRYPTEDSTREAMTESTS_H +#define CRYPTEDSTREAMTESTS_H +#include + + +class CryptedStreamTests : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void CryptedStreamToMemory_data(); + void CryptedStreamToMemory(); +}; + +#endif // CRYPTEDSTREAMTESTS_H diff --git a/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.cpp b/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.cpp new file mode 100644 index 00000000..809c93e2 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.cpp @@ -0,0 +1,52 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../CryptoAPI/CryptoAPI.h" +#include "CryptoAPITests.h" + +using namespace std; + +void CryptoAPITests::EncryptDecryptBlockTest_data() { + QTest::addColumn("keyWrapper"); + QTest::addColumn("testData"); + + QTest::newRow("0") << "TestWrapperOne" << "Source String One"; + QTest::newRow("1") << "TestWrapperTwo" << + "To sorry world an at do spoil along. Incommode he depending do frankness remainder to."; +} + +void CryptoAPITests::EncryptDecryptBlockTest() { +QFETCH(QString, keyWrapper); +QFETCH(QString, testData); + try { + auto testDataStr = testData.toStdString(); + auto dataIn = + std::make_shared >(testDataStr.length()); + memcpy(dataIn->data(), testDataStr.data(), dataIn->size()); + + + auto encData = rmscrypto::api::EncryptWithAutoKey(dataIn, + rmscrypto::api::CIPHER_MODE_CBC4K, + keyWrapper.toStdString()); + QVERIFY2(encData.get() != nullptr && + encData->size() != 0, "Failed to encrypt data!"); + + auto decData = rmscrypto::api::DecryptWithAutoKey(encData, + rmscrypto::api::CIPHER_MODE_CBC4K, + keyWrapper.toStdString()); + + QVERIFY2(decData.get() != nullptr && + decData->size() == dataIn->size(), "Failed to decrypt data!"); + + QVERIFY2(memcmp(decData->data(), dataIn->data(), + dataIn->size()) == 0, "Failed to decrypt data!"); + } catch(const std::exception& e) { + qDebug() << "Exeption: " << e.what(); + } +} diff --git a/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.h b/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.h new file mode 100644 index 00000000..99c1dbb1 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/CryptoAPITests.h @@ -0,0 +1,25 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef CRYPTOAPITEST +#define CRYPTOAPITEST + +#include + +class CryptoAPITests : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void EncryptDecryptBlockTest_data(); + void EncryptDecryptBlockTest(); +}; + +#endif // CRYPTOAPITEST + diff --git a/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.cpp b/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.cpp new file mode 100644 index 00000000..cef991e6 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.cpp @@ -0,0 +1,57 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "../CryptoStreams/Platform/KeyStorage/IKeyStorage.h" +#include "KeyStorageTests.h" + +using namespace std; + +void KeyStorageTests::KeyUsage_data() +{ + QTest::addColumn("keyWrapper"); + QTest::addColumn("key"); + + QTest::newRow("0") << "TestWrapperOne" << "TestKeyOne"; + QTest::newRow("1") << "TestWrapperTwo" << "TestKeyTwo"; +} + +void KeyStorageTests::KeyUsage() +{ + QFETCH(QString, keyWrapper); + QFETCH(QString, key); + + try { + + auto ks = rmscrypto::platform::keystorage::IKeyStorage::Create(); + + // remove old key data + ks->RemoveKey(keyWrapper.toStdString()); + + // store key + ks->StoreKey(keyWrapper.toStdString(), key.toStdString()); + + // find key + auto findKey = ks->LookupKey(keyWrapper.toStdString()); + + QVERIFY2(findKey.get() != nullptr && findKey->compare(key.toStdString()) == 0,"Invalid key found!"); + + // remove key data + ks->RemoveKey(keyWrapper.toStdString()); + + // find key + findKey = ks->LookupKey(keyWrapper.toStdString()); + + QVERIFY2(findKey.get() == nullptr,"Found removed key!"); + + + } catch(const std::exception& e) { + qDebug() << "Exeption: " << e.what(); + } + +} diff --git a/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.h b/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.h new file mode 100644 index 00000000..79c26d46 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/KeyStorageTests.h @@ -0,0 +1,22 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef COMMONTESTA_H +#define COMMONTESTA_H +#include + +class KeyStorageTests : public QObject { + Q_OBJECT + +private Q_SLOTS: + + void KeyUsage_data(); + void KeyUsage(); +}; + +#endif // COMMONTESTA_H diff --git a/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.cpp b/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.cpp new file mode 100644 index 00000000..8bf23785 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.cpp @@ -0,0 +1,327 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "TestHelpers.h" +#include "PlatformCryptoTest.h" + +using namespace rmscrypto::api; +namespace rmscore { +namespace test { + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-comparison" +#endif + +QString HashString(std::shared_ptr& hashProv, + const QString & inStr) { + std::vector res; + + res.resize(hashProv->GetOutputSize()); + uint32_t resSize = static_cast(res.size()); + auto strCopy = inStr.toStdString(); + + hashProv->Hash(reinterpret_cast(strCopy.data()), + static_cast(strCopy.size()), &res[0], resSize); + + // convert to hex + QByteArray arr( + reinterpret_cast(res.data()), static_cast(res.size())); + QString resStr(arr.toHex()); + + return resStr; +} + +QString TransformData(bool encrypt, + CryptoAlgorithm algo, + const QString & iv, + const QString & key, + const QString & inData) { + QByteArray keyArray = + QByteArray::fromHex(key.toUtf8()); + QByteArray ivArray = + QByteArray::fromHex(iv.toUtf8()); + QByteArray dataArray = + QByteArray::fromHex(inData.toUtf8()); + + std::vector res; + + res.resize(dataArray.size() + 64); + uint32_t resSize = static_cast(res.size()); + + auto pcrypto = CreateCryptoEngine(); + auto aesEcb = + pcrypto->CreateKey( + reinterpret_cast(keyArray.data()), + static_cast(keyArray.size()), algo); + + if (encrypt) { + aesEcb->Encrypt(reinterpret_cast(dataArray.data()), + static_cast(dataArray.size()), &res[0], resSize, + reinterpret_cast(ivArray.data()), + static_cast(ivArray.size())); + } else { + aesEcb->Decrypt(reinterpret_cast(dataArray.data()), + static_cast(dataArray.size()), &res[0], resSize, + reinterpret_cast(ivArray.data()), + static_cast(ivArray.size())); + } + + // convert to hex + QByteArray arr( + reinterpret_cast(res.data()), static_cast(resSize)); + QString resStr(arr.toHex()); + + return resStr; +} + +PlatformCryptoTest::PlatformCryptoTest() +{} + +PlatformCryptoTest::~PlatformCryptoTest() +{} + +void PlatformCryptoTest::testSHA_data() { + // SHA data + QTest::addColumn("data"); + QTest::addColumn("result_sha1"); + QTest::addColumn("result_sha256"); + + QTest::newRow("Test1") << + "You disposal strongly quitting his endeavor two settling him." + << "beace21418f741d6b32680ecd8620a66d3ba5687" + << + "453fbf8b062ab5a96fc074edfc428e1cf97498ec5f154aa2bbbeb1aefd0f9c22"; + + QTest::newRow("Test2") << "Manners ham him hearted hundred expense." + << "2eab5bf8dd1fe4c92f1318f6faf4f7005cc4e567" + << + "e4e4325eb9de4083c84a6adb7f7d231c0d73e892552760eb064771caf4507452"; +} + +void PlatformCryptoTest::testSHA() +{ + auto pcrypto = CreateCryptoEngine(); + auto hashSha1 = pcrypto->CreateHash(CRYPTO_HASH_ALGORITHM_SHA1); + auto hashSha256 = pcrypto->CreateHash(CRYPTO_HASH_ALGORITHM_SHA256); + + QFETCH(QString, data); + QFETCH(QString, result_sha1); + QFETCH(QString, result_sha256); + + QCOMPARE(HashString(hashSha1, data), result_sha1); + QCOMPARE(HashString(hashSha256, data), result_sha256); +} + +void PlatformCryptoTest::testAESECB_data() { + // AES_ECB data + QTest::addColumn("key"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("Test1") << "7bddca3c7ff9bdc8eea7a8eb63d01f11" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "ce3d1036732f9f972376abf20dda87e0323a33637ed1ad1059f1531417b4c8927042ba3cbfafabbbeefba2e527777efc47fae5642a5dbb3da5abbacc7353c51d"; + + QTest::newRow("Test2") << "01c15b1521add51f2e6f5df073c9e8cb" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "4de93d1165fc0fc958cb36b7016ca9166be18b64872f5a9230920f842b07487acda0173cfa8c13f0b31d1f8f62e45169d0c84a755009bd88d8056d583dded294"; +} + +void PlatformCryptoTest::testAESECB() +{ + QFETCH(QString, key); + QFETCH(QString, data); + QFETCH(QString, result); + + QCOMPARE(TransformData(true, + CRYPTO_ALGORITHM_AES_ECB, QString(), key, + data), result); + QCOMPARE(TransformData(false, + CRYPTO_ALGORITHM_AES_ECB, QString(), key, + result), data); +} + +void PlatformCryptoTest::testAESECB_Bad_data() { + // AES_ECB Bad data + QTest::addColumn("key"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("BadTest1") << "01c15b1521add51f2e6f5df073c9e8" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "4de93d1165fc0fc958cb36b7016ca9166be18b64872f5a9230920f842b07487acda0173cfa8c13f0b31d1f8f62e45169d0c84a755009bd88d8056d583dded294"; +} + +void PlatformCryptoTest::testAESECB_Bad() +{ + QFETCH(QString, key); + QFETCH(QString, data); + QFETCH(QString, result); + + QVERIFY_THROW(TransformData(true, + CRYPTO_ALGORITHM_AES_ECB, QString(), key, + data) != result, std::exception); + QVERIFY_THROW(TransformData(false, + CRYPTO_ALGORITHM_AES_ECB, QString(), key, + result) != data, std::exception); +} + +void PlatformCryptoTest::testAESCBC_data() { + // AES_ECB data + QTest::addColumn("key"); + QTest::addColumn("iv"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("Test1") << "7bddca3c7ff9bdc8eea7a8eb63d01f11" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "c1c5345e988975bf2ce28395f5af450758993b51e593a074fab737736191e4f81e06686f2ee839e0c1a62f98eac5754f7006bee30631ab1c113180238ef008d8"; + + QTest::newRow("Test2") << "01c15b1521add51f2e6f5df073c9e8cb" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "1f9cf5f21cb44f96c32848038b138379c6647100740afa8eb9c5bfd76c724d504f067d28c5d5bbcccad95b2b4f60e663210b58e8514a5c0a383ea211ff44136a"; +} + +void PlatformCryptoTest::testAESCBC() +{ + QFETCH(QString, key); + QFETCH(QString, iv); + QFETCH(QString, data); + QFETCH(QString, result); + + QCOMPARE(TransformData(true, CRYPTO_ALGORITHM_AES_CBC, iv, key, + data), result); + QCOMPARE(TransformData(false, CRYPTO_ALGORITHM_AES_CBC, iv, key, + result), data); +} + +void PlatformCryptoTest::testAESCBC_Bad_data() { + // AES_ECB Bad data + QTest::addColumn("key"); + QTest::addColumn("iv"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("BadTest1") << "7bddca3c7ff9bdc8eea7a8eb63d01f" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "c1c5345e988975bf2ce28395f5af450758993b51e593a074fab737736191e4f81e06686f2ee839e0c1a62f98eac5754f7006bee30631ab1c113180238ef008d8"; + + QTest::newRow("BadTest2") << "01c15b1521add51f2e6f5df073c9e8cb" + << "c506d1092830c5a3a3db0792589f2d" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4d1619e" + << + "1f9cf5f21cb44f96c32848038b138379c6647100740afa8eb9c5bfd76c724d504f067d28c5d5bbcccad95b2b4f60e663210b58e8514a5c0a383ea211ff44136a"; +} + +void PlatformCryptoTest::testAESCBC_Bad() +{ + QFETCH(QString, key); + QFETCH(QString, iv); + QFETCH(QString, data); + QFETCH(QString, result); + + QVERIFY_THROW(TransformData(true, + CRYPTO_ALGORITHM_AES_CBC, iv, key, + data) != result, std::exception); + QVERIFY_THROW(TransformData(false, + CRYPTO_ALGORITHM_AES_CBC, iv, key, + result) != data, std::exception); +} + +void PlatformCryptoTest::testAESCBCPKCS7_data() { + // AES_ECB PKCS7 data + QTest::addColumn("key"); + QTest::addColumn("iv"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("Test1") << "7bddca3c7ff9bdc8eea7a8eb63d01f11" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4" + << + "c1c5345e988975bf2ce28395f5af450758993b51e593a074fab737736191e4f81e06686f2ee839e0c1a62f98eac5754f8e06bd5cbbbea04e2db99ca495394f08"; + + QTest::newRow("Test2") << "01c15b1521add51f2e6f5df073c9e8cb" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4" + << + "1f9cf5f21cb44f96c32848038b138379c6647100740afa8eb9c5bfd76c724d504f067d28c5d5bbcccad95b2b4f60e6638b528feb4251506a995df5e6313a45e2"; +} + +void PlatformCryptoTest::testAESCBCPKCS7() { + QFETCH(QString, key); + QFETCH(QString, iv); + QFETCH(QString, data); + QFETCH(QString, result); + + QCOMPARE(TransformData(true, CRYPTO_ALGORITHM_AES_CBC_PKCS7, iv, key, + data), result); + QCOMPARE(TransformData(false, CRYPTO_ALGORITHM_AES_CBC_PKCS7, iv, key, + result), data); +} + +void PlatformCryptoTest::testAESCBCPKCS7_Bad_data() { + // AES_ECB PKCS7 data + QTest::addColumn("key"); + QTest::addColumn("iv"); + QTest::addColumn("data"); + QTest::addColumn("result"); + + QTest::newRow("BadTest1") << "7bddca3c7ff9bdc8eea7a8eb63d01f" + << "c506d1092830c5a3a3db0792589f2dba" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4" + << + "c1c5345e988975bf2ce28395f5af450758993b51e593a074fab737736191e4f81e06686f2ee839e0c1a62f98eac5754f8e06bd5cbbbea04e2db99ca495394f08"; + + QTest::newRow("BadTest2") << "01c15b1521add51f2e6f5df073c9e8cb" + << "c506d1092830c5a3a3db0792589f2d" + << + "5b87acdac4539856a91cb8de24e0b96e1ad2a7bfcd5f77456fba98ff9786f4131ed96b20585d5d930f9bdf6234e64fd0c76a7fef01b1c7abaa9b1cd1a4" + << + "1f9cf5f21cb44f96c32848038b138379c6647100740afa8eb9c5bfd76c724d504f067d28c5d5bbcccad95b2b4f60e6638b528feb4251506a995df5e6313a45e2"; +} + +void PlatformCryptoTest::testAESCBCPKCS7_Bad() { + QFETCH(QString, key); + QFETCH(QString, iv); + QFETCH(QString, data); + QFETCH(QString, result); + + QVERIFY_THROW(TransformData(true, + CRYPTO_ALGORITHM_AES_CBC_PKCS7, iv, key, + data) != result, std::exception); + QVERIFY_THROW(TransformData(false, + CRYPTO_ALGORITHM_AES_CBC_PKCS7, iv, key, + result) != data, std::exception); +} +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +} // namespace test +} // namespace rmscore diff --git a/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.h b/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.h new file mode 100644 index 00000000..754f738c --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/PlatformCryptoTest.h @@ -0,0 +1,42 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef _RMS_LIB_PLATFORMCRYPTOTEST_H +#define _RMS_LIB_PLATFORMCRYPTOTEST_H +#include + +namespace rmscore { +namespace test { +class PlatformCryptoTest : public QObject { + Q_OBJECT + +public: + + PlatformCryptoTest(); + ~PlatformCryptoTest(); + +private Q_SLOTS: + + void testSHA_data(); + void testSHA(); + void testAESECB_data(); + void testAESECB(); + void testAESECB_Bad_data(); + void testAESECB_Bad(); + void testAESCBC_data(); + void testAESCBC(); + void testAESCBC_Bad_data(); + void testAESCBC_Bad(); + void testAESCBCPKCS7_data(); + void testAESCBCPKCS7(); + void testAESCBCPKCS7_Bad_data(); + void testAESCBCPKCS7_Bad(); +}; +} // namespace test +} // namespace rmscore +#endif // _RMS_LIB_PLATFORMCRYPTOTEST_H diff --git a/sdk/rmscrypto_sdk/UnitTests/TestHelpers.h b/sdk/rmscrypto_sdk/UnitTests/TestHelpers.h new file mode 100644 index 00000000..7b08ddf3 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/TestHelpers.h @@ -0,0 +1,23 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#ifndef TESTHELPERS_H +#define TESTHELPERS_H + +#define QVERIFY_THROW(expression, ExpectedExceptionType) \ + do \ + { \ + bool caught_ = false; \ + try { expression; } \ + catch (ExpectedExceptionType const&) { caught_ = true; } \ + catch (...) {} \ + if (!QTest::qVerify(caught_, # expression ", " # ExpectedExceptionType, "", \ + __FILE__, __LINE__)) return; \ + } while (0) + +#endif // TESTHELPERS_H diff --git a/sdk/rmscrypto_sdk/UnitTests/UnitTests.pro b/sdk/rmscrypto_sdk/UnitTests/UnitTests.pro new file mode 100644 index 00000000..fd642d11 --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/UnitTests.pro @@ -0,0 +1,44 @@ +REPO_ROOT = $$PWD/../../.. +DESTDIR = $$REPO_ROOT/bin/tests +TARGET = rmscryptoUnitTests + +QT += core testlib widgets + +CONFIG -= app_bundle +CONFIG += console c++11 debug_and_release warn_on + +win32:INCLUDEPATH += $$REPO_ROOT/third_party/include +unix:!mac:INCLUDEPATH += /usr/include/glib-2.0/ /usr/include/libsecret-1/ /usr/lib/x86_64-linux-gnu/glib-2.0/include/ +# mac:INCLUDEPATH += + +INCLUDEPATH += $$REPO_ROOT/sdk/rmscrypto_sdk/CryptoStreams/CryptoAPI + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +LIBS += -L$$REPO_ROOT/bin -L$$REPO_ROOT/bin/crypto -L$$REPO_ROOT/bin/crypto/platform +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + LIBS += -lmodcryptod -lplatformkeystoraged -lplatformcryptod -lrmscryptod +}else { + LIBS += -lmodcrypto -lplatformkeystorage -lplatformcrypto -lrmscrypto +} + +TEMPLATE = app + +SOURCES += \ + main.cpp \ + PlatformCryptoTest.cpp \ + KeyStorageTests.cpp \ + CryptedStreamTests.cpp \ + CryptoAPITests.cpp + +HEADERS += \ + KeyStorageTests.h \ + PlatformCryptoTest.h \ + CryptedStreamTests.h \ + TestHelpers.h \ + CryptoAPITests.h + +win32:LIBS += -L$$REPO_ROOT/third_party/lib/eay/ -lssleay32MDd -llibeay32MDd -lGdi32 -lUser32 -lAdvapi32 +unix:!mac:LIBS += -lssl -lcrypto -lsecret-1 -lglib-2.0 +mac:LIBS += -lssl -lcrypto diff --git a/sdk/rmscrypto_sdk/UnitTests/main.cpp b/sdk/rmscrypto_sdk/UnitTests/main.cpp new file mode 100644 index 00000000..6593efdc --- /dev/null +++ b/sdk/rmscrypto_sdk/UnitTests/main.cpp @@ -0,0 +1,23 @@ +/* + * ====================================================================== + * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + * Licensed under the MIT License. + * See LICENSE.md in the project root for license information. + * ====================================================================== +*/ + +#include +#include "KeyStorageTests.h" +#include "CryptedStreamTests.h" +#include "CryptoAPITests.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QTest::qExec(new CryptoAPITests(), argc, argv); + QTest::qExec(new KeyStorageTests(), argc, argv); + QTest::qExec(new CryptedStreamTests(), argc, argv); + + return 0; +} diff --git a/sdk/rmscrypto_sdk/rmscrypto_sdk.pro b/sdk/rmscrypto_sdk/rmscrypto_sdk.pro new file mode 100644 index 00000000..ccaf6489 --- /dev/null +++ b/sdk/rmscrypto_sdk/rmscrypto_sdk.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + CryptoStreams\ + UnitTests + +UnitTests.depends = CryptoStreams diff --git a/sdk/sdk.pro b/sdk/sdk.pro new file mode 100644 index 00000000..64c79081 --- /dev/null +++ b/sdk/sdk.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs + +SUBDIRS += rmscrypto_sdk rmsauth_sdk rms_sdk + +rmsauth_sdk.depends = rmscrypto_sdk +rms_sdk.depends = rmscrypto_sdk rmsauth_sdk