Spring security does not redirect after successful login authentication - spring-boot

I am using spring security + thymeleaf to recognise my css and javascript files. These css and javascript files make up my front end login page, and for special reasons, my login form is within a js file and i include this file in my main html file. To authenticate the login credentials, a custom /POST request needs to be called using javascript like below. This function below executes when the form submit button is pressed.
function submitForm() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("username", "<removed>");
urlencoded.append("password", "<removed>");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:8080/userAuth", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
Controller to handle successful login end point
#Controller
public class LoginSuccessController {
#GetMapping("/login_success")
public String success() {
return "success";
}
}
On the browser, I can infer that authentication is successful and there is something that happens related to my successful login endpoint. However, my browser remains at localhost:8080/login and does not redirect to the login_success endpoint. I am unable to figure out why so. Any help is much appreciated.
Browser network activity after submit button

because you use ajax. if you check networks tab I believe you will see response ans 301/302 with Location header.
Edit: you have to either use plain html form or redirect manually from js side
Edit 2:
fetch("http://localhost:8080/userAuth", requestOptions)
.then(response => response.text())
.then(result => {
// do some stuff with response
location.href = '/my-success-page-after-login'; // <- here is redirect
})
.catch(error => console.log('error', error));
Explanation: the problem is that browser doesn't follow redirect response for AJAX calls. Ajax call will just return you a response from server(redirect with 301/302 status code in your case) but this will NOT make browser to follow that redirect

Related

Can fetch be a substitute for AJAX?

I am wondering if it is possible to do in fetch all the things you can do in traditional ajax?
Because I'm having a problem with a simple login authentication using express. I want to send a response like Login error if the username/password is incorrect, or to redirect the user to the homepage if both is correct, to the client without refreshing the page.
I understand that you can do this in AJAX, but is it possible to do it in fetch also?
I tried using express js and sending a response through a json, but I can't figure out how to handle the response without refreshing the page.
I tried doing it like this in the express server
//if valid
res.json({
isValid: true
})
//if invalid
res.json({
isValid: false
})
And in the client side, specifically in the login page, I have this javascript that handles the submitting of the information
fetch('https://localhost:3000/auth', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username,
password
})
})
.then(response => response.json())
.then(data => {
//I understand that in this part, you can handle the response, but the problem is, I don't know how.
}
})
.catch(console.log)
You are SO close! You've got the fetch, then you've parsed it with response.json, so the next thing is the .then(). In that, you have the JSON object being passed into a param you've named data. All you need to do is check if that has the isValid property!
fetch('https://localhost:3000/auth', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username,
password
})
})
.then(response => response.json())
.then(data => {
if(data.isValid){
// Do something with a valid user. Redirect or whatever.
} else {
// Here, isValid is not set, or is false.
// Send them packing!
}
}
})
.catch(err => console.error("I died: ", err) );
ALSO, take a look at the .catch() block -- in the event of an error, that catches an Error thrown by either the fetch(), or a then(). So you need to add a parameter for the error, and a function body to handle that. I've edited my code sample to demonstrate.
Won't actually run here, but it's formatted all pretty.

Can't use fetch api in laravel, redirect login page

I'm trying to use fetch api with laravel, but the request goes to the login url, not the given url.
for example;
route
//also this route group has auth and admin middlewares (checks user is authenticated and is admin)
Route::delete("media/delete/{id}", ["as" => "admin.posts.media.delete", "uses" => "AdminController#deletePostMedia"]);
ajax
fetch("../../media/delete/" + id, {
method: "DELETE",
headers: new Headers({
"X-CSRF-TOKEN": document.head.querySelector("[name=csrf-token]").content
})
})
it gives me the below error:
DELETE http://commerce.test/login 405 (Method Not Allowed)
as you can see above, the request goes to login url, not given url..
How can I fix this?
Laravel by default includes axios for ajax requests and it's very easy to use, have a look here.
In your example you'd write something like this:
axios.delete('/media/delete/' + id)
.then(response => {
console.log(response.data);
})
.catch(error=> {
console.log(error);
});

Bypass UI Login using Cypress

