how to access Active directory from WCF service - wcf

I've been asked to create a service in WCF, where input is user EMAIL-ID. there are many domains available in my server. My WCF service is hosted in xxx domain.
I need to get all yyy groups (Domain groups) for the user whose email matches.
Questions:
1. Can we connect to the Active directory from C#
2. How to get the User groups from C#.
3. It is just for user validation, there is nothing to do with Active Directory. (simple search in AD groups)
Since I'm new to this, even I dont know wheather it is possoble from C#. Early reply on this is highly appreciable. Thanks in advance.

The System.DirectoryServices.AccountManagement namespace is exactly what you need.
Here's some code that should get you started.
using System;
using System.DirectoryServices.AccountManagement;
namespace TestADCSharp
{
class Program
{
static void Main(string[] args)
{
PrincipalContext p = new PrincipalContext(
ContextType.Domain,
"your.domain"
);
UserPrincipal u = new UserPrincipal(p);
u.EmailAddress = "your#search.email";
PrincipalSearcher ps = new PrincipalSearcher(u);
PrincipalSearchResult<Principal> results = ps.FindAll();
foreach (Principal r in results) {
PrincipalSearchResult<Principal> groups = r.GetGroups();
Console.WriteLine("Groups:");
foreach (Principal g in groups) {
Console.WriteLine("\t" + g.Name);
}
}
}
}
}

Related

Claims based authorization with ASP.NET MVC

I was reading up a lot of blog posts and stackoverflow answers but still I am unable to find a real world open source project which uses claims based authentication and authorization, so that I can get an idea on how to actually implement these.
So far what I could find is Thinktecture.IdentityModel and this blog implements a claims based authorization on a sample website. If you guys could point me some Open source projects using claims, that would be really helpful.
What I am interested is how to retrieve claims for my application using the database.
So far, what I have tried is that using an in memory claims store to simulate the databsae, I have created a CustomClaimsTransformer and CustomAuthorisationManager like this.
public class CustomClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
//validate name claim
string nameClaimValue = incomingPrincipal.Identity.Name;
return CreatePrincipal(nameClaimValue);
}
private ClaimsPrincipal CreatePrincipal(string userName)
{
int userId = ClaimStore.Users.First(u => u.Value == userName).Key;
var claims = ClaimStore.ClaimsSet.Where(c => c.Key == userId);
var claimsCollection = claims.Select(kp => kp.Value).ToList();
return new ClaimsPrincipal(new ClaimsIdentity(claimsCollection, "Custom"));
}
}
public class CustomAuthorisationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
string resource = context.Resource.First().Value;
string action = context.Action.First().Value;
if (action == "Show" && resource == "Code")
{
bool likesJava = context.Principal.HasClaim(ClaimStore._httpMyclaimsUsers, "True");
return likesJava;
}
else if (action == "Read" && resource == "Departments")
{
bool readDeps = context.Principal.HasClaim(ClaimStore._httpMyclaimsDepartments, "Read");
return readDeps;
}
return false;
}
}
How to implement these in a real world scenario without having too many IF conditions?
Try the following link , it seems like a decent solution
http://developers.axiomatics.com/blog/index/entry/custom-claims-based-authorization-in-net-using-axiomatics-pep-sdk-for-net.html
Also you can define your policy and load it
http://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthorizationmanager.loadcustomconfiguration.aspx
How to: Implement Claims Authorization in a Claims-Aware ASP.NET Application Using WIF and ACS
http://msdn.microsoft.com/en-us/library/gg185907.aspx
I finally managed to design my own system with the required functionality using the existing asp.net identity 2.0 tables + a few of my own.
I'm gonna call every AREA-CONTROLLER-ACTION trio as resources in my system. WebAPI included. Area itself is a resource. Controller itself is a resource. Action itself is a resource. Any combination of them, is also a resource. I'll auto generate everything from the system itself using reflection.
Also, I'm going to use the same AspNetRoles table to store my User Groups. Users belong to one or more groups (Super Admin, Admin, Agent, Client etc.).
Using the existing Role based model as a user group based model with claims, I could get it working.Super admins are on god mode. They can create lower level users/groups/assign permissions etc.
Users can have special permissions. For example, Everyone in Agent group is denied access to updating a hotel, but a special agent who might also be the owner of a hotel can be given specific access to updating only their hotel.
Since the entire access control system runs on MVC area-controller-action sets. No one initially has no access (including super admins) and we gradually define which parts the groups/users has access to. And we give super admins and admins exclusive access through a claim. Access to everywhere is denied by default.
Once I Auto generated the AREA-CONTROLLER-ACTION sets, I let the user select which group has access to which item.
When the user logs in, I get all the resources the current user has access to and store them as claims. Based on that, using a claims auth manager, when a user request access to some resource, I can check their claims and decide if they should be given access to.
foreach(var claim in permissionClaims) {
var parts = claim.Value.Split(new [] {
'|'
}, StringSplitOptions.None);
if (parts.Length == 3) {
//var httpMethod = parts[0];
var action = parts[1];
var api = parts[2];
//Current.Log.Warn("Checking Access : " + req + " [action: " + action + "]");
// is this request for a API action?
if (api.Contains("API")) {
// if so, req must be for a API action
if (req.Contains("Api") && action.Contains(req)) {
Log.Trace("User has access to API : " + req + " [action: " + action + "]");
return true;
}
} else {
// this is for a MVC action
if (action.Contains(req)) {
Log.Trace("User has access to MVC : " + req + " [action: " + action + "]");
return true;
}
}
}
}
I have explained the approach in detail here - ASP.NET MVC Fine Grained Identity & Access Control.

