I'm using a uniqueidentifier to validate the email address of a user in my ASP.NET application. When I try to validate any email address using the uniqueidentifier, I can do so without problem. 80% of my users, however, cannot do so. I cannot figure out why this is happening! I've had users email me directly, forwarding their activation email and I can activate their account without issue.
Here's an example of the validation link that's in the email.
mysite.org/petition.aspx?uid=0fcc9582-386c-4738-943d-36e09c8df4bd
Here's the exception that's occurring:
problem loading petition screen: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).:
at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException)
at System.Guid.TryParseGuidWithDashes(String guidString, GuidResult& result)
at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
at System.Guid..ctor(String g)
at MAP.Umbraco.UserControls.SignPetitionUserControl.get_PetitionGuid()
at MAP.Umbraco.UserControls.SignPetitionUserControl.OnLoad(EventArgs e)
UPDATE: Here's the get method for my PetitionGuid property.
private Guid? PetitionGuid
{
get
{
if (Page.Request.QueryString["uid"] == null)
return null;
else
return new Guid( Page.Request.QueryString["uid"].ToString());
}
}
Is there anything obvious that I'm missing here?
Feel free to ask any questions that you might need to ask.
You're missing a character.
0fcc9582-386c-4738-943d-36e09c8df4b <---
12345678 1234 1234 1234 123456789012
Update
Based on your update above, your implementation for petition guid is not coded very defensively.
private Guid? PetitionGuid
{
get
{
if (Page.Request.QueryString["uid"] == null)
return null;
else
return new Guid( Page.Request.QueryString["uid"].ToString());
}
}
so basically, if the uid parameter is ANYTHING other than null, (a number, random string, other garbage) you are going to try and turn it into a guid. and that's obviously causing failures... put some logging in, and record the values of UID that are being submitted.
You should probably be using something like tryParse, instead of just puking an exception.
if(string.IsNullOrEmpty(s))
Console.WriteLine("Null or Empty");
Guid g;
Guid.TryParse(s, out g);
if(g == Guid.MinValue)
Console.WriteLine("Couldn't Parse");
else
Console.WriteLine("G: {0}", g);
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
Does tihs 0fcc9582-386c-4738-943d-36e09c8df4b meet to requirement? You lost one digit in last part. You have 11 digit instead of 12.
Based on the current answers and comments and the fact that you use Umbraco I supect the QueryString is delivered to you in an encoded form. Better make sure that what we get is sane and valid and in the format we can actually handle it. The main improvement is in usimg HttpUtility.Decode to get the querystring into shape.
private Guid? PetitionGuid
{
get
{
Guid? guid = null;
var raw = Page.Request.QueryString["uid"];
if (!String.IsNullOrEmpty(raw))
{
var decoded = HttpUtility.UrlDecode(raw);
Guid parsed;
if (Guid.TryParse(decoded, out parsed))
{
guid = parsed;
}
else
{
Trace.WriteLine(String.Format(
"illigal uid {0}:{1}", raw,decoded));
}
}
return guid;
}
}
Related
Scenario: Deactivate the user whose login date is less than 42 from today. I have an user whose last login date is 1/22/2020(US Date format)/22/1/2020 5:12 pm. Here I wrote a batch apex for deactivating. My code has executed successfully and my batch status is completed but the user record is not deactivating.
Here is the code:
global class User_Deactivation implements Database.Batchable<SObject>
{
dateTime dt = date.today()-42;
public String query = 'SELECT Name, LastLoginDate, Id From User WHERE IsActive = true AND LastLoginDate=:dt ';
global Database.querylocator start(Database.BatchableContext bc)
{
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc,List<User> scope)
{
List<User> userList = new List<User>();
for(User s:scope)
{
User u =(user)s;
userList.add(u);
}
if(userList.size() > 0)
{
for(User usr : userList)
{
usr.isActive = false;
}
}
update userList;
}
global void finish(Database.BatchableContext bc)
{
AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :BC.getJobId()];
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Job Status: ' + a.Status);
mail.setPlainTextBody('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
please help me out on this
Multiple things you can improve here, where do I begin...
Initialisation(?) piece
dateTime dt = date.today()-42;
String query = 'SELECT Name, LastLoginDate, Id From User WHERE IsActive = true AND LastLoginDate=:dt';
Do you need Date or DateTime match? The way you wrote it it'll match only people who logged in exactly at midnight. System.debug(dt); would say 2020-01-23T00:00:00.000Z. It shouldn't be an equals sign, should be "less than" or "less or equal".
Or even better - you can make it bit more clear what you want to do, bit more "semantic" so the poor guy who's going to maintain it can understand it without extra comments. This reads more natural and uses the SOQL date literals, special "constants" to simplify your logic: SELECT Id, LastLoginDate FROM User WHERE isActive = true AND LastLoginDate != LAST_N_DAYS:42
What is this section of code anyway. It's not really static variables, it's not a constructor... I think it'll behave as a constructor. Be very, very careful with constructors for batches. The state of the class at the end of the constructor gets saved (serialised) and restored every time the class is scheduled to run. It's tempting to put some initialisation code into constructor, maybe read some custom settings, precalculate stuff... But then you'll be in for nasty surprise when admin adds new custom setting and the batch doesn't pick it up. In your case it's even worse, I'd suspect it'll serialise the dt and your today() will be frozen in time, not what you expected. To be safe move all initialisation logic to start()
And I'd even say whoever gave you the requirement didn't think it through. When you make new user they get a link they need to click in next 72h. If they didn't do it (maybe it was sent late Friday and they want to login on Monday) - this thing will dutifully kill their access at Friday night without giving them any chance to login. You need some "grace period". Maybe something like WHERE isActive = true AND (LastLoginDate < :x OR (LastLoginDate = null AND CreatedDate < :x))
start()
Queries in strings work and that's how a lot of batch documentation is written but they are poor practice. Where possible use a compiled query, in brackets. You get minimal improvement in execution (precompiled), you get compile-time warnings when you mess up (better than a runtime error which you might not notice if you don't monitor jobs). And most importantly - if somebody wants to delete a field - SF will detect a dependency and stop him/her. Use return Database.getQueryLocator([SELECT ...]); wherever you can.
execute()
Your scope already is a list of users, why do you do extra casts to User? Why do you add them to a helper list? Why 2 loops?
for(User u : scope){
u.isActive = false;
}
update users;
and you're done?
P.S. Why "global" all over the place?
I m developping an application where user can provide text informations and images. I want to save images on file system and in DB, I will add a link of each user to its images So I need to add the user ID to the image name to not get images with same name. I m using SPRING MVC.
in my Controller :
#RequestMapping(value="/save",method=RequestMethod.POST)
public String add ( #RequestParam("prix") Long prix,
RequestParam("adresse") String ville,
#RequestParam("categorie") String categorie,
#RequestParam("photos") MultipartFile file,
) throws FileNotFoundException
{
String chemin=null;
if (!file.isEmpty())
{
try {
String orgName = file.getOriginalFilename();
// this line to retreive just file name
String
name=orgName.substring(orgName.lastIndexOf("\\")+1,orgName.length());
chemin="e:\\images\\"+name; //here I want to add id (auto generated)
File file1=new File(chemin);
file.transferTo(file1);
} catch (IOException e) {
e.printStackTrace();
}
}
annonce.setImage(chemin);
annonce.setTitre(prix);
annonce.setCorps(ville);
annonce.setPrix(cetegorie)
annoncedao.save(annonce);
return "SuccessAddAnnonce";
}
but I can not get the ID witch is auto generated so I can not get it throw #RequestParam like adress or categorie because it is auto generated and I still don t have it until we call save method witch is last .
Any suggestions are welcome .
I got the Id using query with Select max (id)
#Query("SELECT MAX(id) FROM Annonce")
Long findAutoincrementAnnonce();
I wish help someone.
You can generate a random ID for each user and assign it to a particular user, and thus its image name also (what you intend to do here I guess).
I will illustrate it simply.
// Get a random ID coressponding to the user address or whatever, here i will just use address
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] hash = digest.digest(ville.getBytes("UTF-8"));
String randomId = DatatypeConverter.printHexBinary(hash);
// Here you have a uniqueID for an address.
// You could have just used ville.hashCode() also but it might give you collisions with some different Strings.
if Input: "64th Street, Downtown, StackOverFlow" then
randomId = 8AB126F8EBC0F7B5CCBBEB3E21582ADF
I am retrieving the contents of a database using a object (its returning only one field) and then comparing it with a string which has been hashed with SHA1 .The code is as follows :
protected void Onbutton_click_login(object sender, System.EventArgs e)
{
var dbcontext = new PrepLicensingSolution2010.DAL.LicensingEntities1();
var user = dbcontext.getloginname(loginName.Text);
string HashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(Password.Text, "sha1");
if (user.ToString() == HashedPassword)
{
Response.Redirect("faqs.aspx");
}
else
{
Response.Redirect("Default.aspx");
}
}
I put breakpoints and checked the data at each stage of the flow and the data in the object result set and in the string are the same but even then the conditional if fails
whats interesting is both the types being compared are of the type string and of the same value,so why is that that the redirect goes to the default.aspx page.
The image contains the data from the breakpoints
Any inputs would be great.
Thanks
Based on the screenshot, user.ToString() looks to be returning the string {System.Data.Objects.ObjectResult<string>}. This, of course, does not equal the hashed password.
Your problem is that the result of your getloginname call is a sequence of strings containing a single string, not a single string itself. The default implementation of ToString() simply returns the class name, and you can see it in the Value column for the "user" row in the screenshot. Changing your conditional statement to the following should fix it:
if (user.FirstOrDefault() == HashedPassword)
Hii,
I have a query string like "http://project/page1.aspx?userID=5". The operation won't be performed, if the 'userID' parameter changed manually. How it is possible?
Hii all, thank you for your assistance... and i got some difference sort of solution from some other sites. i don't know that the best solution. that is to encode the value using an encryption and decryption algorithm... The sample code has been written like this...
<a href='Page1.aspx?UserID=<%= HttpUtility.UrlEncode(TamperProofStringEncode("5","F44fggjj")) %>'>
Click Here</a> <!--Created one anchor tag and call the function for TamperProofStringEncode-->
private string TamperProofStringEncode(string value, string key)
{
System.Security.Cryptography.MACTripleDES mac3des = new System.Security.Cryptography.MACTripleDES();
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
mac3des.Key = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(key));
return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(value)) + "-" + Convert.ToBase64String(mac3des.ComputeHash(System.Text.Encoding.UTF8.GetBytes(value)));
}
In the page load of 'Page1' call the decode algorithm to decode the query string
try
{
string DataString = TamperProofStringDecode(Request.QueryString["UserID"], "F44fggjj");
Response.Write(DataString);
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
private string TamperProofStringDecode(string value, string key)
{
string dataValue = "";
string calcHash = "";
string storedHash = "";
System.Security.Cryptography.MACTripleDES mac3des = new System.Security.Cryptography.MACTripleDES();
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
mac3des.Key = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(key));
try
{
dataValue = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value.Split('-')[0]));
storedHash = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value.Split('-')[1]));
calcHash = System.Text.Encoding.UTF8.GetString(mac3des.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dataValue)));
if (storedHash != calcHash)
{
//'Data was corrupted
throw new ArgumentException("Hash value does not match");
// 'This error is immediately caught below
}
}
catch (Exception ex)
{
throw new ArgumentException("Invalid TamperProofString");
}
return dataValue;
}
It sounds like a strange requirement. Are you trying to implement some sort of home-grown security? If it's so, you really shouldn't.
Anyway, one way you could do it would be to take the entire url http://project/page1.aspx?userID=5 and calculate its md5 sum. Then you append the md5 sum to the final url, such as http://project/page1.aspx?userID=5&checksum=YOURCALCULATEDMD5SUM. Then in page1.aspx you will have to validate that the checksum parameter is correct.
However, this approach is quite naïve and it would not necesarily take very long for anyone to figure out the algorithm you have used. If they did they could "easily" change the userid and calculate an md5 sum themselves. A more robust approach would be one where the checksum was encrypted by a key that only you had access to. But again I have to question your motive for wanting to do this, because other security solutions exist that are much better.
Here is another option that I found incredibly useful for my requirements:
4 Guys From Rolla - Passing Tamper-Proof QueryString Parameters
You can't.
Anything in the HTTP request (including URL, query string, cookies, ...) is under the control of the client and is easy to fake.
This is why it is important to whitelist valid content, because the client can arbitrarily add anything it likes in addition to what you you prompt to receive.
My favourite is the following. It uses a HTTPmodule to transparently encode and decode the Querystring with the explicit purpose of preventing tamperring of the querystring.
http://www.mvps.org/emorcillo/en/code/aspnet/qse.shtml
It is perfect when Session is not an option!
You can't tell whether it has been changed manually. If you use query strings then you hyave to make sure that it doesn't matter if it is changed. e.g. if you are using it to show a user their account details, you need to check wether the selected user, is the current user and show an error message instead of user data if it is not.
If the user is allowed to change record 5, but not record 7 for example, this has to be enforced server-side. To do this you need to be able to identify the user, by requiring a login, and giving them a unique session key that is stored in their browser cookie, or as another parameter in the url query string.
There are abundant packages/modules/libraries in man languages for dealing with authentication and sessions in a sensible way - roll you own at your own peril :)
Well - it depends :)
One possibility is to put the userID into a session variable. So the user cannot see or edit the value.
If you have other means to detect if the value is invalid (i.e. does not exist or cannot be for that user (who you can identify through some other way) or the like) you might get away with validating the input yourself in code behind.
But as you probably know you cannot prevent the user changing the query string.
I have a requirement to have a multiline textbox that accepts any text from any language and stores this into the database for later use.
I am using Linq with ASP .NET 3.5 with a SQL Server 2005 database.
Any/all information you can provide me with is much appreciated :D
You'll need to Encode and Decode the text depending if you're updating/inserting or Viewing the data.
Look at System.Text.Encoding
After a lot of research and fretting I found a some stuff I pieced together and used to come up with my ultimate solution. This handles being able to insert any character I could throw at it:
I created 2 methods to handle the 2 scenarios I was looking to solve.
1st going from the user interface to the database.
I made sure that my web page was sporting the Unicode(utf-8) encoding content type.
public string unicodeToIso(string InStr)
{
if (InStr != null)
{
Encoding iso = Encoding.GetEncoding(1252);
Encoding unicode = Encoding.Unicode;
byte[] unicodeBytes = unicode.GetBytes(InStr);
return iso.GetString(unicodeBytes);
}
else
return null;
}
Then I handled the return of the data to the user interface.
public string isoToUnicode(string InStr)
{
if (InStr != null)
{
// I originally used the string: "iso8859-1" instead of 1252
// 1252 helped 'catch' ALL of the Chinese characters as opposed to most
Encoding iso = Encoding.GetEncoding(1252);
Encoding unicode = Encoding.Unicode;
byte[] isoBytes = iso.GetBytes(InStr);
return unicode.GetString(isoBytes);
}
else
return null;
}
I truly hope this helps anyone else out there that may be stumbling on this same problem :)