PDA

View Full Version : Getting a "mixed" objet in a Before Advice impleme


cylt
12-29-2005, 01:55 PM
I'm trying to use a combination of a "Introduction" , "Before advice" and a custom attribute for implementing a custom security check. The "Introduction" extend some classes with a property representative of a user cretentials and the "Before advice" implementation test this property to check the user role and determine if the current user is allow or not for calling a method. The class's methods to be controled are tagged with a custom attribute.

here his the code snippets :

The AcessControled advice Interface

public interface IAccessControled:IAdvice,ITargetAware
{
UserCredential Credential { get;set;}
}


The Advisor

public class AccessControledAdvisor:DefaultIntroductionAdvisor
{
public AccessControledAdvisor():base(new AccessControledMixin())
{
}
}


The Mixin


public class AccessControledMixin:IAccessControled
{
private UserCredential m_Credential;
private IAopProxy m_TargetProxy;

public DML.UserCredential Credential
{
get{return m_Credential;}set{m_Credential = value;}
}

public IAopProxy TargetProxy
{
set { m_TargetProxy=value; }
}
}



The Factory


ProxyFactory factory = new ProxyFactory(_obj);
factory.AddIntroduction(new AccessControledAdvisor());
factory.AddAdvice(new BLLTransactionAdvice());
factory.AddAdvice(new BLLSecurityAdvice());
Object _proxy = factory.GetProxy();


The advice implementation


public void Before(System.Reflection.MethodInfo method, object[] args, object target)
{
object _returnValue;

if(method.IsDefined(typeof(AccessControlAttribute) , true))
{
object[] attrs = method.GetCustomAttributes(typeof(AccessControlAtt ribute), true);
AccessControlAttribute _trsAttr = (AccessControlAttribute)attrs[0];

string login = ((IAccessControled)target).Credential.Login;
if(!Security.SecurityControler.IsInRole(login, (int)_trsAttr.Role))
{
throw new AccessControlException();
}
}

}


the problem is that the target objet i get with the Before method parameter is not the "proxified" instance (it's the original one) and could not be cast in IAccessControled. If i try to cast the objet directly returned by the "factory.GetProxy();" it work fine... this one has been corretly "mixed" by the introduction operation.
How could i get this "mixed" instance in the Before advice implementation scope ?

cylt.

Aleks Seovic
12-29-2005, 04:38 PM
Once I finish inheritance-based proxy implementation (god, this statement is getting old, I relly need to start working on it...), target object and proxy will be one and the same, so your code should work just fine.

Until then, you can set ExposeProxy property on the proxy factory to true and use AopContext.CurrentProxy to retrieve the proxy:


ProxyFactory factory = new ProxyFactory(_obj);
factory.AddIntroduction(new AccessControledAdvisor());
factory.AddAdvice(new BLLTransactionAdvice());
factory.AddAdvice(new BLLSecurityAdvice());
factory.ExposeProxy = true;
Object _proxy = factory.GetProxy();

...

public void Before(System.Reflection.MethodInfo method, object[] args, object target)
{
object _returnValue;

if(method.IsDefined(typeof(AccessControlAttribute) , true))
{
object[] attrs = method.GetCustomAttributes(typeof(AccessControlAtt ribute), true);
AccessControlAttribute _trsAttr = (AccessControlAttribute)attrs[0];

string login = ((IAccessControled) AopContext.CurrentProxy).Credential.Login;
if(!Security.SecurityControler.IsInRole(login, (int)_trsAttr.Role))
{
throw new AccessControlException();
}
}
}


HTH,

Aleks

Aleks Seovic
12-29-2005, 08:15 PM
As a sidenote, I'm not sure that the introduction is the best place to hold user credentials in. Credentials are tied to the user, not to the service, so they probably shouldn't become part of the service's state. At the risk of being completely off because I don't fully understand your requirements and don't know what type of application you are building, I'll describe how I would approach similar problem in two most common scenarios.

In a Spring.NET web application you would typically get such information from the request principal, or from the session-scoped user profile object. In a desktop application you could also get user's name from the OS or again from the user profile object.

Either way, you should be able to inject an object that gives you access to user's credentials into your security advice, which would greatly simplify your code and make introduction unnecessary.

I would also inject SecurityController instance into the advice instead of using what seems like a static property on the Security class to get to it -- it will make your advice much easier to unit test.

Hope you'll find some of these suggestions useful,

Aleks

P.S. This is really just a minor thing that I caught while reading your example: wherever you have 'Controler' or 'Controled' it should be spelled as 'Controller' and 'Controlled', with double 'l's.

cylt
12-30-2005, 08:44 AM
Thank you for having responded so quickly,

The solution you have given work fine (and make me happy !)

Concerning your sidenote, effectively, I'm according to you that my sample is not a good conception but this code was not part of real application : I'm discovering and evaluating the Spring framework since 5 days before possibly using it in a the "real world" (I'm testing the Castle project too but I think Spring will be my favorite :wink: ). So, i try to go throw a maximum of features...

At all events, your advices are completly relevants and I take them in note for my comming conception.

Concerning the spelling I apologize :oops:, but like you could notice english is not my natural language, meanwhile I try to code in English because having, in the same file, some keywords in English and others in french make the things very strange...

Thanks

cylt.

Aleks Seovic
12-30-2005, 09:08 AM
Great, glad to hear that the problem is solved and that you like Spring so far :)

As for the spelling, there is no need to appologize. I was thinking whether I should even mention it or not -- for the purposes of our discussion it was irrelevant, but I figured it wouldn't hurt and it would improve your APIs.

So please, keep posting code samples in English, even if things are misspelled -- most of us understand misspelled English much better than perfectly spelled French, except for Bruno, who will be able to help you either way :)

Enjoy your evaluation and don't hesitate to post any questions or suggestions you might have.

- Aleks