Best way to add a RequestInterceptor to a single FeignClient - spring-cloud-feign

I need to add a RequestInterceptor to a specific feign client. The interceptor will add auth information that I do not want to leak to a third party, hence I do not want it to trigger for ALL Feign clients. I have this working, but this seems a tad messy, and am hoping there is a cleaner (less code) option.
I am hoping someone can point to where I can simplify things. Particularly around the encoder/decoder stuff. I really dislike them cluttering up my services constructor like that and find it odd that they even need to be specified in the first place.
I have
// build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
I have a RequestInterceptor as
import feign.RequestInterceptor;
import feign.RequestTemplate;
public class BearerAuthRequestInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate requestTemplate) {
// ... SNIP ... (just adds an Authorization header)
}
}
I have a FeignClient as
#FeignClient(name = "myfeignclient")
public interface MyFeignClient {
#GetMapping(value = "/doTheThing")
String doTheThing();
}
I use my FeignClient from a service like so:
#Service
#Import(FeignClientsConfiguration.class)
public class MyService {
private final MyFeignClient myFeignClient;
#Autowired
public MyService(Decoder decoder, Encoder encoder, Contract contract) {
this.myFeignClient = Feign.builder()
.contract(contract)
.encoder(encoder)
.decoder(decoder)
.requestInterceptor(new BearerAuthRequestInterceptor())
.target(MyFeignClient.class, "https://whatever.com");
}
public void callTheFeignClient() {
myFeignClient.doTheThing();
}
}

Thanks to this comment, I managed to tidy up my implementation a little bit. So no more need for specifying encode/decoder nonsense, or having to manually build my Feign client.
The docs here provide some info, but as is typical they are a bit thin on concrete examples, so perhaps the below will help someone else. Note: I'm using spring boot, and including feign like so in build.gradle implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
First, create the RequestInterceptor like so:
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import feign.RequestInterceptor;
import lombok.extern.slf4j.Slf4j;
/**
* A Feign configuration to add the incoming Bearer token to an outgoing feign client request.
* Only annotate this class with "#Configuration" if you want this interceptor to apply globally to all your Feign clients.
* Otherwise you risk exposing the auth token to a third party, or adding it unnecessarily to requests that don't need it.
*/
#Slf4j
public class BearerAuthFeignConfig {
#Bean
public RequestInterceptor bearerAuthRequestInterceptor() {
return requestTemplate -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof Jwt) {
Jwt jwt = (Jwt) authentication.getPrincipal();
requestTemplate.header("Authorization", "Bearer " + jwt.getTokenValue());
} else {
log.error("Unable to add Authoriation header to Feign requestTemplate");
}
};
}
}
Then when declaring your feign client, pass the configuration
#FeignClient(
name = "my-client-that-needs-the-auth",
configuration = BearerAuthFeignConfig.class,
url = "http://whatever.com"
)
public interface PlayerManagementClient {
...
You'll also need the #EnableFeignClients annotation on your #SpringBootApplication class

Related

How to access a DurableEntityClient in an injected class with Azure Durable Functions

I have an Azure Functions project that leverages Dependency Injection (Startup.cs injects services based on the different interfaces). Those services that implement the interfaces are using constructor dependency injection as well.
In one of those implementations, I want to call a method on a Durable Entity, but I prefer not to make the DurableEntityClient part of the method signature (as other implementations might not need the EntityClient at all). So therefore, I was hoping to see that IDurableEntityClient injected in the constructor of my class.
But it turns out the value is null. Wondering if this is something that is supported and feasible? (to have a DI-friendly way of injecting classes that want to get the EntityClient for the Functions runtime they are running in)
Some code snippets:
Startup.cs
builder.Services.AddSingleton<IReceiver, TableReceiver>();
Actual Function
public class ItemWatchHttpTrigger
{
private IReceiver _receiver;
public ItemWatchHttpTrigger(IReceiver receiver)
{
_receiver = receiver;
}
[FunctionName("item-watcher")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "item/{itemId}")]
HttpRequest request, string itemId, [DurableClient] IDurableEntityClient client, ILogger logger)
{
// Actual implementation
}
}
Referenced class
public class TableReceiver : IReceiver
{
private IDurableEntityClient _entityClient;
public TableReceiver(IDurableEntityClient client)
{
_entityClient = client; // client is null :(
}
}
Based on the answer of my github issue, it seems it is possible to inject this in Startup, since the 2.4.0 version of the Microsoft.Azure.WebJobs.Extensions.DurableTask package:
Some code snippets:
Startup.cs
builder.Services.AddSingleton<IReceiver, TableReceiver>();
builder.Services.AddDurableClientFactory();
Referenced class
public class TableReceiver : IReceiver
{
private IDurableEntityClient _entityClient;
public TableReceiver(IDurableClientFactory entityClientFactory, IConfiguration configuration)
{
_entityClient = entityClientFactory.CreateClient(new DurableClientOptions
{
TaskHub = configuration["TaskHubName"]
});
}
}
Github issue