Get AD Guid from HttpContext.Current.User

I have tried many, many different ways, to get this data. But I can't get it to work.
I have a MVC4 application, hooked up with Active Directory. But I need the users AD GUID.
I tried:
(Guid)Membership.GetUser(User.Identity.Name).ProviderUserKey;
WebSecurity.CurrentUserId;
But none of them work.
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, User.Identity.Name);
if(user != null)
{
Guid userGuid = user.Guid ?? Guid.Empty;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
I managed to solve it (Not pretty...):
string login = HttpContext.Current.User.Identity.Name;
string domain = login.Substring(0, login.IndexOf('\\'));
string userName = login.Substring(login.IndexOf('\\') + 1);
DirectoryEntry domainEntry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher searcher = new DirectorySearcher(domainEntry);
searcher.Filter = string.Format("(&(objectCategory=person)(objectClass=user)(sAMAccountName={0}))",userName);
SearchResult searchResult = searcher.FindOne();
DirectoryEntry entry = searchResult.GetDirectoryEntry();
Guid objectGuid = entry.Guid;
The original code used : entry.NativeGuid, but I changed because of Little / Big endian "problems"
entry.Guid has the same "format" as in AD.

ASP.NET Active Directory Search

I'm trying to create an intranet Website on ASP.NET MVC 4 using Windows Login. I have successfully done the windows login. The only thing I am stuck up with is searching the active directory with partial username. I tried searching the web and stackoverflow website but still couldn't find the answer.
DirectoryEntry directory = new DirectoryEntry("LDAP://DC=NUAXIS");
string filter = "(&(cn=jinal*))";
string[] strCats = { "cn" };
List<string> items = new List<string>();
DirectorySearcher dirComp = new DirectorySearcher(directory, filter, strCats, SearchScope.Subtree);
SearchResultCollection results = dirComp.FindAll();
You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for a UserPrincipal
// and with the first name (GivenName) of "Jinal*"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "Jinal*";
// create your principal searcher passing in the QBE principal
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" -
// it could be user, group, computer.....
}
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.
Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:
DisplayName (typically: first name + space + last name)
SAM Account Name - your Windows/AD account name
User Principal Name - your "username#yourcompany.com" style name
You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher.
Your current code is on the right track.
I think you had your wildcard backwards.
Consider this:
search.Filter = string.Format("(&(sn={0}*)(givenName={1}*)(objectSid=*))", lastName, firstName);

