Spring - OAuth2AccessTokenSupport Override rest template custom SSLSocketFactory - spring-mvc

I'm using ClientCredentialsAccessTokenProvider to get the OAuth access token for client credentials. However, the accessTokenURI is https.
what is the recommended way to override the default RestTemplate to provide a custom SSLSocketFactory.
The RestTemplate on OAuth2AccessTokenSupport is marked private without any setters.

ah never mind,
you can set the reqestFactory on the RestTemplate.
code is as follows,
Create the Request Factory,
RequestConfig timeoutConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).build();
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
.setDefaultRequestConfig(timeoutConfig) .disableCookieManagement().setMaxConnPerRoute(CONNECTION_MAX).setMaxConnTotal(CONNECTION_MAX).build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
ClientCredentialsAccessTokenProvider accessTokenProvider = new ClientCredentialsAccessTokenProvider();
accessTokenProvider.setRequestFactory(clientHttpRequestFactory);

Related

Access MassTransit ConsumeContext in MSDI IServiceCollection.AddTransient service

We need to access a header in our ConsumeContext when adding a transient service.
We have been using IHttpContextAccessor previously to get the headers for a normal http request, and we now need to do similarly for our event consumers.
How would we go about accessing the headers for a consumed event when using MassTransit, when setting up our dependencies/services?
services.TryAddTransient<ISapService>(provider =>
{
var httpContextAccessor = provider.GetService<IHttpContextAccessor>();
httpContextAccessor.HttpContext.Request.Headers.TryGetValue(
"x-plant-id",
out var plantHeader
);
return new SapService(plantHeader);
});
I'm not sure if it works with transient services, but MassTransit does support scoped filters. They're resolved within the consumer scope.

How to add HTTP header to MicroShedTest and SharedContainerConfig JUnit tests

I have integration tests that have been running smoothly until I added security to my application. The security uses a custom generated api key and validation is done in a custom HttpAuthenticationMechanism from header 'X-API-Key'.
I need to find out if it is possible to add headers to calls made by the test suite. I have checked the internet and all I found was #BasicAuthConfig and #JwtConfig which was not of any use.
I need to added a header 'X-API-Key' to http calls made to the containers.
I did not find anything useful so I created my own solution. Instead of relying on #RESTClient to give me the resource proxy I created my own like so:
public static <T> T getResourceProxy(Class<T> t) {
Map<String, String> headerMap = new HashMap<>();
headerMap.put("X-API-Key", "abcdefg.abcdefg1234567hij890");
headerMap.put("Content-Type", "application/json");
headerMap.put("Accept", "application/json, text/plain");
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setHeaders(headerMap);
bean.setResourceClass(t);
bean.setAddress("http://localhost:8080/myApp");
List<Object> providers = new ArrayList<>();
providers.add(new JacksonJaxbJsonProvider());
providers.add(new JacksonJsonProvider());
bean.setProviders(providers);
return bean.create(t);
}

spring MVC controller versioning

