Spring and SimpleMailMessage: change setTo and setFrom - spring

I am building a Spring app that allows the user to send an email to customer support.
I have noticed though that it doesn't matter what I put in the attributes "setTo" and "setFrom" of the SimpleMailMessage, I keep receiving the email from myself to myself.
Here is my code:
Controller Endpoint
#PostMapping("/send-email")
public ResponseEntity<Object> sendEmail(#RequestParam String userEmail) {
log.info("[START] send-email");
notificationService.sendNotification();
return new ResponseEntity<>(HttpStatus.OK);
}
Service
public void sendNotification(String emailUtente) {
SimpleMailMessage messaggio = new SimpleMailMessage();
messaggio.setTo(customerServiceAddress);
messaggio.setFrom(emailUtente);
messaggio.setSubject("Test Spring Email");
messaggio.setText("Tadaaaa! Email da Spring!");
try{
javaMailSender.send(messaggio);
} catch (Exception ex){
log.error("Error! " + ex.getMessage());
}
}
application.properties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=theCustomerServiceAddress
spring.mail.password=thePassword
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
Where am I mistaking?
Also, I am not sure what should be put into the property spring.mail.username, I guessed the email address of whom is receiving the email?
Thank you for your experience and time.

Related

meesenger4j how to handle request from diffrent facbook app

