Angular : accepting cookie send by backend - javascript

So, I'm currently working on session management and found out that one of the ways of doing so is by using cookies. I'm using spring boot as my backend tool.
So,
#PostMapping("/addUser")
public User addUser(#RequestBody String name, HttpServletRequest request, HttpServletResponse response) {
HttpSession getSession = (HttpSession) request.getAttribute("session");
Cookie cookie = new Cookie("sessionId", getSession.getId());
response.addCookie(cookie);
sessionService.addSession(getSession);
String session = (String) getSession.getId();
System.out.println("Session id is " + session);
User newUser = new User(name, session);
userService.addUser(newUser);
return newUser;
}
This is the code that's responsible for creating cookies. Where, what happen is user will enter the username on a form and click on submit and then it will be post mapped on this method.
So, I tried checking if I'm getting cookies from frontend or not using this method
#PostMapping("/noOfUsers")
public int userCount(#RequestBody String sessionId, HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getSession().getId());
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("sessionId")) {
System.out.println(cookie.getValue());
}
}
}
return this.userService.noOfUser();
}
When I used postman, I did get the cookie value printed but don't know how in angular I'm suppose to accept the cookie send by backend and in the end send back the cookie on each request made using frontend.

Related

Showing error while using response.json() in ember js to fetch response from API

I have to create a web app to add a user in mySQL Database and implement UI using ember js.
app/components/user.hbs
<h1>User Management!</h1>
<div>
<label1>User Id </label1> <colon1>:</colon1>
<input1>{{input type="text" value=id placeholder="Enter id"}}</input1>
<label2>Firstname</label2> <colon2>:</colon2>
<input2>{{input type="text" value=firstname placeholder="Enter firstname"}}</input2>
<label3>Lastname</label3> <colon3>:</colon3>
<input3>{{input type="text" value=lastname placeholder="Enter lastname"}}</input3>
<label4>Mail Id</label4> <colon4>:</colon4>
<input4>{{input type="text" value=mailid placeholder="Enter mailid"}}</input4>
</div>
<button1 {{on "click" (fn this.user "add" id firstname lastname mailid )}}>Add User</button1>
<button2 {{on "click" (fn this.user "delete" id firstname lastname mailid )}}>Delete User</button2>
app/components/user.js
import Component from '#glimmer/component';
import {action} from "#ember/object";
import {tracked} from "#glimmer/tracking";
export default class UserComponent extends Component {
#action
async user (type,id,firstname,lastname,mailid){
let response=await fetch("http://localhost:8080/UserManagement/UserManagementServlet",
{ method: "POST",
mode:"no-cors",
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({
"type": type,
"id": id,
"firstname":firstname,
"lastname":lastname,
"mailid":mailid
})
});
let parsed=await response.json();
alert(parsed.status);
}
}
Servlet API code
//Required Header files
#WebServlet("/UserManagementServlet")
public class UserManagementServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest req,HttpServletResponse res) throws ServletException, IOException
{ res.setContentType("application/json");
res.setCharacterEncoding("UTF-8");
Gson gson=new Gson();
BufferedReader br=new BufferedReader(new InputStreamReader(req.getInputStream()));
String param=br.readLine();
User user = gson.fromJson(param, User.class);
HashMap<String,String> jsonfile=new HashMap<String,String>();
PrintWriter out=res.getWriter();
String url="jdbc:mysql://localhost:3306/employee",username="root";
String password="root";
Connection con=null;
PreparedStatement pst;
String query="select*from user";
ResultSet rs;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con = DriverManager.getConnection(url,username, password);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Entered");
if (user.getType().equals("add")) {
try {
String insertquery="INSERT INTO user" +" (id,firstname,lastname, mailid) VALUES " +" (?,?, ?, ?);";
pst = con.prepareStatement(insertquery);
pst.setString(1, String.valueOf(user.getId()));
pst.setString(2, user.getFirstName());
pst.setString(3, user.getLastName());
pst.setString(4, user.getMailid());
jsonfile.put("id", String.valueOf(user.getId()));
jsonfile.put("firstname", user.getFirstName());
jsonfile.put("lastname", user.getLastName());
jsonfile.put("mailid", user.getMailid());
jsonfile.put("status","User Added Successfully");
String final1=gson.toJson(jsonfile);
System.out.println(final1);
out.println(final1);
pst.executeUpdate();
} catch (Exception e) {
out.println("error"+e);
}
}
out.flush();
}
}
It showed Cors error so I added "mode":"no-cors" in user.js but after that cors error got disappeared but this error didn't.
While Clicking Add User Button, it shows an error in this line " let parsed=await response.json();"
user.js:54 Uncaught (in promise) SyntaxError: Unexpected end of input
at UserComponent.user (user.js:54)"
Basically I can just recommend to understand what CORS is. In short, you're trying to make a cross-origin request (probably from http://localhost:4200 to http://localhost:8080) and then you have to use CORS or the browser will block this for security reasons.
However this is probably not what you want. This issue arises because you run the ember development server and so have a different origin then your backend. However later in production this wont happen - you wont run the ember server there but probably have one webserver serve both your backend and your frontend.
For this case (and this is not always true but often) the ember development server has the --proxy option. So you would run ember serve --proxy=http://localhost:8080 and then it will proxy all AJAX requests from http://localhost:4200 to http://localhost:8080.
Then you change the URL you fetch from "http://localhost:8080/UserManagement/UserManagementServlet" to "/UserManagement/UserManagementServlet".
This is because if you dont specify a origin but start with a / its always the current origin. This also has the benefit that you wont have to change this for production.
Then the browser will request to "http://localhost:4200/UserManagement/UserManagementServlet" which will work without CORS (also no need for mode:"no-cors") and the ember development server will redirect it.
However if you plan to have seperate servers for the backend and the frontend in production this wont work and you'll need to use CORS.
A quick note about mode:"no-cors". This will always prevent you from reading the response and so make the request useless for loading data. This is only ever relevant for sending data. See here:
JavaScript may not access any properties of the resulting Response.

