Get JSESSIONID in Angular applications - java

hope you can help me with this.
I am developing an application using Angular 8, that calls some Java REST Services (not a Spring backend, the services are written using only Jersey). When developing backend services, i used Postman app to test them, and this took me to an error: it seems that Postman automatically manages JSESSIONID, so when i try to call my service in Angular application, i realised that i have to do it manually.
The real question is, how to manage that ID in Angular? When i call my first service, a login service, in "Network" session of Chrome console i can see in response's headers the field:
Set-Cookie: JSESSIONID=averylongstring
I tried, following different other questions, to get it with
response.headers.get('Set-Cookie')
but it returns null. If i write
console.log(response.headers)
in .subscribe method, i can't see any relevant header, picture is following:
How can I access to that id? Is an error in Angular response handling or in service? I tried to return first a custom serializable bean and then a javax.ws.rs.core.Response object, hoping to fix, but i get the same situation.

Sometimes, mostly while responding to authentication/authorization request, the server uses "Set-Cookie" to set an "Http-Only" cookie for JSESSIONID to prevent XSS exploits, or so.
In these cases, you cannot read/get JSESSIONID cookie from client side, even if you see it on your browser's console.

We use ngx-cookie-service for managing cookies in our Angular applications. Here is how you can set it up:
npm install ngx-cookie-service --save
or
yarn add ngx-cookie-service
Add the cookie service to your app.module.ts as a provider:
import { CookieService } from 'ngx-cookie-service';
#NgModule({
...
providers: [ CookieService ],
...
})
export class AppModule { }
Then, import and inject it into a constructor:
constructor( private cookieService: CookieService ) {
this.cookieValue = this.cookieService.get('JSESSIONID');
}
Alternatively you can just access document.cookie but that would be much less explicit.

Related

AADAuthenticationFilter called only Once

I downloaded the Azure AD with spring boot from https://github.com/microsoft/azure-spring-boot. Its all nice and works well as long as I run theazure-active-directory-spring-boot-sample using
mvn spring-boot:run
as shown in the README file.
I am trying just a basic real-life scenario where the angular/react app is running separately on a separate port using npm. The moment I separated them out the main Filter AADAuthenticationFilter is only invoked once on the first request where it does token verification and never again for subsequent requests.
I went around and configured an nginx proxy so that the domains of these two are now same
localhost:9999 and I redirect based on the next path like web for the npm and app for the Spring boot. This enabled the cookies to be available at every request.
This helps because what I learned is that Spring uses cookies to maintain a session. But ideally, the AAD filter should revalidate the token every request.
But if I add a property of azure.activedirectory.session-stateless=true to my application.properties, as mentioned in the filter's code to make it stateless and validate on every request. It expects roles as a different attribute in AD instead of it being a group of the user.
I also don't understand get the behaviour, when the js files are embedded within the spring app and run all this works perfectly fine and the filter is invoked at every request. But when I separate them out it just doesn't work.
Any help or pointers would be appreciated.
I realize that a lot more info may be required for someone to debug the above problem. But I was just able to solve this - at least found the problem that was causing it. Like I mentioned earlier the problem started when I separated the client and spring APIs. And since the client was not able to send back the cookies set by server, due to change in domains I had to put a proxy server.
What I found out later was that every GET request was always invoking the AAD filter. Even multiple requests. But other requests like POST, PUT were failing. I tried disabling the csrf config in spring WebSecurityConfig.java -->> http.csrf().disable();
This solved my problem and now I receive a request and all works as expected. Now I am trying to figure out how not to disable csrf completely.
Thanks

IntelliJ Static Web Project to Tomcat or Angular CORs

I have a static web angular project in IntelliJ IDEA. The static page gets deployed to http://localhost:63342/Calculator/app/index.html. I have run into a problem where I try to post some data to a server to get a response back but when I try to post I get this error:
XMLHttpRequest cannot load <url>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 401.
Here is my post angular code:
WebIdServer.prototype.getId = function(id) {
var _this = this;
var request = {
method: 'POST',
url: 'https://<url>,
headers: {
'Authorization':'Bearer QWE234J234JNSDFMNNKWENSN2M3',
'Content-Type':'application/json',
},
data: {
id:id
}
};
_this.$log.debug(request);
return _this.$http(request)
.success(function(data, status, headers, config){
_this.$log.debug("Successfull request.");
/*called for result & error because 200 status*/
_this.uid = data.id;
_this.$log.debug(_this.uid);
})
.error(function(data, status, headers, config){
_this.$log.debug("Something went wrong with the request.");
_this.$log.debug(data);
/*handle non 200 statuses*/
});
};
I know for a fact that post works because I tried it on a local url of my application that I had running on a different port.
So my question is, since I can't post from localhost I was wondering if maybe deploying this to a tomcat server would fix things. If so, how do you deploy this static web project to a tomcat server? If that's not necessary, then how do I get around this problem I'm having?
There's a few things regarding CORS. It's a web browser telling you you cannot make a particular call. This is only a front end problem, a script running on a server can call any api regardless of the location. Three different options:
without config; same hosts
Without any configuration on your server, your front end's AJAX requests need to match both the domain and the port of the service you're calling. In your case, your angular app at http://localhost:63342 should be calling a service also hosted on http://localhost:63342 and then you're sweet. No CORS issues.
with server side config; different hosts
If the API is hosted elsewhere, you'll have to configure the API host. Most servers will let you configure access controls, to allow a particular domain to bypass the CORS block. If you have access to the server you're trying to call, see if you can set it up. The enable CORS website has examples for most servers. Usually this is pretty simple.
Create a proxy
This is your Tomcat idea. CORS is only a problem if your front end calls another service. A server script can call anything it likes. So, you could use Tomcat (or Apache, or NGINX, or NodeJS...) to host a script that'll pass on the request. Essentially, all it needs to do is add Access-Control-Allow-Origin: * to the response of the API.
I have never used Tomcat myself, but here's a blog post that might have some useful info on how to do that. Combine it with the info on enable CORS and you should be able to route anything to anywhere.
This process is common. Just look at the popularity of a node package like CORS anywhere, which is what your tomcat does.
As a disclaimer, how good of an idea this is depends on how you can pass along the credentials and tokens. You don't really want to create a service that'll just blindly call someone else's API with your credentials.

