Custom IPrincipal with a Generic

S

sloan

I'm working on a custom IPrincipal.

Sometimes I use the "good ole" MS system of strings.

Lately, I've been storing my roles and rights as Guids.

Check out the below code.

I'm not sure if this is the way to go or not.

What stinks is that I don't see how to keep IRolesAndRightsPrincipalT<T> to
be ~only string or guid based. ( The "where" seems to only like base class
stuff for trying to constrain <T>)

Aka, somebody could right a

public interface IRolesAndRightsPrincipalABC :
IRolesAndRightsPrincipalT<Employee>
{

}

which really doesn't make any sense.



This is a very , very "top level" interface I'm trying to create, so that it
fills IPrincipal needs throughout the company.
There might be 20-25 concrete implementations. ( << Don't ask )



I don't know. I'm just looking for some "This is dumb" or "That's ok"
comments.



public interface IRolesAndRightsPrincipalT<T> :
System.Security.Principal.IPrincipal

{

bool IsInRole(T role);

bool IsInAnyRole(T[] roles);

bool IsInAllRoles(T[] roles);

bool HasRight(T right);

bool HasAnyRight(T[] rights);

bool HasAllRights(T[] rights);

}



public interface IRolesAndRightsPrincipalString :
IRolesAndRightsPrincipalT<string>

{

}

public interface IRolesAndRightsPrincipalGuid :
IRolesAndRightsPrincipalT<System.Guid>

{

}
 
N

Nicholas Paldino [.NET/C# MVP]

I wouldn't use generics here. I also wouldn't extend IPrincipal in the
way that you are.

First, if I did use generics, I would do something like this instead:

public interface IRolesAndRightsPrincipal :
System.Security.Principal.IPrincipal
{
bool IsInRole<T>(T role);
bool IsInAnyRole<T>(T[] roles);
bool IsInAllRoles<T>(T[] roles);
bool HasRight<T>(T right);
bool HasAnyRight<T>(T[] rights);
bool HasAllRights<T>(T[] rights);
}

The reason for this is that you might want to use strings or Guids on
any of the methods.

The constraint system fails you here, in that you can't say "allow this
or this". If you have the type parameter on the type level, you could at
least create a static constructor to perform a run-time check to see if the
type parameters are valid (it's not preferred, but it's the only way right
now). You don't have any such thing for method type parameters.

However, in this case, using strings seems to me to be nothing more than
a utility method to prevent the user from having to perform conversions to a
Guid. If this is the case, then this isn't something that you need to
provide a custom interface implementation for. You can just create a
utility wrapper which takes strings and performs the conversions, providing
overloaded methods which take string parameters. This would change your
interface to this:

public interface IRolesAndRightsPrincipal :
System.Security.Principal.IPrincipal
{
bool IsInRole(Guid role);
bool IsInAnyRole(Guid[] roles);
bool IsInAllRoles(Guid [] roles);
bool HasRight(Guid right);
bool HasAnyRight(Guid[] rights);
bool HasAllRights(Guid[] rights);
}

Your utility class would look like this:

public class RolesAndRightsPrincipalUtils : IRolesAndRightsPrincipal
{
// The implementation to defer to.
private IRolesAndRightsPrincipal implementation = null;

public RolesAndRightsPrincipalUtils(IRolesAndRightsPrincipal
implementation)
{
// Store the implementation.
this.implementation = implementation;
}

public bool IsInRole(Guid role)
{
// Forward the call.
return implementation.IsInRole(role);
}

public bool IsInRole(string role)
{
// Convert to a guid, and call the overload.
return implementation.IsInRole(new Guid(role));
}

// And so on...
}

This would keep your design clean, assuming everything was represented
with Guids (roles and rights).

Now, I am assuming that you are actually doing some work on the
combination of guids and rights to come up with a string which you are
passing to the IPrincipal implementation of IsInRole to determine if the
user has the appropriate rights. If this is the case, then you really don't
need the IRolesAndRightsPrincipal interface, as you can just have the logic
in the RolesAndRightsPrincipalUtils class, performing the transformation and
then calling IsInRole on the IPrincipal implementation.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)
}

sloan said:
I'm working on a custom IPrincipal.

Sometimes I use the "good ole" MS system of strings.

Lately, I've been storing my roles and rights as Guids.

Check out the below code.

I'm not sure if this is the way to go or not.

What stinks is that I don't see how to keep IRolesAndRightsPrincipalT<T>
to
be ~only string or guid based. ( The "where" seems to only like base
class
stuff for trying to constrain <T>)

Aka, somebody could right a

public interface IRolesAndRightsPrincipalABC :
IRolesAndRightsPrincipalT<Employee>
{

}

which really doesn't make any sense.



