I'm attempting to create an application in Sails.js where users are routed to a specific subdomain based on a company attribute in their profile.
For example, Jack Smith belongs to company "pluto". If Jack logs in to the application at myapp.com , he would be redirected to the dashboard at pluto.myapp.com.
There seems to be a lot of resources on this for express.js but I can't seem to find a straight answer on how to apply those principles in Sails (see this). I'm a novice in Sails/NodeJs so this is MORE than likely a fault on my part :)
Any help is greatly appreciated.
A lot of articles you find on express will apply to sails, but they can over engineer the problem since you are using authentication.
Your dashboards will change based on user or company settings. Since your dashboard is behind a login, then the sub domain is irrelevant to achieve your goal since the variable that adjusts the data being shown on your dashboard is just as easily found via a session or token depending on how you authenticate.
The simplest answer I can give you to your problem assumes you already have your sub domains routed correctly to your main domain. Then all you have to do is log them in and direct them to the correct sub-domain via res.redirect(subDomain+'.mysite.com'). The dashboard can then be displayed based on their login credentials without really caring what the sub-domain is. In this instance, the sub-domain is merely for decoration.
Now if you want to enforce and make sure the correct sub domain is always displayed for a person's credentials, you can always verify that in a policy.
Related
I currently have a multi-tenant SPA application that uses wild-card URL to differentiate tenants and databases. For example https://tenant1.appname.com might tie to database tenant1_db and https://tenant2.appname.com would tie to database tenant2_db.
Currently, the front end SPA is hosted on the same server as the backend .Net API. I use cookie authentication with HTTP Only cookies and because everything is hosted on the same site -- I don't have to deal with CORS or anything like that.
I'm exploring the possibility of authentication from Azure AD using OIDC. My understanding is that RFC specs state that OIDC callbacks MUST be made to an absolute URI. So, I wouldn't be able to callback to things like https://tenant1.appname.com.
I've read a few places that talk about using state to keep track of the tenant and redirect after OIDC login. I'm just curious how this works in regards to the cookies and tracking the tokens. If the callback URL is https://appname.com/callback and then the SPA client forwards to https://tenant1.appname.com, it seems like my cookies/tokens would now be invalid or un-accessible due to the different domain.
Can someone explain how this would work?
Interesting question and I thought I'd post some details based on experience. It may not be a complete answer though.
DESIGN THOUGHTS
I would start with how the simplest option would work, based on systems I have provided for investment banks:
All users from all tenants share the same database, APIs and application URLs
A tenant ID claim is included in tokens
APIs ensure that users from Tenant A can never see data from Tenant B
Customers who are not happy with this can pay extra to get their own dedicated servers and URLs - as you describe. If cookies are used for Tenant A they must not be usable for a Tenant B domain.
A key benefit of this is that you keep your code simple - everything is standard including the callback URL issue you mention. For different tenants you deploy the same code with different configuration settings.
AZURE AD
This has an option to use different OAuth URLs per tenant, and also to include Tenant IDs as claims in tokens. It may not be what you want though, because not all tenants are the same:
90% of tenants may be happy to share the same system - this will be all of the small customers
10% of clients may be willing to.pay extra - this will be the big customers
TECHNICAL SOLUTIONS
Hopefully thets across that there is not usually a magic technical solution to this problem. Sharing cookies across tenants or doing non standard OAuth things can lead to exploits.
ROUTING SOLUTIONS
Another option to consider is around dynamic user routing. You could possibly identify all users in the same system, then route them to the correct URLs dynamically.
Most systems don't support this but in case it gives you some ideas, have a look at this recent article from Curity - in particular the possibilities that reverse proxies provide.
I am working on a Meteor application that uses Iron Router. We have a login page in our application. Even when the user is not logged in, if I call the below code on developer console as un-authenticated user:
Router.routes
It gives all the routes and the respective paths. Is there a way to disable access to these paths or do I need to push these end points in the server code ?
Everything you define on the client is visible on the client. So is all the routes definitions and routes logic, too. In production code this will be obfuscated but it's still there.
If you are concerned, that clients can read your routes, then you should be more concerned about the fact that it concerns you. Sounds a bit confusing but the point is: you should double check each data published to client via publications or manipulated / created via methods on server. If your backend is robust and secured as much as possible (100% will never be possible), then you don't need to care, if clients can see which routes exist and get access to them.
An example:
Bob found the route /admin and disabled the router's triggers to redirect him if he is not Admin.
Now Bob could see all data, that Admins can see. To prevent this, you may check in the publication if Bob has the role 'admin' on don't publish to him if he's not admin.
Ada also found this way to the Admin panel and wants to create a new user. Because your server method for creating new users is a ValidatedMedthod that checks if Ava has the 'admin' role it will fail to create a new user, because Ava is not an admin.
Conclusion:
Preventing access on the client side is just UI Magic bot not secure at all. Simple tweaks, however on the server side will help you to sleep better.
More help:
A good way to get started is to read the Meteor Security Guide:
https://guide.meteor.com/security.html
There is also at the end a security checklist, which I just cite for completeness and SEO reasons here:
Make sure your app doesn’t have the insecure or autopublish packages.
Validate all Method and publication arguments, and include the audit-argument-checks to check this automatically.
Deny writes to the profile field on user documents.
Use Methods instead of client-side insert/update/remove and allow/deny.
Use specific selectors and filter fields in publications.
Don’t use raw HTML inclusion in Blaze unless you really know what you are doing.
Make sure secret API keys and passwords aren’t in your source code.
Secure the data, not the UI - redirecting away from a client-side route does nothing for security, it’s just a nice UX feature.
Don’t ever trust user IDs passed from the client. Use this.userId inside Methods and publications.
Set up browser policy, but know that not all browsers support it so it just provides an extra layer of security to users with modern
browsers.
Useful packages mentioned in the answer:
mdg:validated-method
alanning:roles
audit-argument-checks
Beginner question here. I’m wanting to build an app that will be an intranet of sorts for a 70 unit restaurant chain. What I’m needing is for each physical restaurant location to see data posted to a MongoDB DB and show on a page in the store within a screen hanging on the wall. This data will be specific to each location such as announcements, catering orders that need to be filled by that store, etc... my question is, how do I create routes so that each individual store will see only their data without having to create 70 different routes or use authentication to utilize user IDs?
Trying to avoid user logins and:
“/store1”
“/store2”
“/store3”
Etc...
Seems like I could query a site ID or something like that
Hope this make since.
If you're talking about one centrally located server that is accessed by all 70 restaurants and you want to have the same routes for all, then you need to decipher some other clue from the request to figure out which restaurant it is that is making the request.
Since you have nixed authentication, I will assume that there are no security concerns here - that this is on an intranet only accessible by restaurant employees.
So, here are the clues you could get from any given request to decide which restaurant's data to show:
Cookie that contains desired restaurant ID.
Query parameter that contains desired restaurant ID.
IP address of request to discern which restaurant the request is coming from.
Separate sub-domain for each restaurant (all pointing to the same host).
Here's more info on each option:
Cookie
In this implementation, if a client arrives with no cookie set for the restaurant ID, then you take them to an opening page where they select which restaurant they want to see the data for and you ask the user to manually select the desired restaurant. Then, you set a long lasting cookie in that browser and from then on (as long as the cookie is not removed), your server can default to showing them info only for their restaurant.
Query Parameter
In this implementation, you use some initial restaurant specification like in the cookie option and then you generate pages where all the links have a query parameter specified in them that lists the restaurant ID (likely using a template system). This is generally not favored these days over a plain cookie system.
IP address
If all your restaurants have their own sub-network (presumably some sort of broadband connection connecting to a central server over some sort of private connection, then you could perhaps build a small table of restaurant source IP addresses so you could identify which restaurant was making the request purely by the IP address of the request. This may or may not be feasible depending upon your network topology. This would be much more automatic than any of the other options.
Separate sub-domain
This would work somewhat like the cookie-based option, but instead of setting a cookie, once the desired restaurant was selected, you would redirect to a subdomain specific to that restaurant. All sub-domains would still point to the same host, but the host could identify the desired restaurant from the sub-domain making the request. Similar to the query parameter option, you'd some template system on the server side to rewrite all links to include the proper sub-domain so you'd stay on the same sub-domain as you navigate.
Of all of these options, the IP address scheme is the only one that would be completely automatic, but may or may not be feasible depending upon your network topology. Of the other choices, the cookie is the most straightforward to implement because the page links themselves don't have to be rewritten.
Enterprise Configuration
In an enterprise scenario where you "manage" any browser that is approved for use, you may also be able to pre-configure the browser in each restaurant to automatically provide some identification (either a custom header or a cookie) and your server could use that identification info to determine which restaurant was making the choice. This would require accessing your site only through pre-configured and approved and properly maintained browsers (which may be more pain than it's worth).
For example, here's how you would configure a custom header on all requests with Microsoft Edge.
I'm writing a new JavaScript based Web app, which I need to secure in the following specific manner:
I should only allow for my app's index.html to be served if the request for it comes from a specific site.
By doing that, I will be forcing my users to go to that specific corporate site first, which will require for them to authenticate. Once the user is logged onto that site, they are provided with a link to my app. If my app's index.html is requested in any other way, beside following that corporate link, I would like to redirect the user to that corporate site.
How can this be accomplished?
You can use document.referrer to get the referral page. Once you get that from your corporate site you can probably put in some logic to redirect to the corporate site if it doesn't match where you're expecting.
Something tells me this isn't the best way to handle user authentication, but I'm new to that aspect.
Note: I'm on my phone, so excuse lack of code tags for that tiny bit up there.
Set a variable to the document.referrer().Then check the condition properly to determine if the referrer is in the proper page and if its not do a redirect..
I have a 'little' problem.
I am working on a project for school in Ruby on Rails: a platform where people can share things with eachother. I recently started working on widgets which people can place on their website.
In the widget you see this 'thing' and how much it is shared. But now when someone loads the widget I want to check if he is logged in on my website and then show him which friends of him/her also shared that thing. I've Been thinking and trying a few hours now but haven't figured something out yet.
I have tried to use the Facebook SDK but could not get it to work because this is domain limited. Altough Facebook would not have been the best option I think because then it is only available for people who have their Facebook account linked to their account on my website.
Probably I have to create something by my own. But I have no clue how to do it right now. I hope someone can point me in the right direction.
If A and b are on the same domain as a subdomains you can use cookies to store authentication token and in that case that will work.
If not, you can use OAuth for example http://en.wikipedia.org/wiki/OAuth.
Ruby has a bunch of gems to support that. Devise has OAuth integration as well as authlogic.
Twitter uses that widely.
Also there are CAS and WebAUTH those do quite the same.
You can list both domains (A and B) on application settings under Basic section in App Domain field. This will allow you to use Facebook JS-SDK on both sites with same application id.
You should understand that this will allow both sites to access personal info of your users and this should be done only if you have control on those sites since you are responsible for application who uses JS-SDK