Bug #42574 ValidateUser does not use the application id, allowing cross application login
Submitted: 3 Feb 2009 21:50 Modified: 5 Mar 2009 11:26
Reporter: Craig Nagy Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / NET Severity:S3 (Non-critical)
Version:5.2.5 OS:Any
Assigned to: CPU Architecture:Any
Tags: applicationname, membershipprovider, validateuser

[3 Feb 2009 21:50] Craig Nagy
Description:
MySQLMembershipProvider.ValidateUser only uses the userId to validate. It must also use the applicationId. It looks like this was intended, but left out of the actual sql query string.

Example Generated Query:
SELECT Password, PasswordKey, PasswordFormat, IsApproved,
Islockedout FROM my_aspnet_Membership WHERE userId=13

How to repeat:
1. Create two applications using the same provider, with different applicationNames
2. Create a user in one application with a set user name (e.g. XXXXX)
3. Login to the _other_ application using the same user name
4. Login will succeed when it shouldn't.

Suggested fix:
Add the applicationId criteria to the sql query. Note, the correct parameter is already being added.

Line ~1073:
string sql = @"SELECT Password, PasswordKey, PasswordFormat, IsApproved,
Islockedout FROM my_aspnet_Membership WHERE userId=@userId AND applicationId=@appId";

MySqlCommand cmd = new MySqlCommand(sql, connection);
cmd.Parameters.AddWithValue("@userId", userId);
cmd.Parameters.AddWithValue("@appId", applicationId);
[3 Feb 2009 22:28] Craig Nagy
Sorry, fix is incorrect. There is no applicationId in the my_aspnet_Membership table. Perhaps fix should be in GetUserId. Users should be retrieved with application id in mind.
[4 Feb 2009 8:27] Tonci Grgin
Hi Craig and thanks for your report.

AFAIS in latest sources, same error is present, both for unreleased versions and 5.2:
    // first get the user id.  If that is -1, then the user doesn't exist
    // so we just return false since we can't bump any counters
    int userId = GetUserId(connection, username);
    if (-1 == userId) return false;

    string sql = @"SELECT Password, PasswordKey, PasswordFormat, IsApproved,
                 Islockedout FROM my_aspnet_Membership WHERE userId=@userId";
                 MySqlCommand cmd = new MySqlCommand(sql, connection);
    cmd.Parameters.AddWithValue("@userId", userId);
    cmd.Parameters.AddWithValue("@appId", applicationId); <<<

Verified as described by looking into sources although not using AppID is not an error per-se but the way things can be set up, according to MSDN:
http://msdn.microsoft.com/en-us/library/0580x1f5.aspx
 ApplicationName property	

The application name that is stored with each profile. The profile provider uses the application name to store profile information separately for each application. This enables multiple ASP.NET applications to use the same data source without a conflict if the same user name is created in different applications. Alternatively, multiple ASP.NET applications can share a profile data source by specifying the same application name.

So it is my opinion you should lover the severity of reported problem to at least S3 if not S4.
[4 Feb 2009 14:06] Craig Nagy
Severity lowered to S3 per Tonci's comment since it's likely that the situation encountered is rare. However, it seems like a potentially serious security hole since two applications sharing the provider may expect users to be maintained separately.

Applying the fix to GetUserById as follows resolves the issue.

private int GetUserId(MySqlConnection connection, string username)
{
  MySqlCommand cmd = new MySqlCommand(
    "SELECT id FROM my_aspnet_Users WHERE name LIKE @name AND applicationId=@appId", connection);
  cmd.Parameters.AddWithValue("@name", username);
  cmd.Parameters.AddWithValue("@appId", applicationId);
  object id = cmd.ExecuteScalar();
  if (id == null) return -1;
  return (int)id;
}
[4 Feb 2009 14:48] Craig Nagy
applicationId is also missing from the query in IsUserInRole.
[4 Feb 2009 17:43] Tonci Grgin
Craig, thank you.

I do see this as rare complication but all necessary code seems to be in place so I notified c/NET team leader to take a look at this.
[4 Mar 2009 7:01] Tonci Grgin
Same problem reported in Bug#43339.
[4 Mar 2009 16:20] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/68268
[4 Mar 2009 16:21] Reggie Burnett
fixed in 5.2.6
[5 Mar 2009 11:26] Tony Bedford
An entry was added to the 5.2.6 changelog:

MySQLMembershipProvider.ValidateUser only used the userId to validate. However, it should also use the applicationId to perform the validation correctly.

The generated query was, for example:

SELECT Password, PasswordKey, PasswordFormat, IsApproved, Islockedout 
FROM my_aspnet_Membership WHERE userId=13

Note that applicationId is not used.