Veto a CDI bean if another of the same type is present

Not sure if I'm thinking right about this, I'm looking[in CDI] for something similar to what we have in Spring - #ConditionalOnMissingBean - that allows you tell spring - create only if the bean specified is missing.
I've tried using extensions, looks like one can tap several events, and use those to VETO beans. One way might be to have BeanManager at this stage, and look for already present beans, and if it contains the one you're about to inject, VETO this one. BUT, this would only work when we HAVE LOOKED AT ALL the beans.
AfterBeanDiscovery looks suitable, however, before it is invoked, validation fails, complaining of multiple beans of the same type.
Would be great if I could get some help here.
Your question is interesting and can be solved using a CDI extension (almost as you describe, actually), see below for a naive, working, proof-of-concept implementation. It is naive because it does not handle e.g. producer methods/fields and may be missing more.
CDI extensions are really great and powerful, but can be rather technical, so let's discuss other alternatives first.
Specialization: Maybe it is enough for your use case to document explicitly that you provide the default implementation of SomeService through, say, public class SomeServiceDefaultImpl and in order to override it the developer should do:
#Specializes
public class SomeServiceSpecialImpl extends SomeServiceDefaultImpl {...}
Also consider the alternatives, as mentioned in the comment from John Ament.
Qualifiers: If this service is used only in one place/a few places and only inside your code, you could qualify your SomeServiceDefaultImpl with a custom qualifier, say #MyDefaultImpl. Then inject an Instance<SomeService>, look for an unqualified instance first and, if that is not satisfied, look for the qualified - something along the lines of:
private SomeService someService;
#Inject
void setSomeServiceInstance(Instance<SomeService> s) {
// not tried, please adapt as needed
if( s.isUnsatisfied() ) {
someService = s.select(new MyDefaultImplAnnotation()).get();
}
else {
someService = s.get();
}
}
Provide a default implementation that is #Vetoed so as to force the client of your code to provide an implementation. If the client wants to use the default, they can simply use a producer.
Having said the above, the implementation below is a proof of concept that:
Requires the following annotation to be present on the default implementation:
#Target({ TYPE, METHOD, FIELD })
#Retention(RUNTIME)
#Documented
public #interface ConditionalOnMissingBean {
Class<?> value();
}
The value() is required and denotes the bean type that is "defaulted". Your implementation can be smarter, i.e. detect the bean type from the actual default implementation, but, hey, that's only a proof of concept!
Blatantly ignores producers!
Is lightly tested, so there are probably evil corner cases, so BEWARE!
In addition to the code you need all the choreography of an extension (META-INF/services/javax.enterprise.inject.spi.Extension, beans.xml).
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanAttributes;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionTargetFactory;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
public class ConditionalOnMissingBeanExtension implements Extension {
private Map<Class<?>, AnnotatedType<?>> map = new HashMap<>();
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> pat) {
AnnotatedType<?> annotatedType = pat.getAnnotatedType();
ConditionalOnMissingBean annotation = annotatedType.getAnnotation(ConditionalOnMissingBean.class);
if( annotation != null ) {
map.put(annotation.value(), annotatedType);
pat.veto();
}
}
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd, BeanManager beanManager) {
map.entrySet().stream()
.filter(e -> doesNotHaveBeanOfType(beanManager, e.getKey()))
.map(e -> defineBean(beanManager, e.getValue()))
.forEach(abd::addBean);
map = null;
}
private boolean doesNotHaveBeanOfType(BeanManager beanManager, Class<?> type) {
return beanManager.getBeans(type).isEmpty();
}
private <T> Bean<T> defineBean(BeanManager beanManager, AnnotatedType<T> annotatedType) {
BeanAttributes<T> beanAttributes = beanManager.createBeanAttributes(annotatedType);
InjectionTargetFactory<T> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
return beanManager.createBean(beanAttributes, annotatedType.getJavaClass(), injectionTargetFactory);
}
}
An example of a default implementation of a service interface would be:
#ApplicationScoped
#ConditionalOnMissingBean(SomeService.class)
public class SomeServiceDefaultImpl implements SomeService {
#Override
public String doSomeCalculation() {
return "from default implementation";
}
}

