WL#2925: Improve our medium/partial trust footprint

Affects: Connector/.NET-6.5   —   Status: In-Documentation   —   Priority: Low

The connector doesn't work correctly under medium or partial trust scenarios.  
This worklog will correct that via two changes.  

One we will provide a Permission class that allows hosters to provide MySQL 
support without opening up generic permissions such as SocketPermission.  The 
second change will be introducing some permission asserts throughout the code.  
This will enable our code to function correctly when installed in the GAC.

We are not really attempting to make our provider work well in medium or partial 
trust scenarios when not installed in the GAC.  Our story to site hosters will be 
that they need to install our provider in the GAC and then add 
MySqlClientPermission to their trust policy.
The first required element will be a MySqlClientPermission class.  This class will 
function just like SqlClientPermission.  An application or host can include this 
permission in it's trust policy to allow use of our provider.  If this permission 
is not included, then our connector doesn't function.

At the code level, this will essentially be our code issuing a Demand for this 
permission.  Please review the documentation around CAS and demanding a cetain 
permission.


The second part of this worklog will be including impertiave asserts for various 
permissions throughout the code.  An example is SocketPermission.  In order to be 
able to connect to a remote socket, you have to  Assert that you have 
SocketPermission to do do.  This will be in code and I *think* you have to qualify 
every single request by host and by port.  

We would need to check performance and make sure that this addition doesn't 
adversely affect performance.

We would need additional asserts throughout the code for things like TraceSource 
(for tracing), for pinvoke (for our named pipe and shared memory code), etc. 

To test this just create a website and set it's web.config to be in medium trust 
mode.  Then attempt to use the website to do things with our connector.  You'll 
see the areas where security exceptions are thrown due to missing permissions.
1 - Using Connector/Net under Medium Trust and the library installed in the GAC

- This documentation covers the implementation released in 6.5.4, 6.6.1, 6.6.2

Connector/Net is enable to work on Medium Trust environments when the library 
is in the GAC and a proper configuration into the web_mediumtrust.config file 
is included (as described below).

This implementation has the following benefits:

		--- ISP can use the default medium trust configuration 
without having to elevate their security or trust level when providing 
Connector/Net for their clients applications.
		--- ISP can enhance and customized the access allowed for 
their MySQL Server defining this at a machine-level Web.config file which makes 
easy to have a higher security in the use of their shared System resources.
		--- The MySQLClientPermissions class allows to define 
specific configurations to which connection string parameters can be used in 
their hosted applications.
		--- ISP can define a custom policy file based on the 
existing Web_MediumTrust.config of the .Net framework.

1.1 Set up for the library when using 6.5.4, 6.6.1, 6.6.2 

To set up this approach should be done the following

- Install one of these Connector/Net versions: 6.5.4, 6.6.1, 6.6.2

- After installing the library the following configuration should be done:

In the Security Classes a definition for the MySqlClientPermission should be 
added including the version to use (6.5.4 or later).
		
<configuration>
    <mscorlib>
        <security>
            <policy>
                <PolicyLevel version="1">
                    <SecurityClasses>
					.
					.
					.
					.
					<SecurityClass 
Name="MySqlClientPermission" 
Description="MySql.Data.MySqlClient.MySqlClientPermission, MySql.Data, 
Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
					.
					.
					.
					
In the NamedPermissionSets PermissionSet a new entry should be added in order 
to allow Database connections in the clients applications.
				
					.
					.
					.
				
				   <PermissionSet
                                class="NamedPermissionSet"
                                version="1"
                                Name="ASP.Net">
	
					.
					.
					.
	
				  <IPermission
							
	class="MySqlClientPermission"
							
	version="1" Unrestricted="true"				
				
							/>
				  
		


Note: The above configuration will give an unrestricted use of settings in all 
the connections strings of the .net applications.

In order to customize or restrict the settings of the connections a specific 
configuration should be done based in a predefined set of settings. So instead 
of use the previous configuration some settings need to be added.

