Play running in a Load Balancer is requesting wrong POST URL

15 views
Skip to first unread message

Renan Geraldo

unread,
Dec 12, 2017, 7:54:23 AM12/12/17
to Play Framework
Hi everyone,

I have a Play! application running on AWS Elastic Load Balancer. I developed my API and all links are working correctly. When I created a form to a recover password page (followed this tutorial: https://ics-software-engineering.github.io/play-example-form/) , the URL that is being called when I click in submit button is always wrong. I read in java play documentation, on section "Relative Routes" the problem. They say: "The routes returned by play.mvc.Call are always absolute (they lead with a /), which can lead to problems when requests to your web application are rewritten by HTTP proxies, load balancers, and API gateways." Ok, this is exactly the problem that I have, but really guys, I could not solve this with the documentation's explanation. Did anybody already face this situation? (Thanks and sorry for all the code)

The right URL should be:

POST myApplication/api/recoverPasswordAction

And the url that is being called is:

POST myApplication/myApplication/api/recoverPasswordAction

This is my class Index.Scala.html: 

@(changePassword: Form[views.formdata.ChangePasswordForm])
@import helper._

@Main("Index") {

<div class="container">

 
<div class="well">

   
@form(routes.UserPasswordRecoveryController.postCreateNewPassword(), 'class -> "form-horizontal") {

      @fieldset(changePassword)

    }

  </div>

  @if(flash.containsKey("success")) {

  <div class="well">

    <div id="success-message" class="text-success">

      @flash.get("success")

    </div>

  </div>

  }

  @if(flash.containsKey("error")) {

  <div class="well">

    <div id="error-message" class="text-danger">

      @flash.get("error")

  </div>

    </div>

  }

</div>


}


My ChangePasswordForm.java:


public class ChangePasswordForm {


 
public String password;

 
public String confirmPassword;

 
public long userId;

 
private PBKDF2Generator pbkdf2Generator;




 
/** Required for form instantiation. */

 
public ChangePasswordForm() {

 
}




 
public List<ValidationError> validate() {

 
List<ValidationError> errors = new ArrayList<>();

 
if (password == null || password.length() == 0) {

 errors
.add(new ValidationError("password", "Por favor, digite uma senha."));

 
}else if(password.length() < 4){

 errors
.add(new ValidationError("password", "Por favor, digite uma senha com no mínimo 4 dígitos."));

 
}else if(password.length() > 12){

 errors
.add(new ValidationError("password", "Por favor, digite uma senha com no máximo 12 dígitos."));

 
}else if(confirmPassword.length() == 0 || confirmPassword.equals("")){

 errors
.add(new ValidationError("confirmPassword", "Por favor, digite a confirmação da senha."));

 
}else if(!confirmPassword.equals(password)){

 errors
.add(new ValidationError("confirmPassword", "Senha incorreta."));

 
}


 
if(errors.size() > 0){

 
return errors;

 
}else{    

 
try {

 
String uuid = UUID.randomUUID().toString().replace("-", "");

 
this.pbkdf2Generator = new PBKDF2Generator();

 
this.password = pbkdf2Generator.generateStrongPasswordHash(password, uuid);

 
this.confirmPassword = pbkdf2Generator.generateStrongPasswordHash(confirmPassword, uuid);

 

 
} catch (NoSuchAlgorithmException | InvalidKeySpecException | UnsupportedEncodingException e) {

 
// TODO Auto-generated catch block

 e
.printStackTrace();

 
}

 

 
return null;

 
}

 
}

}


UserPasswordRecoveryController.java


public class UserPasswordRecoveryController extends BaseController{



 
private UserPasswordRecoveryServices userPasswordRecoveryServices;

 
ChangePasswordForm changePassword;




 
public UserPasswordRecoveryController(){

 
this.userPasswordRecoveryServices = new UserPasswordRecoveryServices();

 
this.changePassword = new ChangePasswordForm();

 
}




 
public Result recoverPassword(){

 
Status methodStatus = null;




 
JsonNode json = this.getContentFromBodyAsJSON();

 
if(json == null) {

 methodStatus
= badRequest("Expecting Json data");

 
} else {

 
String email = json.findPath("email").asText();

 
String cpf = json.findPath("cpf").asText();

 
try{

 
this.userPasswordRecoveryServices.passwordRecovery(email, cpf);

 methodStatus
=  ok(Json.toJson("OK"));

 
}catch(BusinessException | UserNotFoundException ex){




 methodStatus
=  ex.getHttpErrorStatus();




 
}

 
}      

 
return methodStatus;

 
}




 
public Result postCreateNewPassword() {




 
// Get the submitted form data from the request object, and run validation.

 
Form<ChangePasswordForm> formData = Form.form(ChangePasswordForm.class).bindFromRequest();




 
if (formData.hasErrors()) {

 
// Don't call formData.get() when there are errors, pass 'null' to helpers instead.

 flash
("error", "Por favor, corrija os erros acima.");

 
return badRequest(Index.render(formData));

 
}else{




 
try{

 
Logger.error(formData.get().password);

 
this.userPasswordRecoveryServices.changePassword(this.changePassword.userId, formData.get().password, formData.get().confirmPassword);

 
return ok(Success.render());

 

 
}catch(BusinessException | ChangePasswordExpiredException | PasswordInvalidException ex){

 

 
return badRequest(Expired.render());

 
}

 
}




 
}



 
public Result getRecoverPasswordPage(String token, long userId) {

 
try{


 
this.userPasswordRecoveryServices.checkIfPageIsStillValid(userId, token);

 
this.changePassword.userId = userId;

 
Form<ChangePasswordForm> formData = Form.form(ChangePasswordForm.class).fill(changePassword);

 


 
return ok(Index.render(formData));




 
}catch(BusinessException | UserNotFoundException | ChangePasswordExpiredException ex){

 
return badRequest(Expired.render());

 
}

 
}


 
public Result index() {

 
Logger.error("Passou no index");

     
return redirect(controllers.routes.UserPasswordRecoveryController.postCreateNewPassword());

 
}



My routes related to recover password:

GET /api/recoverPasswordPage/:token/:userid controllers.UserPasswordRecoveryController.getRecoverPasswordPage(token: String, userid: Long)

POST /api/recoverPassword controllers.UserPasswordRecoveryController.recoverPassword()

POST /api/recoverPasswordAction    controllers.UserPasswordRecoveryController.postCreateNewPassword()

 


Marcos Pereira

unread,
Dec 14, 2017, 3:10:31 PM12/14/17
to play-fr...@googlegroups.com
Hi Renan,

I think you a looking for `play.http.context` configuration. Try to add the following to your `conf/application.conf` file:

play.http.context = "/myApplication"

Unfortunately, this is still not documented:


But a PR to fix the issue above would be very welcomed.

Best.

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/f515649f-4314-4b77-adf8-a0505cca769b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Marcos Pereira
Software Engineer, Lightbend.com

Reply all
Reply to author
Forward
0 new messages