This is a very , very "top level" interface I'm trying to create, so that
it
fills IPrincipal needs throughout the company.
There might be 20-25 concrete implementations. ( << Don't ask )



I don't know. I'm just looking for some "This is dumb" or "That's ok"
comments.



public interface IRolesAndRightsPrincipalT<T> :
System.Security.Principal.IPrincipal

{

bool IsInRole(T role);

bool IsInAnyRole(T[] roles);

bool IsInAllRoles(T[] roles);

bool HasRight(T right);

bool HasAnyRight(T[] rights);

bool HasAllRights(T[] rights);

}



public interface IRolesAndRightsPrincipalString :
IRolesAndRightsPrincipalT<string>

{

}

public interface IRolesAndRightsPrincipalGuid :
IRolesAndRightsPrincipalT<System.Guid>

{

}
 
S

sloan

Hmm.

I think your RolesAndRightsPrincipalUtils
(aka, the Adapter Design Pattern I think)
seems like a better solution.

Ok, thanks.

But sometimes I am using roles / rights in a string format.

string ROLE_1 = "Admin";
string ROLE_2 = "NormalUser";
string ROLE_3 = "Guest";

I'm going to think about it some more.

But I think we (me and the mouse in my pocket) are going to mostly guid
solution.

Thanks Nicholas.




Nicholas Paldino said:
I wouldn't use generics here. I also wouldn't extend IPrincipal in the
way that you are.

First, if I did use generics, I would do something like this instead:

public interface IRolesAndRightsPrincipal :
System.Security.Principal.IPrincipal
{
bool IsInRole<T>(T role);
bool IsInAnyRole<T>(T[] roles);
bool IsInAllRoles<T>(T[] roles);
bool HasRight<T>(T right);
bool HasAnyRight<T>(T[] rights);
bool HasAllRights<T>(T[] rights);
}

The reason for this is that you might want to use strings or Guids on
any of the methods.

The constraint system fails you here, in that you can't say "allow this
or this". If you have the type parameter on the type level, you could at
least create a static constructor to perform a run-time check to see if the
type parameters are valid (it's not preferred, but it's the only way right
now). You don't have any such thing for method type parameters.

However, in this case, using strings seems to me to be nothing more than
a utility method to prevent the user from having to perform conversions to a
Guid. If this is the case, then this isn't something that you need to
provide a custom interface implementation for. You can just create a
utility wrapper which takes strings and performs the conversions, providing
overloaded methods which take string parameters. This would change your
interface to this:

public interface IRolesAndRightsPrincipal :
System.Security.Principal.IPrincipal
{
bool IsInRole(Guid role);
bool IsInAnyRole(Guid[] roles);
bool IsInAllRoles(Guid [] roles);
bool HasRight(Guid right);
bool HasAnyRight(Guid[] rights);
bool HasAllRights(Guid[] rights);
}

Your utility class would look like this:

public class RolesAndRightsPrincipalUtils : IRolesAndRightsPrincipal
{
// The implementation to defer to.
private IRolesAndRightsPrincipal implementation = null;

public RolesAndRightsPrincipalUtils(IRolesAndRightsPrincipal
implementation)
{
// Store the implementation.
this.implementation = implementation;
}

public bool IsInRole(Guid role)
{
// Forward the call.
return implementation.IsInRole(role);
}

public bool IsInRole(string role)
{
// Convert to a guid, and call the overload.
return implementation.IsInRole(new Guid(role));
}

// And so on...
}

This would keep your design clean, assuming everything was represented
with Guids (roles and rights).

Now, I am assuming that you are actually doing some work on the
combination of guids and rights to come up with a string which you are
passing to the IPrincipal implementation of IsInRole to determine if the
user has the appropriate rights. If this is the case, then you really don't
need the IRolesAndRightsPrincipal interface, as you can just have the logic
in the RolesAndRightsPrincipalUtils class, performing the transformation and
then calling IsInRole on the IPrincipal implementation.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)
}

sloan said:
I'm working on a custom IPrincipal.

Sometimes I use the "good ole" MS system of strings.

Lately, I've been storing my roles and rights as Guids.

Check out the below code.

I'm not sure if this is the way to go or not.

What stinks is that I don't see how to keep IRolesAndRightsPrincipalT<T>
to
be ~only string or guid based. ( The "where" seems to only like base
class
stuff for trying to constrain <T>)

Aka, somebody could right a

public interface IRolesAndRightsPrincipalABC :
IRolesAndRightsPrincipalT<Employee>
{

}

which really doesn't make any sense.



This is a very , very "top level" interface I'm trying to create, so that
it
fills IPrincipal needs throughout the company.
There might be 20-25 concrete implementations. ( << Don't ask )



I don't know. I'm just looking for some "This is dumb" or "That's ok"
comments.



public interface IRolesAndRightsPrincipalT<T> :
System.Security.Principal.IPrincipal

{

bool IsInRole(T role);

bool IsInAnyRole(T[] roles);

bool IsInAllRoles(T[] roles);

bool HasRight(T right);

bool HasAnyRight(T[] rights);

bool HasAllRights(T[] rights);

}



public interface IRolesAndRightsPrincipalString :
IRolesAndRightsPrincipalT<string>

{

}

public interface IRolesAndRightsPrincipalGuid :
IRolesAndRightsPrincipalT<System.Guid>

{

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top