Spring Boot Mail send email using acces token - spring

I have simple mail sending functionality in project which configured in one bean.
#Bean
public JavaMailSender javaMailSender() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
Properties properties = new Properties();
properties.setProperty("mail.smtp.auth", "false");
properties.setProperty("mail.smtp.socketFactory.port", "465");
properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.setProperty("smtp.socketFactory.fallback", "false");
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.smtp.starttls.required", "true");
javaMailSender.setHost("smtp.gmail.com");
javaMailSender.setProtocol("smtp");
javaMailSender.setUsername("username");
javaMailSender.setPassword("password");
javaMailSender.setJavaMailProperties(properties);
return javaMailSender;
}
and it works great.
Now I want to add functionality for sending emails via accessToken/refreshToken of specific email.
How to do it? What should I extend in my bean or add another bean for sending with token? I couldn't find some example which is full explained. As I understand I should add setFrom() and in setPassword() put accessToken

The use of OAUTH2 with JavaMail is explained on the JavaMail project page.
Also, you should fix these common mistakes in your code.

Related

OAuth2 | ClientCredentialsResourceDetails | deprecated

I am new to spring security, and i come across to implement OAuth2 with client_credentials as Grant type.
i am using below piece of code, but i am getting suggestion that ClientCredentialsResourceDetails, OAuth2RestTemplate & OAuth2AccessToken are deprecated.
Can someone help with the alternate to this ?
private String getAuthTocken(){
final ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setClientId("ceapiClientId");
resourceDetails.setClientSecret("ceapiClientSecret");
resourceDetails.setGrantType("client_credentials");
resourceDetails.setAccessTokenUri("https://auth.abcdcommerce.com/oauth-server/oauth/token");
final OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resourceDetails);
final OAuth2AccessToken accessToken = oAuth2RestTemplate.getAccessToken();
final String accessTokenAsString = accessToken.getValue();
return accessTokenAsString;
}
The alternative is to use the new non-blocking WebClient or a RestTemplate with an interceptor over the deprecated OAuthRestTemplate. Everything in the spring-security-oauth artifacts has an end of life road map.
https://spring.io/blog/2019/11/14/spring-security-oauth-2-0-roadmap-update
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix
The migration guide can be found here,
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide
From the migration guide,
Spring Security chooses to favor composition and instead exposes an OAuth2AuthorizedClientService, which is useful for creating RestTemplateinterceptors or WebClient exchange filter functions. Spring Security provides ExchangeFilterFunction s for both Servlet- and WebFlux-based applications that both leverage this service.
There is a migration example available here,
https://github.com/jgrandja/spring-security-oauth-5-2-migrate

JavaMail with gmail SMTP - How to handle an unexisting email addresses

In my project I'm using a JavaMail implementation to send emails through GMAIL's SMTP server.
The general concept is ok, my custom validators checks whether the e-mail was correctly formulated etc...
Everything is fine, however I am not able to catch anything what should be considered, as unsent email. I went deeper into JavaMail docs, and they advised to catch SendMailException and MessageException, but based on the code, it handles only an incorrectly formulated e-mail addresses or an empty Strings. If the user will come up with an unexisting email, but well formulated, the API will not inform that anything happened.
Did anyone handle with the similar issue and knows how to go forward?
Thanks in advance for your help.
#Bean
public JavaMailSender javaMailSender(EmailProperties prop) {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(prop.getHost());
mailSender.setPort(prop.getPort());
mailSender.setUsername(prop.getUsername());
mailSender.setPassword(prop.getPassword());
mailSender.setDefaultFileTypeMap(FileTypeMap.getDefaultFileTypeMap());
mailSender.setJavaMailProperties(getProperties(prop));
mailSender.setProtocol(prop.getProtocol());
mailSender.setDefaultEncoding("UTF-8");
return mailSender;
}
private Properties getProperties(EmailProperties prop) {
Properties props = new Properties();
props.put("mail.transport.protocol", prop.getProtocol());
props.put("mail.smtp.auth", prop.getAuth());
props.put("mail.smtp.starttls.enable", prop.getStarttls());
props.put("mail.debug", prop.getDebug());
return props;
}

Invalid JWToken: kid is a required JOSE Header

I am trying to implement an Oauth2 Authorization Server with SpringBoot using this guide as a reference.
My keystore has a single key. I have successfully managed to create a JWToken (I can check it at jwt.io).
I have also a test Resource Server. When I try to access any endpoint I receive the following message:
{
"error": "invalid_token",
"error_description": "Invalid JWT/JWS: kid is a required JOSE Header"
}
The token really does not have a kid header but I can not figure out how to add it. I can only add data to its payload, using a TokenEnchancer. It also seems that I am not the first one with this issue.
Is there any way to add this header or, at least, ignore it at the resource server?
I've been working on an article that might help you out here:
https://www.baeldung.com/spring-security-oauth2-jws-jwk
So, to configure a Spring Security OAuth Authorization Server to add a JWT kid header, you can follow the steps of section 4.9:
create a new class extending the JwtAccessTokenConverter
In the constructor:
configure the parent class using the same approach you've been using
obtain a Signer object using the signing key you're using
override the encode method. The implementation will be the same as the parent one, with the only difference that you’ll also pass the custom headers when creating the String token
public class JwtCustomHeadersAccessTokenConverter extends JwtAccessTokenConverter {
private JsonParser objectMapper = JsonParserFactory.create();
final RsaSigner signer;
public JwtCustomHeadersAccessTokenConverter(KeyPair keyPair) {
super();
super.setKeyPair(keyPair);
this.signer = new RsaSigner((RSAPrivateKey) keyPair.getPrivate());
}
#Override
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String content;
try {
content = this.objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication));
} catch (Exception ex) {
throw new IllegalStateException("Cannot convert access token to JSON", ex);
}
Map<String, String> customHeaders = Collections.singletonMap("kid", "my_kid");
String token = JwtHelper.encode(content, this.signer, this.customHeaders)
.getEncoded();
return token;
}
}
Then, of course, create a bean using this converter:
#Bean
public JwtAccessTokenConverter accessTokenConverter(KeyPair keyPair) {
return new JwtCustomHeadersAccessTokenConverter(keyPair);
}
Here I used a KeyPair instance to obtain the signing key and configure the converter (based on the example of the article), but you might adapt that to your configuration.
In the article I also explain the relevant endpoints provided by the Spring Security OAuth Authentication Server.
Also, regarding #Ortomala Lokni's comment, I wouldn't expect Spring Security OAuth to add any new features at this point. As an alternative, you probably can wait to have a look at Spring Security's Authorization Server features, planned to be released in 5.3.0
I managed to solve it by changing the parameter used to identify the URL where the clients will retrieve the pubkey.
On application.properties, instead of:
security.oauth2.resource.jwk.key-set-uri=http://{auth_server}/.well-known/jwks.json
I used:
security.oauth2.resource.jwt.key-uri=http://{auth_server}/oauth/token_key
If I understood correctly, the key-set-uri config points to an endpoint that presents a set of keys and there is the need for a kid. On the other side key-uri config points to an endpoint with a single key.

