... μιας και κανείς δεν προσφέρθηκε, αναγκάστηκα να λύσω μόνος το
πρόβλημά μου, ε, και σκέφτηκα να γράψω και κάτι σαν απλό παράδειγμα της
διαδικασίας δημιουργίας μιας Custom Security Permission και του
αντίστοιχου Attribute.
Ας δούμε λοιπόν.
Οι δύο βασικές κλάσσεις/interfaces στο framework που αφορούν τα
παραπάνω είναι το interface IPermission και το
CodeAccessSecurityAttribute. Σε περίπτωση που αναρωτιέστε, αν το custom
attribute σας δεν είναι derived απ'το CodeAccessSecurityAttribute, το
σύστημα, αν και θα το προσθέσει σαν declaration στο assembly της
εφαρμογής σας, δεν θα το κάνει ποτέ evaluate στο runtime .. θα περνάει
.. "στο ντούκου" που λέει κι ο λαός.
Ας τα πάρουμε απ'την αρχή όμως. Πρώτα, η κλάσση AccessPermission, η custom Security Permission μου ...
using System;
using System.Security;
using
System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace NetStore.Security {
[Serializable()]
public
class AccessPermission : IPermission,
IUnrestrictedPermission {
private string
_right;
public AccessPermission() {
MessageBox.Show("AccessPermission.ctor
1");
}
public AccessPermission(PermissionState state) {
MessageBox.Show("AccessPermission.ctor
2");
MessageBox.Show("state="
+ state.ToString());
}
public AccessPermission(string
right) {
MessageBox.Show("AccessPermission.ctor
3");
_right
= right;
}
public IPermission Copy() {
MessageBox.Show("AccessPermission.Copy");
return this;
}
public IPermission Intersect(IPermission target) {
MessageBox.Show("AccessPermission.Intersect");
return this;
}
public bool IsSubsetOf(IPermission target) {
MessageBox.Show("AccessPermission.IsSubsetOf");
return false;
}
public IPermission
Union(IPermission target) {
MessageBox.Show("AccessPermission.Union");
return this;
}
public void Demand() {
MessageBox.Show("AccessPermission.Demand,
Right=" + _right);
MessageBox.Show(((UserPrincipal)Thread.CurrentPrincipal).Identity.Name);
if(!((UserPrincipal)Thread.CurrentPrincipal).HasRight(_right))
throw
new SecurityException("from
AccessPermission.Demand()");
else
((UserPrincipal)Thread.CurrentPrincipal).CurrentPermission
= this;
}
public SecurityElement
ToXml() {
MessageBox.Show("AccessPermission.ToXml");
SecurityElement element = new SecurityElement("Permission");
Type type = this.GetType();
StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
AssemblyName.Replace('\"', '\'');
element.AddAttribute("class",
type.FullName + ", " + AssemblyName);
element.AddAttribute("version",
"1");
element.AddAttribute("right",
_right);
return
element;
}
public void FromXml(SecurityElement element) {
MessageBox.Show("AccessPermission.FromXml");
_right = (string)element.Attributes["right"];
}
public bool IsUnrestricted() {
return true;
}
public string Right {
get {
return
_right;
}
set {
_right = value;
}
}
}
}
Το βασικό "catch" που πρέπει να προσέξει κάποιος εδώ, είναι να μην
επιστρέφει σε καμμία περίπτωση null απο τις μεθόδους του IPermission
(Union, Copy, etc.) οι οποίες έχουν IPermission return type. Κατα τη
διαδικασία του compile της εφαρμογής που θα χρησιμοποιεί το Permission
σας, θα εμφανιστούν τα απίστευτα copmilation error messages του στύλ
"cannot emit attribute", "failed to decode embedded permission set
object" και διάφορα τέτοια μηνύματα γεμάτα χρήσιμη πληροφορία ...
Δεύτερο catch ... πρέπει να υπάρχει constructor με μοναδική παράμετρο ένα PermissionState, ακόμη κι αν δεν κάνει τίποτα.
Περνάω στην κλάσση του custom attribute τώρα ...
using System;
using System.Security;
using
System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
namespace NetStore.Security
{
[AttributeUsageAttribute(AttributeTargets.All)]
public
class AccessPermissionAttribute:
CodeAccessSecurityAttribute {
private string
_right;
public AccessPermissionAttribute(SecurityAction
action) : base (action) {
}
public override
IPermission CreatePermission() {
MessageBox.Show("AccessPermissionAttribute.CreatePermission()");
return new
AccessPermission(_right);
}
public string Right {
set { _right = value;
}
get { return(_right);
}
}
}
}
Το catch εδώ είναι η παρουσία ενός και μόνο constructor, ο οποίος έχει
ως παράμετρο ένα SecurityAction (.Demand, .ListDemand etc.). Οτιδήποτε
άλλο θα θέλατε να έχετε ως παράμετρο στον constructor το κάνετε
Property. Το framework δε θα σας αφήσει να χρησιμοποιήσετε οποιοδήποτε
άλλο footprint για τον constructor ( gay or what ... ).
Το δεύτερο catch είναι το
public override
IPermission CreatePermission() ...
Μέσα εκεί κάνετε instantiate ένα AccessPermission, ανάλογα με τις τιμές των properties του custom attribute.
Τώρα, κάνετε compile και sign το assembly (οπωσδήποτε !!!), και το προσθέτετε στο GAC.
( Όταν με το καλό επιχειρήσετε να χρησιμοποιήσετε το assembly σε κάποιο
project, κατα το compile όσο και να έχετε το assembly με το
custom permission/attribute referenced ... το VS.NET θα κοιτάξει στο
GAC να το βρεί ... bummer ... )
Ωραία ως εδώ ... τώρα κάνετε ένα νέο project, reference το assembly με τις custom-ιες μας, και γράφετε κάτι σαν κι αυτό:
[AccessPermission(SecurityAction.Demand, Right="right5")]
public static void SecuredMethod() {
MessageBox.Show("in
SecuredMethod");
}
... compile (θα πεταχτούν κάτι MessageBox pop-ups αν κάνετε copy-paste
τον κώδικα ως έχει, αλλά δεν ανησυχούμε .. όλα πάνε καλά ! ), run ...
και θεωρητικά, ανάλογα με το τι έχετε κάνει declare στο attribute θα
"περάσει" ή θα πετάξει το custom permission ένα SecurityException
... :)
Αυτά γι'αυτό :) .. happy custom permission coding παίδες !
Y.Γ. ... τώρα που το ξαναδιάβασα .. μου θύμισα λίγο τη Βέφα Αλεξιάδου !!! :D
Angel
O:]