I am having problem bypassing UI login. My web application doesn't use API to authenticate users. There are no endpoints like /login. index.php will just open the login page and submit the form to login.
The application authenticate the user by
auth($_REQUEST['username'], $_REQUEST['password_tx']);
This is what cypress printed after UI login submit.
I have no idea how to move on from here.
// This doesn't work. The application doesn't get the user details from the body. It is in the submitted form.
cy.request({
method: 'POST',
url: '/index.php?p=sys001',
form: true,
body: {
username: 'user',
password_tx: 'pass'
}
})
This is the complete testcase for the issue. Added comments to make them understandable.
it("login via form spoof", () => {
cy.get("div#mDiv > form").invoke("attr", "action").then(($action) => { //get
the attribute of 'action' and pass encoded uname and pwd to it
let username = Cypress.env("username");
let password = Cypress.env("password");
cy.intercept("POST", $action, (req) => { //post request and populate body
// intercepting the POST form to spoof it.
req.body = $action + encodeURIComponent(username)+ encodeURIComponent(password)
})
.as("loginForm"); //alias
});
cy.get("div#mDiv > div.login > form")
.submit(); //Submit the form after locating it.
});

Express.js res.render not redirecting, just displayed in console

This time I want to use res.render to display html as success of DB update. I did it several times, but this time it doesn't work. It's not render html file, just displayed on chrome's console.
I think it caused because of async problem or duplicated response. I tried to many ways but I couldn't solve it, so pointers appreciated.
The code is related when the user paid service, increase user's level.
Get Access Token => Validate => res.render
app.post('/payment/validate', function(req, res, next){
// Get access token
request.post({
url : 'https://payment-company/get/token'
}, function(err, response, body) {
if(!err & response.statusCode == 200) {
var result = JSON.parse(body);
var accessToken = result.response.access_token;
// Validate payment (compare paid and would be paid)
request.get({
headers : { 'Authorization' : accessToken }
url : 'https://payment-company/find/paymentid'
}, function (err, response, body) {
if (!err && response.statusCode == 200){
var result = JSON.parse(body);
if (result.response.amount == req.body.price){
Members.findOne({id : req.user.id}, function(err, member){
// If no problem, update user level
member.level = 2;
member.save(function(err, result){
if (err) return next();
res.render('payment.view.result.ejs',
{
title : 'Success !',
description : 'level up.'
});
});
});
}
} else {
...
}
});
}
})
});
sorry to verbose code I tried to shorten code, No problem until res.render, res.render will work but it's not display page instead it just send html code to chrome's console.
Looks like there's a bit of a misunderstanding of how these requests work. What I think you intend:
Browser makes a GET request, server responds with an HTML document, the browser renders it
User takes an action
Browser makes a POST request, server responds with an HTML document, the browser renders it
What you've started coded on the frontend is an alternate method:
You make a POST request via AJAX, server responds with some JSON, you modify the current document with JavaScript to let the user know

Symfony2 send back login form on each AJAX request

I'm doing a back-office image upload form using Symfony 2.5.12 (yeah I know I'm a little out of date, but I will work on that soon :)). I want to upload the images via AJAX, but I get a 302 redirect to the login form on every AJAX request I send.
Here is the JS part on my stuff (it is simplified because for the moment I just want to do a successful AJAX call without 302 redirect to the login page, so I deleted the data related stuff) :
form.addEventListener('submit', event => {
event.preventDefault();
const url = form.getAttribute('action'); // '/admin/uploadImage'
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
});
And here is my action in my controller, bound to /admin/uploadImage URL :
public function uploadAction() {
return new JsonResponse(array('test' => 'hello world'));
}
Every /admin URL requires ROLE_ADMIN role, I defined it in security.yml :
security:
#...
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
This way, it is normal that a login form shows when I want to access to this kind of URL. But when I trigger my AJAX call, I'm already logged in because I'm on /admin/gallery page.
Does anybody can figure out what is wrong with what I'm doing ?
Thank you very much.
I absolutely don't know why, but it seems the issue was related to whatwg-fetch fetch implementation. I replaced it with axios and the problem is gone.

Resources