Spring Integration: Microsoft Outlook oauth2 - spring

i've a spring integration java application with a flow configured like this:
String emailStoreUri = emailProtocol + "://" + emailUsername + ":" + emailPassword + "#" + emailHost + ":" + emailPort + "/" + emailFolderInbox;
return IntegrationFlows.from(Mail.imapInboundAdapter(emailStoreUri)
.shouldMarkMessagesAsRead(emailShouldMarkMessagesAsRead)
.simpleContent(true).maxFetchSize(msgPerPoll)
.searchTermStrategy(new AcceptAllEmailStrategy())
.javaMailProperties(p -> {
p.put("mail.store.protocol", emailProtocol);
p.put("mail.debug", emailDebug);
p.put("mail.imaps.timeout", "5000");
p.put("mail.imaps.connectionpoolsize", "1");
p.put("mail.imaps.connectiontimeout", "5000");
p.put("mail.imaps.connectionpool.debug","true");
p.put("mail.debug", "true");
}).simpleContent(true),
e -> e.autoStartup(emailAutoStart).poller(pollerMetadata))
.channel(MessageChannels.rendezvous("inboundEmailChannel")).log("DEBUG").get();
}
This just work for basi auth, how to fix to let this codw work with OAUTH2?
I'm searching online but i didn't find anything about this problem

I somehow think that this is your Gitter question as well: https://gitter.im/spring-projects/spring-integration?at=63ce9304624f3f4330280089.
So, to have a full context over here, please, look into this GH issue: https://github.com/spring-projects/spring-integration-samples/issues/341.
To be precise: you need to implement an Authenticator to obtain OAuth token against the user. Feel free to raise a GH issue, so we will document this approach. Although this has nothing to do with Spring Integration - plain Java Mail feature, - too many people are asking it in Spring Integration context.
Such an Authenticator has to be injected into an ImapMailReceiver via its property:
/**
* Optional, sets the Authenticator to be used to obtain a session. This will not be used if
* {#link AbstractMailReceiver#setSession} has been used to configure the {#link Session} directly.
* #param javaMailAuthenticator The javamail authenticator.
* #see #setSession(Session)
*/
public void setJavaMailAuthenticator(Authenticator javaMailAuthenticator) {
Don't forget to set Java Mail mail.imap.auth.mechanisms=XOAUTH2 property!

Related

Use external api having oauth2 in spring boot

I need to call an external API from my spring boot project. The external API is using OAuth 2 security authentication using authorization_code. I have the client id and secret key, any suggestion would be great.
Tried using SDK provided by DocuSign but while getting access token facing issue as 400 with message consent required.
The easiest way to do this is do download a "quickstart" from DocuSign and pick Java for your language. This does a lot more than just give you Java code, it also configures everything you need for you to be able to make API calls.
https://developers.docusign.com/docs/esign-rest-api/quickstart/
The specific Java code that does Auth Code Grant authentication can be found here:
https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/core/controller/GlobalControllerAdvice.java
OAuth2AuthenticationToken oauth = (OAuth2AuthenticationToken) authentication;
OAuth2User oauthUser = oauth.getPrincipal();
OAuth2AuthorizedClient oauthClient = authorizedClientService.loadAuthorizedClient(
oauth.getAuthorizedClientRegistrationId(),
oauthUser.getName()
);
if (oauth.isAuthenticated()) {
user.setName(oauthUser.getAttribute("name"));
if (oauthClient != null){
user.setAccessToken(oauthClient.getAccessToken().getTokenValue());
} else {
user.setAccessToken(((OAuth.OAuthToken) oauthUser.getAttribute("access_token")).getAccessToken());
}
if (account.isEmpty()) {
account = Optional.ofNullable(getDefaultAccountInfo(getOAuthAccounts(oauthUser)));
}
OAuth.Account oauthAccount = account.orElseThrow(() -> new NoSuchElementException(ERROR_ACCOUNT_NOT_FOUND));
session.setAccountId(oauthAccount.getAccountId());
session.setAccountName(oauthAccount.getAccountName());
// TODO set this more efficiently with more APIs as they're added in
String basePath = this.getBaseUrl(apiIndex, oauthAccount) + apiIndex.getBaseUrlSuffix();
session.setBasePath(basePath);
}

webflux Mono response empty

I have a very simple spring webflux rest endpoint in my project.
#Bean
public RouterFunction authRoute() {
return RouterFunctions.route(POST("/auth/signin").and(accept(APPLICATION_JSON)), this::signIn)
.andRoute(POST("/auth/signup").and(accept(APPLICATION_JSON)), this::signUp)
.andRoute(POST("/auth/test").and(accept(APPLICATION_JSON)), this::test);
}
And /auth/test endpoint just reply back with the username supplied.
public Mono<ServerResponse> test(ServerRequest request) {
System.out.println("Start test ");
Mono<JwtRequest> jwtRequestMono = request.bodyToMono(JwtRequest.class);
jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
return jwtRequestMono
.flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));
}
The problem I am facing is that the response body is empty, it should be the username. I also verified that when I return the hardcoded string, it passes. It fails when I depend on jwtRequestMono.flatMap(...
This line is almost certainly your downfall:
jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
Your request can't be subscribed to multiple times - so you subscribe to it on this line (which works and prints out the values as expected), then the framework subscribes to it, and it blows up. I'd expect to see an exception and a 500 response returned when this happens by default, so chances are you're swallowing an exception somewhere.
Never subscribe within your own application. That's the frameworks job.
Instead, if you want to have a "side-effect" where you print the values as they come in, then use doOnNext() as part of your reactive chain:
return jwtRequestMono
.doOnNext(v -> System.out.println(v.getUsername() + ":" + v.getPassword()))
.flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));