how to get the values that were sent from axios.post in the backend

I am using react for the frontend and springboot for the backend. I am not able to retrieve the data that I sent using axios in the backend. The first code below is the frontend where I make post and send 3 objects that I want to use in the backend. And the second code segment is the backend where I have post mapping but really confused on how to get those 3 objects that I sent from frontend. Also the user is where I have the getter and setters for name, message, and email so I want to set the data from frontend into those variables in User. I am somewhat new to springboot but I have some experience in connecting database to springboot but in this case I dont need to use database to store anything. The overall goal is for me to achieve a working contact form where users can submit comments/complaints about a webpage and it will direct those emails to me.
const info = {
name: "Test"
message: "This is comment for test",
email: "test#test.com
};
axios.post("http://localhost:8080/postgressApp/signup-success", info)
.then(response => {
if(response.data != null) {
this.setState({show:true});
setTimeout(() => this.setState({show:false}), 3000);
window.location.reload();
} else {
this.setState({show:false});
}
});
#RestController
#RequestMapping("/postgressApp")
#CrossOrigin(origins="http://localhost:3000")
public class RegistrationController {
private Logger logger = LoggerFactory.getLogger(RegistrationController.class);
#Autowired
private NotificationService notificationService;
#PostMapping("/signup-success")
public String signupSuccess(){
// create user
User user = new User();
// send a notification
try {
notificationService.sendNotificaitoin(user);
}catch( MailException e ){
// catch error
logger.info("Error Sending Email: " + e.getMessage());
}
return "Thank you for registering with us.";
}
}
Change your method signature like this:
...
#PostMapping("/signup-success")
public String signupSuccess(#RequestBody User user) {
...
}
#RequestBodyannotation tells Spring to bind the incoming http request's body to your type. It will check your request parameter keys and values, check the type you provided after the annotation, try to match parameter keys with the fields in your User class and then copy the values from request to your User instance.

How to connect jade-agents (java) and babylon.js (html/javascript) - Servlet to html?

