Multiple Active Directory look-ups in MVC3 application - c#

My MVC application allows a subset of users to insert/edit records in a table, and since I'm using Windows authentication I get their samaccountnames "for free" and can insert these in a "Last Updated By" field in the mentioned records.
One of the most important (and frequently used) views in my application will display lists of 50-100 records per page, but I don't want to display their samaccountnames. I want their more user-friendly display names that I want to get from Active Directory.
I've seen several posts here suggesting linking AD to SQL, but that requires installing components on the SQL server which I'd rather not do. Instead, I was thinking of creating the following interface and derived class:
public interface IUserInformationStore
{
UserInformation FindBySamAccountName(string samAccountName)
}
public class ActiveDirectoryStore
{
HashSet<UserInformation> _cache;
public UserInformation FindBySamAccountName(string samAccountName)
{
// Look for samaccountname in _cache and if not found
// retrieve information from AD with DirectorySearcher.
// Store information in _cache and return correct user.
}
My problem now is how to access this information. I was thinking of using Ninject's ToSingleton, but I suspect that might be "Singleton Per Worker process". So maybe the Cache would be a better place for it. But what would be the best way of accessing the object? Static class with static property that checks if it's in the Cache already, initializes it otherwise, and returns the object?
Or is there a completely better way of solving this problem?

I tried 2 solutions eventually:
1
kernel.Bind<IUserRepository>().To<ActiveDirectoryUserRepository>().InSingletonScope().WithConstructorArgument("rootPath", "LDAP://dc=tessdata,dc=no");
public static MvcHtmlString GetDisplayNameSingleton(this HtmlHelper htmlHelper, string samAccountName)
{
var userRepository = DependencyResolver.Current.GetService<IUserRepository>();
return new MvcHtmlString(userRepository != null ? userRepository.FindByUsername(samAccountName).DisplayName : "Ukjent");
}
2
kernel.Bind<IUserRepository>().To<ActiveDirectoryUserRepository>().WithConstructorArgument("rootPath", "LDAP://dc=tessdata,dc=no");
public static MvcHtmlString GetDisplayName(this HtmlHelper htmlHelper, string samAccountName)
{
if (HttpRuntime.Cache["UserRepository"] == null)
{
var newUserRepository = DependencyResolver.Current.GetService<IUserRepository>();
HttpRuntime.Cache.Add("UserRepository", newUserRepository, null, DateTime.MaxValue,
TimeSpan.FromMinutes(20), CacheItemPriority.Default, null);
}
var userRepository = HttpRuntime.Cache["UserRepository"] as IUserRepository;
return new MvcHtmlString(userRepository != null ? userRepository.FindByUsername(samAccountName).DisplayName : "Ukjent");
}
The second method was noticeably faster, especially after the first call when the repository was cached. You get better control over caching too. The first method will stay in memory until the application is restarted.
I'm not sure about best practice in either case though.

Related

Dynamics CRM Online Object caching not caching correctly

I have a requirement where we need a plugin to retrieve a session id from an external system and cache it for a certain time. I use a field on the entity to test if the session is actually being cached. When I refresh the CRM form a couple of times, from the output, it appears there are four versions (at any time consistently) of the same key. I have tried clearing the cache and testing again, but still the same results.
Any help appreciated, thanks in advance.
Output on each refresh of the page:
20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125410:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
To accomplish this, I have implemented the following code:
public class SessionPlugin : IPlugin
{
public static readonly ObjectCache Cache = MemoryCache.Default;
private static readonly string _sessionField = "new_sessionid";
#endregion
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
try
{
if (context.MessageName.ToLower() != "retrieve" && context.Stage != 40)
return;
var userId = context.InitiatingUserId.ToString();
// Use the userid as key for the cache
var sessionId = CacheSessionId(userId, GetSessionId(userId));
sessionId = $"{sessionId}:{Cache.Select(kvp => kvp.Key == userId).ToList().Count}:{userId}";
// Assign session id to entity
var entity = (Entity)context.OutputParameters["BusinessEntity"];
if (entity.Contains(_sessionField))
entity[_sessionField] = sessionId;
else
entity.Attributes.Add(new KeyValuePair<string, object>(_sessionField, sessionId));
}
catch (Exception e)
{
throw new InvalidPluginExecutionException(e.Message);
}
}
private string CacheSessionId(string key, string sessionId)
{
// If value is in cache, return it
if (Cache.Contains(key))
return Cache.Get(key).ToString();
var cacheItemPolicy = new CacheItemPolicy()
{
AbsoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration,
Priority = CacheItemPriority.Default
};
Cache.Add(key, sessionId, cacheItemPolicy);
return sessionId;
}
private string GetSessionId(string user)
{
// this will be replaced with the actual call to the external service for the session id
return DateTime.Now.ToString("yyyyMMdd_hhmmss");
}
}
This has been greatly explained by Daryl here: https://stackoverflow.com/a/35643860/7708157
Basically you are not having one MemoryCache instance per whole CRM system, your code simply proves that there are multiple app domains for every plugin, so even static variables stored in such plugin can have multiple values, which you cannot rely on. There is no documentation on MSDN that would explain how the sanboxing works (especially app domains in this case), but certainly using static variables is not a good idea.Of course if you are dealing with online, you cannot be sure if there is only single front-end server or many of them (which will also result in such behaviour)
Class level variables should be limited to configuration information. Using a class level variable as you are doing is not supported. In CRM Online, because of multiple web front ends, a specific request may be executed on a different server by a different instance of the plugin class than another request. Overall, assume CRM is stateless and that unless persisted and retrieved nothing should be assumed to be continuous between plugin executions.
Per the SDK:
The plug-in's Execute method should be written to be stateless because
the constructor is not called for every invocation of the plug-in.
Also, multiple system threads could execute the plug-in at the same
time. All per invocation state information is stored in the context,
so you should not use global variables or attempt to store any data in
member variables for use during the next plug-in invocation unless
that data was obtained from the configuration parameter provided to
the constructor.
Reference: https://msdn.microsoft.com/en-us/library/gg328263.aspx