I would like to create a rest api that handle user messenger app credential (token,appsecret,verifToken) as parameters instead of define them as env variable.
So that more than one user (facebook app) can subscribe to my rest api throw messenger webhook .
Is that possible?
First, i tried with credential in app.prop and injected the Messenger4j client in Restcontroller constructor and it works like charm (webhook call, conversation...).
Now is it possible to do that for more than one facebook app to communicate with my rest api :
the logic will be:
first connect(accesToken,appSecret) to our backend and save app credential and get response with myBackendApiUrl and generate verifToken.
#RequestMapping(value = "/connect", method = RequestMethod.POST)
public ResponseEntity<String> connect(#RequestParam final String pageAccessToken,
#RequestParam final String appSecret,
) {
logger.debug(" connect ");
try {
logger.debug("********");
//Messenger messenger = Messenger.create(pageAccessToken, appSecret, verifyToken).;
String verifyToken= UUID.randomUUID().toString();
MessengerCredentials msgerCred = new MessengerCredentials(pageAccessToken,appSecret,verifyToken);
messengerCredentialRepo.save(msgerCred);
return ResponseEntity.ok("webhookurl: myurl"+ "verifToken:"+verifyToken);
} catch (Exception e) {
logger.warn("failed to connect", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
After that the user should configure messenger app webhook with url and verif token recived in the response body method connect() to avonke the webhook handler and this is how it may be like
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> verifyWebhook(#RequestParam(MODE_REQUEST_PARAM_NAME) final String mode,
#RequestParam(CHALLENGE_REQUEST_PARAM_NAME) final String challenge,
#RequestParam(VERIFY_TOKEN_REQUEST_PARAM_NAME) final String verifyToken
) {
logger.debug("Received Webhook verification request - mode: {} | verifyToken: {} | challenge: {}", mode, verifyToken, challenge);
try {
logger.debug("********");
this.messenger.verifyWebhook(mode, verifyToken);
return ResponseEntity.ok(challenge);
} catch (MessengerVerificationException e) {
logger.warn("Webhook verification failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
Is that possible?!
and how can i deal with post handler to handel users events it my Messenger4j bean not instanciate yet.

Change the Bad credentials error response spring security oauth2

I have a AuthorizationServer which uses password grant_type using spring security. I am using this for mobile application, when a user enter username password to log in, the app calls the token endpoint and generate a token if he/she is an authenticated user. This is all handled by password grant_type itself. For a unsuccessful log in it returns below general error with 400 HTTP status code.
{
"error": "invalid_grant",
"error_description": "Bad credentials"
}
But for my scenario I need customize this error message. Is their a way to change this error message ?
Note that i tried the suggested duplicate question -
Customize authentication failure response in Spring Security using AuthenticationFailureHandler
but it uses the formLogin and it's not working with my implementation.
Thank you,
Rajith
I couldn't find an answer to this problem for many days. Finally, I got help from one of my colleagues. He asked me to follow this tutorial and it worked for me. Now I could transform the default spring framework response to my response template as follows.
{
"status": 400,
"message": "Invalid username or password",
"timestamp": "2020-06-19T10:58:29.973+00:00",
"payload": null
}
But still, we don't know, why authenticationFailure handler is not working. Hope this helps.
If you want to change only the message text in the response, than it will be enough to add the messages.properties file to the classpath of your application with the following content:
AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password
This will lead to the response below:
{
"error": "invalid_grant",
"error_description": "Invalid username or password"
}
Sabin answer is works, but i need to throw the exception using BadCredentialsException,
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final static Logger LOGGER = LogManager.getLogger(CustomAuthenticationProvider.class);
#Autowired
private UserService userService;
#Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException{
final String username = authentication.getName();
final String password = authentication.getCredentials().toString();
try {
/* CHECKING USER CREDENTIAL */
/* check account */
User userDetail = userService.findByUsername(username);
if (userDetail == null){
throw new Exception("User not found!");
}
/* check password */
String origPass = Utilities.getEncrypted(new String(Base64.decodeBase64(password)), username);
if(!userDetail.getPassword().equals(origPass)){
throw new Exception("Wrong username or password!");
}
/* check is active */
if(!userDetail.getIsActive()){
throw new Exception("User is not active!");
}
/* check allowance in web type */
if(Access.isWeb()){
if(!userDetail.getIsWeb())
throw new Exception("Web access prohibited!");
}
/* check allowance in mobile type */
if(Access.isMobile()){
if(!userDetail.getIsMobile())
throw new Exception("Mobile access prohibited!");
}
/* do some logs */
userService.login(userDetail);
return new UsernamePasswordAuthenticationToken(userDetail, "{noop}".concat(origPass), userDetail.getAuthorities());
} catch (Exception e) {
LOGGER.error("[OAUTH] Error : " + e.getLocalizedMessage());
throw new BadCredentialsException(e.getLocalizedMessage(), e);
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

How to copy email in sent folder?

I am using java mail api for sending mail.In that for sending email i configured yahoo smtp port.I am able to send mail from yahoo account but sent mail is not saving in sent item.For incoming service i configured imap yahoo server.
service:
#Component
public class SmtpMailSender {
#Autowired
private JavaMailSender javaMailSender;
private static String folderName = "Sent";
private String host="smtp.mail.yahoo.com";
private String user="abc#yahoo.com";
private String pass="xxxx";
public void send(String to,String subject,String body, String from) throws MessagingException
{
// Java Mail properties
Properties props = System.getProperties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", "465");
props.put("mail.smtp.auth", "true");
// Mail session authentified
Session session = Session.getInstance(props);
MimeMessage message=javaMailSender.createMimeMessage();
MimeMessageHelper helper=new MimeMessageHelper(message,true);
helper.setTo(to);
helper.setFrom(from);
helper.setSubject(subject);
helper.setText(body,true);
javaMailSender.send(message);
// Copy message to "Sent Items" folder as read
Store store = session.getStore();
store.connect("imap.mail.yahoo.com", user, pass);
Folder folder = store.getFolder(folderName);
if (!folder.exists()) {
folder.create(Folder.HOLDS_MESSAGES);
}
folder.open(Folder.READ_WRITE);
folder.appendMessages(new Message[] {message});
message.setFlag(FLAGS.Flag.RECENT, true);
System.out.println("Msg send and saved ....");
store.close();
}
}
Controller:
#RestController
public class EmailController {
#Autowired private SmtpMailSender smtpMailSenderObj;
#RequestMapping("/send")
public void sendMail() throws MessagingException {
smtpMailSenderObj
.send
("pqr#gmail.com", "verify sendMail",
"Hii...this is demo for java email send",
"abc#yahoo.com");
}
}
Application.properties:
spring.mail.host=smtp.mail.yahoo.com
spring.mail.username=abc#yahoo.com
spring.mail.password=xxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.transport.protocol : smtp
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.debug=true
spring.mail.properties.mail.smtp.socketfactory.port=465
spring.mail.properties.mail.imap.ssl.required=true
spring.mail.properties.mail.imap.port=993
You need to explicitly append the message object to the "Sent" Folder.
This is because of imap port connection send mail was not saving in sent items.
Need to add set property in properties file.
props.setProperty("mail.store.protocol", "imaps");
By adding this now i am able to save my sent mail in sent item.

Spring Boot Camel Route - get data from rest endpoint

I want to create camel route in Spring Boot (2.1.1) project to get the data from some (rest) endpoint (http://localhost:8080/getAllUsers) and to send that data to activeMq.
I have tried with timer data to send it on activeMq and to consume it and it is working. But I have problem with collecting data from endpoint.
I have tried several things but no success. This is what I have tried.
In this example I am not sending the data to ActiveMq, I just want to see the response...
public void createNewRoute() {
CamelContext context = new DefaultCamelContext();
try {
ProducerTemplate template = context.createProducerTemplate();
context.start();
Exchange exchange = template.request("http://localhost:8080/getAllUsers",
new Processor() {
public void process(Exchange exchange) throws Exception {
}
});
if (null != exchange) {
Message out = exchange.getOut();
int responseCode = out.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
System.out.println("Response: " + String.valueOf(responseCode));
}
Thread.sleep(1000 * 3);
context.stop();
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
System.out.println("DONE!!");
}
Another route:
from("servlet://localhost:8080/getAllUsers").to("activemq://all-users");
And another:
rest("//localhost:8080/getAllUsers")
.get().consumes("application/json")
.to("activemq://all-users");
I will go with your second example:
from("timer://test?repeatCount=1").routeId("newRoute")
.streamCaching()
.process(exchange -> exchange.getIn()
.setBody(exchange.getIn()
.getBody()))
.marshal()
.json(JsonLibrary.Jackson)
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.to("http://localhost:8080/getAllUsers")
.log(LoggingLevel.INFO, "This is my body: ${body}")
.to("activemq:queue://new-queue");
This will trigger it once.
Try this without context.start() ....
CamelContext camelContext = new DefaultCamelContext();
ProducerTemplate template = camelContext.createProducerTemplate();
Exchange exchange = template.send("http://localhost:8080/getAllUsers", new Processor() {
public void process(Exchange exchange) throws Exception {}
});
Message out = exchange.getOut();
The http components are streaming based, so you can ask Camel to give you the response as string instead.
String s = exchange.getMessage().getBody(String.class);
See more in these links
http://camel.apache.org/stream-caching
http://camel.apache.org/why-is-my-message-body-empty.html

How to implement the observer pattern for REST API's?

I'm looking to create a REST API to which clients subscribe to certain data. When the data changes (due to some external event) I want to notify the clients (observers) with the new data.
I want to use Spring for the REST API's, I have no clue how to register and notify the observers though.
Some guidance and or good practises would be very helpful.
Thank you
In spring boot you can register call back urls, an example controller is:
#RestController
public class Controller {
private List<Listener> listeners = new ArrayList<>();
#RequestMapping(value = "/register/{name}", method = RequestMethod.POST)
public ResponseEntity<Void> register(#PathVariable("name") String name, #RequestParam("callbackurl") String callBackUrl) throws Exception {
System.out.println("register, name=" + name + ", callBackUrl=" + callBackUrl);
Listener listener = new Listener(name, URLDecoder.decode(callBackUrl, "UTF-8"));
listeners.add(listener);
System.out.println(listener);
return new ResponseEntity<>(HttpStatus.OK);
}
#RequestMapping(value = "/callback/*", method = RequestMethod.POST)
public ResponseEntity callBack(#RequestBody String message) {
System.out.println("call back with message=" + message);
return new ResponseEntity(HttpStatus.OK);
}
#Scheduled(fixedRate = 10000)
public void notifyListeners() {
System.out.println("notifying listeners");
for (Listener listener : listeners) {
System.out.println("listener " + listener);
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(listener.getCallBackUrl());
try {
httpPost.setEntity(new StringEntity("hello listener " + listener));
CloseableHttpResponse response = client.execute(httpPost);
client.close();
} catch (Exception e) {
}
}
}
}
Can be tested like so, register 2 call backs, the URL http://127.0.0.1:8080/callback/app1 is encoded so it can be a paramter.
curl -X POST http://127.0.0.1:8080/register/listener1?callbackurl=http%3A%2F%2F127.0.0.1%3A8080%2Fcallback%2Fapp1
curl -X POST http://127.0.0.1:8080/register/listener1?callbackurl=http%3A%2F%2F127.0.0.1%3A8080%2Fcallback%2Fapp2
In my case for simplicity the client and server are the same application, but they could be different.
You can use Spring 5 with WebFlux. It's a combination of an Iterator and the Observer pattern. The client always gets a new Object, whenever there is one on the server. You can start learning more on that on the Spring documentation pages or on e.g.
New in Spring 5: Functional Web Framework

Resources