Authentication, Authorization, User and Role Management and general Security in .NET - c#

I need to know how to go about implementing general security for a C# application. What options do I have in this regard? I would prefer to use an existing framework if it meets my needs - I don't want to re-invent the wheel.
My requirements are as follows:
the usual username/password authentication
managing of users - assign permissions to users
managing of roles - assign users to roles, assign permissions to roles
authorization of users based on their username and role
I am looking for a free / open-source framework/library that has been time-tesed and used by the .Net community.
My application takes a client/server approach, with the server running as a windows service, connecting to a SQL Server database. Communication between client and server will be through WCF.
One other thing that is important is that I need to be able to assign specific users or roles permissions to View/Update/Delete a specific entity, whether it be a Customer, or Product etc. For e.g. Jack can view a certain 3 of 10 customers, but only update the details of customers Microsoft, Yahoo and Google, and can only delete Yahoo.

For coarse-grained security, you might find the inbuilt principal code useful; the user object (and their roles) are controlled in .NET by the "principal", but usefully the runtime itself can enforce this.
The implementation of a principal can be implementation-defined, and you can usually inject your own; for example in WCF.
To see the runtime enforcing coarse access (i.e. which functionality can be accessed, but not limited to which specific data):
static class Roles {
public const string Administrator = "ADMIN";
}
static class Program {
static void Main() {
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("Fred"), new string[] { Roles.Administrator });
DeleteDatabase(); // fine
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("Barney"), new string[] { });
DeleteDatabase(); // boom
}
[PrincipalPermission(SecurityAction.Demand, Role = Roles.Administrator)]
public static void DeleteDatabase()
{
Console.WriteLine(
Thread.CurrentPrincipal.Identity.Name + " has deleted the database...");
}
}
However, this doesn't help with the fine-grained access (i.e. "Fred can access customer A but not customer B").
Additional; Of course, for fine-grained, you can simply check the required roles at runtime, by checking IsInRole on the principal:
static void EnforceRole(string role)
{
if (string.IsNullOrEmpty(role)) { return; } // assume anon OK
IPrincipal principal = Thread.CurrentPrincipal;
if (principal == null || !principal.IsInRole(role))
{
throw new SecurityException("Access denied to role: " + role);
}
}
public static User GetUser(string id)
{
User user = Repository.GetUser(id);
EnforceRole(user.AccessRole);
return user;
}
You can also write your own principal / identity objects that do lazy tests / caching of the roles, rather than having to know them all up-front:
class CustomPrincipal : IPrincipal, IIdentity
{
private string cn;
public CustomPrincipal(string cn)
{
if (string.IsNullOrEmpty(cn)) throw new ArgumentNullException("cn");
this.cn = cn;
}
// perhaps not ideal, but serves as an example
readonly Dictionary<string, bool> roleCache =
new Dictionary<string, bool>();
public override string ToString() { return cn; }
bool IIdentity.IsAuthenticated { get { return true; } }
string IIdentity.AuthenticationType { get { return "iris scan"; } }
string IIdentity.Name { get { return cn; } }
IIdentity IPrincipal.Identity { get { return this; } }
bool IPrincipal.IsInRole(string role)
{
if (string.IsNullOrEmpty(role)) return true; // assume anon OK
lock (roleCache)
{
bool value;
if (!roleCache.TryGetValue(role, out value)) {
value = RoleHasAccess(cn, role);
roleCache.Add(role, value);
}
return value;
}
}
private static bool RoleHasAccess(string cn, string role)
{
//TODO: talk to your own security store
}
}

