Subdomains in Asp.Net MVC Application - asp.net-mvc

Helo Guys!
I'll start to develop a website of marketing and the users will be able to create accounts in this website. I'd like to separete the area of users using Subdomains, just like wordpress.com, ning.com, etc. If a user create an account for example: "john", the website should respond in john.mydomain.com for this user area, but it'll be the same code (separating my subdomain).
I'd like to know, How can I do a code to identify the account (in subdomain) to show the correct account for the website ?
PS: Of course it isn't to be authenticated to show the website.
Thanks

My buddy and I get this one of our sites. We had a database table that held the SiteId, along with the Domain.
In a base controller, we parsed the domain when it came in, and then found the appropriate SiteId in the database. All the controllers inherited from this base controller, and the SiteId was passed though to each call to our model.
Admin.Site.com -> SiteId = 1
Frank.Site.com -> SiteId = 2
When someone hit Admin.Site.com, SiteId of 1 was passed to the model to either retrieve the data, or save/edit/add/delete it.
Here is the code we used to get the domain:
public Website CurrentWebsite
{
get
{
if (_website == null)
{
var domain = HttpContext.Request.Url.Host;
_website = _websiteRepository.GetWebsiteByDomain(domain);
}
return _website;
}
}

The route handling in asp.net mvc starts after the domain name so it can not be caught using regular route handling.
You can create a route handler that adds the subdomain into the route data (taking it from the Request.Url) before the route is evaluated.

Related

Web Api Security client and user

