I. Introduction

La problématique de la sécurisation des applications a toujours été complexe par le fait qu'elle n'est pas dissociable de l'administration du poste de travail.

On distingue généralement dans les concepts de sécurité les cas suivants :

  • Qualité du code
  • Cryptographie
  • Authentification & Privilège

Qualité du code

Très souvent, les concepts de l'authentification et des privilèges font défaut. En effet, au niveau du poste de travail, c'est l'authentification qui donne accès à un certain nombre de privilèges selon l'appartenance à un groupe d'utilisateurs et/ou par attribution de droits spécifiques à un utilisateur donné.

Ceci induit un problème maintenant bien connu, puisqu'une application possède généralement les privilèges du compte qui l'exécute.

Il y a fort peu de chances que les utilisateurs deviennent spontanément les experts administrations ce qui est pourtant la condition sine qua non d'une véritable sécurité. Le Framework .Net utilise aussi une technique de gestion des privilèges appelée « sécurité d'accès au code »

II. Concepts généraux

La sécurité d'accès au code propose sur le principe de l'attribution de privilèges selon l'origine du code. On retrouve ce concept parfois sous le nom de preuve par l'origine. Comme pour la sécurité Windows, ce système de sécurité se doit d'être administré. Dans son principe général, le Framework considère l'existence de zones dites « de sécurité » permettant ou non l'accès à un certain nombre de privilèges. Évidemment, le compte de l'utilisateur doit posséder les privilèges nécessaires à l'exécution. Autrement dit, il s'agit d'un contrôle de sécurité qui ne préempte pas sur la sécurité système.

II-A. Zones de sécurité

