Spring boot rest controller POST request always create new sessionid using #SessionScope? - reactjs

I have searched a lot and found no suitable answers.
I have 2 post controller method as
#PostMapping("/saveStudentInfo")
public String saveStudentInfo(#RequestBody Students stud, HttpServletRequest request) {
students.setId(stud.getId());
students.setStudentName(stud.getStudentName());
students.setSchoolInfo(stud.getSchoolInfo());
System.out.println("Hello A= "+request.getSession(false).getId());
return "Saved Sucessfully";
}
#PostMapping("/saveSubjectInfo")
public String saveSubjectInfo(#RequestBody Subjects sub, HttpServletRequest request) {
subject.setSubjectName(sub.getSubjectName());
subject.setSubjectTeacher(sub.getSubjectTeacher());
System.out.println("Hello B= "+request.getSession(false).getId());
return "Saved Sucessfully Subject";
}
Now from postman these calls, works successfully, as same JSessionId is generated
==>Problem
When called from react app via browser on 2nd
saveSubjectInfo request I get different JSessionId, as in New-Session was Created
And I have annotated both Students and Subjects as #SessionScoped.
==>Requirement
Need to maintain session, and for that JSessionId needed to be same.

By default browsers support the GET method when API is hit directly from the browser URL bar. Also the POST and PUT method are usually supposed to make request along with some data to the serving method as the body so that it is not viewed in the browser request. For POST or PUT Postman app can be used.

Related

Session Id is changing every request in ASP.NET core 2.1 web api

I am working on asp.net core web application. I am not much aware of session state. When i login the application i have got the session id and I have pushed some user data's into session using HttpContext.Session. That values are under current sessionid. And then i sent that sessionid to client(browser). where i having using angularjs.
Whenever i sent the request after login. i have sending the sessionid along with request in request header. But after request reached my backend(WebApi) where i have seen another sessionid in HttpContext.Session. but i have my sessionid which that having those session values. But using current HttpContext.Session's sessionid couldn't get those session values.
Whether i have to get those session values by my sessionid which was came along request header or have to change HttpContext.Session's sessionid or Won't allow to change HttpContext.Session's sessionid for every request. Everything i have mentioned is have tried but couldn't do anything.What else is there? Please someone help me!. I could seen lot of answers about it in online but everything is for .Net Framework not for ASP.Net core 2.1.
Here is my code,
I have set session values in my user controller. and after login i will fill data in my quote creation page and give submit. Meanwhile i have to get my session values(which i stored in user controller login method) in my quote controller create method. So current request sessionid is changed in Httpcontext(even i use IHttpContextAccessor).so couldn't get my session values
public class UserController : Controller {
public string Login(User objUser)
{...
HttpContext.Session.SetString("CompanyId", "1");
...}
}
public class QuoteController : Controller {
public string CreateQuote([FromBody]Quote objQuote)
{...
var companyId = HttpContext.Session.GetString("CompanyId");
...}
}
This should help. You can access season
by HttpContext.
Check this example how work with seasson string.
using Microsoft.AspNetCore.Http;
public class HomeController : Controller {
public IActionResult Index()
{
HttpContext.Session.SetString("Test", "Testing Session.");
return View();
}
public IActionResult About()
{
ViewBag.Message = HttpContext.Session.GetString("Test");
return View();
}
}

Spring Social The OAuth2 'state' parameter is missing or doesn't match? [duplicate]