I have a spring boot application , which have a spring MVC controller. I am trying to version my rest api using Accept header.
The following is how my Controller looks like
RestController
#RequestMapping(value = "/private/")
public class AppleController {
private final AppleService appleService;
public AppleController(AppleService appleService) {
this.appleService = appleService;
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=1.0",
headers = "Accept=application/json; v=1.0")
public ResponseEntity getByappleId(#PathVariable("id") Long appleId) {
System.out.println("version1");
GetByappleIdResponse response = appleService.findByappleId(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=2.0",
headers = "Accept=application/json; v=2.0")
public ResponseEntity getByappleId2(#PathVariable("id") Long appleId) {
System.out.println("version2");
GetByappleIdResponse response = appleService.findByappleId2(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
Irrespective of the version that I am passing in the Accept header when calling the API always "getByappleId" method is called, hence only version 1 response is returned.
Is there anything wrong in my controller ?
There are many options to implement versioning of REST API:
suggested in the comments approach for manually routing your request;
making version as a part of your Accept header value, f.e.:
(headers = "Accept=application/vnd.name.v1+json")
(headers = "Accept=application/vnd.name.v2+json")
making version as a part of your mapping:
#GetMapping("apples/v1/{id})"
#GetMapping("apples/v2/{id})
So you need to decide which way to go. Some useful links:
Versioning a REST API
Best practices for API versioning?
As described in this answer: https://stackoverflow.com/a/34427044/258813 (and mentioned in the comments) Spring does not support routing using the headers like that.
If you want to support routing via a version header, I would recommend a custom routing condition and annotation - certainly if you are building a large API, it will result in less code and a more elegant solution.
You would define some annotation like #ApiVersion(1) that you can add to any method that is also a request mapping and then add the custom routing condition and it will behave correctly.
I have described using custom routing conditions and annotations (based on subdomains - but that could easily be switched to check headers instead) here: http://automateddeveloper.blogspot.co.uk/2014/12/spring-mvc-custom-routing-conditions.html

WCF service act as proxy for external web service

I'm working on developing proxy WCF service. So tasks that I have to achieve as part of this assignment are:
I have to capture headers and content from an incoming request (from
a web browser).
Construct a web request for external web service with headers and
content from incoming request.
Execute web request.
Capture headers/cookies/content form the Response of external web
service.
Construct response, add headers/cookies and send response back to
browser.
I'm able to manage 1, 2 , 3 and 4 with help of web and stackoverflow. But not find any solution for task 5.
Questions:
Response message from external web service is a json. How to send the same message in json format to web browser?
Response from external web service has 'set-cookie' header. How to add this to web browser response?
I'm new to WCF and Web Service world. Using System.Net.Http.HttpClient to make a call to external web service. Open to change it to any other client library to achieve tasks 1 to 5.
Code blocks:
IService1.cs
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "client/api")]
string ProxyAPI(Stream inp);
Service1.cs
public string ProxyAPI(Stream contentStream)
{
// Task 1: Capture Headers and content
// Task 2: Construct web request with headers and content from incoming request
HttpClient proxyClient = new HttpClient();
Uri extWSuri = new Uri("http://router.sdc.com:8090/service/api");
proxyClient.BaseAddress = extWSuri;
// get input reqquest headers and add to httpclient onject
WebOperationContext current = WebOperationContext.Current;
WebHeaderCollection headers = current.IncomingRequest.Headers;
string[] headerKeys = headers.AllKeys;
foreach (string keyStr in headerKeys)
{
if (keyStr.ToLower().Equals("host"))
{
proxyClient.DefaultRequestHeaders.Add(keyStr, "router.simplifydc.com:8080");
}
else if (!keyStr.ToLower().StartsWith("cont"))
{
proxyClient.DefaultRequestHeaders.Add(keyStr, headers.GetValues(keyStr));
}
}
// get input content data
StreamReader reader = new StreamReader(contentStream);
string contentData = reader.ReadToEnd();
reader.Close();
// create content for httpclient request
StringContent contentRequest = new StringContent(contentData, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
// Task 3: execute web request
Task<HttpResponseMessage> responseTask = proxyClient.PostAsync(extWSuri, contentRequest);
responseTask.Wait();
// Task 4: Capture headers/cookies/contnet from web response
HttpResponseMessage response = responseTask.Result;
HttpResponseHeaders resHeaders = response.Headers;
Task<string> contentTask = response.Content.ReadAsStringAsync();
contentTask.Wait();
string responseMsg = contentTask.Result;
// Task 5: construct response for incoming web browser request
// ?????????????
return responseMsg;
}
If I get it right, the client application for your WCF service is a web browser. This means that it expects an HTML document as a response right? In this case, I would suggest to avoid using a WCF service.
Why don't you use an ASP.NET page which forms the HTML to return? In your ASP.NET code behind, you could execute the 4 four steps you describe. In your 5th step, you would adjust the HTML to contain the data you got in the previous steps from the external web service.
You could always construct the HTML response using the WCF service, but I cannot see why. You could use and HTML DOM parser (like this to construct the HTML response programmatically, but this would not be my first approach.
If your page requires pure data and not HTML, your WCF service could return data in JSON format. As you can see, JSON is a simple string which could be very easy to construct. It depends on the data you want to return, but it could be very easy implemented either manually, or using some specific library like Json.NET. Then your UI application would parse JSON and display data accordingly.
Hope I helped!

Apache HTTP client 4.3 credentials per request

I have been having a look to a digest authentication example at:
http://hc.apache.org/httpcomponents-client-4.3.x/examples.html
In my scenario the there are several threads issuing HTTP requests and each of them has to be authenticated with their own set of credentials. Additionally, please consider this question is probably very specific for the Apache HTTP client 4.3 onwards, 4.2 handles authentication probably in a different way, although I didn't check it myself. That said, there goes the actual question.
I want to use just one client instance (static member of the class, that is threadsafe) and give it a connection manager to support several concurrent requests. The point is that each request will provide different credentials and I am not seeing the way to assign credentials per request as the credentials provider is set when building the http client. From the link above:
[...]
HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials("username", "password"));
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider).build();
[...]
Checking:
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html#d5e600
The code sample in point 4.4 (seek 4.4. HTTP authentication and execution context), seems to say that the HttpClientContext is given the auth cache and the credentials provider and then is passed to the HTTP request. Next to it the request is executed and it seems that the client will get credentials filtering by the host in the HTTP request. In other words: if the context (or the cache) has valid credentials for the target host of the current HTTP request, he will use them. The problem for me is that different threads will perform different requests to the same host.
Is there any way to provide custom credentials per HTTP request?
Thanks in advance for your time! :)
The problem for me is that different threads will perform different requests to the same host.
Why should this be a problem? As long as you use a different HttpContext instance per thread, execution contexts of those threads are going to be completely indepenent
CloseableHttpClient httpclient = HttpClients.createDefault();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user:pass"));
HttpClientContext localContext = HttpClientContext.create();
localContext.setCredentialsProvider(credentialsProvider);
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget, localContext);
try {
EntityUtils.consume(response.getEntity());
} finally {
response.close();
}
I have a similar issue.
I must call n-times a service with a single system user, authenticated with NTLM. I want to do this using multiple threads.
What I came up with is creating a single HTTPClient with no default credential provider. When a request needs to be performed I use an injected CredentialProviderFactory into the method performing the request (in a specific thread). Using this I get a brand new CredentialsProvider and I put this into a Context (created in the thread).
Then I call the execute method on the client using the overload execute(method, context).
class MilestoneBarClient implements IMilestoneBarClient {
private static final Logger log = LoggerFactory.getLogger(MilestoneBarClient.class);
private MilestoneBarBuilder builder;
private CloseableHttpClient httpclient;
private MilestoneBarUriBuilder uriBuilder;
private ICredentialsProviderFactory credsProviderFactory;
MilestoneBarClient(CloseableHttpClient client, ICredentialsProviderFactory credsProviderFactory, MilestoneBarUriBuilder uriBuilder) {
this(client, credsProviderFactory, uriBuilder, new MilestoneBarBuilder());
}
MilestoneBarClient(CloseableHttpClient client, ICredentialsProviderFactory credsProviderFactory, MilestoneBarUriBuilder uriBuilder, MilestoneBarBuilder milestoneBarBuilder) {
this.credsProviderFactory = credsProviderFactory;
this.uriBuilder = uriBuilder;
this.builder = milestoneBarBuilder;
this.httpclient = client;
}
// This method is called by multiple threads
#Override
public MilestoneBar get(String npdNumber) {
log.debug("Asking milestone bar info for {}", npdNumber);
try {
String url = uriBuilder.getPathFor(npdNumber);
log.debug("Building request for URL {}", url);
HttpClientContext localContext = HttpClientContext.create();
localContext.setCredentialsProvider(credsProviderFactory.create());
HttpGet httpGet = new HttpGet(url);
long start = System.currentTimeMillis();
try(CloseableHttpResponse resp = httpclient.execute(httpGet, localContext)){
[...]
For some reasons I sometimes get an error, but I guess it's an NTLMCredentials issue (not being thread-safe...).
In your case, you could probably pass the factory to the get methods instead of passing in creation.

Resources