The following example allows connection strings that use any database, but only 
on the server specified, with any user and password combination and containing 
no other connection string keywords:

					<IPermission 
class="MySqlClientPermission" version="1">
						<add 
connectionString="Server=ServerName;"
					
	restrictions="database=; user id=; password=;"
					
	KeyRestrictionBehavior="AllowOnly" />
					</IPermission>


			
How to use MySQLClientPermissions class to define Database access security 
policies.

MySQLClientPermissions is an implementation based on the abstract class 
DBDataPermission which allows to explicitly define policies that can be used to 
give access to users inside an application when using MySQL databases and 
Connector/Net.

Constructors:

  public MySqlClientPermission(PermissionState permissionState) : Initialize a 
new instance of the MySqlClientPermission class.
  
 Overridden Methods:

	Add(string connectionString, string restrictions, 
KeyRestrictionBehavior behavior);
  
	IPermission Copy()

Examples:


The following code throws a Security Exception when the user attempts to make a 
Connection with a Connection string that doesn't match the policy defined 
previously:
 
     PermissionSet permissionset = new PermissionSet(PermissionState.None);

      MySqlClientPermission permission = new MySqlClientPermission
(PermissionState.None);

      MySqlConnectionStringBuilder strConn = new MySqlConnectionStringBuilder
(conn.ConnectionString);

      //// Allow connections only to specified database no additional optional 