Use Guice nested injects

I'm relatively new to Guice, and some things still give me a pretty hard time.
My particular question is, how do you handle nested injections in Guice.
Example:
Class A uses Class B via #Inject, and Class B uses Class C.
Explicitly:
My Module where I bind to Providers.
public class ModuleBinder extends AbstractModule {
#Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.toProvider(DatabaseControllerProvider.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.toProvider(AnalyzerProvider.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.toProvider(SystemAdministrationProvider.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.toProvider(LogInServiceProvider.class);
}
}
The DatabaseControllerProvider:
public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> {
#Override
public DatabaseControllerInterface get() {
return new DatabaseControllerImpl();
}
}
The LogInServiceProvider:
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
#Override
public LogInServiceInterface get() {
return new LogInServiceImpl();
}
}
And finally, the LogInService uses:
public class LogInServiceImpl implements LogInServiceInterface{
#Inject
private DatabaseControllerProvider databaseControllerProvider;
private final DatabaseControllerInterface databaseController;
public LogInServiceImpl() {
this.databaseController = databaseControllerProvider.get();
}
#Override
public User register(final String mail, final String userName, final String password) {
databaseController.registerUser(userName, mail, password, UserRole.ADMIN);
}
}
The call is then:
public class Test() {
public static test() {
final Injector injector = Guice.createInjector(new ModuleBinder());
logInService = injector.getInstance(LogInServiceInterface.class);
logInService.registerUser("test", "test", "test");
}
}
I know most of you guys will get sick with that code, but hey, I'm a beginner with Guice, so please be gentle with me.
I want to use Constructor injection, I already realized that field injection is considered "evil". Do you have any idea how to get that working by keeping the providers (I need them)?
Using the injections in the example does nothing on the "second" level, the DatabaseControllerImpl in LogInServiceImpl is null.
Did I configure something wrong? Did I misunderstand the usage of Provides and/or Modules?
I hope somebody can and wants to help me. If you need more informations, post a comment.
With best regards,
JosefRucksack
Your direct answer: You're calling new T(); in your Providers, which doesn't support field injection.
First, a real timesaver: Don't keep your explicit Providers. If you have bound a T, Guice allows you to inject a Provider or call Injector.getProvider for that T, even if you haven't explicitly created a Provider yourself. See the Built-In Bindings page on the wiki,
or the Injector docs (emphasis mine):
Contains several default bindings:
This Injector instance itself
A Provider<T> for each binding of type T
The Logger for the class being injected
The Stage in which the Injector was created
Instead, do it this way:
public class ModuleBinder extends AbstractModule {
#Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.to(DatabaseControllerImpl.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.to(AnalyzerImpl.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.to(SystemAdministrationImpl.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.to(LogInServiceImpl.class);
}
}
You then have the same choice you do now, to inject T or Provider<T> and call getInstance or getProvider as needed.
If your Providers are absolutely necessary, especially if they actually receive an instance from some other system or service locator, one other option is to add your #Inject fields into them as in the Provider bindings wiki page and pass them into your constructor, or to just inject a MembersInjector<T>:
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
#Inject MembersInjector<LogInServiceImpl> logInServiceImplInjector;
#Override
public LogInServiceInterface get() {
LogInServiceImpl logInServiceImpl = YourExternalDep.getLogInService();
logInServiceImplInjector.injectMembers(logInServiceImpl);
return logInServiceImpl;
}
}
However, this explicit-Provider solution is not idiomatic Guice, and should only be used with external or legacy code. Guice's whole reason for existence is to automate away boilerplate and let your systems come together clearly and flexibly. Providers are an implementation detail; let Guice create them for you.

angular2 CanActivate with http

