Manual Session in Spring MVC Not Working - session

I am trying to set a session variable and retrieve it on a future request. I see there are several ways to do this in Spring MVC. I have tried several ways but none of them are working. I went back to the simplest way (manual session manipulation) and still no luck.
Here is my code:
#Controller
public class Test {
private static final Logger LOG = Logger.getLogger(Test.class);
#RequestMapping({ "/set", "/set/" })
public final ModelAndView set(
final HttpServletRequest request,
final HttpServletResponse response,
final HttpSession session) {
LOG.info("setting the session");
session.setAttribute("userId", new Object());
request.getSession(true).setAttribute("userId", new Object());
return new ModelAndView("someView");
}
#RequestMapping({ "/get", "/get/" })
public final ModelAndView get(
final HttpServletRequest request,
final HttpServletResponse response,
final HttpSession session) {
final HttpSession session1 = request.getSession();
final Object userId = session.getAttribute("userId");
final Object userId1 = session1.getAttribute("userId");
LOG.info("and the userId is '" + userId + "' '" + userId1 + "'");
return new ModelAndView("someView");
}
}
I hit my server at /set, then at /get. I look at my logs and see:
setting the session
and the userId is 'null' 'null'
Why is this not working?

I don't know why, but putting the following in my web.xml fixed the problem:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>

Related

Returning errors in HTML instead of JSON

I followed some tutorial for Spring Boot Security, and in that tutorial the guy is not creating a Frontend so his message for wrong credentials when user is trying to log in are in JSON. I did some changes to my own and created a page for login and registration, but I have problem to show errors when user insert wrong credentials.
This is method that show me JSON when user insert wrong data:
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
logger.error("Unauthorized error: {}", authException.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
final Map<String, Object> body = new HashMap<>();
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
body.put("error", "Unauthorized");
body.put("message", authException.getMessage());
body.put("path", request.getServletPath());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), body);
}
And in my controller I have this:
#PostMapping("/login")
#Transactional
public String login(#Valid #ModelAttribute("login") LoginRequest loginRequest, BindingResult result, HttpServletResponse response, Model model) {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
ResponseCookie jwtCookie = jwtUtils.generateJwtCookie(user);
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
model.addAttribute("login", loginRequest);
return "login_form";
}
model.addAttribute("login", loginRequest);
response.addHeader(HttpHeaders.SET_COOKIE, jwtCookie.toString());
return "redirect:/api/test/homePage";
}
So far its return error messages (validation field) on HTML if user doesn't populate fields, but if user enter wrong data I'm getting JSON {"path":"/api/auth/login","error":"Unauthorized","message":"Bad credentials","status":401}
I'm guessing that you're using thymeleaf to generate your html because that's the default option in most spring-boot projects, if so - take a look at this example.
Basically you need to pass the information about login error to the model object, and use it in your html template. For example .:
Controller method
model.addAttribute("loginError", true);
Login page template
<p th:if="${loginError}" class="error">Wrong user or password</p>

Not able to call SOAP API in WebServiceGatewaySupport by Spring WebServiceTemplate - Need help to fix this issue