Le Framework définit 5 zones de sécurité :

  • Sites sensibles ( Sites identifiés ainsi dans votre navigateur
  • Internet ( Application s'exécutant depuis Internet hors sites sensibles ou de confiance
  • Sites de confiance ( Sites identifiés ainsi dans votre navigateur
  • Intranet ( Applications installées sur l'Intranet du poste
  • Poste de Travail ( Applications installées sur l'ordinateur

Sites sensibles ( Sites identifiés ainsi dans votre navigateur

C'est zones de sécurité ne font rien par elle-même, elle détermine juste un niveau de confiance auquel est associé un jeu d'autorisations. C'est celui-ci qui détermine les ressources accessibles.

Comme nous le verrons un peu plus loin, il est possible d'ajouter de nouvelles zones de sécurité le cas échéant

II-B. Jeu d'autorisations

Parfois appelé aussi niveau de confiance. Il existe des jeux nommés déjà définis :

Jeu d'autorisations Description
Nothing Pas d'autorisations (le code ne s'exécute pas).
Execution Autorisations d'exécuter sans utiliser des ressources protégées.
Internet Jeu d'autorisations de la stratégie par défaut adaptée au contenu d'origine inconnue.
LocalIntranet Jeu d'autorisations de la stratégie par défaut au sein d'une entreprise.
Everything Toutes autorisations standard (intégrées), à l'exception de l'autorisation d'ignorer la vérification.
SkipVerification Ignorer la vérification
FullTrust Accès intégral à toutes les ressources.

Les jeux d'autorisations Intranet et Internet possèdent des autorisations qui sont définies par les stratégies de sécurité du poste de travail, de l'entreprise et/ou de l'utilisateur.

Le Framework expose les autorisations suivantes :

Nom de classe de l'autorisation Droit correspondant
AspNetHostingPermission Accès aux ressources dans des environnements hébergés par ASP.NET.
DirectoryServicesPermission Accès aux classes System.DirectoryServices.
DnsPermission Accès au système de noms de domaine (DNS).
EnvironmentPermission Lecture ou écriture de variables d'environnement.
EventLogPermission Accès en lecture ou en écriture aux services de journaux des événements.
FileDialogPermission Accès aux fichiers que l'utilisateur a sélectionné dans une boîte de dialogue Ouvrir.
FileIOPermission Lecture, ajout ou écriture de fichiers ou de répertoires.
IsolatedStorageFilePermission Accès à un stockage isolé, c'est-à-dire un stockage associé à un utilisateur particulier et à certains aspects de l'identité du code, tel que son site Web, son éditeur ou sa signature.
MessageQueuePermission Accès aux files d'attente de messages par le biais des interfaces MSMQ (Microsoft Message Queuing).
OdbcPermission Accès à une source de données ODBC.
OleDbPermission Accès à des bases de données utilisant OLE DB.
OraclePermission Accès à une base de données Oracle.
PerformanceCounterPermission Accès aux compteurs de performance.
PrintingPermission Accès aux imprimantes.
ReflectionPermission Identification d'informations se rapportant à un type au moment de l'exécution.
RegistryPermission Lecture, écriture, création ou suppression de clés et de valeurs de la base de registres.
SecurityPermission Exécution, assertion d'autorisations, appel dans du code non managé, omission de vérification et autres droits.
ServiceControllerPermission Accès à des services en cours d'exécution ou arrêtés.
SocketPermission Établissement ou acceptation de connexions sur une adresse de transport.
SqlClientPermission Accès à des bases de données SQL.
UIPermission Accès aux fonctionnalités de l'interface utilisateur.
WebPermission Établissement ou acceptation de connexions sur une adresse Web.

Chacune de ces classes peut gérer un grand nombre d'autorisations spécifiques avec plusieurs types d'accès différents. Par exemple chaque variable d'environnement peut être définie séparément, pour un accès en lecture et/ou en écriture ou pour en interdire l'accès.

Le nombre de jeu de permissions réalisable est donc gigantesque.

II-C. Outil d'administration

Il existe de nombreux outils pour manipuler ces concepts de sécurité. Le plus simple à utiliser ce trouve dans le panneau de configuration, c'est l'outil de configuration du Framework.

Il se présente sous la forme suivante :

Image non disponible

A partir de ce gestionnaire, il est possible d'ajouter des zones de sécurité, de créer et/ou de modifier des jeux de permissions, etc….

Par exemple je peux créer assez facilement un jeu d'autorisation :

Pour cela il suffit de sélectionner « Jeux d'autorisations » dans le volet de gauche, de cliquer sur le lien « Créer un nouveau jeu d'autorisations ». Puis de suivre les instructions, par exemple :

Image non disponible
Image non disponible
Image non disponible

III. Principe de fonctionnement

Généralement, c'est parce qu'on ne comprend pas bien le cheminement de l'évaluation qu'on se trompe.

III-A. Preuves & autorisations

Lors du chargement d'un assembly, le runtime commence par évaluer les preuves fournies pas l'assembly. Comme nous l'avons dit, celles-ci sont toujours aux moins fixées par la zone de sécurité d'où s'exécute l'assembly, mais il peut en posséder d'autres, tel qu'un nom fort, un chemin d'accès spécifique, un certificat, etc.…

Selon ces preuves, le runtime calcule un jeu d'autorisation. Si à un moment votre code appelle une ressource sans en avoir l'autorisation, il y a levée d'une exception.

Commençons à définir, les règles de fonctionnement :

Règle n 1 : C'est toujours la stratégie de sécurité qui attribue les autorisations

Autrement dit, vous n'avez pas la certitude qu'un code fonctionnant sur un poste avec ses preuves fonctionnera sur un autre poste avec les mêmes preuves car la stratégie de sécurité peut différer d'un poste à l'autre.

Règle n 2 : On ne peut pas obtenir par le code des autorisations non données par la stratégie de sécurité

Votre code ne peut pas augmenter ses privilèges.

Règle n 3 : C'est au développeur de gérer les exceptions de sécurité

Sans gestion de la sécurité, le programme s'arrêtera de fonctionner lors de l'appel de la ressource interdite.

Pour pouvoir anticiper sur ces erreurs éventuelles, le Framework met à votre disposition des mécanismes de demandes d'autorisation que nous verrons un peu plus loin.

III-B. Vérification des appelants

Comme vous l'avez surement remarqué, il y a un défaut à la cuirasse. Si la principale source de preuve est l'origine, tout assembly installé sur le poste de travail puis exécuté recevra le jeu d'autorisations maximales. Tout comme pour la sécurité du système d'exploitation, il incombe à l'utilisateur de savoir ce qu'il fait.

Par extension, on pourrait croire qu'un code s'exécutant d'une zone de sécurité restreinte peut augmenter ses privilèges en appelant un assembly installé sur le poste de travail. Ceci est faux, car le Framework implémente un contrôle de sécurité des appelants appelé communément « parcours de pile ».

Dans le principe, lors de l'appel d'une ressource protégée par un code managé, le CLR parcours en remontant la pile des appelants de la méthode qui sollicite la ressource. Si un de ces appelants n'a pas l'autorisation nécessaire, l'appel de la méthode échoue et une exception est levée. Il est possible d'influer sur le parcours de pile par le code.

IV. Utilisation

Ne perdons pas de vue que dans certains cas, les vérifications de sécurité sont inutiles. Par exemple si votre code ne nécessite aucune ressource protégée ou si votre assembly ne peut pas être appelé par un code tierce.

IV-A. Vérification de ses autorisations

Comme la règle 2 nous le dit, le contrôle des autorisations ne change rien au fait qu'une ressource interdite le sera mais permet uniquement de savoir quand l'exception sera levée et traitée.

Pour comprendre cela, envisageons le cas suivant. Je crée une application de type WinForms qui lit un fichier XML (un dataset) et l'affiche dans une grille. Le code est aussi simple que :

 
Sélectionnez
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim MonDS As New Data.DataSet("biblio")
        MonDS.ReadXml("d:\tutoriel\pubs.xml", XmlReadMode.ReadSchema)
        Me.DataGrid1.DataSource = MonDS.Tables(0)
    End Sub

Comme le fichier existe bien et sur mon poste de travail le code s'exécute correctement, j'affiche bien ma table dans ma grille. Maintenant, j'upload l'exécutable sur internet. Avec mon navigateur, je vais sélectionner cet exécutable.

Je vais recevoir un premier message d'alerte de la forme :

Image non disponible

Comme nous l'avons vu, il est maintenant plus sur d'exécuter le code distant que de l'enregistrer sur le disque, puisqu'une fois sur le disque dur, il sera considéré comme un code de confiance totale. Je clique donc sur le bouton « Exécuter ».

Le navigateur m'envoie un deuxième message d'erreur, tel que :

Image non disponible

Celui-ci est du à l'absence de certificat de mon exécutable. Il y aurait beaucoup à dire sur la sécurité et les certificats, cependant demander l'exécution d'un code sans certificat peut déclencher l'apparition de cette boite de dialogue selon le paramétrage du navigateur. Je clique donc une nouvelle fois sur « Exécuter » et j'obtiens :

Image non disponible

Nous voyons bien que la stratégie de sécurité a joué son rôle et qu'un code issu de la zone de sécurité « Internet » ne peut pas utiliser des ressources de fichier locales. A ce moment l'erreur se produit bien sur la ligne :

 
Sélectionnez
MonDS.ReadXml("d:\tutoriel\pubs.xml", XmlReadMode.ReadSchema)

Si vous voulez en être sur, il suffit d'ajouter la ligne :

 
Sélectionnez
MessageBox.Show("je charge le dataset maintenant")

Juste avant l'appel de ReadXML. Dans ce cas vous verrez apparaître la boite de message puis l'erreur.

Le fait que cette boite de dialogue s'affiche alors que le code va et doit lever une exception n'est pas une bonne chose. Pour éviter le problème on procède généralement à des vérifications d'autorisation.

IV-A-1. Sécurité déclarative

La sécurité déclarative consiste à indiquer au niveau de l'assembly, les autorisations exigées, optionnelles ou refusées. On utilise pour cela, dans le manifeste de l'assembly, des attributs de permissions qui définissent celles-ci. La forme sera toujours :

<Assembly:ClassePermissionAttribute(SecurityAction.Request…,[Param])>

Les SecurityAction déclaratives sont généralement :

RequestMinimumDemande des autorisations minimales pour que le code fonctionne.
RequestOptionalDemande d'autorisations supplémentaires et facultatives (non requises pour le fonctionnement).
RequestRefuseDemande pour que les autorisations qui peuvent être utilisées abusivement ne soient pas accordées au code appelant.

Comment cela fonctionne-t-il ?

Lors du chargement de l'assembly, le CLR calcule les autorisations que possède l'assembly. Si tout ou partie des autorisations requises ne peuvent être accordées, aucun code de l'assembly ne sera exécutée et une exception de sécurité sera levée. Si tout ou partie des autorisations optionnelles ne peuvent être accordées, il y a aussi levée d'une exception mais le code de l'assembly peut s'exécuter.

Imaginons que dans mon code précédant, j'ajoute dans le manifeste de l'assembly les deux attributs suivants :

 
Sélectionnez
<Assembly: Security.Permissions.FileIOPermission(Security.Permissions.SecurityAction.RequestMinimum, _
 Read:="d:\tutoriel\pubs.xml")> 
<Assembly: Security.Permissions.FileIOPermission(Security.Permissions.SecurityAction.RequestOptional, _
 Write:="d:\tutoriel\pubs.xml")> 

Si j'exécute ce code depuis Internet, j'obtiens une erreur non récupérable (sauf à lancer le debogueur). Ce n'est pas tellement plus propre me direz-vous. En effet, on ne doit pas perdre de vue que toute cette gestion est basée sur la vérification des appelants. En l'occurrence, mon code n'a pas d'appelant, les exceptions au niveau assembly ne peuvent être interceptées, je dois donc gérer mes vérifications autrement.

IV-A-2. Sécurité impérative

La sécurité impérative se gère au moment de l'exécution. Elle présente l'avantage d'être applicable au niveau de la classe ou de la méthode, mais elle induit que le code d'un assembly de confiance partielle va s'exécuter jusqu'au moment de la vérification.

Reprenons notre code précédent, en utilisant la sécurité déclarative :

 
Sélectionnez
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim MonDS As New Data.DataSet("biblio")
        MessageBox.Show("je charge le dataset maintenant")
        Dim MaPerm As New Security.Permissions.FileIOPermission(Security.Permissions.PermissionState.Unrestricted, _
 "d:\tutoriel\pubs.xml")
        Try
            MaPerm.Demand()
        Catch ex As Exception
            MessageBox.Show("vous n'avez pas l'autorisation nécessaire", "Erreur", _
 MessageBoxButtons.OK, MessageBoxIcon.Error)
            Me.Close()
        End Try
        MonDS.ReadXml("d:\tutoriel\pubs.xml", XmlReadMode.ReadSchema)
        Me.DataGrid1.DataSource = MonDS.Tables(0)
    End Sub

Là à l'exécution je verrais bien apparaître ma boite de dialogue annonçant l'erreur et l'exécution s'arrêtera.

Cependant l'appel explicite d'une demande force très souvent un parcours de pile inutile. En effet, comme nous l'avons vu dans le premier exemple, il y a eu un parcours de pile généré par l'appel de la méthode ReadXML du dataset. On utilise généralement Demand de façon explicite lorsqu'on souhaite protéger des ressources qui ne sont pas protégées naturellement par le Framework.

IV-B. Augmenter les privilèges

Dans les cas comme celui-là, on a trop souvent tendance à prendre des mesures disproportionnées par rapport au problème. Bien sur mon exemple est loin d'être un cas réel car on se demande bien quel serait l'intérêt d'un tel code. Cependant pour contourner les problèmes, on a trop souvent tendance à vouloir modifier la stratégie de sécurité ou de forcer l'installation sur le poste de travail. Ce qui nous mène à la règle suivante :

Règle n 4 : L'ignorance et la fainéantise sont les deux plus grandes failles de sécurité.

En effet, avant d'envisager forcément un octroi démesuré de droit sur la zone « Internet » ou de forcer l'installation locale, il est plus sage de définir un ou plusieurs nouveaux groupes de code sur lequel on appliquera une accumulation de preuve donnant droit à des accès. Ainsi dans mon cas, je pourrais créer un jeu d'autorisation donnant accès à mon fichier XML, puis créer un groupe de code qui vérifierais le nom fort et le site d'origine de l'appelant et en cas de concordance lui octroyer ce jeu d'autorisations. Bien sur, cela demande d'intervenir sur la stratégie de sécurité du poste, ce qui peut être lourd si vous ciblez de nombreux poste, mais il est possible de préparer des fichiers XML permettant de simplifier l'opération.

Dans certains cas, on peut aussi envisager des stratégies de déploiement particulières, d'utiliser le stockage isolé, etc.

IV-C. Parcours de pile

La sécurité repose donc sur le parcours de la pile des appelants. Dans certains cas, il peut être intéressant de modifier l'action de celle-ci, sous réserve de prendre en charge les implications de sécurité. Ces opérations qu'on retrouve sous le nom de substitution de vérification de sécurité sont de deux sortes :

IV-C-1. Assert

L'assertion indique que vous pouvez exécuter une tache pour un appelant moins sécurisé. Autrement dit, vous savez que votre composant va interagir sans risque avec une ressource protégée et qu'aucun code appelant ne peut détourner votre code. Dans ce cas, vous pouvez faire un appel à Assert pour bloquer les vérifications de sécurité pour la ou les permissions désignées comme cible de l'assertion.

IV-C-2. PermitOnly & Deny

Ce sont les substitutions inverses de l'assertion. Le but est de refuser des autorisations au code appelant. PermitOnly refuse toute les autorisations qui ne sont pas comprises dans le jeu soumis à PermitOnly, Deny refuse toutes celles qui sont comprises dans ce jeu. On utilise l'un ou l'autre selon qu'il soit plus court de décrire un jeu de celles qui sont autorisées ou de celles qui ne le sont pas. PermitOnly permet aussi de résoudre certains problèmes de représentation canonique.

IV-C-3. Règles d'utilisation

Les substitutions de sécurité doivent toujours être explicitement annulées à l'aide d'une des méthodes suivantes : RevertAll, RevertAssert, RevertDeny ou RevertPermitOnly.

Le code utilisant une substitution doit être hautement sécurisé. Les substitutions peuvent avoir des effets redoutables si vous n'en comprenez pas bien les implications. Par exemple un Appel de type PermitOnly sur le système de fichier peut interdire tout appels ultérieurs par les appelants en aval de l'interface utilisateur. Vous ne devez donc substituer qu'en toute connaissance de cause.

IV-C-4. Exemple

Jusqu'à présent, j'ai écrit du code de goret puisque le seul but était de montrer le principe des autorisations. Appliquons nous maintenant, puisque pour la suite nous allons générer un composant de code. Créons la classe suivante :

 
Sélectionnez
Imports System.Security
Imports System.Data
Imports System.IO
<Assembly: AllowPartiallyTrustedCallers()> 
Public Class DtsXML
 
    Private m_FileName As String = ""
 
    Public Sub New()
 
    End Sub
 
    Public Sub New(ByVal Fichier As String)
        Me.NomFichier = Fichier
    End Sub
 
    Public Property NomFichier() As String
        Get
            Return m_FileName
        End Get
        Set(ByVal Value As String)
            m_FileName = Value
        End Set
    End Property
 
    Public Function ExtractDataset() As DataSet
 
        If Me.NomFichier.Length = 0 OrElse Me.NomFichier.EndsWith("xml") = False Then
            Throw New ArgumentException("Le nom de fichier n'est pas valide")
            Return Nothing
        End If
        Dim MonDts As New DataSet
        Dim pAssert As New Permissions.FileIOPermission(Permissions.FileIOPermissionAccess.Read, Me.NomFichier)
        Dim pDeny As New Permissions.FileDialogPermission(Permissions.PermissionState.Unrestricted)
        pAssert.Assert()
        pDeny.Deny()
        Try
            MonDts.ReadXml(Me.NomFichier, XmlReadMode.ReadSchema)
        Catch ex As FileNotFoundException
            Throw New ApplicationException("Le fichier" & Me.NomFichier & " n'est pas accessible")
        Catch ex As Xml.XmlException
            Throw New ApplicationException("Le fichier " & Me.NomFichier & " n'est pas un fichier xml valide")
        Finally
            pAssert.RevertAssert()
            pDeny.RevertDeny()
        End Try
        Return MonDts
    End Function
 
End Class

Quelques remarques sur ce code. J'ai écris un composant que je souhaite déployer dans le cache global d'assemblies (GAC). Dès lors je vais devoir lui donner un nom fort. Pour qu'un assembly ayant un nom fort puisse être invoqué par du code partiellement fiable, je dois lui ajouter l'attribut AllowPartiallyTrustedCallers.

Pour que ce composant soit utilisable d'une zone de confiance partielle, je vais donc faire une assertion sur l'accès en lecture au fichier passé en paramètre. Par ailleurs je fais aussi un Deny sur l'accès aux boites de dialogue de fichier qui n'a aucun autre intérêt que d'être un exemple de code.

En faisant mon assertion, je prends le risque de donner le droit de lecture sur le fichier cible à mon composant même si le code appelant ne possède pas ce droit. Je ne prends pas un gros risque puisqu'il s'agit :

  • Possédant des ACL compatibles avec la session utilisateur en cours
  • D'un fichier XML interprétable comme un Dataset
  • D'un accès en lecture seul

Possédant des ACL compatibles avec la session utilisateur en cours

J'encapsule ma méthode ReadXML dans un try…Catch…Finally afin de pouvoir annuler mes substitutions en cas d'échec.

J'écris ensuite un projet WinForms pour faire un test. Dans ce projet j'ajoute une référence à mon composant de code. Je mets sur la feuille un bouton et une grille et j'écris le code :

 
Sélectionnez
    Private Sub cmdChargement_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                                       Handles cmdChargement.Click
        Dim MonDS As New DataSet
        Dim objExtr As New clsDtsXML.DtsXML("d:\tutoriel\pubs.xml")
        Try
            MonDS = objExtr.ExtractDataset
            Me.DataGrid1.DataSource = MonDS.Tables(0)
        Catch ex As Exception
            MessageBox.Show("Echec de l'extraction " & vbCrLf & ex.Message, "Erreur", _
            MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
 
    End Sub

Je génère cet exécutable. Même si je l'installe sur Internet, j'aurais bien remplissage de ma grille puisque l'assertion supprime le parcours de pile.

IV-D. Autres demandes

IV-D-1. Demande de liaison

Une demande de liaison, LinkDemand, est une demande de sécurité un peu particulière, puisqu'elle ne vérifie que l'appelant immédiat. Elle se vérifie pendant la compilation JIT. L'avantage de ce type de demande est qu'elle est moins couteuse qu'une vérification complète mais comme il ne s'agit pas d'une demande normale, elle suppose que l'appelant soit lui-même correctement sécurisé.

IV-D-2. InheritanceDemand

Ce type de demande sert à vérifier qu'un héritier possède bien les droits nécessaires. Généralement, lorsqu'on veut sécuriser une classe dans des scénarios d'héritage, on tend à sceller celle-ci (NotInheritable en VB ou Sealed en C#). Si on veut pouvoir permettre l'héritage tout en vérifiant quand même la sécurité, on utilise alors InheritanceDemand.

V. Personnalisation

Pour finir nous allons voir la création d'une autorisation personnalisé. Pour cela je vais créer une nouvelle bibliothèque de classe. Je dois générer un Assembly avec nom fort, j'utilise donc Sn.exe pour générer la signature que j'appel dans le manifeste de l'assembly.

Cette permission est utilisée dans une entreprise pour accéder à des clés de cryptage d'entreprise, c'est-à-dire permettant à quiconque dans l'entreprise de crypter et décrypter des données avec la même paire de clé.

Je crée donc une classe SocietyPermission telle que :

 
Sélectionnez
Imports System.Security
Imports System.Security.Permissions
 
<Serializable()> Public NotInheritable Class PermissionSociety
    Inherits CodeAccessPermission
    Implements IUnrestrictedPermission
 
    Private p_AllowAccess As Boolean
    Private p_State As PermissionState
 
    Public Sub New(ByVal State As PermissionState)
        If State = PermissionState.Unrestricted Then Me.CanAccess = True
        Me.p_State = PermissionState.Unrestricted
    End Sub
 
    Public Property CanAccess() As Boolean
        Get
            Return Me.p_AllowAccess
        End Get
        Set(ByVal Value As Boolean)
            Me.p_AllowAccess = Value
            If Value Then Me.p_State = PermissionState.Unrestricted Else Me.p_State = PermissionState.None
        End Set
    End Property
 
    Public Overrides Function Copy() As System.Security.IPermission
        Return New PermissionSociety(Me.p_State)
    End Function
 
    Public Overrides Function Intersect(ByVal target As System.Security.IPermission) As System.Security.IPermission
        If target Is Nothing Then Return Nothing
        If Not TypeOf target Is PermissionSociety Then
            Throw New ArgumentException("Le paramètre doit être de type PermissionSociety")
        End If
        Dim TargetPerm As PermissionSociety = CType(target, PermissionSociety)
        If TargetPerm.CanAccess And Me.CanAccess Then
            Return New PermissionSociety(PermissionState.Unrestricted)
        Else
            Return New PermissionSociety(PermissionState.None)
        End If
    End Function
 
    Public Overrides Function Union(ByVal other As System.Security.IPermission) As System.Security.IPermission
 
        If other Is Nothing Then Return Me.Copy
        If Not TypeOf other Is PermissionSociety Then
            Throw New ArgumentException("Le paramètre doit être de type PermissionSociety")
        End If
        Dim OtherPerm As PermissionSociety = CType(other, PermissionSociety)
        If OtherPerm.CanAccess Or Me.CanAccess Then
            Return New PermissionSociety(PermissionState.Unrestricted)
        Else
            Return New PermissionSociety(PermissionState.None)
        End If
 
    End Function
 
    Public Overrides Function IsSubsetOf(ByVal target As System.Security.IPermission) As Boolean
        If target Is Nothing Then
            If Me.CanAccess Then Return False Else Return True
        End If
        If Not TypeOf target Is PermissionSociety Then
            Throw New ArgumentException("Le paramètre doit être de type PermissionSociety")
        End If
        Dim TargetPerm As PermissionSociety = CType(target, PermissionSociety)
        If TargetPerm.CanAccess Xor Me.CanAccess Then
            Return False
        Else
            Return True
        End If
    End Function
 
    Public Overrides Sub FromXml(ByVal elem As System.Security.SecurityElement)
        Dim strUnrestricted As String = elem.Attribute("Unrestricted")
        If CBool(strUnrestricted) Then Me.CanAccess = True Else _
                                                         Me.CanAccess = False
    End Sub
 
    Public Overrides Function ToXml() As System.Security.SecurityElement
        Dim elem As New SecurityElement("IPermission")
        Dim Nom As String = Me.GetType.AssemblyQualifiedName.ToString
        With elem
            .AddAttribute("class", Nom)
            .AddAttribute("version", CStr(1))
            If Me.CanAccess Then
                .AddAttribute("Unrestricted", Boolean.TrueString)
            Else
                .AddAttribute("Unrestricted", Boolean.FalseString)
            End If
        End With
        Return elem
    End Function
 
    Public Function IsUnrestricted() As Boolean _
           Implements System.Security.Permissions.IUnrestrictedPermission.IsUnrestricted
        If Me.CanAccess Then Return True Else Return False
    End Function
 
End Class

Comme vous le voyez, c'est une permission assez simple puisqu'elle est vraie ou fausse, autrement dit on l'a entièrement ou pas du tout.

Les méthodes écrites sont obligatoires (MustOverrides) sauf IsUnrestricted qui est donnée par IUnrestrictedPermission.

Je crée ensuite l'attribut qui permet la vérification de cette permission au niveau Assembly. Là encore il s'agit d'un code assez simple :

 
Sélectionnez
Imports System.Security
Imports System.Diagnostics
Imports System.Security.Permissions
 
<Serializable(), AttributeUsage(AttributeTargets.Assembly Or _
                                AttributeTargets.Class Or _
                                AttributeTargets.Method Or _
                                AttributeTargets.Constructor, AllowMultiple:=True, Inherited:=False)> _
Public NotInheritable Class PermissionSocietyAttribute
    Inherits CodeAccessSecurityAttribute
 
    Private m_Access As Boolean
 
    Public Sub New(ByVal Action As SecurityAction)
        MyBase.New(Action)
    End Sub
 
    Public Property CanAccess() As Boolean
        Get
            Return Me.m_Access
        End Get
        Set(ByVal Value As Boolean)
            Me.m_Access = Value
        End Set
    End Property
 
    Public Overrides Function CreatePermission() As System.Security.IPermission
        If Unrestricted Then
            Return New PermissionSociety(PermissionState.Unrestricted)
        End If
        If Me.CanAccess Then
            Return New PermissionSociety(PermissionState.Unrestricted)
        Else
            Return New PermissionSociety(PermissionState.None)
        End If
    End Function
End Class

Enfin, je dois allouer cette permission. Dans ma configuration de sécurité, j'ai un groupe de code « Société », enfant du groupe LocalIntranet qui est obtenu pour tout les assemblies ayant une clé publique définie.

Je dois donc ajouter mon assembly de permission dans les assemblies de stratégie.

Mon jeu de permission « société » se trouve en fait dans le fichier :

C:\Windows\Microsoft.NET\Framework\v1.1.4322\CONFIG\security.config

Il faut alors ouvrir ce fichier. Dans la partie Security Class je dois ajouter :

<SecurityClass Name="SocietyPermission" Description="clsPermSociety.SocietyPermission, clsPermSociety, Version=1.0.0.1, Culture=neutral, PublicKeyToken=a3d67cf8fe365b39"/>

Puis dans le jeu de permission “Societe”, ajouter :

<IPermission class="PermissionSociety"

version="1"

Unrestricted="True"/>

Si je regarde maintenant les autorisations du groupe de code dans le manager de sécurité, je vois bien apparaitre ma permission personnalisée.