I am having a component that has canactivate
import {isLoggedIn} from '../login/isLoginedIn';
#CanActivate((next, previous) => {
isLoggedIn()
})
My "isLoggedIn" is as below
import {Http, Headers} from 'angular2/http';
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
export const isLoggedIn = () => {
let injector = Injector.resolveAndCreate([Auth, Http]);
let auth = injector.get(Auth);
return auth.check();
};
I can't inject a service which has http as dependancy. Can this be done like this or is there a better way to do it?
Since the CanActivate is a decorator instead of a method as with OnActivate or CanDeactivate then you are correct in assuming that constructor dependency injection of the component that you are attempting to authorize is not an option.
The method which you are using will work, but there is a missed #Injectable() on your Auth class.
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
#Injectable()
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
This approach is sound and I don't think that besides some syntactic sugar or minor refactoring that there would be much to improve this and still achieve the same amount of readability / maintainability for this approach.
One other addition that could be made to improve the flow and prevent a potential bug would be to return the observable in CanActivate so that the navigation will wait for the Http request to complete before deciding to continue or cancel.
#CanActivate((next, previous) => {
return isLoggedIn()
})
or for short
#CanActivate(() => isLoggedIn())
(Single statement arrow functions are auto-returning)

Simulate Anonymous Authentication in Spring MVC Unit Test

I am trying to write a unit test for a guest user account. The code under test checks guest by calling this method, which in Unit Test returns null for the guest account.
/**
* Determines if the user is a guest account.
*
* #return True if the account is guest account, false otherwise.
*/
public boolean isGuest() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
if (auth instanceof AnonymousAuthenticationToken) {
return true;
} else {
return false;
}
} else {
return false;
}
}
In the server Tomcat container, the anonymous user is okay it returns an instance of AnonymousAuthenticationToken. Because the container environment & unit test environment both share the same security configuration class, assume the security config is probably correct.
The test code below also works with the MockUser so I also think the security test configuration is probably okay:
#Test
#WithMockUser(username="Test.Customer.1#mailinator.com", roles = {"ADMIN"})
public void testCheckoutPage() throws Exception{
logger.entry();
String targetView = OrderViews.convertViewReference(getPageDirectory(), OrderViews.CHECKOUT_LOGIN_PAGE, false);
String targetUrl = "/checkout";
Order order = OrderBuilder.buildSampleGuestOrder(OrderStatus.NEW, 5);
prepareMocks(order);
Map<String, Object> sessionAttrs = new HashMap<>();
sessionAttrs.put(OrderConstants.OPEN_ORDER_ID_ATTRIBUTE, order.getId());
this.mockMvc.perform(get(targetUrl).sessionAttrs(sessionAttrs))
.andExpect(status().isOk())
.andExpect(view().name(targetView))
.andExpect(model().attribute("order", order))
.andExpect(model().attributeExists("loginForm"));
this.mockMvc.perform(MockMvcRequestBuilders.post(targetUrl))
.andExpect(status().isMethodNotAllowed());
logger.exit();
}
Does anyone have an idea how to simulate the anonymous authentication token in Unit Test?
In Spring Security 4.1 (not yet GA) we are introducing support for #WithAnonymousUser.
The #WithAnonymousUser support is built using #WithSecurityContext. This means you could easily add the support to your codebase in 4.0.x until 4.1.x is released. To get it to work you would need to copy the following classes to your test source folders:
package org.springframework.security.test.context.support;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#Documented
#WithSecurityContext(factory = WithAnonymousUserSecurityContextFactory.class)
public #interface WithAnonymousUser {}
package org.springframework.security.test.context.support;
import java.util.List;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
final class WithAnonymousUserSecurityContextFactory implements
WithSecurityContextFactory<WithAnonymousUser> {
public SecurityContext createSecurityContext(WithAnonymousUser withUser) {
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS");
Authentication authentication = new AnonymousAuthenticationToken("key", "anonymous", authorities);
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
return context;
}
}
Then you can use the following to run as an anonymous user:
#Test
#WithAnonymousUser
public void testAnonymous() throws Exception {
// ...
}
NOTE: It is important to note that just as you needed to do for #WithMockUser you need to ensure you setup MockMvc with apply(springSecurity()) as outlined in the reference.
Set the authentication before running test
#Before
public void setupAuthentication(){
SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("GUEST","USERNAME", AuthorityUtils
.createAuthorityList("ROLE_ONE", "ROLE_TWO")));
}

Resources