Require login per controller/view (Angular JS) - angularjs

Parts of my app require user validation which is done either automatically (using an existing refresh token stored as a cookie) or manually using a login form.
While I can implement this using a Service it feels rather hackish (the various services are designed to return data). But I can't think of a better way to share capabilities between different controllers.
P.S
I did check out https://github.com/witoldsz/angular-http-auth but catching the 401 error and initiating a login means that I will make an extra call even though I can tell it will fail.

I think you can definitely break up the login process into a service, as it can be incredibly important to store and pass info to various controllers in your app, and this is precisely what services are for.
I have created a bug-reporting app using something similar to that link you pointed out, but I customized it using a service and a controller as well. These are the steps I followed as I set it up:
First, I set up the interceptor to catch the 401 errors and
broadcasts a message that login is required.
I then set up an authService to log all those bad 401 calls. If
there is a bad call, it gets stored.
I also have a login controller that also uses the authService than
handles the form, registration, login, logout, etc etc. The
controller is used in the menu on every page, so there is no chance
that a broadcast event could be missed. My controller listens for
the broadcast event, and when received, displays the login form.
After a successful login, I tell my authService to repeat all those
stored calls and delete them.
Now this works great, but what if someone refreshes the page, the authService is deleted, and the interceptor will have to do all the work again, events will need to be broadcast, and ultimately it is a pain. To overcome this I did a simple check in my login controller.
First just check to see if the authService has the user object stored.
If not, do a check with the server, if the result is that the user is logged in, populate the authService again.
If the user is not logged in, do nothing, but let the authService know that you have checked against the server and seen that the user wasn't logged in.
Again, in my case I didn't want to force users to log in unless they were trying to perform specific actions that required a login. As a bug-reporting app, I wanted to allow anonymous users to read content, but as soon as they were going to post they had to register or login.
If your case involves being logged in 100% of the time, you can completely ignore the interceptor. Just set up a service and a controller. If the login controller sees that the authService isn't populated, redirect to the login screen. Upon refresh, do a simple check against the server to ensure they are still logged in, otherwise redirect to the login screen.

A service is very appropriate in this case. As described in this video about best practices, Services aren't as much about "Getting data", as it is separation of logic from the controller. A controller says what to do, a service says how to do it.
So, in your case, a Controller says "I need to check if the user is authenticated" but to know how to do that, it depends on a service.
This fits perfectly with the data-gathering concept as well. A controller says "I need to get all of the Employee Information." The service defines how.
He specifically says in this meeting that whenever there is information that needs to be shared between controllers, a service is pretty much always the best way to do it.

Related

Can the client modify react component state?

