Permissions
Whenever networking classes are used, permissions are required. For networking issues we have three permissions to consider:
DnsPermission
WebPermission
SocketPermission
The DnsPermission is required to do DNS name lookups with the Dns class. The WebPermission is used by classes from the System.Net namespace that use URIs to send and receive data from the Internet; the SocketPermission is used to accept data on a local socket or to connect to a host using a transport protocol.
Applications that are installed locally on a system have full trust, so all permissions are available by default. .NET applications can also be started from a network share, or assemblies can be downloaded from the Internet-in these situations many permissions are not available by default. Therefore, we have to configure the security settings for these applications. First, we are going to discuss the programmatic aspects of the security, and after that we will look at how the permissions can be configured.
DnsPermission
Using the Dns class to make an IP address lookup, we need the DnsPermission. With this permission we only differentiate between allow and deny. Making DNS queries can be either completely unrestricted or not allowed at all.
WebPermission
The WebPermission is required for classes like WebRequest and WebResponse for sending data to and receiving data from the Internet.
Here we differentiate between Accept and Connect permissions. Accept is needed for URIs used inside classes and methods; client applications that use URIs to connect to a server need the Connect privilege. The WebPermission class also has a list for URIs that we can connect to, and a list for URIs that are accepted.
SocketPermission
SocketPermissions are needed for socket classes from the System.Net.Sockets namespace that we deal with in Chapter 4. This is the most flexible permission of the three network permission classes.
For server applications that wait for clients to be connected, we can pass the NetworkAccess.Accept enumeration value in the constructor; client applications that connect to servers use the value NetworkAccess.Connect. We can restrict the connection to specific host and port numbers, and also define a transport protocol used.
Using Permission Attributes
If a required permission is not available, the program fails with an exception of type SecurityException as soon as the privileged method is called. The user may have been using the application for some time when the exception is thrown, and may possibly lose some data if we don't handle the exception gracefully. A good way of avoiding this is to mark the assembly with the permissions that we need.
If we use the WebRequest class to get some data from the Internet, we need the WebPermission permission. We can mark classes and methods that require the permission with the WebPermission attribute (that's implemented in the class WebPermissionAttribute) as follows:
[WebPermission(SecurityAction.Demand,
ConnectPattern="http://www.wrox.com")]
class PermissionDemo
{
In this case, the SecurityException happens as soon as the PermissionDemo class is instantiated. If we want this check at program startup we can apply the WebPermission attribute to the assembly scope:
[assembly: WebPemission(SecurityAction.RequestMinimum,
ConnectPattern="http://www.wrox.com")]
If this WebPermission attribute is applied to the assembly, the runtime checks if the program has the required permission at program startup. If it doesn't have the required permission it stops immediately prior to the user entering (and losing) information.
Using the command-line utility permview that's part of the .NET Framework SDK, we can display the required assembly permissions:
Permission Attribute Parameters
With all permission attributes we can pass a value of the enumeration SecurityAction in the constructor. Here we only look at the most important enumeration values.
SecurityAction Enumeration Values
Description
Demand
Deny
The enumeration values SecurityAction.Demand and SecurityAction.Deny can be used with classes and methods. With Demand we specify that the class or method needs the permission, Deny says that we don't want this permission.
RequestMinimum
RequestOptional
The RequestXXX enumeration value can only be used for assembly scope; it cannot be specified with classes and methods.
RequestRefuse
RequestMinimum defines that this permission is mandatory for using the program. With RequestOptional we say that the program can do some useful work without this permission. Here we have to handle a SecurityException gracefully. RequestRefuse defines that we don't want to have this permission. This is used in cases when there can be some misuse of permissions, such as calling some assemblies when we don't have the sources and we don't trust them fully.
With the WebPermission attribute in addition to the SecurityAction we can set these properties:
WebPermissionAttribute properties
Description
Accept
AcceptPattern
With the Accept property we can define a URI to a resource that can be used within a class, method, or assembly where this attribute applies. With the AcceptPattern property we can specify a regular expression to allow or deny access to URIs.
Connect
ConnectPattern
The two ConnectXX properties are similar to the AcceptXX properties, with the difference that these properties are used for a URI connection string.
The class SocketPermissionAttribute defines these additional properties:
SocketPermissionAttribute properties
Description
Access
With this property we can define the allowed network access method. Just two string values are allowed: Accept and Connect. Accept is used for a server application that listens to and accepts client connections, and Connect is for a client connecting to a server.
Host
With the Host property we can set the host name with DNS syntax or an IP address where the permission applies.
Port
The Port is a string property to specify the port number where we need permission. This can be used to restrict client applications to some specific servers. This property is of type string because different protocols don't necessarily define the port number as an integer.
Transport
With the Transport property we can restrict the network connection to a specific transport protocol. Possible values are All, Connectionless, ConnectionOriented, Tcp, and Udp. Connectionless allows the use of all connectionless protocols such as UDP; ConnectionOriented allows the use of connection-oriented protocols such as TCP.
Strong Name Assemblies
If we start network applications from an intranet or the Internet, we have to assign the permissions we discussed. However, it wouldn't be a pleasant task if these permissions had to be assigned to all Internet or intranet applications-this would be a lot of work and add a tremendous complexity. It would be much better to identify the specific assembly or a group of assemblies to configure permissions only for it.
With .NET, strong names may be used to uniquely identify assemblies, and are also a way to prevent tampering with assemblies.
We will not cover all features of strongly named assemblies in this book. You can read more about them in Professional C# 2nd Edition, Wrox Press (ISBN 1-86100-704-3).
To create a strong name we can create a public/private key pair with the sn utility:
>sn - k mykey.snk
Using the assembly attribute AssemblyKeyFile (the class AssemblyKeyFileAttribute is in the namespace System.Reflection) we add a public key and a signature to the assembly:
[assembly: AssemblyKeyFile("../.. /mykey. snk")]
This strongly named assembly can now be used for security configuration as we will see next.
Configuring Permissions
Applications that are installed locally have full trust by default; configuring these applications is not necessary. If an application is downloaded from the Internet, it has no permissions by default-we have to add the permissions explicitly. When starting applications from an intranet, we have Dns permissions by default, but we must configure the WebPermission and SocketPermission permissions explicitly.
For permission configurations we have the command-line utility caspol.exe, and the .NET Framework Configuration Tool Windows application in the Control Panel.
First, we have to create a new permission set that will be used by our networking application. If you are happy with an existing permission set that already has the required permissions included, it's not necessary to create a new one. With the .NET Framework Configuration Tool I'm creating a new permission set called Network Permissions:
Clicking Next brings us on to a dialog for assigning the permissions to the permission set itself. This permission set includes the required permissions-DNS for name lookups, and Web Access for the WebXX classes. I'm configuring these permissions as unrestricted; you can also restrict the Web Access to a specific URI. The User Interface permission is needed for Windows applications.
For the assembly that needs these permissions I'm creating a new code group, Professional .NET Networking Zone:
With this code group the condition type can be specified to define the assemblies that belong to this code group. The condition can be an application directory, a URI, or a site for example. Here I'm selecting the strong name condition and importing the strong name of the assembly created earlier. Selecting the check boxes for the name and version would restrict the code group to this specific assembly. Without selecting these options the code group includes all assemblies that use the same public key:
Pressing the Next key selects the previously created permission set for this code group.
With this configuration it is now possible to start the network application from a network share, or downloaded with a link from a web server.
You can read more about .NET permissions in Professional C# 2nd Edition, Wrox Press (ISBN 1-86100-704-3).