my answer is probably dependent upon the answer to this question: Is this an Enterprise application which lives within a network with Active Directory?
IF the answer is yes, then these are the steps I would provide:
1) Create Global Groups for your application, in my case, I had a APPUSER group and an APPADMIN group.
2) Have your SQL Server be able to be accessed in MIXED AUTHENTICATION mode, and then assign your APPUSER group(s) as the SQL SERVER LOGIN to your database with the appropriate CRUD rights to your DB(s), and ensure that you access the SQL SERVER with Trusted Connection = True in your connection string.
At this point, your AD store will be responsible for authentication. Since, you're accessing the application via a TRUSTED CONNECTION, it will pass the identity of whatever account is running the application to the SQL Server.
Now, for AUTHORIZATION (i.e. telling your application what the logged in user is allowed to do) it's a simple matter of querying AD for a list of groups which the logged in user is a member of. Then check for the appropriate group names and build your UI based upon membership this way.
The way my applications work are thus:
Launching the application, credentials are based upon the logged-in user, this is the primary aspect of authentication (i.e. they can log in therefore they exist)
I Get all Groups For the Windows Identity in question
I check for the Standard USER Group -- if this group does not exist for the Windows Identity in question, then that's an authentication FAIL
I check for ADMIN User Group -- With this existing in the user's groups, I modify the UI to allow access to administration components
Display the UI
I then have either a PRINCIPLE object with the determined rights/etc on it, or I utilize GLOBAL variables that I can access to determine the appropriate UI while building my forms (i.e. if my user is not a member of the ADMIN group, then I'd hide all the DELETE buttons).
Why do I suggest this?
It's a matter of deployment.
It has been my experience that most Enterprise Applications are deployed by Network Engineers rather than programmers--therefore, having Authentication/Authorization to be the responsibility of AD makes sense, as that is where the Network guys go when you discuss Authentication/Authorization.
Additionally, during the creation of new users for the network, a Network Engineer (or whoever is responsible for creating new network users) is more apt to remember to perform group assignments while they are IN AD than the fact that they have to go into a dozen applications to parse out assignments of authorization.
Doing this helps with the maze of permissions and rights that new hires need to be granted or those leaving the company need to be denied and it maintains authentication and authorization in the central repository where it belongs (i.e. in AD # the Domain Controller level).

Look into ASP.NET's Membership Providers. I don't think the out of box SQLMembershipProvider will work in your case but it's easy enough to roll your own provider.

I would take a look at something like CSLA.net: Expert C# 2008 Business Objects
It should provide everything you require.

WCF have rich security related functionality provides both authorization and authentication.
In details here:
http://msdn.microsoft.com/en-us/library/ms735093.aspx

I think you are looking at a few separate problems here--it is no accident most security systems separate authentication and authorization.
For authentication, the bigger question is logistical. Or, is there a logical place for these users to live, be it locally to the application, in Active Directory, some other LDAP store or even in some other application. Exactly where is pretty immaterial--we just need to be able to solidly identify users and preferably make that task someone else's problem. End of the day you really just need a unique identifier and the comfort that Bob from Accounting is actually Bob from Accounting.
Authorization is the more interesting part of the problem here. I think, if it is truly fine-grained, you really want to manage this wholly within your application, no matter where the users come from. Marc Gravell really hit on a good way to model at least some of this--use some custom implementation of IPrincipal and PrincipalPermission to manage things is a very clean way to get started. Beyond that you can use techniques like this one to make more complex authorization decisions in a rather clean manner.

I would use the term - 'RBAC' (Role based Access Control system) as the Solution to all your requirements.
I would not go in much detail for explaining 'RBAC' here, rather I would briefly describe it as:
It basically contains 3 features.
1) Authentication - It confirms the user's identity. Usually it is done via user accounts and passwords or credentials.
2) Authorization - It defines what user can do and cannot do in an application. Ex. ‘Modifying order’ is allowed but ‘creating new order’ is not allowed.
3) Auditing of user actions on applications. - It keeps track of user's actions on applications, as well as who has granted which access to which users?
you can check RBAC on wiki here.
https://en.wikipedia.org/wiki/Role-based_access_control
Now, regarding answer to your requirements - one of the possible solution is to extend ASP.NET membership as per your needs.
And regarding, some ready to use framework , I would recommend VisualGuard for which I work, you should check this, It does all the things what you need very easily, and what is most important is, It manages all your users, roles, permissions, and applications via Central Administration Console, and for defining permissions, administrators do not require developer's knowledge, i.e he/she can create restrictions on activities via UI.
you can also check this article to have more understanding on permission and role based system.
http://www.visual-guard.com/EN/net-powerbuilder-application-security-authentication-permission-access-control-rbac-articles/dotnet-security-article-ressources/role-based-access-control-source_soforum.html