I'm building an admin page for an application and have a state value 'authenticated' that flips from 'false' to 'true' after a successful login (which is authenticated on the server) which then shows the actual admin panel.
Are component state values safe from tampering by the client? Basically, if the client can modify my 'authenticated' state value to 'true', they can skip the login and go straight to the admin panel (which I obviously don't want).
I read that React Dev Tools allows the client to modify values yet everyone says "validate on the server" but I am validating on the server and updating my state accordingly, if the user is approved. If it is not wise to have a state value manage this, what is the right way to conditionally show the admin page after a successful, server-side authenticated login?
I think this is an important question since tampering with state values in a React app can have huge negative consequences on data integrity within an app/database.
TL;DR: Either require an authentication token with every request or require authentication through a session.
Never trust users always. One potentially big issue is if you "hide" admin actions behind the admins page without requiring authentication.
For example, assume the backend server uses a REST API to accept commands. In the admin panel you get links to administrative actions like a button 'Delete Everything' that sends a DELETE request to server.net:8080/api/admin/everything without requiring any authentication. If you're a user, you can find that in the code potentially and then send a DELETE request to that address from anywhere without any repercussions.
We'd never give administrative privileges to anyone who would want to delete everything... Because we'll never untrust someone. Right?
Worse, someone might find the server and fuzz some inputs to it, and oops! They manage to delete everything (or even worse, GET everything stored in the database). This wouldn't be hard to do, especially if the server you use to authenticate is the same server you use to issue commands. History has proven "security through obscurity" to be a very bad paradigm. Every action should be authenticated, even if it seems like the actions will be hard to find.
Generally, providing a JSON web token or some other form of authentication token and having the user send that with every request is a good start at least, especially if it has an expiration date. The token would be provided through a separate request with valid credentials.
Sending a token with every single request obviously isn't ideal. There are a couple of other things to try. For servers using PHP, you can probably trust sessions (though very many people who know more than me would probably disagree). In more modern cases, you could try to use Web Sockets, requiring the token after connection. Then only after authentication with the token do you allow the user to make administrative requests.
That way, even if a user knows the exact command they can send to perform any action, the server won't let them without a current session or token. Unfortunately, unless you're already using Web Sockets or depending on a session, it will likely require a lot of changes. I'd consider this to be critical though.
It is always possible to tamper values in the front-end, there is no way you can rely solely on the front end to ensure security.
Your best approach is to implement some form of authentication and authorization on your backend. In this way, even is some users pretend to be admin, they will be blocked when you do the next request to the server.
Perhaps if you can send more information regarding your problem, we can think of a more specific solution.

Does authentication differ at all when creating an app with angular?

In a regular web app, when someone logs into the system they simply save an encrypted cookie that gets send on each request and the backend decrypts the cookie and uses the e.g. user_id/guid to lookup the user.
How do things differ when authenticating with a angular app?
Is there anything else to consider or it is basically the same process?
We use more or less the same mechanism.
Access to the application as a whole requires authentication - that is unless you're logged in, you don't get any of the javascript experience at all. This could make the login / login failure much less wizzy for the user, but in our authentication provider it's fine.
Part of our auth mechanism means the list of roles that the user has is a data object available within the browser. The javascript code uses this to decide which buttons / menus etc. are displayed. I checked with our security guy and he said something like "Well, it's a kind of direct object reference issue, but as long as each action is authorised properly, you're probably ok." So it's possible that a user could hack data values and change what they can see, but because of the next bit, they can't break our data (or see stuff that they shouldn't).
Each service call our javascript makes is authenticated and authorised. That is, the javascript call will fail if the auth token is missing or bad, but also, we internally match the auth token with a user and a set of permissions, and only execute that if the user is authorised to do so. (Note that this is good practice whether you're using Angular or not). Also note that this applies to GETs as well as POSTs - we don't want to give them data they should not see.
It gets much trickier if your API is hosted separately from your Angular site.

AngularJS + Socket.IO + Authentication

I am curious how others are solving the following problem...
I have an angular application that requires user authentication. The user must log in to the system to make requests. The user must also be authorized to create a socket.io connection.
When the application first starts up I must determine if the user is already authorized. I was planning on looking in sessionStorage for a user object/token. Does that make sense? And if the user is not authorized, the application will make a request to get the current user. If/When that fails, a 401 error is returned and angular intercepts/prompts for a username/password.
Given that there are two different code paths for authentication (check sesssionStorage vs make a request and wait for the response) how do you trigger the requests for all the other information that is required for the application? Do you emit/listen to a LOGIN event that gets broadcast in both scenarios?
My plan was to wrap the socket.io connection attempt and the ".on(...)" calls inside of the LOGIN event, does that make sense?
And if you want to listen to socket.io events or grab information from the server in a controller that is loaded after the LOGIN event has fired, how do you trigger the data from being retrieved from the server?
Sorry for the long winded questions, but I've hit a road block and I'm wondering how others are managing all the authentication and different pieces of information that is required to get from the server.
Ok, I guess let's go in order of question asked.
Does it make sense to use sessionStorage to hold user auth info?
Yes. You will need to decide between local/session Storage depending on how you want it to work. We decided we wanted the session to still be active for the time period that the backend recognizes, so even if the user closes the browser and reopens it, they will be logged in, and so we opted for localStorage instead of sessionStorage.
How do you trigger the requests for all the other information that is required for the application? Do you emit/listen to a LOGIN event that gets broadcast in both scenarios?
After login, we redirect the user to the "landing" page (route). All of our route/state changes wait on a resolve function which is doing the session auth. We only store the session id in localStorage. After the successful state change, the controllers that go with the newly loaded views start requesting data from our services. All of our controllers are designed to load data on init. So no, we do not use events. It feels like events should be used only as a last resort - and that is also the impression I get from core Angular devs since I get chastised for event usage in pull requests :)
My plan was to wrap the socket.io connection attempt and the ".on(...)" calls inside of the LOGIN event, does that make sense?
Maybe. I am not using socket.io outright, but instead have been experimenting with atmosphere (mainly because we had a java backend requirement). I do initiate the connection in the login success handler. But the general atmosphere event handling I have put into an application-level controller that is on <body>.
And if you want to listen to socket.io events or grab information from the server in a controller that is loaded after the LOGIN event has fired, how do you trigger the data from being retrieved from the server?
I could imagine (again using an app-level controller, or a service, or in my case, likely both) a function that returns the socket.io connection. A controller that has come into being could grab the socket.io stuff on init, and setup the listeners for the events that it is interested in.
My advice is to get all of your session and auth stuff worked out first, especially with regard to how you are going to do routing. Once all of it is working to your satisfaction, then add the socket.io stuff in. I realize that this might not be possible in all cases because perhaps you need something from the socket.io connection that is critical to your app even at an early stage.

How can i persist value in angular.js?

How can i persist user details in angularjs unless user logs out of the system?
My header is using a variable called user, so when the user logs in successfully, i set the user attributes from REST response.Once , user is set then using ng:show and $scope.watch i change parts of the header and show welcome 'username'.
The issue comes when user again refreshes the page, in that case User is reset and user sees the landing page header.How can i correct it?How can i persist the User value unless user logs out of the system?Should i set user in rootScope or is there any other better way to handle this?
This is an open-ended question and to really answer it, I'd need to know what your back end looks like and what your security requirements are.
I can see a two ways forward:
(1) If can rely on and trust cookies for security, you could just log the user in with data from cookies just like you log them in via the REST response. The cool thing about this is that, to the user, it would be instantaneous (the next option won't be).
(2) Have a separate controller that handles the header that will always make a request to the server for user data (logged in or not). SEN does something like this (and it drives me crazy btw). I don't know if you have a SEN account, but if you do, you could log in/out and try it out. You'll see that when you hit the page initially, you get a loading screen, but even after that loads, the header even has a little "Signing in..." loading widget itself.
You can use the local storage (a key-value pair HTML5 storage) to store the information and retrieve it on page load. There is a very simple library for this, if you don't want to write javascript yourself, called Lawnchair. Otherwise google for html5 local storage tutorials.

Preventing user access without duplicating the user validation logic

How do you prevent people from reaching certain routes, for example, edit and delete, if they are not registered, or not authorized?
In other words, how can I make so that the router rejects or redirects calls like:
http://appname.com/#/photo/1/edit
without duplicating the validation logic?
What I see as a very buzzing problem is the following: if I go to the aforementioned url, my router method won't bother to fetch info from the server if I have the photo model already (because this is what stateful apps should do, right ). However, now there is completely no way to tell if the current user is the owner of the photo (to be able to edit), unless the router method checks explicitly if their IDs match ... which is already duplication of the validation logic (because the server always makes a validation).
Dilemmas like this are simply ruining my day
Your models shouldn't be doing any authentication logic. If you have the logic in your server-side code, what's the problem? Your server should return unauthorized (401 or something similar), and then your model can respond appropriately (e.g., printing an error message to the user).

Resources