ASP.NET Security: single entry of role names

We're building an ASP.NET app, and have a requirement to use the corporate LDAP system (Siteminder) for authentication (upside: no login dialogs). Roles are created in the LDAP tool, and users are assigned to the roles by userland managers (read: the structure has to be easily understood). Currently, all apps that use the system use a dual-entry process whereby the roles identified in the app are hand-entered into the LDAP system and users are assigned, then app functions are assigned to their role mirrors in an app-based control panel. This works, but it bothers me that dual-entry is required.
What I would like to achieve is something where the app queries the LDAP system to get a list of roles that are assigned to the app (which is identified in the LDAP system) and populate the role:function control panel with them. This part seems really straightforward. However, I lose clarity when it comes to figuring out what to put in the Authorize attribute:
[Authorize(Roles = "Admin, Moderator")]
would become... what?
[Authorize(LoadedRoles(r => r.FindAll("some expression that describes the roles that have a particular permission")))]
I'm seriously into blue sky territory here. I read this question, and liked - from an architectural standpoint - the answer that suggested making the permissions the roles. But that might not be acceptable to the userland managers that needed to manage users. On the other hand, this question turns things into non-string resources, but I can't conceive of how to translate that into "roles that have this sort of function included".
Any suggestions?
Update:
Based on the advice of #venerik below, I've made some progress. For the time being, I'm encapsulating everything in the [AuthorizeFunctionAttribute], and will farm the individual pieces out where they belong later. To that end, I created three variables:
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
...then put static data in them:
Roles = new ICollection<KeyValuePair<long, string>>();
Roles.Add(KeyValuePair<long, string>(1, "Basic User"));
Roles.Add(KeyValuePair<long, string>(2, "Administrator"));
Functions = new ICollection<KeyValuePair<long, string>>();
Functions.Add(KeyValuePair<long,string>(1,"List Things"));
Functions.Add(KeyValuePair<long,string>(2,"Add Or Edit Things"));
Functions.Add(KeyValuePair<long,string>(3,"Delete Things"));
...and finally bound them together (in a complicated manner that lays the groundwork for the future):
RoleFunctions = new IList<RoleFunction>();
RoleFunctions.Add(
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Basic User").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "List Things" ).FirstOrDefault().Key,
isAuthorized = true
},
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Administrator").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "Add or Edit Things" ).FirstOrDefault().Key,
isAuthorized = true
},
// More binding...
);
I feel good about this so far. So I went researching AuthorizeCore to see what I needed to do there. However, per the comment at the bottom of the page, it's not very helpful. I more or less get that at the end, the method needs to return a bool value. And I get that I need to check that one of the User.Roles array fits the permission that's passed in through [AuthorizeFunction("List Things")].
Update (again):
I've got the following code, which seems like it will do what I need (one method needs fleshing out):
/// <summary>An authorization attribute that takes "function name" as a parameter
/// and checks to see if the logged-in user is authorized to use that function.
/// </summary>
public class AuthorizeFunctionAttribute : AuthorizeAttribute
{
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
public string Function { get; private set; }
public AuthorizeFunctionAttribute(string FunctionName)
{
Function = FunctionName;
Roles = SetApplicationRoles();
Functions = SetApplicationFunctions();
RoleFunctions = SetRoleFunctions();
}
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
bool userIsAuthorized = false;
foreach (string ur in GetUserRoles(httpContext.Current.Request.Headers["SM_USER"]))
{
long roleId = Roles.Where( sr => sr.Value == ur )
.First().Key;
long functionId = Functions.Where( sf => sf.Value == Function )
.First().Key;
// If any role is authorized for this function, set userIsAuthorized to true.
// DO NOT set userIsAuthorized to false within this loop.
if (RoleFunctions.Where(rf => rf.RoleId == roleId && rf.FunctionId == functionId)
.First().isAuthorized)
{
userIsAuthorized = true;
}
}
return userIsAuthorized;
}
Previously I didn't know enough about the underlying bits of creating a custom attribute to get out of my own way. However, this MSDN article told me what should have been obvious to me in the beginning: build it yourself. So, once I get the GetUserRoles() method put together, I should be underway.
I think you can solve this using a custom AuthorizeAttribute. In a project I worked close to they used that to access Active Directory (as described in this answer).
In your case it would look something like:
public class AuthorizeWithLDAPAttribute(string functionName) : AuthorizeAttribute
{
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
// check LDAP to verify that user has
// a role that's linked to `functionName`
}
}
Next you can use this attribute on your controllers and/or methods:
[AuthorizeWithLDAP("functionName1")]
public class BlogController : Controller
{
....
[AuthorizeWithLDAP("functionName2")]
public ViewResult Index()
{
return View();
}
}
The controller is now only accessible to users whose role are linked to functionName1 and the method is only accessible to users whose role are linked to functionName1 and functionName2

