I'm developing plugin for nopcommerce shopping cart(ASP.NET Core 2.1).
Before registering routes in RouteProvider class,i need to access current domain name in order to some validation checks but when using IHttpContextAccessor to get Httpcontext and get current domain, Httpcontext is null.
Is there any solution to access current domain name in route provider class?
public void RegisterRoutes(IRouteBuilder routes)
{
var httpContextAccessor = EngineContext.Current.Resolve<IHttpContextAccessor>();
var domainName = httpContextAccessor.HttpContext.Request.Host.Value.ToString();
var pluginValidtyChecker = new PluginValidityChecker.ValidityChecker();
if (pluginValidtyChecker.CheckIsValid(domainName))
{
//Register routes
}
}
In the application developed by me users first enter the domain name the plugin should work on and then buy plugin.After purchasing we generate a license key that's mapped with domain name and users must be entered this license key in plugin settings.
Because plugin override some main route of nopcommerce i need first check that license key and domain name that's plugin currently work on, is valid or not.
This route must be registered on compile time.
It’s not easy to ensure, that the domain name is always available, because it’s up to the programmers to define it either in a configuration-file, or as Environment-Variable.
Furthermore, if the application runs in an AWS-container, the configuration is a bit more complicated, because the configuration-file has a different structure.
There is an Nuget-Package available the easy up things, but still not everybody uses it.
So what you want can’t be ensured in a bulletproof way.
If anybody can correct me. I would be quite happy, because I had a similar issue, which I could solve for my own application, but I‘m not glad with my solution yet.
Related
I have an APP using restful server. I want to store PDF's, images, etc. in folders on my server. How can I make the folders private on server, yet allow App to access only certain folders depending on their app access.
I have different users in app and security/tokens established, etc. But if they upload an image for their avatar (and now PDF's), they get stored in folders on the server, and I just display with image source=https://blahblah.com/org1/images/user232.jpg.
How can I make that not accessible to outside (like just going to browser), yet make accessible to app if they have correct login privilege's for that organization/user? And then further extend that logic to more sensative PDF's, and other docs uploaded through app. I didn't want to store in SQL since then harder to use simple image display tools and I already have upload and media managers using folders structures.
I can see how to secure if logging onto server through browser (credentials), but can't see how you connect App with that security level and maintain it for the session.
For future readers. Most of the work was done on the restful (ASP.NET) side. I first tried using authorization/Authentication in web.config and having Allow and deny. This allowed a redirect of a user to a login page; however, it didn't do it if they entered an image exactly correct on website.
Found HTTPHandlers (adding in webconfig ) where I could write code that would be executed once the user entered the specific Image address xyz/abc/image.png. I found this a bit feeling like a hack.
So lastly modified my
routes.MapRoute(
name: "staticFileRoute",
url: "publicstor/{*file}",
defaults: new { controller = "Home", action = "HandleStatic" }
And add a function like this to home controller.
[System.Web.Http.HttpGet]
public ActionResult HandleStatic(string file)
{
if (Session["OrgId"] == null) //todo need to add full security check.
{
return View("Login");
}
else //Either coming from app or coming from web interface
{
string mimeType = MimeInfo.GetMimeType(Path.GetExtension(file));
return File(file, mimeType);
}
}
The final bit is on the Xamarin side to now pass security when getting an image. Since just a simple Xamarin.Forms.Image doesn't have a way to pass login info or tokens/authentication I used
https://forums.xamarin.com/discussion/145575/image-from-url-needing-auth
And established an appwide webclient that logged in generally once forcing my restful to go through security validation, then just accessed the images/documents through out my app from that webclient. So far so good. Hopefully there are no holes.
This gives the gist to a future reader.
I'm using the Symfony CMF Routing Bundle to create dynamic routes (I'm using one example here):
$route = new Route('/dynamic-url');
$route->setMethods("GET");
$route->setDefault('_controller', 'AppBundle:MyRoute:getResponse');
$routeCollection->add('my-dynamic-route', $route);
The response is loaded from the getResponseAction() function inside the MyRouteController:
/**
* No annotations here, because I want the url to be dynamic from the database
*/
public function getResponseAction(Request $request) {
return $this->render('dynamic-page-template.html.twig');
}
When I go to '/dynamic-url', it works.
When in another controller, I want to redirect to this dynamic route, like this:
return $this->redirectToRoute('my-dynamic-route');
But I get this error: "None of the chained routers were able to generate route: Route 'my-dynamic-route' not found"
Also interesting: when I go to '/dynamic-url', the dev bar actually says that the Route name is 'my-dynamic-route'.
Edit
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Since it's a dynamic route, which wasn't saved anywhere (like routing.yml ) it will be only availabe for Request where it has been defined. So at the end of Request your app will immediately "forget" about new Route generated at runtime.
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Actualy No. It depends on where you call $this->get('router')->getRouteCollection();
Just try to call
dump($this->get('router')->getRouteCollection();)
right before the return statement in your Action where you're adding the my-dynamic-route route. I'm sure you'll see your my-dynamic-route in the list of routes, but if you call it anywhere else - you won't see it.
It's less about symfony rather about stateless nature of web (see Why say that HTTP is a stateless protocol?)
I started to think about this and pointed your question to an routing issue on symfony-cmf. You tagged with #symfony-cmf and i think this would be important feature for us.
I also think, when you persist your route with /my-route you should also ask the router for that name (or in case of the CMF with an content object with that a route.)
If you use the CmfRoutingBundle dynamic router, you should persist your routes to doctrine. The idea of dynamic here is that they can be created at runtime, e.g. in an admin interface or elsewhere by code. The DynamicRouter loads routes from the database.
If you use PHPCR-ODM, the route name is the repository id, typically something like /cms/routes/my-route and you can generate it with that name. If you have access to the route object loaded from the database, you can also generate from that, rather than the path. If you have to hardcode a path in your application, its an indication that probably a normally configured route would be better.
If you just add a route to the route collection on the fly, you would have to make sure that happens in each request, its only available when you add it. With the CMF ChainRouter you could register your own router that does that, but i would not know of a good use case for that. Either you know the route, then you can configure it in the routing.xml|yml|php config file. Or routes are loaded dynamically, in which point you should use DynamicRouter, potentially with a custom route loader.
I'm building a simple CMS using ASP.NET MVC 5 and Entity Framework 6. I have 2 sites: Public and Admin. Public site to diplay all the content and Admin site to manage all the content.
I only need a single Admin account to handle all the content in the Admin site.
I'm thinking to use a session to keep the logged in user data and check for the session details when accessing an authorized page.
Keep the user data in a session.
var obj = db.UserProfiles.Where(a => a.UserName.Equals(objUser.UserName) && a.Password.Equals(objUser.Password)).FirstOrDefault();
if (obj != null)
{
Session["UserID"] = obj.UserId.ToString();
Session["UserName"] = obj.UserName.ToString();
return RedirectToAction("UserDashBoard");
}
Check before accessing an authorized page.
public ActionResult UserDashBoard()
{
if (Session["UserID"] != null)
{
return View();
} else
{
return RedirectToAction("Login");
}
}
So with this approach I wouldn't need to implement advance ASP Identity functions for the authorization.
Is this approach correct and would there be any downsides using this approach?
NEVER EVER EVER EVER EVER use session for authentication. It's insecure for starters, and it won't survive a loss of session (which IIS can kill at any time, for any reason). Session cookies are not encrypted, so they can be grabbed and used easily (assuming a non-encrypted link, even if you use HTTPS for authentication pages).
Another issue is that you are doing your authentication way too late in the pipeline. OnAuthenticate runs at the very beginning of the pipeline, while you action methods are towards the end. This means that the site is doing a lot of work it doesn't have to do if the user is not authorized.
I'm not sure why you are so against using Identity, the MVC basic templates already roll a full identity implementation for you. You don't have to do much.
The downside is that you have to write it all yourself anyway. You already need role-based authorisation and have to write cludges. Identity already have this implemented and tested for you. Also keeping information in session is not very secure.
And you don't need to implement much yourself anyway. Yes, there are lot of functionality that you'll probably won't need, but just don't use it.
Don't build your own authorisation system. Since you ask this question, you are probably not qualified enough to make it secure.
I have an ASP.NET 3.5 application that I recently extended with multiple membership and role providers to "attach" a second application within this application. I do not have direct access to the IIS configuration, so I can't break this off into a separate application directory.
That said, I have successfully separated the logins; however, after I login, I am able to verify the groups the user belongs to through custom role routines, and I am capable of having identical usernames with different passwords for both "applications."
The problem that I am running into is when I create a user with an identical username to the other membership (which uses web.config roles on directories), I am able to switch URLs manually to the other application, and it picks up the username, and loads the roles for that application. Obviously, this is bad, as it allows a user to create a username of someone who has access to the other application, and cross into the other application with the roles of the other user.
How can I mitigate this? If I am limited to one application to work with, with multiple role and membership providers, and the auth cookie stores the username that is apparently transferable, is there anything I can do?
I realize the situation is not ideal, but these are the imposed limitations at the moment.
Example Authentication (upon validation):
FormsAuthentication.SetAuthCookie(usr.UserName, false);
This cookie needs to be based on the user token I suspect, rather than UserName in order to separate the two providers? Is that possible?
Have you tried specifying the applicationName attribute in your membership connection string?
https://msdn.microsoft.com/en-us/library/6e9y4s5t.aspx?f=255&MSPPError=-2147217396
Perhaps not the answer I'd prefer to go with, but I was able to separate the two by having one application use the username for the auth cookie, and the other use the ProviderUserKey (guid). This way the auth cookie would not be recognized from one "application" to the other.
FormsAuthentication.SetAuthCookie(user.ProviderUserKey.ToString(), false);
This required me to handle things a little oddly, but it simply came down to adding some extension methods, and handling a lot of membership utilities through my own class (which I was doing anyhow).
ex. Extension Method:
public static string GetUserName(this IPrincipal ip)
{
return MNMember.MNMembership.GetUser(new Guid(ip.Identity.Name), false).UserName;
}
Where MNMember is a static class, MNMembership is returning the secondary membership provider, and GetUser is the standard function of membership providers.
var validRoles = new List<string>() { "MNExpired", "MNAdmins", "MNUsers" };
var isValidRole = validRoles.Intersect(uroles).Any();
if (isValidRole)
{
var userIsAdmin = uroles.Contains("MNAdmins");
if (isAdmin && !userIsAdmin)
{
Response.Redirect("/MNLogin.aspx");
}
else if (!userIsAdmin && !uroles.Contains("MNUsers"))
{
Response.Redirect("/MNLogin.aspx");
}...
Where isAdmin is checking to see if a subdirectory shows up in the path.
Seems hacky, but also seems to work.
Edit:Now that I'm not using the username as the token, I should be able to go back to using the web.config for directory security, which means the master page hack should be able to be removed. (theoretically?)
Edit 2:Nope - asp.net uses the username auth cookie to resolve the roles specified in the web.config.
I'm using FormsAuthentication (with cookies) for users authentication, with the default cookie name (".ASPXAUTH").
What I need is a different login system for the "/Admin/" virtual directory (backed by an ASP.NET MVC controller, "AdminController")... as if the "/Admin/" directory was another web application, but without creating another web project inside my solution.
How can I customize, at runtime, the cookie name used by FormsAuthentication? The FormsAuthentication.FormsCookieName is readonly (and static...), and can be customized only once inside the web.config...
Should I create a custom FormsAuthenticationModule?
A controller filter, like the following, could be great:
[CustomFormsAuthenticationCookie("NewCookieName")]
public class AdminController : Controller
{
Trick is the underlying authentication framework really can't handle this--you can't have multiple forms authentication bits running. Easiest solution would be to break the admin bits off into a separate website which would end up living elsewhere and not get caught up in the public site's authentication.