pretty new to creating Web APIs, I am currently trying to secure my API and have a couple of questions
So basically I have a Web API and an MVC app. The API currently has a controller called Account that has two methods Register and Login. The MVC app has the same controller with actions but just calls the api methods.
Now basically they way I see it, I only ever want my MVC app to use the Web API, so ill have an api key in the MVC app webconfig that gets passed to the API each time? Also users need to authenticate so at the same time passing the user details?
Will this mean I need to setup two AuthAttributes? One for a user and one for the api details?
EDIT
To take this example a bit further and to demonstrate what I need
I have an WebUI that has a controller called CreateTeam. This passes a Team model up to the api Controller method CreateTeam, the api method requires that the user is authorized to create a team. Now this works fine but....
I also have a controller on my api called LeaguesController, which has a method AddNewTeamsToLeagues. Now I have a console app that runs every hour that calls this method on the api to add new teams to leagues. Now I dont ever want anyone to call this method on the api, I only ever want the console app to be able to use it. Whats the best way to secure this?
One solution is to use the token generated by [AntiForgeryValidation] (the Razor helper is #Html.AntiForgeryToken). You can use the following token (generated on your MVC View) to assist with validation if you'd like (it can be very helpful) or use your own:
<input name="__RequestVerificationToken" type="hidden" value="some-generated-value" />
If you're using jQuery you can override the default Ajax options (jQuery.ajaxSetup() - API documentation) to automatically add this to your request headers and validate against it (in whatever implementation you want). You can also obviously send in a username and whatever else you'd like for verification uses.
Then, you can have your Web API have a filter that validates against this information (and whatever else you'd like) using AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);.
Unfortunately, until MVC6/Web API3 the two controller types have completely different implementation so you may have to write a customer filter yourself to handle authentication. There are dedicated [Authorize] attributes for both MVC and Web API but they have have different namespaces (System.Web.Http.AuthorizeAttribute vs System.Web.Mvc.AuthorizeAttribute).
Hope this helps. For further reading, you can check out this blog post.
-- Edit to reply to your updated comment about your Console application --
You could always create a Filter that only allows local connections, specific IP addresses, certain LDAP/AD Security Groups, etc to have access to a specific controller/controller action. In your case of a Console application you would need to decide how you'd want that to be secured; once you decide to you can go from there. So, say you want to allow only specific members of an AD Security Group to access the controller, you could throw together a filter like so:
namespace YourAppName.Filters
{
public class AuthorizeADAttribute : AuthorizeAttribute
{
public string Groups { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (base.AuthorizeCore(httpContext))
{
var groups = Groups.Split(',').ToList();
var context = new PrincipalContext(ContextType.Domain, "YourDomainHere");
var userPrincipal = UserPrincipal.FindByIdentity(
context,
IdentityType.SamAccountName,
httpContext.User.Identity.Name);
foreach (var group in groups)
if (userPrincipal.IsMemberOf(context,
IdentityType.Name,
group))
return true;
}
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
var result = new ViewResult();
result.ViewName = "NotAuthorized";
result.MasterName = "_Layout";
filterContext.Result = result;
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
}
And then apply it to a controller or a method inside of your controller, like so:
[AuthorizeAD(Groups = "SecurityGroupToAuth, League Admins, Console App Group")]
public YourViewModelHere AddNewTeamsToLeagues()
{
// do stuff
}
So, to answer your initial question: you'll likely need two different attributes/filters for the different types (between handling the AntiforgeryToken and then the console app). Unfortunately without knowing how your application and console application are hosted (different machines, same subnet, on the same network, etc) I can't give much more information but hopefully this helps point you in the right direction for creating your own filter/attribute(s).

In asp.net mvc when updating data how does one know that the data beeing manipulated does really belong to the user making the call?

In asp.net mvc when creating, updating, deleting data how does one know that the data beeing manipulated does really belong to the user making the call?
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
// edit data in database
}
If a user is only to manipulate his own data but can see and easily find out information of other users witch is public to manipulate.
How can i be sure that the user is really who he says when for example Edit is called?
The Authorize only makes sure that a user has logged in.
I'm thinking about using controller.User.Identity.Name in the update to make sure the user how created the data is the one that changes it.
But then comes the question could it be possible for a user to go around this by manipulating controller.User.Identity.Name ?
How can one know that a user is who he says he is with regard to this?
There are two kinds of authorization.
One, which is very "vertical", has helpers provided by the framework (such as the Authorize attribute). This "vertical authorization" determines if a user is allowed to make a request or perform an action. It knows nothing of the data of the request or the action being performed, just the request/action itself.
The second, which is more "horizontal", doesn't have built-in helpers in the framework because it's subjective based on the business logic of your application. This one is up to you. This "horizontal authorization" determines if a user is permitted to manipulate specific data elements (specific records in the data) under specific conditions.
To put it simply... If a user submits a request to your application (invoking an edit action on a record for example) then while the framework can tell you if that user is permitted to invoke that action you need to manually determine if that user is permitted to edit that specific data.
For example, let's say two users create records in a table. In that table there should be a column indicating the user which created that record. (Username, some identifier, however you want to link it to a user.) This value isn't provided by the user when inserting the data, it's provided by your code when you build the record. You'd probably pull this value from the logged-in identity of the user (however you track username/id in the application).
Later, when a user attempts to edit a record in that table, you would need to validate that the user performing the action (again, based on their logged-in identity) is the user who originally wrote that record (based on the data that's in the table). Or an admin, or in some other way authorized to manage that data based on your business logic. None of this is based on values being sent from the client, it's all entirely server-side.
So while the client-side code may store an identifier for the record being edited, that value can be changed by any savvy user. That value isn't to be trusted. If a user requests a page, edits values, and submits that page then your server-side code would use the page-provided identifier to know which record the user is attempting to edit, but would use the logged-in user identity to determine if the user is allowed to edit that record. In the event that the user has manipulated the form values to edit somebody else's record, the server-side code should just respond with an error or friendly message denying that action.
This is a loaded question. You could do this with roles (if only Admins can edit). You can do this via user IDs (if you only want them to edit their own personal data).
It seems your question on more based on personal user data so lets go that route.
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
var userId = WebSecurity.CurrentUserId;
var previousRecdord = //Logic or service call to get previous record
if (previousRecord.AUthorId != userId)
{
//Do Something
}
else
{
//Edit something
}
}
You could even throw all of this into a service method and have a validate method that is called before the actions on the service are run. something like
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
var userId = WebSecurity.CurrentUserId;
var profileEntity = //some mapper that maps profile to entity
_UserService.EditUserProfile(userId, profileEntity)
}
and then in some service method:
public void EditUserProfile(int userId, profileEntity profile)
{
validateProfile(userId, profile);
saveProfile(profile);
}
private void validateProfile(int userId, profileEntity profile)
{
var previousRecdord = //Logic or service call to get previous record
if (previousRecord.AUthorId != userId)
{
//throw exp of some sort
}
}

.NET web application - how to find logged in user's database records?

In my .NET CRUD web application I implemented MembershipProvider class.
Now I have function that lists records from database (this controller requires authenticated user). I need to filter out these records with respect to this logged-in user.
//
// GET: /Library/
public ViewResult Index(String orderBy = "")
{
var books = db.Books.Include(b => b.Category).Include(b => b.Writer).Include(b => b.User);
return View(books.ToList());
}
I need to know how to get logged in user's UserId and use it in Where condition (every tutorial I found talks about getting username but I need UserId). Thank you in advance.
Data I store in *.mdf data file.
I think that what you need is:
Membership.GetUser().ProviderUserKey
The type of this is object, but if you are using the out of the box membership, it should be a guid. This can then be used to filter your select accordingly.
Membership is part of the built in Membership Provider with a number of static methods.
Without knowing your DB structure/ORM, I can't exactly say, but it will be something like:
Guid userId = (Guid)Membership.GetUser().ProviderUserKey;
var books = db.Books.Where(b => b.UserId == userId);

ASP.NET MVC Multi site - where to store site configuration data

I'm developing an ASP.NET MVC multi site application (can host multiple sites from the same application instance / multi-tenant application).
I've previously done this in a web forms application and loaded up the appropriate site configuration data (by inspecting the url) on the page_load event of a custom base page.
With ASP.NET MVC would I be best to do the same in Application_BeginRequest? I can then add the configuration object to HttpContext.Current.Items.
I'm doing something similar with the current system I'm working on.
I'm determining the site by the url the user accesses the application as follows:
public class BaseController : Controller
{
protected override void Initialize(RequestContext requestContext)
{
var host = requestContext.HttpContext.Request.Url.Host;
Site = _siteService.GetSiteByHost(host);
base.Initialize(requestContext);
}
}
Every Controller then extends BaseController, so the Site object is available to every Controller. If you have any more specific questions, ask and I'll let you know what we did.
update
What you see above is _siteService.GetSiteByHost(host). SiteService has a caching layer between it and the Repository, which takes care of all the cache related stuff. it is defined as:
public Site GetSiteByHost(string host)
{
string rawKey = GetCacheKey(string.Format("GetSiteByHost by host{0}", host));
var site = (Site)_cachingService.GetCacheItem(rawKey);
if (site == null)
{
site = _siteRepository.GetSiteByHost(host);
AddCacheItem(rawKey, site);
}
return site;
}
We try not to use the Session unless we're dealing with simple data types, like an integer. I wouldn't store a Site object in the Session, but I would store an integer that represents the SiteId in the session. Then the next time the user accesses the application, I can get the Site object that's associated with the current user from the cache by Id. In the case above though that's not necessary.
This blogger has what looks to be a decent series of articles about multi-tenancy in asp.net-mvc
What you mention sounds like a workable way of doing what you want, though it may not be the idiomatic solution.

asp.net MVC, how to redirect registered users that don't have a profile to page?

We are building a site using asp.net mvc. We want to allow the user to easily register and create an account. There is though a very special piece of information, that will be registered in his profile, that we want to show to him *after registration is finished, and he is logging in for the first time.
The logic is whatever the URL that was hit, if the user is authenticated and does not have a valid profile, redirect him to the "Create Profile" page.
The whole ui will depend on those profile choices. What approach should we use within the MVC framework, to force this workflow on the visitor? The ideas I can come up with require tons of code duplication in controllers etc, so its clearly a bad idea.
We are using Membership for users, but profile is our own implementation (no profile provider) that will connect profile data to a userId.
I think the easiest way to do this is either create a custom AuthorizeAttribute, extending the existing one or create a separate FilterAttribute. Either one of these would get applied to all of your controllers and ensure that an authenticated user has a profile. In the case where no profile exists, the filter would redirect the user to the page where the profile is created. This would be done by setting the result property on the context to a RedirectResult to the profile creation action. Only if the profile exists and is complete would the filter allow the user to proceed to the desired action.
Alternatively, you could create a base controller that overrides OnActionExecuting and performs the same task. I prefer the attribute mechanism as it is more flexible, i.e., you could have some public actions that are available without the profile (including the profile setting action).
Answering my own question: In the end I created a custom actionFilter. In the beginning, I took the path of subclassing [authorize] into [AuthorizeCheckProfile]. But then I realized that the use case was wrong: I did not want the logged-in only parts of my site to redirect to the create-profile page, if no user profile existed. I wanted any page of my site to redirect to that page, if its a logged-in user with no profile. The only place I don't want to check that is in the actual profile-create. Here's the code:
public class AssertProfileAttribute : ActionFilterAttribute {
public AssertProfileAttribute() {
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.Request.IsAuthenticated == false)
return;
//we have a user, but does he have a profile?
if (filterContext.HttpContext.Session["UserProfile"] == null) { //not in the session
IUnityContainer container = filterContext.HttpContext.Application["container"] as IUnityContainer;
Profile hasProfile = container.Resolve<IProfileRepository>().GetUserProfile(Membership.GetUser());
if (hasProfile == null) {
//we have to redirect to the create profile
string returnURL = filterContext.HttpContext.Request.AppRelativeCurrentExecutionFilePath;
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Profile", action = "Create", returnTo = returnURL }));
} else {
//he has a profile but we haven't put it in session yet
filterContext.HttpContext.Session["UserProfile"] = hasProfile;
}
}
}
}
It has the side-effect that it will store the profile in a Session key. This way it can be easily be fetched so that further role checks can happen in every request with other custom filters. The implementation uses Unity and repositories for db access.
A big thanks to the community.
Try consider ActionFilter and FilterAttribute if not most pages need to do so, or else, you may actually put this redirection logic to global.asax (in those Begin Request or similar events)

Resources