Get AccessToken from spring cloud zuul API Gateway - spring-cloud

We are using zuul as API gateway in spring cloud. Now we want to extract access token from zuul for further implementation.Please provide suggestion how we want to implement. Thank you

To read the authorization header you will need to create a filter in ZUUL my thought is you will need a pre filter you can change it based on your need. Here is what you will need.
public class TestFilter extends ZuulFilter {
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
final RequestContext ctx = RequestContext.getCurrentContext();
final HttpServletRequest request = ctx.getRequest();
//Here is the authorization header being read.
final String xAuth = request.getHeader("Authorization");
//Use the below method to add anything to the request header to read downstream. if needed.
ctx.addZuulRequestHeader("abc", "abc");
return null;
}
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
}
You will need a #Bean declaration for Filter in the class where you have #EnableZuulProxy
#Bean
public TestFilter testFilter() {
return new TestFilter();
}
Hope this helps.!!!

Related

Feign - define param value for each methods

I need to write a client with multiple methods that require the apiKey as query string param. Is it possible to allow the client's user to pass the api key only to the method withApiKey, so I can avoid to request the apiKey as first parameter of each method?
public interface Client {
#RequestLine("GET /search/search?key={apiKey}&query={query}&limit={limit}&offset={offset}")
SearchResponse search(#Param("apiKey") String apiKey, #Param("query") String query, #Param("limit") Integer limit, #Param("offset") Integer offset);
#RequestLine("GET /product/attributes?key={apiKey}&products={products}")
List<Product> getProduct(#Param("apiKey") String apiKey, #Param("products") String products);
public class Builder {
private String basePath;
private String apiKey;
public Client build() {
return Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.client(new ApacheHttpClient())
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(Client.class, basePath);
}
public Builder withBasePath(String basePath) {
this.basePath = basePath;
return this;
}
public Builder withApiKey(String apiKey) {
this.apiKey = apiKey;
return this;
}
}
}
Depending on the setup request-interceptors might work: https://github.com/OpenFeign/feign#request-interceptors
Hopefully the example below will help.
You can swap the builder out for just the interface annotation and then move the configuration to a configuration class, if you are using spring it could be like:
#FeignClient(
name = "ClerkClient",
url = "${clery-client.url}", // instead of the withBasePath method
configuration = {ClerkClientConfiguration.class}
)
public interface Client {
Then the ClerkClientConfiguration class can define the required config beans including a ClerkClientInterceptor
public class ClerkClientConfiguration {
#Bean
public RequestInterceptor clerkClientInterceptor() {
return new ClerkClientInterceptor();
}
Then the interceptor can have a value picked up from the config and added to the queries (or header etc)
public class ClerkClientInterceptor implements RequestInterceptor {
#Value("${clerk-client.key}")
private String apiKey
#Override public void apply(RequestTemplate template) {
requestTemplate.query( "key", apiKey);
}

eureka: Custom clientFilter is useless

For more complex needs you can create a #Bean of type
DiscoveryClientOptionalArgs and inject ClientFilter instances into it,
all of which will be applied to the calls from the client to the
server.
this description in spring-cloud wiki
#Bean
public DiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
DiscoveryClientOptionalArgs discoveryClientOptionalArgs = new DiscoveryClientOptionalArgs();
discoveryClientOptionalArgs.setAdditionalFilters(Collections.singletonList(new IpCilentFilter()));
return discoveryClientOptionalArgs;
}
public class IpCilentFilter extends ClientFilter {
#Override
public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException {
// here How to disallow clients to connect
return getNext().handle(clientRequest);
}
}
How to disallow clients to connect?
throws ClientHandlerException useless
return null useless
what should I do?

delivery headers by ZuulFilter fail

I have overridden the run() method in a ZuulFilter as
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader('header name', 'value');
However, in another service I can't find the header from the request.
More details, filterType is "pre" and there is only one filter.
Header added in a Zuul filter,
context.addZuulRequestHeader("my-header", "my-value");
can be retrieved in another filter this way,
context.getZuulRequestHeaders().get("my-header");
I also try to keep my pre-filter order low, e.g., -1000;
You can retrieve the header in an internal service, a client of Zuul, as you would do it for any other header. There is no distinction between regular request header and Zuul header, e.g.,
#RequestMapping(value = /abc/hello, method = RequestMethod.GET)
public MyObject read(#RequestHeader("my-header") String value) {
...
}
Example filter adding a header:
public class AddHeaderFilter extends ZuulFilter {
public String filterType() {
return "pre";
}
public int filterOrder() {
return 100;
}
public boolean shouldFilter() {
return true;
}
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
context.addZuulRequestHeader('header name', "value");
return null;
}
}
Then in the application configuration you have to load the filter as a bean:
#Bean
AddHeaderFilter addHeaderFilter() {
return new AddHeaderFilter();
}

Mock Rest Server Response for Unit Testing

In integration testing, I use a real remote server to consume REST APIs.
What's the simplest way to provide those responses within a unit test w/o depending on external entity.
One possible approach is to build
public class TestHttpResponse implements org.apache.http.client.methods.CloseableHttpResponse
override
#Override
public StatusLine getStatusLine() {
return new StatusLine() {
#Override
public ProtocolVersion getProtocolVersion() {
return null;
}
#Override
public int getStatusCode() {
return statusCode;
}
#Override
public String getReasonPhrase() {
return reasonPhrase;
}
};
}
...
Is there a simpler and better way for mocking REST API response payloads?
I'm a fan of Mockito for this purpose:
http://www.vogella.com/tutorials/Mockito/article.html#testing-with-mock-objects
The nice part about Mockito is how you can control it's behavior dynamically.

delegate HTTP request to Jersey

I have a nano HTTP based web server, that is supposed to delegate its calls to a jersey 2.22.2. On the webserver class constructor I declare an ApplicationHandler as a instance variable:
ApplicationHandler newHandler;
Then in the constructor I initilize it and register a Sample resource class:
Object[] instances = new Object[1];
instances[0] = new SampleResource();
ResourceConfig app = new ResourceConfig();
app.registerInstances(instances);
newHandler = new ApplicationHandler(app);
On the method that processes Http requests I create a ContainerRequest and execute the apply method on the application handler :
SecurityContext secContext = new SecurityContext() {
#Override
public Principal getUserPrincipal() {
return new Principal() {
#Override
public String getName() {
return "user";
}
};
}
#Override
public boolean isUserInRole(String s) {
return true;
}
#Override
public boolean isSecure() {
return true;
}
#Override
public String getAuthenticationScheme() {
return null;
}
};
PropertiesDelegate propertiesDelegate = new PropertiesDelegate() {
Map<String, Object> props = new HashMap<>();
#Override
public Object getProperty(String s) {
return props.get(s);
}
#Override
public Collection<String> getPropertyNames() {
return props.keySet();
}
#Override
public void setProperty(String s, Object o) {
props.put(s, o);
}
#Override
public void removeProperty(String s) {
props.remove(s);
}
};
ContainerRequest request = new ContainerRequest(new URI("http://localhost:2000"), new URI("/test"), session.getMethod().toString(), secContext, propertiesDelegate);
Future<ContainerResponse> responseFuture = newHandler.apply(request);
ContainerResponse response = responseFuture.get();
Object entity = response.getEntity();
Below is the code for the SampleResource class :
public class SampleResource {
#GET
#Path("test")
public Response testMethod() {
return Response.status(Response.Status.OK).build();
}
}
The main reason for doing this is that I want to call a custom API that injects objects into the annotated resource classes.
Stepping through the code, all I get is a NotFoundException.
If you want to inject custom Objects to the resources class you can do that in two waus
using #Context -- By adding your custom object to application context
usign #Inject -- By binding the application to resource config
to use #Context , you need to extend the java.security.Principal object and declare your object fields, and you can instantiate and assign values by using security context.
to user #InJect , you need to register org.glassfish.hk2.utilities.binding.AbstractBinder like below
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("org.foo.rest;org.bar.rest");
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ObjectThatneedtoInject.class).to(yourClass.class);
}
});
}
}