WL#2925: Improve our medium/partial trust footprint

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.