Related

ASP.NET Boilerplate Allow Self-Provisioning Tenant Registration

so im trying to create a SaaS application with ASP.NET Boilerplate, and i come into some problem as follows:
As i observe the framework, i noted that the "RegisterAsync" function in UserRegistrationManager create user based on the currently active tenant. It means if i currently log in on tenant '1', then when i register new user, the new user will have tenantId '1'. On the other hand, when i currently not logged in, if i register a new user, the app will show exception 'cannot register host user'.
public async Task<User> RegisterAsync(string name, string surname, string emailAddress, string phoneNumber, string userName, string plainPassword, bool isEmailConfirmed)
{
CheckForTenant();
var tenant = await GetActiveTenantAsync();
var user = new User
{
TenantId = tenant.Id,
Name = name,
Surname = surname,
EmailAddress = emailAddress,
PhoneNumber = phoneNumber,
IsActive = true,
UserName = userName,
IsEmailConfirmed = isEmailConfirmed,
Roles = new List<UserRole>()
};
return user;
}
private void CheckForTenant()
{
if (!AbpSession.TenantId.HasValue)
{
throw new InvalidOperationException("Can not register host users!");
}
}
The application that i want to build requires the function for new user to be able to sign up along with free trial and then paid subscription. So i think that the new user should be able to create tenant by themself. So if the new user register, they will be forced to create new tenant before they can do any other thing in the app.
The problem is that the tenantId column in User table cannot be null, so i can register without tenant. Im thinking of assign all newly created user to 'Default' tenant at first, but i think that this was not the best practices.
Is there any way to overcome this problem or any references about that? Thanks in advance!
Based on my empirical SaaS Application development experience, a typical Self-Signup flow in Multi-Tenant applications would be like the one given below
User opts to self-signin
Allow the user to pick a subscription plan (most likely a trial plan)
Get the Company Name (tenant name) as part of the signup flow
Create a new tenant that has the subscription (2)
Add the signup user as the administrator for that tenant
In case of a trial plan, set up the suitable request handler to keep validating if the tenant has crossed the subscribed number of trial days, in that case, force redirect to payment page or signout
If the user has opted to Signup for a paid subscription (during signup), after provisioning the tenant go to the payment page. Once payment succeeds, capture the transactionid and allow the user to login and use the application.
The flow that you wanted to be using is straightforward
Build a custom self-signup process, obtain the company name (Tenant Name)
Also capture the emailid of the user that is performing the sign-up
Create the tenant based on info from (1)
Set the administrator for the tenant based on the info from (2)
All your API calls should be working fine.
Note
Have a separate Self-Signup Service like (TenantSelfRegistrationService) so that you can allow anonymous access to that service.
In terms of security, set captcha and set rate-limits or CSRF Tokens etc to enforce security in the signup process.
Hope this clarifies
I looked at the code and the documentation and I think you should never allow an unknown user to create new tenants. This should happen by a person who has the correct authorization to create tenants. This is a user that exists in the host tenant.
You as admin in the host tenant need to create tenant for somebody else and add them as admin for that tenant.
Registering users is then done through the normal way with the register webpage running for that tenant.
How to do that, I leave to you to figure out with the documentation of boilerplate itself! Documentation

ASP.Net MVC claims authorization and authentication