I am trying to use Spring Social on my application and I noticed while debugging that the original 'OAuth2' state parameter is always null on my app.
See Spring Social source code for org.springframework.social.connect.web.ConnectSupport below:
private void verifyStateParameter(NativeWebRequest request) {
String state = request.getParameter("state");
String originalState = extractCachedOAuth2State(request);//Always null...
if (state == null || !state.equals(originalState)) {
throw new IllegalStateException("The OAuth2 'state' parameter is missing or doesn't match.");
}
}
private String extractCachedOAuth2State(WebRequest request) {
String state = (String) sessionStrategy.getAttribute(request, OAUTH2_STATE_ATTRIBUTE);
sessionStrategy.removeAttribute(request, OAUTH2_STATE_ATTRIBUTE);
return state;
}
Can anyone please help?
edit: I do see the state parameter being passed back by facebook:
Request URL:https://www.facebook.com/v2.5/dialog/oauth?client_id=414113641982912&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fconnect%2Ffacebook&scope=public_profile&state=0b7a97b5-b8d1-4f97-9b60-e3242c9c7eb9
Request Method:GET
Status Code:302
Remote Address:179.60.192.36:443
edit 2: By the way, the exception I get is the following:
Exception while handling OAuth2 callback (The OAuth2 'state' parameter is missing or doesn't match.). Redirecting to facebook connection status page.
It turned out that the issue was caused by the fact that I was relying on headers - as opposed to cookies - to manage the session.
By commenting out the following spring session configuration bean:
#Bean
public HttpSessionStrategy sessionStrategy(){
return new HeaderHttpSessionStrategy();
}
The oauth2 state parameter issue was sorted.
P.S. Now I have got to find a way to get Spring Social to work with my current configuration of Spring Session...
Edit: I managed to keep the HeaderHttpSessionStrategy (on the spring session side) and get it to work by implementing my own SessionStrategy (on the spring social side) as follows:
public class CustomSessionStrategy implements SessionStrategy {
public void setAttribute(RequestAttributes request, String name, Object value) {
request.setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
}
public Object getAttribute(RequestAttributes request, String name) {
ServletWebRequest servletWebRequest = (ServletWebRequest) request;
return servletWebRequest.getParameter(name);
}
public void removeAttribute(RequestAttributes request, String name) {
request.removeAttribute(name, RequestAttributes.SCOPE_SESSION);
}
}
Try this work around and see if that works for you:
To my surprise I opened application in a 'incognito' browser and everything worked. Just like that. I think before something got cached and was causing the issue.
I ran into this issue today, My application was working perfectly fine. I just took a break for few hours and when I ran it again it started complaining about 'The OAuth2 'state' parameter is missing or doesn't match.'
The state param is first put into the session then the request goes out to facebook and the request comes back with the same state param but when spring is looking for session object to get the state param, it is not finding the session. I think it is not finding the session because when the request comes back it thinks that it is a different client (or host), even though the old HttpSession object still exists. The container maintains a HttpSession per client.
What you're getting from Facebook is not a request attribute , it's a request parameter.
You should get it by something like:
request.getParameter("state")

How do I get data out of the Authorization header and use it in my API? (Lexik JWT)

I am in the process of making a SPA (hybrid app) using ionic and AngularJS (1.5.x). I am using Symfony 2.8 for my backoffice and to handle my API.
I wanted to use JWT, and i'm using the Lexik JWT package for it. Everything works fine. When the user logs in, he gets a token that is then saved in the Authorization header. Only users with this token (or rather token in this header) can access the API and do API calls.
The only thing which is unclear to me is how to make it so that the user can only do API calls (Get user information, update only their own posts or such) that concerns their OWN information.
So far I've tried to get the data out of the Authorization header to further on somehow use this token's data (username is in there) to check if it is equal to the user's name who has made this report.
Tried several things such as getallheaders(), $token = $_SERVER['Authorization']; and other general functions that check the request headers, but everytime I'm getting errors as well.
Am I misunderstanding something or am I missing a step? Am I incorrectly using JWT? Is my reasoning correct that this is how I should do it or is there a more fluent way/logical to do this?
I'm also using FOSRestBundle for my API as well as NelmioCORS, NelmioApiDoc and FOSUSERBundle
When your are behind the firewall provided by the bundle and if the user is correctly logged in, you can get the user object from your controller by calling the methods getToken() then getUser() of the security.token_storage service.
If your controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller, you can directly call $this->getUser().
<?php
namespace AcmeBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* #Route("/api")
*/
class ApiController extends Controller
{
/**
* #Route("/hello")
* #Security("is_granted('ROLE_USER')")
*/
public function helloAction()
{
$token = $this->get('security.token_storage')->getToken();
$if (null !== $token) {
//$token should be an instance of Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken
$user = $token->getUser();
}
// or
$user = $this->getUser();
...
}
}

Override binding of Authentication class in Shiro with Guice

The problem I encountered is connected with message of a type:
OPTIONS http://localhost:8080
XMLHttpRequest cannot load http://localhost:8080/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
So basically it is an issue of our Angular JS 1.4.3 frontend sending OPTIONS request to the server before actual request. Problem occurs, because there is no way to add authentication data to this request and it is being blocked by Apache Shiro as it tries to access protected address.
Since I can not fix it on Angular side, I thought it would be easy on the server side. Would be, but we use Guice 4.
In Guice config we properly set up Shiro:
install(new EEShiroModule(getServletContext()));
filter("/services/*").through(GuiceShiroFilter.class);
so far so good. But now I want to make a hole in the system, allowing the OPTIONS request not to be authenticated. I have found a similar approach here: http://blog.awolski.com/cors-dart-dropwizard-and-shiro/.
At the end I am supposed to override the BasicHttpAuthenticationFilter but it is not so simple as it would be in Spring or Ini configuration because I can not override class binding.
What would be the best approach? Thanks!
Today I meet similar problem here. For CORS requests, the OPTIONS pre-flight request will be regarded as unauthenticated by Apache Shiro since the browser won't add custom headers to the OPTIONS request.
To solve this problem. I overrode the AuthenticatingFilter's isAccessAllowed method to make it always return true when the request's method is OPTIONS.
public class CORSAuthenticationFilter extends AuthenticatingFilter {
#Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//Always return true if the request's method is OPTIONS
if(request instanceof HttpServletRequest){
if(((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")){
return true;
}
}
return super.isAccessAllowed(request, response, mappedValue);
}
}
If you are using PermissionsAuthorizationFilter, you need to override it too.
public class CORSPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
#Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
if(request instanceof HttpServletRequest){
if(((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")){
return true;
}
}
return super.isAccessAllowed(request, response, mappedValue);
}
}
After having these filters overridden. They should be declared to be the running implementation in shiro's config file.
That is how i get things to work. Hope it helps, a little bit late though.

Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter..?

I am trying to send a PUT request to an amazonS3 presigned URL. My request seems to be called twice even if I only have one PUT request. The first request returns 200 OK, the second one returns 400 Bad Request.
Here is my code:
var req = {
method: 'PUT',
url: presignedUrl,
headers: {
'Content-Type': 'text/csv'
},
data: <some file in base64 format>
};
$http(req).success(function(result) {
console.log('SUCCESS!');
}).error(function(error) {
console.log('FAILED!', error);
});
The 400 Bad Request error in more detail:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>
<ArgumentName>Authorization</ArgumentName>
<ArgumentValue>Bearer someToken</ArgumentValue>
<RequestId>someRequestId</RequestId>
<HostId>someHostId</HostId>
</Error>
What I don't understand is, why is it returning 400? and What's the workaround?
Your client is probably sending an initial request that uses an Authorization header, which is being responded with a 302. The response includes a Location header which has a Signature parameter. The problem is that the headers from the initial request are being copied into the subsequent redirect request, such that it contains both Authorization and Signature. If you remove the Authorization from the subsequent request you should be good.
This happened to me, but in a Java / HttpClient environment. I can provide details of the solution in Java, but unfortunately not for AngularJS.
For the Googlers, if you're sending a signed (signature v4) S3 request via Cloudfront and "Restrict Bucket Access" is set to "Yes" in your Cloudfront Origin settings, Cloudfront will add the Authorization header to your request and you'll get this error. Since you've already signed your request, though, you should be able to turn this setting off and not sacrifice any security.
I know this may be too late to answer, but like #mlohbihler said, the cause of this error for me was the Authorization header being sent by the http interceptor I had setup in Angular.
Essentially, I had not properly filtered out the AWS S3 domain so as to avoid it automatically getting the JWT authorization header.
Also, the 400 "invalid argument" may surface as a result of wrong config/credentials for your S3::Presigner that is presigning the url to begin with. Once you get past the 400, you may encounter a 501 "not implemented" response like I did. Was able to solve it by specifying a Content-Length header (specified here as a required header). Hopefully that helps #arjuncc, it solved my postman issue when testing s3 image uploads with a presigned url.
The message says that ONLY ONE authentication allowed. It could be that You are sending one in URL as auth parameters, another - in headers as Authorization header.
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:scavenger_inc_flutter/utils/AuthUtils.dart';
import 'package:scavenger_inc_flutter/utils/URLS.dart';
class ApiClient {
static Dio dio;
static Dio getClient() {
if (dio == null) {
dio = new Dio();
dio.httpClientAdapter = new CustomHttpAdapter();
}
return dio;
}
}
class CustomHttpAdapter extends HttpClientAdapter {
DefaultHttpClientAdapter _adapter = DefaultHttpClientAdapter();
#override
void close({bool force = false}) {
_adapter.close(force: force);
}
#override
Future<ResponseBody> fetch(RequestOptions options,
Stream<List<int>> requestStream, Future<dynamic> cancelFuture) async {
String url = options.uri.toString();
if (url.contains(URLS.IP_ADDRESS) && await AuthUtils.isLoggedIn()) {
options.followRedirects = false;
options.headers.addAll({"Authorization": await AuthUtils.getJwtToken()});
}
final response = await _adapter.fetch(options, requestStream, cancelFuture);
if (response.statusCode == 302 || response.statusCode == 307) {
String redirect = (response.headers["location"][0]);
if(!redirect.contains(URLS.IP_ADDRESS)) {
options.path = redirect;
options.headers.clear();
}
return await fetch(options, requestStream, cancelFuture);
}
return response;
}
}
I disallowed following redirects.
Used the response object to check if it was redirected.
If it was 302, or 307, (HTTP Redirect Codes), I resent the request after clearing the Auth Headers.
I used an additioal check to send the headers only if the path contained my specific domain URL (or IP Address in this example).
All of the above, using a CustomHttpAdapter in Dio. Can also be used for images, by changing the ResponseType to bytes.
Let me know if this helps you!
I was using django restframework. I applied Token authentication in REST API. I use to pass token in request header (used ModHeader extension of Browser which automatically put Token in Authorization of request header) of django API till here every thing was fine.
But while making a click on Images/Files (which now shows the s3 URL). The Authorization automatically get passed. Thus the issue.
Link look similar to this.
https://.s3.amazonaws.com/media//small_image.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXXXXX%2F20210317%2Fap-south-XXXXXXXXFaws4_request&X-Amz-Date=XXXXXXXXXXXXXXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
I lock the ModHeader extension to pass Authorization Token only while making rest to REST API and not while making resquest to S3 resources. i.e. do not pass any other Authorization while making request to S3 resource.
It's a silly mistake. But in case it helps.
Flutter: if you experience this with the http dart package, then upgrade to Flutter v2.10!
Related bugs in dart issue tracker:
https://github.com/dart-lang/sdk/issues/47246
https://github.com/dart-lang/sdk/issues/45410
--> these has been fixed in dart 2.16, which has been shipped with Flutter v2.10!
https://medium.com/dartlang/dart-2-16-improved-tooling-and-platform-handling-dd87abd6bad1

Resources