Cross-domain authentification with Spring Security

I have a web application built on Spring framework and running on Tomcat (lets call it exampleA.com). It has an API method for authentification - /securityLogin
And i have another site on a different domain (exampleB.com) that have an ability to send authentification request to examleA.com via API. And if the authentification is succesfull, user must be redirected to exampleA.com and be already authentificated. It all works fine by this point, session is created on the server, but user is not authentificated on examleA.com after redirect. I understand that this is because of my applications based on different domains, but i have no idea how can i fix this. Any suggestions?
OK, i have found the solution. I've just added
xhrFields: {
withCredentials: true
}
to my jQuery AJAX call, in order to allow JavaScript to pass my JSESSIONID cookie to the server

Cross Domain Error with self built API

The server sending JSON to the API is a Tomcat server in the Gradle packages (it is built in Java).
I am having trouble's making an API call with Angular. I know my API is working because I can view it on "Postman."
var app = angular.module("todo", []);
app.controller("AppCtrl", function($http){
$http.get("192.168.5.100:8080/aggregators/datafile")
.success(function(data){
console.log(data)
})
})
When I run it I get the following error:
XMLHttpRequest cannot load %3192.168.5.100:8080/aggregators/datafile. Cross origin requests are only supported for HTTP.
The problem you're running into is that you can't make cross origin requests from the browser without CORS or using JSONP.
Postman operates outside of the context of the browser (as if you had issued a cURL request, if you're familiar with cURL).
This is for security reasons.
So, how do you implement JSONP? It really depends on the server, but in general, your resource would look for a GET request that had a pre-determined querystring parameter (normally callback for simplicity):
http://192.168.5.100:8080/aggregators/datafile?callback=mycallback
How do you make a JSONP call?
The server wraps the JSON in that callback, causing it to look something like the following:
mycallback({json:object});
This Stack Overflow answer goes into more detail.
The callback is the function the browser should hit when the request is executed, and that's what allows for cross-domain requests.
Now, on to CORS.
CORS is a system for allowing the browser to communicate with the server to determine whether or not it should accept a cross domain request. It's a bit complicated, but in general it involves settings up certain Headers on your API Server; and then executing an Ajax request in a particular fashion (for JQuery, use the withCredentials property for $.ajax). The server checks where the request is from, and if it's a valid source, it let's the browser know and the browser allows the request (I'm being simplistic).
MDN has a thorough explanation of CORS that is worth reading.

Calling a REST web service secured with Spring Security from Android

I'm hosting a REST web service in a Grails application, using Spring Security, i.e.:
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def save = {
println "Save Ride REST WebMethod called"
}
I'm calling it from an Android app. (Calling the unsecured service works just fine.)
To call the service, I'm manually building up a request (HttpUriRequest) and executing it with an HttpClient.
I'm wondering what the best practices are, and how to implement them... Specifically, should I:
Perform a login once, to retrieve a JSESSION_ID, then add a header containing it into the HttpUriRequest for each subsequent request?
Or (not sure how I would even do this) include the login and password directly on each request, foregoing the cookie/server-side session
I think I can get option 1 working, but am not sure if Spring Security permits (2), if that's the way to go... Thanks!
--also, there isn't any library I'm missing that would do all this for me is there? :)
Spring security does support both basic authentication and form based authentication (embedding the username/password in the URL).
A REST service is generally authenticated on each and every request, not normally by a session. The default spring security authentication (assuming you're on 3.x) should look for basic authentication parameters or form parameters (j_username and j_password) (in the form http://you.com/rest_service?j_username=xyz&j_password=abc).
Manually tacking the j_username/j_password onto the URL, adding them as post parameters (I believe), or setting the basic authentication username/password should all work to authenticate a REST service against the default Spring Security interceptors, right out of the box.
I will admit that I haven't tried this on REST services, though I do clearly recall reading exactly this in the docs as I did the same for basic page logins on spring security recently. Disclaimer over.
I think you can use a login-once-and-get-a-token method that's similar to how oauth works.
sending username and password across the network outside of secured channel(https/ssl) is a terrible idea. anyone on the network can sniff your request package and see the clear text password.
on the other hand, if you use a token method, since the token string is randomly generated, even the token is compromised, the worst case is someone can use the token accessing your REST API.
another solution is going through ssl tunnel(HTTPS). i have actually done a comparison and result shows: 80 requests/min(https) vs 300 requests/min(http)

Categories

Resources