I am trying to call SOAP API in Java Spring Boot using WebServiceGatewaySupport by Spring WebServiceTemplate
Config java class
public WebServiceTemplate createWebServiceTemplate(Jaxb2Marshaller marshaller, ClientInterceptor clientInterceptor) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
//SOAP URL
webServiceTemplate.setDefaultUri("http://host/Services.asmx");
//Auth ---It seems issue is here only????? need to check
webServiceTemplate.setMessageSender(new Authentication());
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
webServiceTemplate.afterPropertiesSet();
webServiceTemplate.setCheckConnectionForFault(true);
webServiceTemplate.setInterceptors((ClientInterceptor[]) Arrays.asList(createLoggingInterceptor()).toArray());
return webServiceTemplate;
}
SOAP Client Call
public class TicketClient extends WebServiceGatewaySupport {
public String getTicket(Ticket req) {
System.out.println("test inside webservice support1");
response = (AcquireTicketResponse) getWebServiceTemplate().marshalSendAndReceive(req);
Authentication Class
public class Authentication extends HttpUrlConnectionMessageSender {
#Override protected void prepareConnection(HttpURLConnection connection) {
String userpassword = username+":"+password+":"+domain;
String encoded =
Base64.getEncoder().withoutPadding().encodeToString(userpassword.getBytes(StandardCharsets.UTF_8));
connection.setRequestProperty("Authorization", "Basic "+encoded); connection.setRequestProperty("Content-Type", "application/xml"); super.prepareConnection(connection);
}
Not using Authetication class and add the above into
ClientInterceptor
public class SoapLoggingInterceptor implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
String username="test";
String password="test";
String domain = "#test";
String userpassword = username+":"+password+domain;
String encoded = Base64.getEncoder().withoutPadding().encodeToString(userpassword.getBytes(StandardCharsets.UTF_8));
messageContext.setProperty("Authorization", "Basic "+encoded);
messageContext.setProperty("Content-type", "XML");
Case -1 --->When I passed (user, pwd, domain and content-type) through messagesender, content type is taking but throwed "BAD REQUEST ERROR 400"....When i comment contenttype property, then it throwed "INTERNAL SERVER ERROR 500".
Case-2...when I passed (user, pwd, domain and content-type) through ClientInterceptor , always it throwed "INTERNAL SERVER ERROR 500"......It seems Authentication properties for the service are not going to API call.............................Please suggest some options
Both the cases, Authentication is not passing to service, if i comment,Authentication code (userid/pwd/domain) in both cases also...no efforts in output
After setting the user ID/pwd
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
String username="test";
String password="test";
String domain = "#test";
String userpassword = username+":"+password+domain;
byte[] userpassword = (username+":"+password).getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(userpassword);
ByteArrayTransportOutputStream os = new
ByteArrayTransportOutputStream();
try {
TransportContext context = TransportContextHolder.getTransportContext();
WebServiceConnection conn = context.getConnection();
((HeadersAwareSenderWebServiceConnection) conn).addRequestHeader("Authorization", "Basic " + encoded);
} catch (IOException e) {
throw new WebServiceIOException(e.getMessage(), e);
}
First of all don't set the content type Spring WebServices will do that for you, messing around with that will only make things worse.
You should get the WebServiceConnection and cast that to a HeadersAwareSenderWebServiceConnection to add a header.
public class BasicAuthenticationInterceptor implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
String username="test#test";
String password="test";
byte[] userpassword = (username+":"+password).getBytes(UTF_8);
String encoded = Base64.getEncoder().encodeToString(userpassword);
WebServiceConnection conn = TransportContext.getConnection();
((HeadersAwareSenderWebServiceConnection) conn).addHeader("Authorization", "Basic " + encoded);
}
}
You also need to configure it. Assuming it is a bean don't call afterPropertiesSet (and ofcourse you are now using the ClientInterceptor remove the new Authentication() for your customized message sender.
The List<ClientInterceptor> will automatically create a list with all the interceptors so you can easily inject them.
#Bean
public WebServiceTemplate createWebServiceTemplate(Jaxb2Marshaller marshaller, List<ClientInterceptor> clientInterceptors) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marshaller);
//SOAP URL
webServiceTemplate.setDefaultUri("http://host/Services.asmx");
webServiceTemplate.setCheckConnectionForFault(true);
webServiceTemplate.setInterceptors(clientInterceptors);
return webServiceTemplate;
}
If this doesn't work there is something else you are doing wrong and you will need to get in touch with the server developers and get more information on the error.
Update:
Apparently you also need to provide a SOAP Action in your request, which you currently don't. For this you can specify the SoapActionCallback in the marshalSendAndReceive method. Which action to specify you can find in the WSDL you are using.
SoapActionCallback soapAction = new SoapActionCallback("SoapActionToUse");
response = (AcquireTicketResponse) getWebServiceTemplate().marshalSendAndReceive(req, soapAction);

handling session with spring mvc

Actually i am setting the attributes which are getting from bean class in modelandveiw method and trying to get that attribute in other modelandveiw method method but getting null values in
rs.getAttribute("customerId")
. Please help me.
#RequestMapping(value ="/insert",method= RequestMethod.Post)
public ModelAndView inserData(#ModelAttribute SavingBean savingBean,HttpServletRequest rs) {
HttpSession session = rs.getSession();
if (savingBean != null)
SavingBean saving = persionalService.insertData(savingBean);
int a = saving.getCustomerId();
rs.setAttribute("customerId",a );
System.out.println(saving.getDisgnProf());
List<SavingBean> list = new ArrayList<SavingBean>();
list.add(saving);
return new ModelAndView("welcome","list", list);
}
#RequestMapping(value ="/insertdata",method= RequestMethod.Post)
public ModelAndView check (#ModelAttribute SavingBean savingBean,HttpServletRequest rs) {
System.out.println(savingBean.getFirstName());
HttpSession session = rs.getSession();
System.out.println("abhishek" + rs.getAttribute("customerId"));
return null ;
}
You're not putting or getting anything from the session in this code. You're putting and getting attributes from rs, and rs is the request, not the session.
Yes you are putting it in the request rs, put it in session instead and you vill se it

Custom Exception when the URL is invalid and when the Database is not connect - Spring MVC