OAuth2 Client should send custom properties

I have implemented Oauth2 client in spring boot
public RestTemplate oAuthRestTemplate() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setId("1");
resourceDetails.setClientId(clientId);
resourceDetails.setClientSecret(clientSecret);
resourceDetails.setAccessTokenUri(accessTokenUrl);
resourceDetails.setTokenName("accessToken");
resourceDetails.setClientAuthenticationScheme(AuthenticationScheme.form);
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext());
return restTemplate;
}
We I run the code, request body for token is as
client_id & client_secret (by default)
Can we send is custome manner.
like I want to send it as clientId & clientSecret.
Note: Class is annotated with #EnableOAuth2Client
The names 'client_id' and 'client_secret' are specified by OAuth 2
So there is normally no need to change these.
However, Spring uses org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler
to post the client_id and client_secret. There you can see the field names are hardcoded :
form.set("client_id", resource.getClientId());
if (StringUtils.hasText(clientSecret)) {
form.set("client_secret", clientSecret);
}
You could try to subclass DefaultClientAuthenticationHandler, and use your own field names. But as it is created with 'new' in OAuth2AccessTokenSupport, you would need to subclass this also, and so on......
This can be tricky, a better way may be to add a
org.springframework.http.client.ClientHttpRequestInterceptor
at the org.springframework.security.oauth2.client.OAuth2RestTemplate
Create a class that implements ClientHttpRequestInterceptor, in its method
org.springframework.http.client.ClientHttpRequestInterceptor#intercept
you need to create a new request using the provided body of type byte[].
Convert it to a String, replace the field names, create a new request using it and proceed as described in the javadoc of the intercept() method.
To register the interceptor, create a spring bean of type OAuth2RestTemplate and register the interceptor there like
#Bean
OAuth2RestTemplate oAuth2RestTemplate(){
OAuth2RestTemplate template=new OAuth2RestTemplate;
ClientHttpRequestInterceptor interceptor= new ... //create your interceptor here
template.setInterceptors(Arrays.asList(interceptor));
return template;
}

Spring RestTemplate with Jackson throws "Can not resolve BeanPropertyFilter" when using #JsonFilter

Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?
I'm not 100% that's what I need to do but see below for details.
Background:
With help from this StackOverflow post I added #JsonFilter to my domain class and edited my jax-rs web service (implemented in CXF). I'm now successfully able to dynamically select which domain class fields to return in my RESTful API. So far so good.
I'm using Spring's RestTemplate in my JUnit tests to test my RESTful API. This was working fine until I added #JasonFilter to my domain class. Now I'm getting the following exception:
org.springframework.web.client.ResourceAccessException: I/O error: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured; nested exception is org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)
rest of stack trace omitted for brevity
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured
at org.codehaus.jackson.map.ser.BeanSerializer.findFilter(BeanSerializer.java:252)
I was getting a similar problem on the server side and was able to resolve it (with help from this post) by giving a FilterProvider to the Jackson ObjectMapper as follows:
ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties));
Can I do something similar on the RestTemplate side? Any ideas of how to solve this issue are appreciated.
Just to be clear, on the client RestTemplate side I do not want to filter the domain object properties at all.
Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?
I was able to force RestTemplate to use a customized ObjectMapper by doing the following:
ObjectMapper mapper = new ObjectMapper();
// set a custom filter
Set<String> filterProperties = new HashSet<String>();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(filterProperties));
mapper.setFilters(filters);
MappingJacksonHttpMessageConverter messageConverter = new MappingJacksonHttpMessageConverter();
messageConverter.setObjectMapper(mapper);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(messageConverter);
restTemplate.setMessageConverters(messageConverters);
This website provided example for part of the above code.
Just adding to the answer. If you are using TestRestTemplate then you can actually get the underlying RestTemplate class and then modify its MappingJackson2HttpMessageConverter to include your filter:
var jackson2HttpMessageConverter = testRestTemplate.getRestTemplate().getMessageConverters().stream()
.filter(mc -> mc instanceof MappingJackson2HttpMessageConverter)
.map(mc -> (MappingJackson2HttpMessageConverter) mc)
.findFirst()
.orElseThrow();
jackson2HttpMessageConverter.getObjectMapper().setFilterProvider(
new SimpleFilterProvider().addFilter("MyFilterName", SimpleBeanPropertyFilter.serializeAll())
);

Resources