I am using PDFSharp in 2 different applications for 2 different reasons. The first is password protect a document and the second is to watermark the document. These processes both work individually in there own applications/workflows. The problem is that application 1 only knows about the password and application 2 only knows about the watermark, application 1 uses a default owner password and a dynamic user password, application 2 opens the document with the owner password to apply the watermark. The problem is that the password is not persisted, it seems PDFSharp while saving the document ignores the previous PDF password?!
Is there a way of keeping the security settings when applying the watermark, without explicitly defining the passwords again?
I posted this on the PDFSharp forum but they are ignoring it which is not a good sign?!
http://forum.pdfsharp.net/viewtopic.php?f=2&t=2003&p=5737#p5737
Kind Regards,
I think this was a limitation of PDF sharp, as I got no response or help from them on there forum. I opened up there code and made the following changes to correct the error. Firstly i added a new property on the SecurityHandler.cs class
public string OwnerPassword
{
set { SecurityHandler.OwnerPassword = value; }
}
/// <summary>
/// TODO: JOSH
/// </summary>
public bool MaintainOwnerAndUserPassword
{
get { return SecurityHandler.MaintainOwnerAndUserPassword; }
set { SecurityHandler.MaintainOwnerAndUserPassword = value; }
}
Then I changed the doSave method on the PdfDocument.cs class to look like the following:
void DoSave(PdfWriter writer)
{
if (this.pages == null || this.pages.Count == 0)
throw new InvalidOperationException("Cannot save a PDF document with no pages.");
try
{
bool encrypt = this.securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None;
if (encrypt)
{
PdfStandardSecurityHandler securityHandler = this.securitySettings.SecurityHandler;
if (securityHandler.Reference == null)
this.irefTable.Add(securityHandler);
else
Debug.Assert(this.irefTable.Contains(securityHandler.ObjectID));
this.trailer.Elements[PdfTrailer.Keys.Encrypt] = this.securitySettings.SecurityHandler.Reference;
}
else
this.trailer.Elements.Remove(PdfTrailer.Keys.Encrypt);
PrepareForSave();
if (encrypt && !securitySettings.SecurityHandler.MaintainOwnerAndUserPassword)
this.securitySettings.SecurityHandler.PrepareEncryption();
...
Finally I changed the CanSave method on the PDFSecuritySettings.cs to this:
internal bool CanSave(ref string message)
{
if (this.documentSecurityLevel != PdfDocumentSecurityLevel.None)
{
if ((SecurityHandler.userPassword == null || SecurityHandler.userPassword.Length == 0) &&
(SecurityHandler.ownerPassword == null || SecurityHandler.ownerPassword.Length == 0) &&
!SecurityHandler.MaintainOwnerAndUserPassword)
{
message = PSSR.UserOrOwnerPasswordRequired;
return false;
}
}
return true;
}
This should allow you to set the MaintainOwnerAndUserPassword setting and assuming you already have a hashed username and password it should work fine and dandy,
Over and out.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I decided to make a list with acounts in it. With a foreach I can automatically check all acounts instead of alot of elseif's. Directly below the foreach I want to check wether what is in the textboxes is equal with the acounts, if this is the case a new Form opens up.
Acount a = new Acount("Admin", "123");
Acount b = new Acount("Admin2", "321");
List<Acount> acounts = new List<Acount>();
acounts.Add(a);
foreach(Acount acount in acounts)
{
if (txtUsername.Text == ???)
{
openForm();
}
else
{
MessageBox.Show("Invalid password or username.");
}
}
Here the Acount class:
class Acount
{
public string Name{ get; set; }
public string Password{ get; set; }
public Acount()
{
}
public Acount(string name, string password)
{
this.Name= name;
this.Password= password;
}
}
I think what your are looking for is something like this:
if (txtUsername.Text == acount.Name && txtPassword.Text == acount.Password)
So if both username and password are correct for any account, you'll end up opening the new form.
Be careful however, the way your loop is currently written, even if the user enters valid credentials for one user in your list, you'll still open the MessageBox on each loop except the one that's good.
I'd suggest either using .Any as suggested by someone else, or using a boolean value to keep track of the matching status as such:
bool isFound = false;
foreach (Account account in accounts)
{
if (txtUsername.Text == account.Name && txtPassword.Text == account.Text)
{
isFound = true; // we found a match
break; // no need to keep searching, we can break
}
}
if (isFound)
openForm();
else
MessageBox.Show("...");
Instead of for loops you can just use the method Any.
Also there is a bug in your code that it would open many forms if there are multiple matches (because the for loop is not broken after finding one).
So, here is a quick solution to the code:
// NOTE: REMOVE THE FOR LOOP as it's not needed anymore.
// Just use the code below instead of the loop.
if (acounts.Any(account => txtUsername.Text == account.Name && account.txtPassword == account.Password)) {
openForm();
} else {
MessageBox.Show("Invalid password or username.");
}
Also don't forget to add the following using statements if you haven't:
using System.Collections.Generic;
using System.Linq;
Create an extension for handling decision call.
public static class Extensions
{
public static void ReactWith(this Acount acct, Action succes, Action failure)
{
Action actionToPerform = acct != null ? succes : failure;
actionToPerform.Invoke();
}
}
In main file call the extension as below.
private void OpenForm()
{
// launch form code here.
}
private void ErrorMesage()
{
// Message box code here.
}
List<Acount> acounts = new List<Acount>();
var validAcct = acounts.Where(a => a.Name == "abc").FirstOrDefault();
validAcct.ReactWith(OpenForm, ErrorMesage);
In my web app the admin can assign a web page to a specific user, therefore that user can only access that specific page.
So to give an idea of how this works:
in my database I have a table with the web pages in, Webpage1.aspx, Webpage2.aspx etc.
The admin can create an user assign Webpage1.aspx to that user
Then when that user logs in they can only see the link to their page (all other links are hidden)
This is now the problem I have:
This works on a DataTable row number so when adding a new web form it re-arranges the DataTable row numbers which then when the user logs in again they can see all other links cause the table numbers have changed.
So to give a visual idea:
if (Session["Privilege"] != null)
{
DataTable dtPrivilege = (DataTable)Session["Privilege"];
/* Dashboard */
if (bool.Parse(dtPrivilege.Rows[1]["Read"].ToString()) == false && dtPrivilege.Rows[1]["FormName"].ToString() == "dashboard.aspx")
lnkDashboard.Visible = false;
/* Settings */
if (bool.Parse(dtPrivilege.Rows[2]["Read"].ToString()) == false && dtPrivilege.Rows[2]["FormName"].ToString() == "general.aspx")
lnkSettings.Visible = false;
/* Web Pages */
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false)
lnkWebpages.Visible = false;
else
{
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false && dtPrivilege.Rows[0]["FormName"].ToString() == "Webpage1.aspx")
lnkWebpage1.Visible = false;
}
So it reads by row number so when you add another page it messes up the row number and the 1st users saved in the database then gets the wrong link assigned to their privilege, because it moved the row number to 1 or 2 depending on how many web forms have been added.
So my question is, how can I make it so that it reads the string instead of the row number? So for example
if (Session["Privilege"] != null)
{
DataTable dtPrivilege = (DataTable)Session["Privilege"];
/* Web Pages */
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false)
lnkWebpages.Visible = false;
else
{
if (bool.Parse(dtPrivilege.Rows[**Webpage1.aspx**]["Read"].ToString()) == false && dtPrivilege.Rows[0]["FormName"].ToString() == "Webpage1.aspx")
lnkWebpage1.Visible = false;
}
Is this possible and if so how can I achieve my goal?
Please let me know if you need more info or I haven't explained properly :-)
Thanks
You can use Linq to achieve this.
Add using System.Linq; at the top of your .cs page.
Then add below line to generate IEnumerable(Array) of all rows inside dtPrivilege DataTable,
DataRow[] allRows = dtPrivilege.Select();
And finally, add if blocks like below for all your webpages.
if (allRows.Any(x => x["FormName"].ToString() == "Webpage1.aspx" &&
x["Read"].ToString().ToLower() == "false"))
{
lnkWebpage1.Visible = false;
}
What above if block says:
It checks if there exists Any row in allRows, which has FormName = "Webpage1.aspx" and Read = "false". And if it exist, just set lnkWebpage1.Visible = false
I have a Xamarin.iOS application that requires users to log-in in order to view content. I have two text fields, one for username and one for password. Once a user has logged in and the API has returned success. how can I save the users credentials so when they launch the app they get signed in automatically?
I tried this, however, I don't know how to retrieve the values or re-save credentials if user logs out
void StoreKeysInKeychain(string key, string value)
{
var s = new SecRecord(SecKind.GenericPassword)
{
ValueData = NSData.FromString(value),
Generic = NSData.FromString(key)
};
var err = SecKeyChain.Add(s);
}
Thanks.
You can install this plugin and all of the work is already done for you: https://github.com/sameerkapps/SecureStorage, nuget: https://www.nuget.org/packages/sameerIOTApps.Plugin.SecureStorage/.
If you use the plugin it is as simple as:
CrossSecureStorage.Current.SetValue("SessionToken", "1234567890");
var sessionToken = CrossSecureStorage.Current.GetValue ("SessionToken");
If you don't want to use it, then look into github repo and see how they did it for iOS:
https://github.com/sameerkapps/SecureStorage/blob/master/SecureStorage/Plugin.SecureStorage.iOSUnified/SecureStorageImplementation.cs
public override string GetValue(string key, string defaultValue)
{
SecStatusCode ssc;
var found = GetRecord(key, out ssc);
if (ssc == SecStatusCode.Success)
{
return found.ValueData.ToString();
}
return defaultValue;
}
private SecRecord GetRecord(string key, out SecStatusCode ssc)
{
var sr = new SecRecord(SecKind.GenericPassword);
sr.Account = key;
return SecKeyChain.QueryAsRecord(sr, out ssc);
}
Better to use iOS default NSUserDefaults.StandardUserDefaults to store your credentials.
Check for stored value in Login ViewController, if it doesn't exist then after successful login set the user name and password to "GetStoredCredentials" else fetch the saved credentials and use.
public String GetStoredCredentials
{
get {
string value = NSUserDefaults.StandardUserDefaults.StringForKey("Key");
if (value == null)
return "";
else
return value;
}
set {
NSUserDefaults.StandardUserDefaults.SetString(value.ToString (), "Key");
NSUserDefaults.StandardUserDefaults.Synchronize ();
}
}
Either you can save as string array or comma seperated value.
Let me know for any further assistance.
For your refrence : https://developer.xamarin.com/guides/ios/application_fundamentals/user-defaults/
I'm using Mailkit to fetch email from mailbox and save it to database to display in my MVC application.
I save html email as plain text in database, i can fetch attachments and save it in file system, but when there are inline images in email, i'm having issue as signatures and other blank images are too being saved as attachment in file system.
Is there a way to distinguish between inline attachment and signatures or other blank images?
Thanks in advance
It doesn't matter which IMAP library you use, none of them have a feature that will help you do what you want to do because it's a non-trivial problem to solve that you are going to need to use some ingenuity to solve.
What you can do is start with the HtmlPreviewVisitor sample from the FAQ and modify it every-so-slightly to just split the attachments into 2 lists:
The list of actual attachments
The list of images actually referenced by the HTML (by walking the HTML and tracking which images are referenced)
code:
/// <summary>
/// Visits a MimeMessage and splits attachments into those that are
/// referenced by the HTML body vs regular attachments.
/// </summary>
class AttachmentVisitor : MimeVisitor
{
List<MultipartRelated> stack = new List<MultipartRelated> ();
List<MimeEntity> attachments = new List<MimeEntity> ();
List<MimePart> embedded = new List<MimePart> ();
bool foundBody;
/// <summary>
/// Creates a new AttachmentVisitor.
/// </summary>
public AttachmentVisitor ()
{
}
/// <summary>
/// The list of attachments that were in the MimeMessage.
/// </summary>
public IList<MimeEntity> Attachments {
get { return attachments; }
}
/// <summary>
/// The list of embedded images that were in the MimeMessage.
/// </summary>
public IList<MimePart> EmbeddedImages {
get { return embedded; }
}
protected override void VisitMultipartAlternative (MultipartAlternative alternative)
{
// walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful
for (int i = alternative.Count - 1; i >= 0 && !foundBody; i--)
alternative[i].Accept (this);
}
protected override void VisitMultipartRelated (MultipartRelated related)
{
var root = related.Root;
// push this multipart/related onto our stack
stack.Add (related);
// visit the root document
root.Accept (this);
// pop this multipart/related off our stack
stack.RemoveAt (stack.Count - 1);
}
// look up the image based on the img src url within our multipart/related stack
bool TryGetImage (string url, out MimePart image)
{
UriKind kind;
int index;
Uri uri;
if (Uri.IsWellFormedUriString (url, UriKind.Absolute))
kind = UriKind.Absolute;
else if (Uri.IsWellFormedUriString (url, UriKind.Relative))
kind = UriKind.Relative;
else
kind = UriKind.RelativeOrAbsolute;
try {
uri = new Uri (url, kind);
} catch {
image = null;
return false;
}
for (int i = stack.Count - 1; i >= 0; i--) {
if ((index = stack[i].IndexOf (uri)) == -1)
continue;
image = stack[i][index] as MimePart;
return image != null;
}
image = null;
return false;
}
// called when an HTML tag is encountered
void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter)
{
if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) {
// search for the src= attribute
foreach (var attribute in ctx.Attributes) {
if (attribute.Id == HtmlAttributeId.Src) {
MimePart image;
if (!TryGetImage (attribute.Value, out image))
continue;
if (!embedded.Contains (image))
embedded.Add (image);
}
}
}
}
protected override void VisitTextPart (TextPart entity)
{
TextConverter converter;
if (foundBody) {
// since we've already found the body, treat this as an
// attachment
attachments.Add (entity);
return;
}
if (entity.IsHtml) {
converter = new HtmlToHtml {
HtmlTagCallback = HtmlTagCallback
};
converter.Convert (entity.Text);
}
foundBody = true;
}
protected override void VisitTnefPart (TnefPart entity)
{
// extract any attachments in the MS-TNEF part
attachments.AddRange (entity.ExtractAttachments ());
}
protected override void VisitMessagePart (MessagePart entity)
{
// treat message/rfc822 parts as attachments
attachments.Add (entity);
}
protected override void VisitMimePart (MimePart entity)
{
// realistically, if we've gotten this far, then we can treat
// this as an attachment even if the IsAttachment property is
// false.
attachments.Add (entity);
}
}
To use it:
var visitor = new AttachmentVisitor ();
message.Accept (visitor);
// Now you can use visitor.Attachments and visitor.EmbeddedImages
An even simpler, although less error-proof (sine it doesn't actually verify whether the image is referenced by the HTML), way of doing it is this:
var embeddedImages = message.BodyParts.OfType<MimePart> ().
Where (x => x.ContentType.IsMimeType ("image", "*") &&
x.ContentDisposition != null &&
x.ContentDisposition.Disposition.Equals ("inline" StringComparison.OrdinalIgnoreCase));
Now that you have your list of embeddedImages, you'll have to figure out a way to determine if they are only used in the signature or used elsewhere in the HTML.
Most likely you'll have to analyze the HTML itself as well.
It is also probably worth noting that some HTML mail will reference images located on the web that are not embedded in the MIME of the message. If you want these images as well, you'll need to modify TryGetImage to fall back to downloading the image from the web if the code I provided fails to locate it within the MIME of the message.
For text/plain messages (which can't use images at all), the common convention to separate the signature from the rest of the message body is a line with only 2 dashes and a space: --.
From my limited experience with HTML messages that have signatures, they do not appear to follow a similar convention. Looking at a few of the HTML messages I receive from co-workers at Microsoft using Outlook, they appear to be within a <table> at the end of the message. However, this assumes that the message is not a reply. Once you start parsing message replies, this <table> ends up in the middle of the message somewhere because the original message being replied to is at the end.
Since everyone's signature is different as well, I'm not sure if this <table> similarity is an Outlook convention or if people are manually constructing their signatures and they are all just using tables out of coincidence (I've also only seen a few, most do not use signatures, so my sample size is very small).
Using https://mailsystem.codeplex.com/:
the class wich read the email:
class readMail:IDisposable
{
public Imap4Client client = new Imap4Client();
public readMail(string mailServer, int port, bool ssl, string login, string password)
{
Pop3Client pop = new Pop3Client();
if (ssl)
{
client.ConnectSsl(mailServer, port);
}
else
client.Connect(mailServer, port);
client.Login(login, password);
}
public IEnumerable<Message> GetAllMails(string mailBox)
{
IEnumerable<Message> ms = GetMails(mailBox, "ALL").Cast<Message>();
return GetMails(mailBox, "ALL").Cast<Message>();
}
protected Imap4Client Client
{
get { return client ?? (client = new Imap4Client()); }
}
private MessageCollection GetMails(string mailBox, string searchPhrase)
{
try
{
MessageCollection messages = new MessageCollection();
Mailbox mails = new Mailbox();
mails = Client.SelectMailbox(mailBox);
messages = mails.SearchParse(searchPhrase);
return messages;
}
catch(Exception ecc)
{
}
}
public void Dispose()
{
throw new NotImplementedException();
}
}
and then:
using (readMail read = new readMail("host.name.information", port, true, username, password) )
{
var emailList = read.GetAllMails(this.folderEmail);
int k = 0;
Mailbox bbb = read.client.SelectMailbox(this.folderEmail);
int[] unseen = bbb.Search("UNSEEN");
foreach (Message email in emailList)
{
/// Contains all parts for which no Content-Disposition header was found. Disposition is left to the final agent.
MimePartCollection im1= email.UnknownDispositionMimeParts;
//Collection containing embedded MIME parts of the message (included text parts)
EmbeddedObjectCollection im2 = email.EmbeddedObjects;
//Collection containing attachments of the message.
AttachmentCollection attach=email.Attachments;
}
}
in my case all the signature's images were in UnknownDispositionMimeParts, but this could be a specific case (different email client and so on)..so for what i know i didn't find any library that separate embedded images from contextual images to signature images
Edit Some have expressed their dislike for my particular solution presented in this problem, but please don't waste my time suggesting completely alternative methods. I have no control over the requirements of what I am working on. If you disagree with it and don't have an answer, just move along. Thanks.
For starters, this is a practice project and will not be used by the general public. I need to secure some pages in my website using session properties for username. This occurs (the username saved into session) when a correct username and password combo is entered. My boss reviewed my implementation and said that "storing the username value into the HttpSessionState directly is wrong, you should set the username property of the session, and store the session object into the HttpSessionState". Now I think I understand what parts of my code he is referring to, but changing this breaks the security (anyone can use a direct link to a page once a single user has logged in).
Make sure to read the comments in code, I added them to describe the lines in question.
What worked in terms of security, but username is stored directly into HttpSessionState:
//login.ascx.cs
private void Login_Click(object sender, EventArgs e)
{
if (sender == null || e == null)
{
throw new ArgumentNullException("Null Exception: Login_Click");
}
User user = new User();
user.Login(_username.Text, _password.Text);
if (user.IsValid() && user.GetIsUser() != false)
{
user.Save();
//the line below is what I used to make the secure pages work properly.
//but based on what my boss says, I think this is what should be changed.
Session["Username"] = _username.Text;
//What i tried instead was to set 'MySession.Current.Username = _username.Text;'
//which allowed successful login, but the pages became insecure once again.
Response.Redirect("Secure/Default.aspx");
}
else
{
DisplayErrors(user._validationErrors);
}
_errors.Text = errorMessage;
}
and MySession.cs
public string Username
{
get
{
if (HttpContext.Current.Session["Username"] == null)
{
return string.Empty;
}
else
{
return HttpContext.Current.Session["Username"].ToString();
}
}
set
{
//when the line below is uncommented, the secure pages are vulnerable
//but if I comment it out, they work properly.
//HttpContext.Current.Session["Username"] = value;
}
}
So how can I Set the username property of the session, and store the session object into the HttpSessionState while still maintaining a secure site?
EDIT: #Win, within Secure/Default.aspx.cs
private void Page_load(object sender, System.EventArgs e)
{
...
if((string)Session["Username"] != _labelusername.Text)
{
Response.Redirect(redirectLogin); //to login page
}
else {} //success
}
You should look into FormsAuthentication. There are many examples online like this one:
http://bradkingsley.com/securing-asp-net-pages-forms-authentication-c-and-net-4/