parameters     
      permission.Add("server=localhost;User Id=root; 
database=YOURDATABASENAME;", "", KeyRestrictionBehavior.PreventUsage);
      permission.PermitOnly();
      permissionset.AddPermission(permission);
      permissionset.Demand();

      // this connection should NOT be allowed
      MySqlConnection dummyconn = new MySqlConnection();
      dummyconn.ConnectionString = "server=localhost;User 
Id=root;database=ADIFFERENTNAME;";
      dummyconn.Open();      
      if (dummyconn.State == ConnectionState.Open) dummyconn.Close();        


This example shows how a connection is properly done after setting the Security 
Policy

   PermissionSet permissionset = new PermissionSet(PermissionState.None);

      MySqlClientPermission permission = new MySqlClientPermission
(PermissionState.None);

      MySqlConnectionStringBuilder strConn = new MySqlConnectionStringBuilder
(conn.ConnectionString);
      
      //// Allow connections only to specified database no additional optional 
parameters     
      permission.Add("server=localhost;User 
Id=root;database=YOURDATABASENAME;port=" + strConn.Port + ";", "", 
KeyRestrictionBehavior.PreventUsage);
      permission.PermitOnly();
      permissionset.AddPermission(permission);
      permissionset.Demand();

      // this conection should be allowed
      MySqlConnection dummyconn = new MySqlConnection();
      dummyconn.ConnectionString = "server=localhost;User 
Id=root;database=YOURDATABASENAME;port=" + strConn.Port ";
      dummyconn.Open();    
      if (dummyconn.State == ConnectionState.Open) dummyconn.Close();

					
						
2 - Using Connector/Net under Medium Trust with the library without installing 
it in the GAC with 6.5.5, 6.6.4 and further versions

You can also have Medium trust support using any of the following versions: 
6.5.5, 6.6.3 or further, without installing the library in the GAC and use it 
from a bin or lib directory included in your solution or project.

There are some configurations needed since Medium trust policy doesn't have 
Socket Permissions supported so you must add it to the medium trust policy.

Open the medium trust policy web config file which should be under this 
folder : (%windir%\Microsoft.NET\Framework\{version}
\CONFIG\web_mediumtrust.config (or Framework64 if you're using a 64 bit 
installation of the Framework)

You should add:

Inside the SecurityClasses tag:

<SecurityClass Name="SocketPermission" 
Description="System.Net.SocketPermission, System, Version=4.0.0.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

Scroll down and look for the following PermissionSet:

	<PermissionSet version="1" Name="ASP.Net">
	

Add the following inside this PermissionSet:
	
<IPermission class="SocketPermission" version="1" Unrestricted="true" />	

This configuration will allow that you can use the driver with the tcp protocol 
which is the default in Windows without having any security issues. This 
approach only supports the tcp protocol so you cannot use any other type of 
connection. 

Also please notice that since the MySQLClientPermissions is not added to the 
medium trust policy you cannot use it. This configuration is the minimum 
required in order to work with the Connector without the GAC. 


3 - Using Connector/Net under Medium Trust with the library installed in the 
GAC in 6.5.5, 6.6.3 and further versions

If the library is installed in the GAC (versions 6.5.5, 6.6.4) you also need to 
include the MySqlClientPermissions in the security policy and configure the 
web_mediumtrust.config file as describe in the Section 1.1.

This version introduced a new setting that performs the security asserts by 
demand when the includesecurityasserts setting is set to true in the Connection 
String. If the user has his application on a Medium trust Hosting Service 
he/she must include the includesecurityassert=true setting when opening a 
Connection to avoid any security issue since the policy for medium trust 
doesn't include the Socket Permissions, Dns Permissions, Reflection among 
others. In this case the library should ask their own permissions in order to 
establish a connection.


3.1 How to use MySQLClientPermissions in 6.5.5, 6.6.4 and further versions

Since this version handles the security asserts in a demanding way. The only 
change to the use of the MySqlClientPermissions class was to add the 
includesecurityasserts=true setting in the Connection String. 

Examples:

The following code throws a Security Exception when the user attempts to make a 
Connection by using a Connection string that doesn't match the correct settings. 
This scenario covers when using MySqlClientPermissions class to define the 
allowed connection string settings in the application.
 
     PermissionSet permissionset = new PermissionSet(PermissionState.None);

      MySqlClientPermission permission = new MySqlClientPermission
(PermissionState.None);

      MySqlConnectionStringBuilder strConn = new MySqlConnectionStringBuilder
(conn.ConnectionString);

      //// Allow connections only to specified database no additional optional 
parameters     
      permission.Add("server=localhost;User Id=root; 
database=YOURDATABASENAME;", "", KeyRestrictionBehavior.PreventUsage);
      permission.PermitOnly();
      permissionset.AddPermission(permission);
      permissionset.Demand();

      // this connection should NOT be allowed
      MySqlConnection dummyconn = new MySqlConnection();
      dummyconn.ConnectionString = "server=localhost;User 
Id=root;database=ADIFFERENTNAME;includesecurityasserts=true;";
      dummyconn.Open();      
      if (dummyconn.State == ConnectionState.Open) dummyconn.Close();        


This example shows how a connection is properly done after setting the Security 
Policy

   PermissionSet permissionset = new PermissionSet(PermissionState.None);

      MySqlClientPermission permission = new MySqlClientPermission
(PermissionState.None);

      MySqlConnectionStringBuilder strConn = new MySqlConnectionStringBuilder
(conn.ConnectionString);
      
      //// Allow connections only to specified database no additional optional 
parameters     
      permission.Add("server=localhost;User 
Id=root;database=YOURDATABASENAME;port=3306;includesecurityasserts=true;", "", 
KeyRestrictionBehavior.PreventUsage);
      permission.PermitOnly();
      permissionset.AddPermission(permission);
      permissionset.Demand();

      // this conection should be allowed
      MySqlConnection dummyconn = new MySqlConnection();
      dummyconn.ConnectionString = "server=localhost;User 
Id=root;database=YOURDATABASENAME;port=3306;
      dummyconn.Open();    
      if (dummyconn.State == ConnectionState.Open) dummyconn.Close();

	  
	  
Summary:


We have two approaches when supporting Medium Trust. One with the Library in 
the GAC and the other with the library only in a bin or lib folder inside a 
project or solution. If the library is in the GAC an additional 
configuration should be done in the medium trust policy. If the library is not 
in the GAC the only protocol supported is tcp.