Please help me decide how to do the authorization for my project.
The project is written in ASP.Net MVC and is an intranet application that lets users log in via Active Directory.
Users can either be Junior Lecturer, Senior Lecturer, HOD or SuperUser. That's easy enough with roles but the situation is more complicated than that because those roles are based on whatever information you are looking at. For instance, a Junior Lecturer can only see information for students that he lectures etc.
As far as I understand it, that's where claims come in. I should assign modules or students to a user.
But the process if further complicated because there is no list of AD usernames and their students/modules in any single place.
I need to be able to check several databases to see if a user should be allowed to see the information.
Sometimes though, a user who has access to see certain information will not pass any of those checks. Because of that I will have to create a database with an AD username, their role and their subjects/students.
So my question is really regarding authorization. Is it possible for me to have that level of control on the claims and how would I assign them and check them?
If its not possible - how am i going to do this authorization?
Having an if statement at the start of every Action in every Controller feels wrong - but that's all my colleagues can come up with.
If you create a class that inherits from AuthorizeAttribute then you have the freedom to do whatever complicated authorization process you see fit. See my answer here on how to do so.
Here is some code I am using to query and cache AD roles:
private static Dictionary<Tuple<string, string>, bool> groupIdentityCache = new Dictionary<Tuple<string, string>, bool>();
..
public static bool UserHasRole(IIdentity identity, string groupShortName)
{
// (we rename our actual AD roles to shorter ones relevant to the site
// e.g. [MyAuthorizeAttribute(Roles = "Support,Admin")])
if (!AdLongGroupNames.ContainsKey(groupShortName.ToUpper())) return false;
string fullADGroupName = AdLongGroupNames[groupShortName.ToUpper()];
Tuple<string, string> key = new Tuple<string, string>(identity.Name.ToUpper(), groupShortName.ToUpper());
if (!groupIdentityCache.ContainsKey(key))
{
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "DOMAINNAME"))
{
using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, fullADGroupName))
{
using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, GetLogin(identity)))
{
groupIdentityCache[key] = userPrincipal.IsMemberOf(groupPrincipal);
}
}
}
}
return groupIdentityCache[key];
}
public static string GetLogin(IIdentity identity)
{
string[] parts = identity.Name.Split('\\');
if (parts.Count() < 2) return parts[0]; else return parts[1];
}
If you cache role memberships, you must also clear the cache on Session_Start for changes to take effect.
You can modify this solution to include roles from non-AD sources (such as a databases of class membership etc.) by adding to the groupIdentityCache dictionary. Modifying groupIdentityCache can also help when testing.
Having an 'if' statement is wrong, it will cost you long iteration and a huge misuse of memory.
Basically, you can control your authorization at every level almost using the authorize attribute.
However, you do need a well-built entity to do so, in order to not get lost withing all of the rules. It is very recommended that you will have a proper plan of your authorization scheme before committing this.
You can try to use switch statements instead, which will be a lot better in practice.
Please note:
Authorization Article that might help you understand.

How to tell if SPUser is Active Directory account

I'm working on a project where the client wants to restrict some content to only Active Directory users . Is there any way to identify that a SPUser is an AD user short of parsing the username string for the domain (or something along those lines). Something like SPUser.IsADUser would be awesome.
Edit
This seems to work, but I'm not sure if this is reliable enough? For this use case, identifying that a user is a windows user is enough (there are no local system accounts)
SPUser user = SPContext.Current.Web.CurrentUser;
string userName = user.LoginName.Substring(user.LoginName.IndexOf('|') + 1);
SPPrincipalInfo info = SPUtility.ResolveWindowsPrincipal(SPContext.Current.Site.WebApplication, userName, SPPrincipalType.User, false);
if(info != null){
//THIS IS A WINDOWS ACCOUNT
}
In my experience it is much better to use audiences for this purpose. You then can easily trim any web part using "Audience" property. You can read about audiences here. Of course it will only work if you have user profile synchronization configured.

NetSqlAzMan vs AzMan vs (?????)