Optimise Consuming messages from rabbitmq using Spring Integration

I am attempting to build an IntegrationFlowFactory to easily build integration flows for passing events between application contexts.
Everything seems to work, and events are being published very quick.
However i cannot figure out why the consuming is so slow. Adding concurrentConsumers or changing prefetchCount does not seem to change anything.
Other posts talk about the network being slow, but as you can see in the RabbitConfig i am using localhost.
I have a repository with my spring integration example here:
https://github.com/teplyuska/spring-integration-example
Your problem is here:
Amqp.inboundGateway(getListenerContainer(queue, concurrentConsumers, prefetchCount)
Meanwhile your downstream flow is one-way and doesn't return any reply:
.handle(p -> {
UpdateSecretEvent payload = (UpdateSecretEvent) p.getPayload();
System.out.println("Account: " + payload.getAccountId() + " has secret: " + payload.getNewSecret());
})
.get();
or
.handle(p -> {
UpdateEmailEvent payload = (UpdateEmailEvent) p.getPayload();
System.out.println("Account: " + payload.getAccountId() + " has email: " + payload.getEmail());
})
.get();
So, that AmqpInboundGateway waits for the reply in its MessagingTemplate.sendAndReceive() for the private static final long DEFAULT_TIMEOUT = 1000L;
Switching to the Amqp.inboundAdapter() there does the trick.

I want to know about spring hateoas

I am working on spring boot. I don't know what is spring hateoas why we go for spring hateoas.
#RequestMapping(value= "/accounts/{id}/{userId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Resource<AccountHolder> findAccountHolderById(#PathVariable("id") Long id, #PathVariable("userId") int i) {
logger.info("accounts findAccountHolderById() invoked: " + id);
Account account = accountRepository.getAccount(id.toString());
AccountHolder accountHolder = account.getAccountHolder();
Resource<AccountHolder> resource = new Resource<AccountHolder>(accountHolder);
resource.add(linkTo(methodOn(AccountController.class).byId(account.getAccountId())).withRel("account"));
logger.info("accounts findAccountHolderById() found: " + account);
return resource;
}
HATEOAS means that a REST webservice not only provides the answer you asked for (e.g. the account) but also links to related data like the customer or subaccounts of that account. You can also provide links to actions like "disable account". That way the clients can navigate through the data more easily.
See https://spring.io/understanding/HATEOAS or https://en.wikipedia.org/wiki/HATEOAS
P.S.: When copy & pasting code, use the "{}" symbol in the edit box to format it correctly.

Grails Spring Security REST + LDAP

I am trying to set up Spring Security in Grails authenticating with a token (via the Spring Security REST plugin) and authorizing against LDAP. I have found several examples (I have about 20 browser tabs open right now), but none of them answer the whole question. Most of the examples are Grails + REST Security or Grails + LDAP Security, but no examples of Grails + REST + LDAP.
My issue is that the application tries to look in the database for users and roles, when I need it to look to LDAP.
I found the solution was to go into resources.groovy and configure the userDetailsService bean to use LDAP instead.The only "prerequisite" is that you must already have correct LDAP configurations to your LDAP server. I found this solution here: http://swordsystems.com/2011/12/21/spring-security-cas-ldap/. And only took the following piece.
// Place your Spring DSL code here
import grails.plugin.springsecurity.SpringSecurityUtils
beans = {
def config = SpringSecurityUtils.securityConfig
if (config.ldap.context.server) {
SpringSecurityUtils.loadSecondaryConfig 'DefaultLdapSecurityConfig'
config = SpringSecurityUtils.securityConfig
initialDirContextFactory(org.springframework.security.ldap.DefaultSpringSecurityContextSource,
config.ldap.context.server){
userDn = config.ldap.context.managerDn
password = config.ldap.context.managerPassword
}
ldapUserSearch(org.springframework.security.ldap.search.FilterBasedLdapUserSearch,
config.ldap.search.base,
config.ldap.search.filter,
initialDirContextFactory){
}
ldapAuthoritiesPopulator(org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator,
initialDirContextFactory,
config.ldap.authorities.groupSearchBase){
groupRoleAttribute = config.ldap.authorities.groupRoleAttribute
groupSearchFilter = config.ldap.authorities.groupSearchFilter
searchSubtree = config.ldap.authorities.searchSubtree
rolePrefix = "ROLE_"
convertToUpperCase = config.ldap.mapper.convertToUpperCase
ignorePartialResultException = config.ldap.authorities.ignorePartialResultException
}
userDetailsService(org.springframework.security.ldap.userdetails.LdapUserDetailsService,
ldapUserSearch,
ldapAuthoritiesPopulator){
}
}
}

Resources