Multiple sessions with Fluent NHibernate and Ninject

I am working on setting up a multi-tenant, seperate database application and have made some good progress from reading this post below on stackoverflow.
Multitenancy with Fluent nHibernate and Ninject. One Database per Tenant
I see two sessions being setup. One is the 'master' session that will be used to get the tenant information and then the tenant session which is specific to the subdomain. I have the app switching nicely to the specified database based on domain and have questions on how to setup the 'master' database session and how to use it.
I tried registering a new session specifically for the master session be get an error regarding having already registered an ISession.
I'm new to nHibernate and not sure the best route to take on this.
NinjectWebCommon.cs
kernel.Bind<WebApplication1.ISessionSource>().To<NHibernateTenantSessionSource>().InSingletonScope();
kernel.Bind<ISession>().ToMethod(c => c.Kernel.Get<WebApplication1.ISessionSource>().CreateSession());
kernel.Bind<ITenantAccessor>().To<DefaultTenantAccessor>();
ITenantAccessor.cs
public Tenant GetCurrentTenant()
{
var host = HttpContext.Current.Request.Url != null ? HttpContext.Current.Request.Url.Host : string.Empty;
var pattern = ConfigurationManager.AppSettings["UrlRegex"];
var regex = new Regex(pattern);
var match = regex.Match(host);
var subdomain = match.Success ? match.Groups[1].Value.ToLowerInvariant() : string.Empty;
Tenant tenant = null;
if (subdomain != null)
{
// Get Tenant info from Master DB.
// Look up needs to be cached
DomainModel.Master.Tenants tenantInfo;
using (ISession session = new NHibernateMasterSessionSource().CreateSession())
{
tenantInfo = session.CreateCriteria<DomainModel.Master.Tenants>()
.Add(Restrictions.Eq("SubDomain", subdomain))
.UniqueResult<WebApplication1.DomainModel.Master.Tenants>();
}
var connectionString = string.Format(ConfigurationManager.AppSettings["TenanatsDataConnectionStringFormat"],
tenantInfo.DbName, tenantInfo.DbUsername, tenantInfo.DbPassword);
tenant = new Tenant();
tenant.Name = subdomain;
tenant.ConnectionString = connectionString;
}
return tenant;
}
Thanks for you time on this.
Add another session binding and add some condition. E.g.
kernel
.Bind<ISession>()
.ToMethod(c => c.Kernel.Get<NHibernateMasterSessionSource>().CreateSession())
.WhenInjectedInto<TenantEvaluationService>();

Consuming WCF from other projects

I'm very new to silverlight and WCF Ria services. I have background experience in WPF and WinForms.
Right now I'm developing a silverlight application that consists basically on a web page fetching data from a remote server.
I've read tons of forums and articles that explain how to use and consume web services and WCF. I've followed the msdn walkthrough on how to create a simple app that gets data from a DB and it worked great.
The problem is that I don't want any WCF related code or resource in my UI controls.
Right now I'm using using the layered programming architecture:
UI --> BLL --> DAL
Each of these elements is a single project in the same solution. My DAL project is the web service (WCF Ria) that comunicates with the server.
I have a simple class (User Service) and method (GetUsers) in my DAL project with the following code:
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
loadOp.Completed += (sender, args) =>
{
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
};
return users;
The thing is that my users object returns null. If I breakpoint I see that first is ending the method and only after is calling the completed event.
Is there any way make my GetUsers() to return the data base information?
Maybe the layered achitecture that I'm using isn't the one suited for what I want...
Thanks
You can use simple Action or Action<T> delegate:
public void LoadUsers(Action<IEnumerable<UserObj>> callBack)
{
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
loadOp.Completed += (sender, args) =>
{
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
if(callBack != null)
callBack(users);
};
}
You're mixing synchronous and asynchronous code together. You're setting up the completed event but the call doesn't return until it completes when you don't specify a handler. See the example here. So your code would be:
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
return users;