I've been trying to "read between the lines" about the original (and/or current) motivation for the NetSqlAzMan project.
Was this written for?
An adapter for Windows Authorization Manager (AzMan). Where the methods in the NetSqlAzMan just passes calls to (Windows Authorization Manager (AzMan)), but perhaps with nicer/cleaner methods?
A replacement for (Windows Authorization Manager (AzMan)). Where (most or all of) the features available in (Windows Authorization Manager (AzMan)) are recreated in NetSqlAzMan, but the code was developed independently.
(Perhaps to provide DotNet 4.0 support???) (Perhaps to remove any COM dependencies)
To provide more features than (Windows Authorization Manager (AzMan)) provided. Aka, a "smarter"/"better" version of (Windows Authorization Manager (AzMan)).
To rewrite but also keep a semi-dead project alive through open-source. (As in, perhaps (Windows Authorization Manager (AzMan))) is a dead or abandoned project by Microsoft).
Other?
................
I like the object model of NetSqlAzMan. But I need to defend any decision to use it to my project manager(s) and other developers.
The object model seems "just right" (think goldilocks and the middle bed) as far as what I desire for security.
I do NOT want to do role based security. I want right(or task or permission) based security.
(See:
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/
and
http://granadacoder.wordpress.com/2010/12/01/rant-hard-coded-security-roles/
)
And basically the question that came up is: "What is the advantage of using NetSqlAzMan instead of (Windows Authorization Manager (AzMan))?"
And the sub question is "Is Windows Authorization Manager (AzMan) dead?". (And something along the lines of Long Live NetSqlAzMan!).
..................
My in-general requirements are:
Non Active-Directory users. (Down the road Active Directory and/or LDAP support would be nice, but not a requirement).
Passwords not stored as plain text.
Be able to handle RIGHTS for security checks.
Group the rights under any role.
Assign roles to users. (But again, the code will check for the right, not the role when performing an action.)
Allow (on occasion) rights to be assigned to users. With a Deny override. (Aka, a single user who does on stupid thing (like "Delete Employee") can have that right revoked.)
Roles and Rights can be maintained for multiple applications.
So other ideas are welcome. But Windows Identity Foundation seems like a little overkill.
Thanks.
I finally found a "compare" article last night.
http://www.c-sharpcorner.com/uploadfile/a.ferendeles/netsqlazman12122006123316pm/netsqlazman.aspx
I am going to paste the relevant portion here (below). (Just in case that website ceases to exist in the future. Small chance, I know, but I hate "The answer is here" links, and when you hit the link, it is a dead one.)
From what I can tell.
NetSqlAzMan provides a (table) user-defined-function that you can overload to provide a list of users (to be assigned to roles/tasks).
NetSqlAzMan provides not only "Yeah you can" mappings (Grant), but also Deny and Grant-With-Delegate as well.
NetSqlAzMan and Azman allows users(groups) to role mappings. Only NetSqlAzMan allows users to Task mappings.
After looking at a few samples ... the object model of NetSqlAzMan is very clean.
=======================================================
Ms Authorization Manager (AzMan) vs .NET Sql Authorization Manager
(NetSqlAzMan)
As pointed out before, an analogous Microsoft product already exists
and is called Authorization Manager (AzMan); AzMan is present, by
default, in Windows Server 2003 and, through the Admin Pack setup, in
Windows XP.
The important difference between AzMan and NetSqlAzMan is that the
first is Role-based, that is, based on the belonging - Role concept
and the operations container in each role, while the second is
Item-based (or if you prefer Operation-based), that is users or users
group or group of groups that can or cannot belong to Roles or execute
such Task and/or Operations (Items).
Here the most important features and differences between the two
products:
Ms AzMan:
* It's COM.
* It's equipped by a MMC 2.0 (COM) console.
* Its storage can be an XML file or ADAM (Active Directory Application Mode - e un LDAP).
* It's role-based.
* It supports static/dynamic applicative groups, members/not-members.
* Structure based on Roles -> Tasks -> Operations. (Hierarchical Roles and Tasks , none Operations).
* Authorizations can be added only to Roles.
* It doesn't implement the "delegate" concept.
* It doesn't manage authorizations "in the time".
* It doesn't trigger events.
* The only type of authorization is "Allow".
(to "deny" it needs to remove the user/group from his Role).
* It supports Scripting / Biz rules.
* It supports Active Directory users/groups and ADAM users.
NetSqlAzMan:
* It's .NET 2.0.
* It's equipped by a MMC 3.0 (.NET) console.
* Its storage is a Sql Server database(2000/MSDE/2005/Express).
* It's based on Tdo - Typed Data Object technology.
* It's Item-based.
* Structure based on Roles -> Tasks -> Operations. (all hierarchical ones).
* Authorizations can be added to Roles, Task and Operations.
* It supports static/dynamic applicative groups, members/not-members.
* LDAP query testing directly from console.
* It's time-dependant.
* It's delegate-compliant.
* It triggers events (ENS).
* It supports 4 authorization types:
o Allow with delegation (authorized and authorized to delegate).
o Allow (authorized).
o Deny (not authorized).
o Neutral (neutral permission, it depends on higher level Item permission).
* Hierarchical authorizations.
* It supports Scripting / Biz rules (compiled in .NET - C# - VB - and not interpreted)
* It supports Active Directory users/groups and custom users defined in SQL Server Database.
Here's another gotcha.
Azman sample code:
http://channel9.msdn.com/forums/sandbox/252978-AzMan-in-the-Enterprise-Sample-Code
http://channel9.msdn.com/forums/sandbox/252973-Programming-AzMan-Sample-Code
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using AZROLESLib;
namespace TreyResearch {
public class AzManHelper : IDisposable {
AzAuthorizationStore store;
IAzApplication app;
string appName;
public AzManHelper(string connectionString, string appName) {
this.appName = appName;
try {
// load and initialize the AzMan runtime
store = new AzAuthorizationStore();
store.Initialize(0, connectionString, null);
// drill down to our application
app = store.OpenApplication(appName, null);
}
catch (COMException x) {
throw new AzManException("Failed to initizlize AzManHelper", x);
}
catch (System.IO.FileNotFoundException x) {
throw new AzManException(string.Format("Failed to load AzMan policy from {0} - make sure your connection string is correct.", connectionString), x);
}
}
public void Dispose() {
if (null == app) return;
Marshal.ReleaseComObject(app);
Marshal.ReleaseComObject(store);
app = null;
store = null;
}
public bool AccessCheck(string audit, Operations op,
WindowsIdentity clientIdentity) {
try {
// first step is to create an AzMan context for the client
// this looks at the security identifiers (SIDs) in the user's
// access token and maps them onto AzMan roles, tasks, and operations
IAzClientContext ctx = app.InitializeClientContextFromToken(
(ulong)clientIdentity.Token.ToInt64(), null);
// next step is to see if this user is authorized for
// the requested operation. Note that AccessCheck allows
// you to check multiple operations at once if you desire
object[] scopes = { "" };
object[] operations = { (int)op };
object[] results = (object[])ctx.AccessCheck(audit, scopes, operations,
null, null, null, null, null);
int result = (int)results[0];
return 0 == result;
}
catch (COMException x) {
throw new AzManException("AccessCheck failed", x);
}
}
public bool AccessCheckWithArg(string audit, Operations op,
WindowsIdentity clientIdentity,
string argName, object argValue) {
try {
// first step is to create an AzMan context for the client
// this looks at the security identifiers (SIDs) in the user's
// access token and maps them onto AzMan roles, tasks, and operations
IAzClientContext ctx = app.InitializeClientContextFromToken(
(ulong)clientIdentity.Token.ToInt64(), null);
// next step is to see if this user is authorized for
// the requested operation. Note that AccessCheck allows
// you to check multiple operations at once if you desire
object[] scopes = { "" };
object[] operations = { (int)op };
object[] argNames = { argName };
object[] argValues = { argValue };
object[] results = (object[])ctx.AccessCheck(audit, scopes, operations,
argNames, argValues,
null, null, null);
int result = (int)results[0];
return 0 == result;
}
catch (COMException x) {
throw new AzManException("AccessCheckWithArg failed", x);
}
}
// use this to update a running app
// after you change the AzMan policy
public void UpdateCache() {
try {
store.UpdateCache(null);
Marshal.ReleaseComObject(app);
app = store.OpenApplication(appName, null);
}
catch (COMException x) {
throw new AzManException("UpdateCache failed", x);
}
}
}
public class AzManException : Exception {
public AzManException(string message, Exception innerException)
: base(message, innerException)
{}
}
}
That is Azman helper code. That is ugly COM/Interopish stuff. :<
Now check the NetSqlAzMan code samples:
http://netsqlazman.codeplex.com/wikipage?title=Samples
/// <summary>
/// Create a Full Storage through .NET code
/// </summary>
private void CreateFullStorage()
{
// USER MUST BE A MEMBER OF SQL DATABASE ROLE: NetSqlAzMan_Administrators
//Sql Storage connection string
string sqlConnectionString = "data source=(local);initial catalog=NetSqlAzManStorage;user id=netsqlazmanuser;password=password";
//Create an instance of SqlAzManStorage class
IAzManStorage storage = new SqlAzManStorage(sqlConnectionString);
//Open Storage Connection
storage.OpenConnection();
//Begin a new Transaction
storage.BeginTransaction(AzManIsolationLevel.ReadUncommitted);
//Create a new Store
IAzManStore newStore = storage.CreateStore("My Store", "Store description");
//Create a new Basic StoreGroup
IAzManStoreGroup newStoreGroup = newStore.CreateStoreGroup(SqlAzManSID.NewSqlAzManSid(), "My Store Group", "Store Group Description", String.Empty, GroupType.Basic);
//Retrieve current user SID
IAzManSid mySid = new SqlAzManSID(WindowsIdentity.GetCurrent().User);
//Add myself as sid of "My Store Group"
IAzManStoreGroupMember storeGroupMember = newStoreGroup.CreateStoreGroupMember(mySid, WhereDefined.Local, true);
//Create a new Application
IAzManApplication newApp = newStore.CreateApplication("New Application", "Application description");
//Create a new Role
IAzManItem newRole = newApp.CreateItem("New Role", "Role description", ItemType.Role);
//Create a new Task
IAzManItem newTask = newApp.CreateItem("New Task", "Task description", ItemType.Task);
//Create a new Operation
IAzManItem newOp = newApp.CreateItem("New Operation", "Operation description", ItemType.Operation);
//Add "New Operation" as a sid of "New Task"
newTask.AddMember(newOp);
//Add "New Task" as a sid of "New Role"
newRole.AddMember(newTask);
//Create an authorization for myself on "New Role"
IAzManAuthorization auth = newRole.CreateAuthorization(mySid, WhereDefined.Local, mySid, WhereDefined.Local, AuthorizationType.AllowWithDelegation, null, null);
//Create a custom attribute
IAzManAttribute<IAzManAuthorization> attr = auth.CreateAttribute("New Key", "New Value");
//Create an authorization for DB User "Andrea" on "New Role"
IAzManAuthorization auth2 = newRole.CreateAuthorization(mySid, WhereDefined.Local, storage.GetDBUser("Andrea").CustomSid, WhereDefined.Local, AuthorizationType.AllowWithDelegation, null, null);
//Commit transaction
storage.CommitTransaction();
//Close connection
storage.CloseConnection();
}
That tells a story in and of itself.
I think the reason for the lack of updates from Microsoft on their blogs and in their SDKs has something to do with them already moving all their tools and designs towards a social network/federation friendly "claims model":
http://msdn.microsoft.com/en-us/magazine/ee335707.aspx
In comparison to any of the AzMan variants, at the low AzMan operation level (what the code demands to decouple it from the rest) we only have a permission type claim. This new style of operation is simply a URN string/action name issued from any trusted claims provider/service validated by signatures you (or later re-configuration) define. They are then just a flat list of roles in the user identity so easy to check with common IsInRole methods.
The justification for this is clear. Modern internet solutions (and perhaps some future corporate intranet applications once the privacy laws are improved) demand multi-domain authentication and authorization, e.g. this StackOverflow.com user account and the connected Facebook account or any OpenID account you may have linked.
So for authorization you can now CODE rules which map between external claims and internal "permission claims" (analogous to AzMan operations). However there is no standard format, hierarchy or administration tool.
Perhaps a hybrid solution of Claims Service (Authentication) + AzMan XML/SQL (Roles to Claims mapping) + Claims Permission demand is the way forwards. All the samples I found so far just have code in the middle. I want to see something with recursive group memberships from Active Directory resolved to Roles to Tasks to claims (operations) like we already have with AzMan.
More investigation is necessary to achieve the "good old" but still essential "role based security" pattern with the newer technology...
If you're looking to start, head towards the Microsoft Windows Identity Foundation (WIF) which first appeared in .NET 3.5.1 but has since been integrated into the .NET 4.5 framework.
http://msdn.microsoft.com/en-us/library/hh377151(v=vs.110).aspx

Getting members of an AD domain group using Sharepoint API

In my Sharepoint code I display a list of all defined users via:
foreach (SPUser user in SPContext.Current.Web.AllUsers)
{
...
}
The great part is, I can add a domain security group to a Sharepoint group (like Visitors) thus adding many users at once (simpler administration). But my code doesn't see those users at least not until they log-in for the first time (if they have sufficient rights). In this case I can only see the domain security group SPUser object instance with its IsDomainGroup set to true.
Is it possible to get domain group members by means of Sharepoint without resorting to Active Directory querying (which is something I would rather avoid because you probably need sufficient rights to do such operations = more administration: Sharepoint rights + AD rights).
You can use the method SPUtility.GetPrincipalsInGroup (MSDN).
All parameters are self-explaining except string input, which is the NT account name of the security group:
bool reachedMaxCount;
SPWeb web = SPContext.Current.Web;
int limit = 100;
string group = "Domain\\SecurityGroup";
SPPrincipalInfo[] users = SPUtility.GetPrincipalsInGroup(web, group, limit, out reachedMaxCount);
Please note that this method does not resolve nested security groups. Further the executing user is required to have browse user info permission (SPBasePermissions.BrowseUserInfo) on the current web.
Update:
private void ResolveGroup(SPWeb w, string name, List<string> users)
{
foreach (SPPrincipalInfo i in SPUtility.GetPrincipalsInGroup(w, name, 100, out b))
{
if (i.PrincipalType == SPPrincipalType.SecurityGroup)
{
ResolveGroup(w, i.LoginName, users);
}
else
{
users.Add(i.LoginName);
}
}
}
List<string> users = new List<string>();
foreach (SPUser user in SPContext.Current.Web.AllUsers)
{
if (user.IsDomainGroup)
{
ResolveGroup(SPContext.Current.Web, user.LoginName, users);
}
else
{
users.Add(user.LoginName);
}
}
Edit:
[...] resorting to Active Directory querying (which is something I would rather avoid because you probably need sufficient rights to do such operations [...]
That's true, of course, but SharePoint has to lookup the AD as well. That's why a application pool service account is required to have read access to the AD.
In other words, you should be safe executing queries against the AD if you run your code reverted to the process account.
I would suggest you just query Active Directory directly. You are spending a lot of effort to try to get SharePoint to make this call to AD for you. Every account that has Domain User access should be able to query the AD groups you have nested in SharePoint. I would just go to the source.
This way you don't have to worry about Browse User Permissions or anything else. In my opinion trying to proxy this through SharePoint is just making your life more difficult.

Categories