Form-based Authentication with a Restful Api in a Java EE Web Application - ajax

we have a problem in our web application and I'm looking for some opinions.
The following scenario:
We have a Java EE Server Application deployed on a JBoss Application Server
Our Web Application is also deployed in the AS
The Web Application communicates with the server via JAX-RS
The Web Application needs authentication
Currently we are using 'form-based authentication', which is directly provided by our Application Server.
The advantage of this approach:
List item
We don't have to do anything, but just specify the auth-method 'FORM' and specify a login page
We can design our login page by ourselves -> the page looks awesome
The disadvantage and also the problem I'd like to discuss:
Our webapplication makes calls (inital-page-load/ajax) to our server application.
If the user is authenticated, it will receive JSON responses. But if the user is not authenticated, the form-based auth will intercept the call and return a html page.
(this looks fishy: WebApp makes a ajax call and expects json, but will receive a http redirect to a html page [login.html]).
The current problem:
At some point the session cookie (of the form-based auth) will timeout, and then the complete application breaks, because each ajax request will not receive any json (as expected), but will receive the login.html page.
Would be really thankful if people who solved that problem could report about their approach and architectural design decisions.
Current Ideas:
Switch from form-based to something else (and provide a /login rest resource)
React on the client code on possible wrong responses (if http code 301 -> redirect on login page)
Something else I can't think of right now

Related

Spring authorization server OAuth2 login from my own login page

I have a front end (angular) with login form, a back-end for that angular application as my OAuth client (spring dependency) then I have a third application that is the Authorization server and finally the forth is the ressources server.
So I want to know is there is any way to jump the redirect to /login from the authorization server?
I want to login the user with angular login page, then make a get with my OAuth client (spring) for the authorization code flow and then, since i'm not authenticated, instead of getting redirect, I want to get an error "401" and then send a post request with my OAuth client (spring) to the auth server again to login the user that have sent the data previously in angular login page.
Essentially I just wanted to login to my auth server with a custom page that exists in the front end application and let the backend build specially for that front, take over the flow.
You want seamless integration between login form and the rest of your Angular app? Share your CSS between Angular (public) client and authorization-server embedded (private) one, don't implement login in public client.
You might need to better grasp OAuth2 concepts.
Login, logout and user-registration are authorization-server business. Leave it there. Reasons are related to security and just being future-proof: what if you want to plug additional clients to your system (mobile apps for instance)? Are you going to implement login, logout and user-registration again and again? What if you have to introduce multi-factor authentication at some point? Would you break all clients at once?
Your "backend" (Spring REST API secured with OAuth2) is a resource-server, not a client. Make sure it is configured as so: depends on spring-boot-starter-oauth2-resource-server (directly or transitively). This is where the HTTP status for missing (or invalid) authorization is handled. The way to do it depends on your resource-server being a servlet or reactive app. The libs in the repo linked just before do what you want by default (401 instead of 302).
In your case, client is Angular app. I hope you use an OAuth2 client lib such as angular-auth-oidc-client to handle:
authorization-code flow (redirects to authorization-server, back from authorization-server with authorization-code and tokens retrieval with this authorization-code)
refresh-token flow (automatic access-token refreshing just before it expires)
requests authorization (add Bearer Authorization header with access-token on configured routes)
What my Angular apps do for login is just redirect users to authorization-server "authorization" end-point and then just wait for a redirect back to "post-login URL" with an authorization-code. How this code was obtained is none of their business (can be a login form, a "remember-me" cookie, some biometry, etc.).
Also, I have to admit that I don't use Spring's authorization-server. I prefer mature / feature-full solutions like Keycloak, Auth0, Okta, etc. which come with much more already implemented: multi-factor authentication, integration with LDAP, identity federation for "social" providers (Google, Facebook, Github, etc.), administration UI, ...
As ch4mp said, it's best to leave all the authentication and authorization logic and pages to the Spring Authorization Server, it's pretty easy to customize and configure all the user accessible pages (login, authorize, etc...) with Thymeleaf, you only have to bring in your CSS to unify the design.
There was a great demo in last year's Spring One which seems like something you'd like to achieve, you can find the code in this repo.
They used Spring Cloud Gateway as a means to run the Angular SPA in the flights-web app, configuring it as the OAuth client. Following this path you can route all calls to your backend API through the gateway's WebClient.

Working with SSO: Ajax request