Summary:
IDE: Eclipse
Server: Java
Client: Html/Javascript
After sending data via ajax/jquery to a servlet and using JadeGateway to send those information to an agent, resulting data should go back to html/javascript.
I need a way to connect either a servlet or an agent with an existing and running html file (ofc without reloading the page).
Background:
I want to create a agent based game using babylon.js and jade/pug (let's call it jade).
During a game, information about game states should go to an agent, so that he could figure out what to do (e.g. create more units or attack). After this, the agent needs to send the information to the game, to call the appropriate function.
What I did so far:
I connected the game (html/javascript) with a servlet using ajax. There I used JadeGateway to send an ACLMessage to an agent.
I also used websockets to connect client/server but this method is too limited for what i need i think.
I now need a tool/method or tips to send information from an agent or the servlet. Both is possible, because the agent can send information back to the jadegateway agent/servlet.
I know how to use ajax to call a servlet from html and right back, but now the information is tranfered to some other classes, so that didn't work anymore.
In the babylon.js scene.registerBeforeRender function I do this:
$.ajax({
url: "AgentListenerServlet",
type: "POST",
data: {playerString: convertPlayerToJson(player1)},
success: function(data) {
alert(data.command)
},
error: function() {
alert("Listener Failed")
}
});
Sending message to an agent via jadegateway:
JadeGateway.execute(new CyclicBehaviour() {
public void action() {
final ACLMessage msgSend = new ACLMessage(ACLMessage.INFORM);
msgSend.setContent(message);
msgSend.addReceiver(new AID("First", AID.ISLOCALNAME));
myAgent.send(msgSend);
final ACLMessage msgReceive = myAgent.receive();
if(msgReceive != null && msgReceive.getContent() != null){
//used this as immediate answer for ajax success function, but maybe it can also be used to send the returning agent message?
Map <String, Object> map = new HashMap<String, Object>();
map.put("command", "information");
write(response, map);
} else {
block();
}
}
});
private void write(HttpServletResponse response, Map<String, Object> map) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson(map));
}
agent code (simplified):
public void action() {
final ACLMessage msgSend = new ACLMessage(ACLMessage.INFORM); //sending message
final ACLMessage msgReceive = receive(); //receiving message
//Here i get information out of sent json objects from jadegateway
//Maybe here send handled information back to html?
} else {
block();
}
}
Maybe showing this codes is not necessary, because they are working and the problem is not there, but the template for asking a question requested these.
Expected and results:
So the problem is not, that it isn't working, but that I need to know how to continue.
I don't know what I expect, because i don't know the possibilities.
Maybe, what would help me, is to send a simple string from the agent or servlet that i can call with the alert function in the game.
Or maybe i should ask this: is it possible to get an answer in ajax (success function) after the data was sent to the servlet and passed to an agent?
Sorry for the huge spam. Hope I made my problem clear.
No need to reply, websockets is the solution after all.
I just figured out, that you can push data from server to client without a client request with
session.getBasicRemote().sendText(msgReceive.getContent());
The session is automatically generated and you can reveice it with websockets onopen method:
#OnOpen
public void onOpen(Session session){
this.session = session;
}

Redirect user with id_token as a parameter in redirect URL causes Identity user to be Null