this example is useful when I want to validate the existence of an object.
#ResponseStatus(value=HttpStatus.NOT_FOUND)
public class CustomGenericException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String errCode;
private String errMsg;
#Controller
public class MainController {
#RequestMapping(value = "/units/{id}", method = RequestMethod.GET)
public ModelAndView getPages(Integer id)
throws Exception {
if ( service.getUnidad(id) == null) {
// go handleCustomException
throw new CustomGenericException("E888", "This is custom message");
}
}
#ExceptionHandler(CustomGenericException.class)
public ModelAndView handleCustomException(CustomGenericException ex) {
ModelAndView model = new ModelAndView("error/generic_error");
model.addObject("errCode", ex.getErrCode());
model.addObject("errMsg", ex.getErrMsg());
return model;
}
URL : /units/85
The unit 85 does not exist.
But I want to custime exception when I enter a URL invalid (For example /thisurlnoexists),
and the output should be THIS URL IS INCORRECT.
So I want to know if there is any way to intercept url exepcion customize without having to type throw new EXAMPLEEXCEPTION in the method. The same would like to know if I get an SQL error.
Thanks in advance
UPDATE
For 404 page not found , its work fine. The code is
web.xml
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
controller
#RequestMapping("error")
public String customError(HttpServletRequest request, HttpServletResponse response, Model model) {
model.addAttribute("errCode", "324");
model.addAttribute("errMsg", "PAGE NOT FOUND");
return "error";
}
But for Database this code not found
#ControllerAdvice
public class GeneralExceptionController {
#ExceptionHandler({SQLException.class,DataAccessException.class})
public String databaseError(ModelMap model, Exception exception) {
model.addAttribute("errCode", "ERROR");
model.addAttribute("errMsg", "SQL");
return "error";
}
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception exception) {
ModelAndView mav = new ModelAndView();
mav.addObject("errCode", exception);
mav.addObject("errMsg", req.getRequestURL());
mav.setViewName("error");
return mav;
}
}
Controller
#RequestMapping(value = "/sites", method = RequestMethod.GET)
public String getSites(#RequestParam(required = false) String error, ModelMap modelMap) {
List sites = siteBusiness.getAllSites(); //assume that the database is offline, at this point the exception originates
modelMap.put("sites", sites);
return "sites";
}
Spring controller has different notions for inexistant, and invalid Urls.
Taking your example :
/uuuunits/* : NoSuchRequestHandlingMethodException (at DispatcherServlet level) -> 404
/units/foo : (you asked for an Integer ) : TypeMismatchException -> 400
/units/85 : to be dealt with by controller.
You will find references on Spring Reference Manual/ Web MVC framework / Handling Exceptions
If you're looking for Urls that are invalid, it means those URL don't Exist. Hence, all that you need is a 404-Page not Found handler, and you can easily set up that in spring.
About connection error to database, The same applies to it also.
You can make your application container handle such exceptions.
Uncaught exceptions within an application can be forwarded to an error page as defined in the deployment descriptor (web.xml).
<error-page>
<exception-type>Your-exception-here</exception-type>
<location>/error</location>
</error-page>
You can a common page for all your DB errors using the following code snippet.

How to avoid redirect loop in spring web mvc

public class ValidateSession extends HandlerInterceptorAdapter {
//before the actual handler will be executed
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
if(session.getAttribute("user")==null){
/*ModelAndView mav = new ModelAndView("/login/index");
throw new ModelAndViewDefiningException(mav);*/
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/login/index.mars");
throw new ModelAndViewDefiningException(mav);
}
return true;
}
}
In my case if session is expired then user can't access my application, but i am stuck with redirection loop. although i have tried many possible ways but not luck :(
Don't associate the ValidateSession handler with the login/index.mars request. Use mvc interceptor. Exclusions possible since 3.2, I think.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/yourpath/*"/>
<exclude-mapping path="/login/index.mars"/>
<bean class="org...ValidateSession " />
</mvc:interceptor>
</mvc:interceptors>
I know this is an old post but thought it may be of help since none of the above worked for me.
In the class implementing HandlerInterceptor:
response.sendRedirect("login?logout=true");
then in controller:
#RequestMapping(value = "login", method = RequestMethod.GET)
public String login(ModelMap modelmap, HttpServletRequest request, HttpSession httpSession, #RequestParam(required = false) String logout, #RequestParam(required = false) String reason, #RequestParam(required = false) String message) {
if (reason != null && MvcStatics.ERROR_MAP.get(reason) != null) {
ArrayList<String> errors = new ArrayList<>();
errors.add(MvcStatics.ERROR_MAP.get(reason));
modelmap.addAttribute("errors", errors);
}
if (logout != null && logout.equalsIgnoreCase("true")) {
httpSession.removeAttribute("loggedIn");
httpSession.removeAttribute("user");
httpSession.removeAttribute("token");
modelmap.addAttribute("message", "You have successfully been logged out.");
}}
i experienced the same issue. just remove the "redirect:" appended before "/login/index.mars"
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/login/index.mars");
//to this and you redirect ll works fine
mav.setViewName("/login/index.mars");
throw new ModelAndViewDefiningException(mav);

Resources