Proper way to setup a flag across entire site

I have multiple partial views that must be shown if a flag is set to true accross the entire site.
I have that flag hardcoded inside appSettings on my web.config file and is working nice. But now this flag must be set trough our back-end.
The site has a lot of traffic and I need a proper way to reach that, I feel like making a SQL request just to check this flag is an overkill.
I've though about reading a simple txt file containing the flag, but I dont know if it's still "too much".
How would be the most optimized way?
Check out MemoryCache. You can create a basic static class with a static property to return the cached flag value, and then you can define an absolute expiration to whatever comfort level you can live with (5 second or 60 minutes or any timespan) upon which you'd update the value in the cache.
Here is a very quick example to handle threading.
public static class CacheStore
{
private static readonly string _keyMySharedFlag = "shared.flag";
private static readonly object _lockMySharedFlag = new object();
public static bool MySharedFlag
{
get
{
var cachedFlag = (bool?)MemoryCache.Default.Get(_keyMySharedFlag);
if (cachedFlag != null)
return cachedFlag.Value;
lock (_lockMySharedFlag)
{
// Confirm no other threads wrote to cache while we waited
cachedFlag = (bool?)MemoryCache.Default.Get(_keyMySharedFlag);
if (cachedFlag != null)
return cachedFlag.Value;
bool? newFlag = true; // Set to your database value
var cachePolicy = new CacheItemPolicy();
cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(5); // 5 minutes
MemoryCache.Default.Set(_keyMySharedFlag, newFlag, cachePolicy);
return newFlag.Value;
}
}
}
}
I would suggest define a global configuration class which has all the flags, common data in it and use Dependency Injection to inject it to where ever you need. This will result in a more testable solution I believe.

