Does Rotativa.MVC support pdf encryption with password? I wasn't able to find any reference about it.
There is no option to add a password in Rotativa.MVC.
You need to generate your pdf via html and add owner password, user password after that.
Basically you will need another piece of software to encrypt that pdf file or to develop that piece of software by yourself.
Using something like: https://github.com/itextsharper/iTextSharp-4.1.6/blob/master/iTextSharp/text/pdf/PdfEncryptor.cs you'll be able to do the following:
Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits, Hashtable newInfo)
using (var input = new FileStream("rotativa_generated.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (var output = new FileStream("rotativa_generated_encrypted.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, "userPassword", "ownerPassword", PdfWriter.ALLOW_PRINTING);
}
Users need only userPassword to get access.
Or you can migrate to something like https://github.com/mstamy2/PyPDF2 just for encryption. (free for commercial use as far as i know)
Related
I have an application(core 2.2.0) which uses a cookie for authentication, below is the code from the Startup.cs file
services.AddAuthentication(cookieConfig.AuthScheme)
.AddCookie(cookieConfig.AuthScheme, options => {
options.LoginPath = new PathString(cookieConfig.LoginPath);
options.AccessDeniedPath = new PathString(cookieConfig.AccessDeniedPath);
options.Cookie = cookie;
options.Events = cookieEvents;
});
And below code is from the Sign-in API
await HttpContext.SignInAsync(_cookieConfig.AuthScheme, userPrincipal, authProps);
Suppose this application generates a cookie 'ABC', and it has a URL1 - https://somedomain.com/api
and I have another API hosted at URL2 - https://somedomain.com/another_api/whatever
But remember both APIs are a different project.
When I pass this cookie to URL1, in the OnAuthorization() I can see the Identities and the Claims properties with correct values of that user and it authorizes the user perfectly. But when I pass the same cookie to URL2 all claims and identity properties show null and it does not authorize.
My question: Is it possible to share authentication between different domains? If yes, then how? If not possible then please suggest an alternative approach.
Additional Details -
We have the above code which generates (at App1) a cookie ABC=some_encrpyted_value.
And in App2 I am trying to unprotect that cookie in below manner
string cookieValue = context.HttpContext.Request.Cookies["ABC"];
var provider = DataProtectionProvider.Create(new DirectoryInfo(#"C:\temp-keys\"));
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, "ABC", "v2");
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
I have placed the data protection key from App1 in the folder 'C:\temp-keys'.
I found this code somewhere in StackOverflow itself and it throws 'CryptographicException: The payload was invalid.' exception at line
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
My understanding of the App1 code is that the Identity and Claim values (with some other values) are encrypted and cookie ABC is generated, and when we send a request this cookie is decrypted and the Identity and Claims are get populated in the context.HttpContext.User
I actually wanted it to work the same way in the App2, I want to pass the cookie and the identity values should be populated in the context.
It is possible. To deal with this type of scenarios we have been using ASP.NET machineKey. That is does is it encrypts/descriptor the auth data using the same key so that different sites can share the same authenticated sessions and data.
In Dotnet Core this machineKey concept has evolved and now called - new data protection system. Microsoft.AspNetCore.DataProtection.SystemWeb package is used to implement the data protection system. To read more on this.
There are various ways how you can store and use the key:
ProtectKeysWithAzureKeyVault (if you are using Azure)
PersistKeysToFileSystem (this is the easier one)
ProtectKeysWith*
UnprotectKeysWithAnyCertificate
Details of the individual scenario is described here.
Working with Kentico 11.0.26 CMS and a MVC website.
Have a custom content-only page type with an image field. After the image is uploaded on a page I need to display it on MVC site. But Kentico's generated code MyPageTypeProvider.GetMyPageType((int nodeId, string cultureName, string siteName) returns a page object that only contains the GUID of the image. No bytes, no URL.
How do I get the bytes or the URL of the uploaded image?
If you need the bytes, you can do this:
var attachment =DocumentHelper.GetAttachment(guid, SiteContext.CurrentSiteName, true);
var bytes = attachment.AttachmentBinary;
If you want a URL to the image, you can do something like this:
imageUrl = $"/getattachment/{guid}/attachment.aspx"
This documentation explains more ways to work with attachments.
You will need to either resolve the URL, or get file by GUID. Problem is, that Kentico Nuget API does not seem to provide enough options to get file binaries.
HelperMethods from Kentico.Content.Web.MVC NuGet seem to be good start:
https://github.com/Kentico/Mvc/tree/master/src/Kentico.Content.Web.Mvc
With these you can get file URL and use:
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");
}
Or you can write your own class or service, reference Kentico DLLs and use:
AttachmentBinaryHelper.GetFilePhysicalPath(string siteName, string guid, string extension)
I have a project ASP.NET Core 2.0 MVC running on IIS.
Want to Export some information from data grid to Excel and save it from web page to the desktop of current user.
string fileName = "SN-export-" + DateTime.Now + ".xlsx";
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
fileName = rgx.Replace(fileName, ".");
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fileName2 = Path.Combine(path, fileName);
FileInfo excelFile = new FileInfo(fileName2);
excel.SaveAs(excelFile);
This works perfect local at Visual Studio, but not after publishing at IIS.
Using simple path string path = #"C:\WINDOWS\TEMP"; It will save this export file at the server temp folder, but not current web page user.
How to get this?
ASP.NET MVC is framework for a web application. So you have fronted and backend parts. This code will executed on the server side of your application. Even if you use Razor pages, they also generated at the backend. So there are several ways to save data on the computer:
use js to iterate data and save it, but I'm not sure that saving to excel with js is easy;
send desired data to backend, save it to excel and then return to the client.
For a second way you can use next code:
[Route("api/[controller]")]
public class DownloadController : Controller {
//GET api/download/12345abc
[HttpGet("{id}"]
public async Task<IActionResult> Download(YourData data) {
Stream stream = await {{__get_stream_based_on_your_data__}}
if(stream == null)
return NotFound();
return File(stream, "application/octet-stream"); // returns a FileStreamResult
}
}
And because of security reasons you can save data only to downloads directory.
I have an ASP.NET MVC application that consumes various operations of a Web API. It uses ACS for security and so users have to log on first with their Microsoft account before they can do anything.
One of these web API operations is getting the list of permissions for the currently logged on user. This call is done for every page request, as we need this information to correctly display, disable or hide UI elements. This works fine.
As permissions don't change often, I would like to cache them so that the call to the web API is only done the first time.
Normally session is the way to keep user-specific data in memory, but I want to remain stateless/sessionless.
Would it be technically OK to use the application cache, in which I store the permissions with a key that includes the user's unique identification? Are there any risks/disadvantages of doing it like this?
[I also would like to keep the option open to later replace it with (Azure) distributed caching later, if needed, but for now the solution should be a simple built in one which is free :)]
EDIT: the cache is meant to live as long as the user is working, so it's mostly short-term cache.
Application cache seems not to be not a good option. First of all, your application process may be restarted and then all the data will be lost. On other hand, if the application is running for a long time and you have a significant number of users, it will cause significant growth process of memory size.
I'd suggest you to use encrypted cookie. Upon successful login you set the cookie with his id / permission and upon logout remove it. This way you make user login really persistent and independent on session / server state and also free your server from unnecessary storage. Encryption protects against the possibility to abuse the cookie by its reverse engineering and receive another user's permissions.
See the sample code below:
// on login successful
string EncryptedUserId = EncriptCookie(UserId, Permissions);
HttpCookie LoginCookie = new HttpCookie("yoursitename");
LoginCookie.Values.Add("userinfo", EncryptedUserId);
LoginCookie.Expires = DateTime.Now.AddYears(10);
HttpContext.Current.Response.AppendCookie(LoginCookie);
public static void Logout()
{
HttpCookie LoginCookie = new HttpCookie("yoursitename");
LoginCookie.Expires = DateTime.Now.AddDays(-1);
HttpContext.Current.Response.AppendCookie(LoginCookie);
}
private static string EncriptCookie(int UserId, string Permissions)
{
string CookieString = UserId.ToString() + "#" + Permissions);
DESCryptoServiceProvider Crypt = new DESCryptoServiceProvider();
Crypt.Key = ASCIIEncoding.ASCII.GetBytes("MYSECRET");
Crypt.IV = ASCIIEncoding.ASCII.GetBytes("MYSECRET");
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, Crypt.CreateEncryptor(), CryptoStreamMode.Write);
byte[] EncBytes = ASCIIEncoding.ASCII.GetBytes(CookieString);
cs.Write(EncBytes, 0, EncBytes.Length);
cs.FlushFinalBlock();
string EncryptedCookie = Convert.ToBase64String(ms.ToArray());
return EncryptedCookie;
}
I want to utilise some form of "simple" encryption that is reasonably secure but very low friction in terms of impact on development process.
Supposing I own both sides of the conversation in a client <> web service situation. My application is a windows phone/win8/silverlight/desktop app and the server is ASP.Net MVC or WebAPI.
In my mind, I want something as simple as:-
<security encryption="off|sometype|someothertype">
<privatekey>12345MyKey54321</privatekey>
</security>
as some form of configuration parameter on both the client and server. Additionally an authentication routine will return and store some form of public key.
Doing so will enable the 'encryption mode' and result in any http requests being encrypted & hashed in the selected manner using the provided keys. The end result being anything sniffed on the local, proxy or remote machines would not be able to view the data without the key and decryption method. On the server, data is decrypted using the same key before hitting controller actions.
Other than swapping out HttpRequest/WebClient calls for something like EncryptedHttpRequest and adding the appropriate hook on the MVC/WebAPI side of things, all other client code and controller actions would be ignorant to the fact the data was encrypted.
Am I missing something or could setup not be this simple? As far as I have searched there is nothing that offers this level of simplicity so I figure I'm missing some gaping flaw in my logic?
All you are looking for can be achieved by simply using HTTPS. Just buy a certificate (or use a self-signed certificate) and there is your encryption.
Do not re-invent the wheel.
I've done this successfully. It isn't too difficult and works well. I use it for activating a license for a product. The most important thing is that your truly control the client and server - no one can extract your private key from your code on the client.
Step 1: Create an MVC controller action method that takes no arguments:
[HttpPost] public ActionResult Activate() { ... }
Step 2: In the controller just use the HttpRequest.InputStream to get ahold of the bytes sent from the client.
var stream = this.HttpContext.Request.InputStream;
Step 3: Create a CryptoStream to deserialize.
I've included creating both encryption and decryption examples here. The sharedSecret is a byte[] of sufficient length (512 bytes) of random bytes - this is what you protect!
public CryptoStream CreateEncryptionStream(Stream writeStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(writeStream, cryptoProvider.CreateEncryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Write);
return cryptoStream;
}
public CryptoStream CreateDecryptionStream(Stream readStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(readStream, cryptoProvider.CreateDecryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Read);
return cryptoStream;
}
Step 4: Use your CryptoStream another stream reader to decrypt.
I use an XmlReader so that all my existing serialization code can work either in the clear (when reading/writing to disk or database on the server) or encrypted (when transmitting).
using (var reader = XmlReader.Create(decryptionStream, settings)) { ... }
Step 5: Formulate a secure response in your controller.
This is doing the reverse of Steps 1-4 to encrypt your response object. Then you just write your encrypted response to a memory stream and return it as a File result. Below, I've shown how I do this for my license response object.
var responseBytes = GetLicenseResponseBytes(licenseResponse);
return File(responseBytes, "application/octet-stream");
private byte[] GetLicenseResponseBytes(LicenseResponse licenseResponse)
{
if (licenseResponse != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
this._licenseResponseSerializer.Write(memoryStream, licenseResponse);
return memoryStream.ToArray();
}
}
return null;
}
Step 6: Implement your client request response.
You can use HttpWebRequest or the WebClient classes to formulate the request. Here's a couple of examples from the code I use.
byte[] postBytes = GetLicenseRequestBytes(licenseRequest);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(licenseServerUrl);
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.Proxy = WebRequest.DefaultWebProxy;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postBytes, 0, postBytes.Length);
}
return request;
private LicenseResponse ProcessHttpResponse(HttpWebResponse response)
{
if ((response.StatusCode == HttpStatusCode.OK) && response.ContentType.Contains("application/octet-stream"))
{
var stream = response.GetResponseStream();
if (stream != null)
{
var licenseResponse = this._licenseResponseSerializer.Read(stream);
return licenseResponse;
}
}
return new LicenseResponse(LicensingResult.Error);
}
Summary and Tips
Use the streams in the request/responses on the client and server to communicate binary octet-stream data
Use CryptoStream along with an encryption algorithm (consider using the strongest encryption possilbe) and a good private key to encrypt data when you serialize/deserialize it.
Make sure to check the size and format all incoming data to the client and server (avoid buffer overruns and throw exceptions early)
Protect your private key on your client using obfuscation if possible (take a look at the DeepSea obfustactor)