asp.net membership provider Guid userID - asp.net

I need (I think) to get the current logged in userID so that I can update one of my tables that uses this userID as a foreign key. The problem is that the userID in the database does not match with this:
Guid currentUser = (Guid)Membership.GetUser().ProviderUserKey;
currentUser.toString();
results in dffaca0c-ae0b-8549-8073-1639985740be
whereas when I look in the database, it is 0CCAFADF0BAE498580731639985740BE
Why are they different values? (I only have one user). I am using an oracle database and provider for asp.net, but shouldn't make any difference.

I believe these are the same values, but the display order is different. Looking at the 2 values:
dffaca0c-ae0b-8549-8073-1639985740be
0CCAFADF-0BAE-4985-8073-1639985740BE
The ordering of bytes for the first 3 segments is of a different order:
0CCA FADF => FADF 0CCA => DFFA CA0C == dffaca0c
0BAE => AE 0B == ae0b
4985 => 85 49 == 8549
As #x0n comments, this looks like a difference in endianness with Oracle. According the this description of the structure, the endianness of the first 8 bytes is system dependent, while the endianness of the last 8 bytes is specifically big endian.

I had the same issue and came up with this which resolved the issue:
public static string TranslateOraceEndianUserID()
{
MembershipUser myObject = Membership.GetUser();
Guid g = new Guid(myObject.ProviderUserKey.ToString());
byte[] b = g.ToByteArray();
string UserID = BitConverter.ToString(b, 0).Replace("-", string.Empty);
return UserID;
}

Or maybe also try using HttpContext.Curent.User to get the current user?

You could always use the Lower Case User Name column to create the foreign Key. It is always unique. Maybe not the best option but it is the simplest and works well. I have used it in several projects.

Related

Objectify Web Safe Key Usage

I am using Objectify to store and retrieve data from App Engine Datastore.
String version of the key is created from the datastore object id.
public String getWebsafeKey() {
return Key.create(UserData.class, id).getString();
}
The websafeKey is used to get the UserData object from the Datastore.
Key<UserData> userDataKey = Key.create(websafeKey);
UserData userData = ofy().load().key(userDataKey).now();
In our Unit testing when the websafeKey is changed a bit, the user data class can still be retrieved.
Passed websafeKey - agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDC
Actual websafeKey - agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDA
Is this a known limitation or this can be addressed?
websafeKey's are base64 encoded strings.
Somehow both
agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDC &
agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDA decode to jj~c2hqualityrMovie
give it a try https://www.base64decode.org/

MVC Login password comparison case sensitive