I have been working with AADB2C Authentication and struggling over redirecting the user to home page with id_token as fragment in redirect url. below is how i initiate authentication challenge in Account controller
public class AccountController : Controller
{
public AzureAdB2COptions AzureAdB2COptions { get; set; }
public AccountController(IOptions<AzureAdB2COptions> b2cOptions)
{
AzureAdB2COptions = b2cOptions.Value;
}
// GET: /<controller>/
[HttpGet]
public IActionResult SignUpSignIn()
{
var redirectUrl = "http://localhost:7878/dasdfsd/home";
return Challenge(
new AuthenticationProperties { RedirectUri = redirectUrl },
OpenIdConnectDefaults.AuthenticationScheme);
}
}
and below is where i redirect user to redirect url(http://localhost:7878/dgddfg/home) with id token fragmented along with url
public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
{
// Use MSAL to swap the code for an access token
// Extract the code from the response notification
var code = context.ProtocolMessage.Code;
string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
TokenCache userTokenCache = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance();
ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);
try
{
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' '));
context.HandleCodeRedemption(result.AccessToken, result.IdToken);
context.HandleResponse();
context.Response.Redirect("dfgfd/home#grant_type=" + context.ProtocolMessage.GrantType + "&id_token=" + result.IdToken);
}
catch (Exception)
{
//TODO: Handle
throw;
}
}
when user redirects to home page using javascript i get the id_token from url and calling Account controller action("GetAccessTokenAsync") to get access token using identity user
[HttpGet]
public async Task<string> GetAccessTokenAsync()
{
string signedInUserID = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
TokenCache userTokenCache = new MSALSessionCache(signedInUserID , HttpContext).GetMsalCacheInstance();
ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);
try
{
var userAccounts = await cca.GetAccountsAsync();
if (userAccounts == null && userAccounts.Count()==0)
{
throw new Exception("The User is NULL. Please clear your cookies and try again. Specifically delete cookies for 'login.microsoftonline.com'. See this GitHub issue for more details: https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/issues/9");
}
AuthenticationResult result = await cca.AcquireTokenSilentAsync(AzureAdB2COptions.ApiScopes.Split(' '),userAccounts.FirstOrDefault());
return result.AccessToken;
}
catch (Exception ex)
{
//TODO: Handle
return "";
}
}
the problem here is the HttpContext.User in action method is null. but if i remove the part where i have written the redirect url with id_token appended and context.HandleResponse();in OnAuthorizationCodeReceived ,
user will be redirected without the id token yet when getAccessToken action executed HttpContext.User will not be null, user will have every detail including claims.
How can i redirect user with id token in url and also to have user without being null to get access token in controller method? Is it something to do with cookie?
I don't know why you need ID token in javascript , ID token contains user profile information (like the user's name, email, and so forth) , these claims are statements about the user but should not include sensitive information.
If you want to get the user claims you can query claims from HttpContext.User object and pass related claims to client side . Or directly get the user's profile information from Azure AD using Microsoft Graph API .
You can use cookie to store the id token in OnAuthorizationCodeReceivedevent, something like :
context.Response.Cookies.Append("IDToken", context.ProtocolMessage.IdToken, new CookieOptions()
{
Path = "/",
HttpOnly = false,
Secure = true
});
And access the value on server side by :
var idToken= Request.Cookies["IDToken"];
But you should concern the security problem . When used with the HttpOnly cookie flag(=true), are not accessible through JavaScript, and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS. However cookies are vulnerable to cross-site request forgery (CSRF) attacks . You can refer to this thread which provides detail discussion about that .
In short , you can store the ID token in cookie . But i would suggest to get the user claims from HttpContext.User object .

Spring stomp - send a message from server using SimpMessagingTemplate

I am trying to send a message using stomp from server to a client. I know that using sock.js and stomp on client side I can send a message from one user to another, without much server-side interaction, simply by using a #SendTo annotation in a controller method. However, the message that I want the user to receive is generated on the server (actually, I'm sending a whole object, but for simplicity's sake, let's just say I'm trying to send a String). Specifically, this deals with friend request acceptance, and when one user accepts a friend request, the one who sent the request should receive a message that his request was accepted. So, after a simple ajax call to a rest controller method for accepting a request, the method should also send the message to the other user. Here's the code:
#RestController
#RequestMapping("/rest/user")
public class UserController{
#Autowired
SimpMessagingTemplate simp;
#RequestMapping(value="/acceptFriendRequest/{id}", method=RequestMethod.GET, produces = "application/json")
public boolean acceptFriendRequest(#PathVariable("id") int id){
UserDTO user = getUser(); // gets logged in user
if (user == null)
return false;
... // Accept friend request, write in database, etc.
String username = ... // gets the username from a service, works fine
simp.convertAndSendToUser(username, "/project_sjs/notify/acceptNotification", "Some processed text!");
return true;
}
}
And here's the web socket configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/sendNotification").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/notify");
config.setApplicationDestinationPrefixes("/project_sjs");
}
}
And this is the javascript function:
function setupWebsockets(){
var socketClient = new SockJS("/project_sjs/sendNotification");
stompClient = Stomp.over(socketClient);
stompClient.connect({}, function(frame){
stompClient.subscribe("/project_sjs/notify/acceptNotification", function(retVal){
console.log(retVal);
});
});
}
When a user accepts the friend request, everything is written fine in the database. I can even see that the other user is my friend now when I refresh the page. However, the other user never receives the message that his request was accepted.
Is there anything I'm doing wrong? Any help would be greatly appreciated. Thanks!
I solved this problem with a different approach. Instead of subscribing all users to the same endpoint "/project_sjs/notify/acceptNotification", and then differentiating them by username, I ended up subscribing each user to a different endpoint, for example "/project_sjs/notify/acceptNotification/John123". This way, everyone with the username John123 (which is only one person, because usernames are unique) will get the notification. And it worked well enough.

Categories

Resources