Storing global variables in c#?

I basically have created a class which when a user logs into a website it then queries the database and stores some settings in a List (So I have key/pair values).
The reason for this is because I want to always be able to access these settings without going to the database again.
I put these in a class and loop through the fields via a SQL query and add them to the list.
How can I then access these variables from another part of the application? or is there a better way to do this? I'm talking server side and not really client side.
Here is an example of what I had at the moment:
public static void createSystemMetaData()
{
string constring = ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
SqlConnection sql = new SqlConnection(constring);
sql.Open();
SqlCommand systemMetaData = new SqlCommand("SELECT * FROM SD_TABLES", sql);
//Set Modules
using (SqlDataReader systemMetaDataReader = systemMetaData.ExecuteReader())
{
while (systemMetaDataReader.Read())
{
var name = systemMetaDataReader.GetOrdinal("Sequence").ToString();
var value = systemMetaDataReader.GetOrdinal("Property").ToString();
var Modules = new List<KeyValuePair<string, string>>();
Modules.Add(new KeyValuePair<string, string>(name, value));
}
}
}
Thanks
Any static properties of a class will be preserved for the lifetime of the application pool, assuming you're using ASP.NET under IIS.
So a very simple class might look like:
public static class MyConfigClass
{
public static Lazy<Something> MyConfig = new Lazy<Something>(() => GetSomethings());
public static Something GetSomethings()
{
// this will only be called once in your web application
}
}
You can then consume this by simply calling
MyConfigClass.MyConfig.Value
For less users you can go with the SessionState as Bob suggested,however with more users you might need to move to a state server or load it from Data Base each time.
As others have pointed out, the risk of holding these values in global memory is that the values might change. Also, global variables are a bad design decision as you can end up with various parts of your application reading and writing to these values, which makes debugging problems harder than it need be.
A commonly adopted solution is to wrap your database access inside a facade class. This class can then cache the values if you wish to avoid hitting the database for each request. In addition, as changes are routed through the facade too, it knows when the data has changed and can empty its cache (forcing a database re-read) when this occurs. As an added bonus, it becomes possible to mock the facade in order to test code without touching the database (database access is notoriously difficult to unit test).
From the looks of things you are using universal values irrespective of users so an SqlCacheDependency would be useful here:
Make sure you setup a database dependency in web.config for the name Test
public static class CacheData {
public static List<KeyValuePair<string,string>> GetData() {
var cache = System.Web.HttpContext.Current.Cache;
SqlCacheDependency SqlDep = null;
var modules = Cache["Modules"] as List<KeyValuePair<string,string>>;
if (modules == null) {
// Because of possible exceptions thrown when this
// code runs, use Try...Catch...Finally syntax.
try {
// Instantiate SqlDep using the SqlCacheDependency constructor.
SqlDep = new SqlCacheDependency("Test", "SD_TABLES");
}
// Handle the DatabaseNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableNotifications method.
catch (DatabaseNotEnabledForNotificationException exDBDis) {
SqlCacheDependencyAdmin.EnableNotifications("Test");
}
// Handle the TableNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableTableForNotifications method.
catch (TableNotEnabledForNotificationException exTabDis) {
SqlCacheDependencyAdmin.EnableTableForNotifications("Test", "SD_TABLES");
}
finally {
// Assign a value to modules here before calling the next line
Cache.Insert("Modules", modules, SqlDep);
}
}
return modules;
}

Caching attribute for method?

Maybe this is dreaming, but is it possible to create an attribute that caches the output of a function (say, in HttpRuntime.Cache) and returns the value from the cache instead of actually executing the function when the parameters to the function are the same?
When I say function, I'm talking about any function, whether it fetches data from a DB, whether it adds two integers, or whether it spits out the content of a file. Any function.
Your best bet is Postsharp. I have no idea if they have what you need, but that's certainly worth checking. By the way, make sure to publish the answer here if you find one.
EDIT: also, googling "postsharp caching" gives some links, like this one: Caching with C#, AOP and PostSharp
UPDATE: I recently stumbled upon this article: Introducing Attribute Based Caching. It describes a postsharp-based library on http://cache.codeplex.com/ if you are still looking for a solution.
I have just the same problem - I have multiply expensive methods in my app and it is necessary for me to cache those results. Some time ago I just copy-pasted similar code but then I decided to factor this logic out of my domain.
This is how I did it before:
static List<News> _topNews = null;
static DateTime _topNewsLastUpdateTime = DateTime.MinValue;
const int CacheTime = 5; // In minutes
public IList<News> GetTopNews()
{
if (_topNewsLastUpdateTime.AddMinutes(CacheTime) < DateTime.Now)
{
_topNews = GetList(TopNewsCount);
}
return _topNews;
}
And that is how I can write it now:
public IList<News> GetTopNews()
{
return Cacher.GetFromCache(() => GetList(TopNewsCount));
}
Cacher - is a simple helper class, here it is:
public static class Cacher
{
const int CacheTime = 5; // In minutes
static Dictionary<long, CacheItem> _cachedResults = new Dictionary<long, CacheItem>();
public static T GetFromCache<T>(Func<T> action)
{
long code = action.GetHashCode();
if (!_cachedResults.ContainsKey(code))
{
lock (_cachedResults)
{
if (!_cachedResults.ContainsKey(code))
{
_cachedResults.Add(code, new CacheItem { LastUpdateTime = DateTime.MinValue });
}
}
}
CacheItem item = _cachedResults[code];
if (item.LastUpdateTime.AddMinutes(CacheTime) >= DateTime.Now)
{
return (T)item.Result;
}
T result = action();
_cachedResults[code] = new CacheItem
{
LastUpdateTime = DateTime.Now,
Result = result
};
return result;
}
}
class CacheItem
{
public DateTime LastUpdateTime { get; set; }
public object Result { get; set; }
}
A few words about Cacher. You might notice that I don't use Monitor.Enter() ( lock(...) ) while computing results. It's because copying CacheItem pointer ( return (T)_cachedResults[code].Result; line) is thread safe operation - it is performed by only one stroke. Also it is ok if more than one thread will change this pointer at the same time - they all will be valid.
You could add a dictionary to your class using a comma separated string including the function name as the key, and the result as the value. Then when your functions can check the dictionary for the existence of that value. Save the dictionary in the cache so that it exists for all users.
PostSharp is your one stop shop for this if you want to create a [Cache] attribute (or similar) that you can stick on any method anywhere. Previously when I used PostSharp I could never get past how slow it made my builds (this was back in 2007ish, so this might not be relevant anymore).
An alternate solution is to look into using Render.Partial with ASP.NET MVC in combination with OutputCaching. This is a great solution for serving html for widgets / page regions.
Another solution that would be with MVC would be to implement your [Cache] attribute as an ActionFilterAttribute. This would allow you to take a controller method and tag it to be cached. It would only work for controller methods since the AOP magic only can occur with the ActionFilterAttributes during the MVC pipeline.
Implementing AOP through ActionFilterAttribute has evolved to be the goto solution for my shop.
AFAIK, frankly, no.
But this would be quite an undertaking to implement within the framework in order for it to work generically for everybody in all circumstances, anyway - you could, however, tailor something quite sufficient to needs by simply (where simplicity is relative to needs, obviously) using abstraction, inheritance and the existing ASP.NET Cache.
If you don't need attribute configuration but accept code configuration, maybe MbCache is what you're looking for?

Categories