I have a web application and API Server, the web application consumes API always via AJAX except in a couple of scenarios.
When I enable SSO for both, I face the well known problem - how to handle redirect in AJAX.
(A bit more details: Azure mandates that the user should login to AD only via its login page - so ideally when a webpage or an api endpoint is accessed, they should get redirected to the azure login page. Since HTTP302 redirect doesn't work well with XmlHTTP, user will not get redirected to the authentication page when API is accessed via AJAX)
I have a few options to solve this issue:
When the web application is authenticated redirect to a predefined api endpoint (eg: 'api/login') and that will take care of api authentication and once that is done, redirect it back to the web app. So the user will be redirected this way:
web -> azure login -> web -> api -> azure login (auto login) -> api ->
web
Load the api endpoint in an iframe (or an image) and wait for the load complete event
Authenticate only web application - Remove api from sso context and find some other of way to identify and validate the web request at API side (tokens, cookies)
Please help me to choose a right pattern.
AJAX follows redirects automatically:
How to prevent ajax requests to follow redirects using jQuery
Detecting a redirect in jQuery $.ajax?
You need to distinguish between the reply from the service and the login page, which you get after AJAX follows the redirect (but not with safari+cors!). For example, detection could be done by checking for a string inside of response body. When detected, just redirect user to the login page by document.location=<login-page-url>.
Another option would be to use a token inside of "Authorization" HTTP header instead of SSO for backend-service protection:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/

Spring Security and Single Page Applications

My application will be:
- Single Page App (say in angular/backbone)
- Spring MVC based Server.
I find many examples about using Spring-Security where the login page, logout page etc.. are all HTMLs. And Spring Security directs to appropriate pages based on Session State.
But in my case the login/logout page will be in JavaScript - All interaction with the server for login/logout is over HTTP(REST style URLs), and response JSON. There is no HTML in play here.
Question
How can i use Spring Security in this case? In other words - How can i expose login/logout behavior as a API?
Since the front end is Browser based app... i guess usual cookies etc. should still work for identifying session.
Yes Cookies still work in your cases. But you need to tap on the ajax urls instead of normal urls. I had an experience with a mobile based - single page application and I managed to do it with a grails backend. When logging in tap on /j_spring_security_check?ajax=true if http response is 302 and it redirects you to /login/ajaxSuccess it means that you have logged in successfully. Otherwise you failed to login.

Securing jQuery calls to Spring MVC REST API using Spring Security

I'm developing a REST JSON API with the Spring MVC Framework. I want to serve a single HTML application to the user and the whole communication between server and client is done with JSON format. So the client single HTML application uses jQuery to send AJAX calls to the server.
My big problem is to find the right way to do integrate a proper security technique. I read a lot about basic, digest or form based authentication via Spring Security, but I don't think this is the right way. I want to get JSON responses if the user isn't logged in and I don't want to send a jsessionid with each request.
Could you please tell me the right way or the best-practice how to authenticate user by performing AJAX requests? Maybe it's OAuth 2-legged? (don't have much clue of OAuth)
If you don't want to store auth information in server-side session (and use JSESSIONID in cookies/urls) you may send auth info with every ajax request using BASIC auth header (created in JS).
I've never used 2-legged oauth, so I won't comment about it.
edit: typo

Ajax authentication without letting browser pop up login dialog

I am desiging a RESTful Web Service (JBoss + RESTeasy). The UI programmer is writing an Ajax web app that will use it. The web app will be one HTML page with everything done in JavaScript. For security, all traffic goes through SSL.
Currently I'm using Basic authentication. The UI programmer can show a dialog to get a username and password and put "Authorization: Basic xxxxx" in the header. Unfortunately if the password is wrong, the ugly browser login dialog box comes up. Also there is no way for the user to log off. This is unacceptable.
There appears to be no way to intercept a 401 response to an XMLHttpRequest in any of the browsers we will use.
Form-based authentication won't work for us. We need an automatic logoff after some period of inactivity (the equivalent of a session timeout). We can't have the server suddenly return a login page when the client expects a JSON object.
JBoss offers four authentication strategies: BASIC, FORM, CLIENT-CERT and DIGEST. I think DIGEST has the same problem as BASIC. None of the four is what we want.
This web application will be the only client (for now) so there is no requirement to use BASIC. Is there any other authentication strategy I can install? For instance is there an implementation of WSSE UsernameToken I can use? (As described in Chapter 8 of the O'Reilly RESTful Web Services book.) The server would send "WSSE" instead of "Basic" in the WWW-Authenticate header and presumably the browser would ignore it and pass it right through.
I want to configure security where it belongs -- in the JBoss configuration files, not in my RESTful Web Service -- so I'm looking for an implementation I can just plug into JBoss.
The browser won't present the password dialog if it doesn't recognize the authentication scheme in the WWW-Authenticate header. Your best bet may be to continue using basic auth on the server while setting the header manually to something like "Basic/MyApp" for 401 responses.

Resources