I need to compare the username field and the password field with the one in database, my code does work but the problem is that the comparison is not case sensitive. below is part of my code, I know I must be missing something silly. any help will be appreciated, Thanks
var UserDetail = db.UserTbls.Where(x => x.UserName == UserModel.UserName &&
x.Password == UserModel.Password).FirstOrDefault();
if (UserDetail == null)
{
UserModel.loginErrorMessage = "Wrong Username or Password";
return View("Login", UserModel);
}
else
{
Session["UserId"] = UserDetail.UserId;
return RedirectToAction("Index", "Home");
}
EF to SQL Server will perform string comparisons case-insensitive. To perform a case-sensitive check like you describe:
var users = var UserDetail = db.UserTbls.Where(x => x.UserName == UserModel.UserName).ToList();
var matchingUser = users.SingleOrDefault(x => x.Password == password);
The .ToList() will mean the next expression will be evaluated against Objects, returning all user records with that name. If user names are unique then this should be a SingleOrDefault(). From there the == operation on the password will be case sensitive by default.
However, as mentioned by Stephen, Passwords should always be hashed with a salt and stored, where the HASHES are compared, not plain-text passwords.
I recommend reading up on SHA-1 hashes.
string.Compare method has and overload which you can use for comparing the username and passwords.
As Stephen mentioned, you certainly need to work on implementing proper security measures.
If you want to compare user names ignoring case, this is an option:
x.UserName.Equals(UserModel.UserName, StringComparison.OrdinalIgnoreCase)
If you want to compare user names case sensitive, this is an option:
x.UserName.Equals(UserModel.UserName, StringComparison.Ordinal)
Update:
For anyone coming to this post who see's my answer, I'd like to point to Steve Py's answer which I've upvoted. And, here is a nice related explanation.
(I figured that I might as well leave my answer here in case it's still helpful for people to see different approaches to comparing strings)

Good way to replace invalid characters in firebase keys?

My use case is saving a user's info. When I try to save data to Firebase using the user's email address as a key, Firebase throws the following error:
Error: Invalid key e#e.ee (cannot contain .$[]#)
So, apparently, I cannot index user info by their email. What is the best practice to replace the .?
I've had success changing the . to a - but that won't cut it since some email's have -s in the address.
Currently, I'm using
var cleanEmail = email.replace('.','`');
but there are likely going to be conflicts down the line with this.
In the email address, replace the dot . with a comma ,. This pattern is best practice.
The comma , is not an allowable character in email addresses but it is allowable in a Firebase key. Symmetrically, the dot . is an allowable character in email addresses but it is not allowable in a Firebase key. So direct substitution will solve your problem. You can index email addresses without looping.
You also have another issue.
const cleanEmail = email.replace('.',','); // only replaces first dot
will only replace the first dot . But email addresses can have multiple dots. To replace all the dots, use a regular expression.
const cleanEmail = email.replace(/\./g, ','); // replaces all dots
Or alternatively, you could also use the split() - join() pattern to replace all dots.
const cleanEmail = email.split('.').join(','); // also replaces all dots
We've dealt with this issue many times and while on the surface it seems like using an email as a key is a simple solution, it leads to a lot of other issues: having to clean/parse the email so it can actually be used. What if the email changes?
We have found that changing the format of how the data is stored is a better path. Suppose you just need to store one thing, the user name.
john#somecompany.com: "John Smith"
changing it to
randomly_generated_node_name
email: "john#somecompany.com"
first: "John"
last: "Smith"
The randomly_generated_node_name is a string that Firebase can generate via childByAutoId, or really any type of reference that is not tied directly to the data.
This offers a lot of flexibility: you can now change the persons last name - say if they get married. Or change their email. You could add an 'index' child 0, 1, 2 etc that could be used for sorting. The data can be queried for any child data. All because the randomly_generated_node_name is a static reference to the variable child data within the node.
It also allows you to expand the data in the future without altering the existing data. Add address, favorite food, an index for sorting etc.
Edit: a Firebase query for email in ObjC:
//references all of the users ordered by email
FQuery *allUsers = [myUsersRef queryOrderedByChild:#"email"];
//ref the user with this email
FQuery *thisSpecificUser = [allUsers queryEqualToValue:#“john#somecompany.com”];
//load the user with this email
[thisSpecificUser observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
//do something with this user
}];
I can think of two major ways to solve this issue:
Encode/Decode function
Because of the limited set of characters allowed in a Firebase key, a solution is to transform the key into an valid format (encode). Then have an inverse function (decode) to transform the encoded key back as the original key.
A general encode/decode function might be transforming the original key into bytes, then converting them to a hexadecimal representation. But the size of the key might be an issue.
Let's say you want to store users using the e-mail as key:
# path: /users/{email} is User;
/users/alice#email.com: {
name: "Alice",
email: "alice#email.com"
}
The example above doesn't work because of the dot in the path. So we use the encode function to transform the key into a valid format. alice#email.com in hexadecimal is 616c69636540656d61696c2e636f6d, then:
# path: /users/{hex(email)} is User;
/users/616c69636540656d61696c2e636f6d: {
name: "Alice",
email: "alice#email.com"
}
Any client can access that resource as long as they share the same hex function.
Edit: Base64 can also be used to encode/decode the key. May be more efficient than hexadecimals, but there are many different implementations. If clients doesn't share the exact same implementation, then they will not work properly.
Specialized functions (ex. that handles e-mails only) can also be used. But be sure to handle all the edge cases.
Encode function with original key stored
Doing one way transformation of the key is a lot easier. So, instead of using a decode function, just store the original key in the database.
A good encode function for this case is the SHA-256 algorithm. It's a common algorithm with implementations in many platforms. And the chances of collisions are very slim.
The previous example with SHA-256 becomes like this:
# path: /users/{sha256(email)} is User;
/users/55bf4952e2308638427d0c28891b31b8cd3a88d1610b81f0a605da25fd9c351a: {
name: "Alice",
email: "alice#email.com"
}
Any client with the original key (the e-mail) can find this entry, because the encode function is known (it is known). And, even if the key gets bigger, the size of the SHA-256 will always be the same, therefore, guaranteed to be a valid Firebase key.
I am using the following code for converting email to hash and then using the hash as key in firebase
public class HashingUtils {
public HashingUtils() {
}
//generate 256 bits hash using SHA-256
public String generateHashkeySHA_256(String email){
String result = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(email.getBytes("UTF-8"));
return byteToHex(hash); // make it printable
}catch(Exception ex) {
ex.printStackTrace();
}
return result;
}
//generate 160bits hash using SHA-1
public String generateHashkeySHA_1(String email){
String result = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] hash = digest.digest(email.getBytes("UTF-8"));
return byteToHex(hash); // make it printable
}catch(Exception ex) {
ex.printStackTrace();
}
return result;
}
public String byteToHex(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
String hex = formatter.toString();
return hex;
}
}
code for adding the user to firebase
public void addUser(User user) {
Log.d(TAG, "addUser: ");
DatabaseReference userRef= database.getReference("User");
if(!TextUtils.isEmpty(user.getEmailId())){
String hashEmailId= hashingUtils.generateHashkeySHA_256(user.getEmailId());
Log.d(TAG, "addUser: hashEmailId"+hashEmailId);
userRef.child(hashEmailId).setValue(user);
}
else {
Log.d(TAG,"addUser: empty emailId");
}
}

How to implement "And"-Condition in ydn db?

I need help in ydn db.
My issue is as follows: How can I fetch records by 2 conditions?
In sql it would be:
"SELECT * FROM store WHERE name='Test' AND cool=1;"
Currently my attempt looks like this:
var keyRange = ydn.db.KeyRange.bound(['Test', true]);
var db = DB.getDatabase();
database
.get('personStore', 'name, cool', keyRange)
.done(function(records) {
console.log(records);
});
Thanks in advance :-)
As discussed in this page, you can use compound index (as you did) or key joining. If you index ['name', 'cool'], you should be able to query by ydn.db.KeyRange.only(['Test', 1]). Note that boolean is not a valid key. Even if cool is boolean value, you have to index as integer value. But my suggestion is index only name and, just query name and filter out cool value on the result set.

Storing DotNetOpenAuth information and user info retrieval

This question is a bit of a structural/design question as I'm having trouble working out the best way to perform the task.
In my MVC app, I am using DotNetOpenAuth (3.4) as my login information provider and just using the standard FormsAuthentication for cookies etc.
The current user table in the DB has:
UserId (PK, uniqueidentifier)
OpenIdIdentifier (nvarchar(255))
OpenIdDisplay (nvarchar(255))
Displayname (nvarchar(50))
Email (nvarchar(50))
PhoneNumber (nvarchar(50))
As the UserId is the clear identifier for a user (they should be able to change their OpenId provider at a later date), it is the key that other tables link to (for a user).
This is the current code, that on a successfull authentication, creates a temporary user and redirects to Create Action.
switch (response.Status)
{
case AuthenticationStatus.Authenticated:
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
var users = new UserRepository();
if (!users.IsOpenIdAssociated(response.ClaimedIdentifier))
{
var newUser = new DueDate.Models.User();
newUser.OpenIdIdentifer = response.ClaimedIdentifier;
newUser.OpenIdDisplay = response.FriendlyIdentifierForDisplay;
TempData["newUser"] = newUser;
return this.RedirectToAction("Create");
}
And now for the crux of the question:
Is the response.ClaimedIdentifier the correct piece of information to be storing against a user?
Is FormAuthentication.SetAuthCookie the preferred way to forms authentication? Or is there a better way?
When I call SetAuthCookie, there is no data relating to the user except for the ClaimedIdentifier. If I'm consistently referring to their UserId, is a better idea to create the user, then store that UserId in the cookie instead of the ClaimedIdentifier?
If I'm using that UserId in a number of places, how do I either retrieve it from the cookie, or store it somewhere else more logical/useful?
A bit long winded but I've been having trouble trying to work out the best way to do this/
1.Is the response.ClaimedIdentifier the correct piece of information to be storing against a user?
Yes. And make sure the column you store it in the database with is case sensitive. Here is a table schema that demonstrates how to make sure it is case sensitive. This comes out of the DotNetOpenAuth project template's database schema. The "CS" bit of the specified collation stand for Case Sensitive.
CREATE TABLE [dbo].[AuthenticationToken] (
[AuthenticationTokenId] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NOT NULL,
[OpenIdClaimedIdentifier] NVARCHAR (250) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
[OpenIdFriendlyIdentifier] NVARCHAR (250) NULL,
[CreatedOn] DATETIME NOT NULL,
[LastUsed] DATETIME NOT NULL,
[UsageCount] INT NOT NULL
);
2.Is FormAuthentication.SetAuthCookie the preferred way to forms authentication? Or is there a better way?
For MVC apps it definitely is, since you still can return your preferred ActionResult from the method.
3.When I call SetAuthCookie, there is no data relating to the user except for the ClaimedIdentifier. If I'm consistently referring to their UserId, is a better idea to create the user, then store that UserId in the cookie instead of the ClaimedIdentifier?
That sounds like personal preference. But I would typically go with user_id, since it might result in a faster database lookup every time an HTTP request comes in that requires you to look up any user information.
4.If I'm using that UserId in a number of places, how do I either retrieve it from the cookie, or store it somewhere else more logical/useful?
FormsAuthentication does provide a way to store more information in its encrypted cookie than just username, but it is harder than you'd expect to use it. This snippet comes out of DotNetOpenAuth's web SSO RP sample:
const int TimeoutInMinutes = 100; // TODO: look up the right value from the web.config file
var ticket = new FormsAuthenticationTicket(
2, // magic number used by FormsAuth
response.ClaimedIdentifier, // username
DateTime.Now,
DateTime.Now.AddMinutes(TimeoutInMinutes),
false, // "remember me"
"your extra data goes here");
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
Response.SetCookie(cookie);
Response.Redirect(Request.QueryString["ReturnUrl"] ?? FormsAuthentication.DefaultUrl);
Then you can get at that extra data in a future HTTP request with this:
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null) {
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (!string.IsNullOrEmpty(ticket.UserData)) {
// do something cool with the extra data here
}
}

Resources