I have just been handed a groovy project that is using the Jodd library (I have little experience with this). I am looking to find out how you setup configuration so that http and https calls can be made behind a company proxy.
At the moment a helper class has been setup
#! /usr/bin/groovy
package org.myOrg
import groovy.json.JsonBuilder
#Grab("org.jodd:jodd-http:3.8.5")
import jodd.http.HttpRequest
/**
* Helper class for making REST calls from a Jenkins Pipeline job.
*/
class JenkinsHttpClient {
// Constants
private static final String USER_AGENT = "User-Agent";
private final HttpRequest httpRequest
private final String userAgent = 'Jenkins'
JenkinsHttpClient() {
httpRequest = new HttpRequest()
}
/**
* GET method
* #param url - This is the endpoint
* #return response body as String
*/
private def get(String url) {
def resp = httpRequest.get(url)
.header(USER_AGENT, userAgent)
.send()
return resp.bodyText()
}
How or where do I add config so that this will work behind a proxy?
HttpConnectionProvider also allows you to specify the proxy. Just provide the ProxyInfo instance with the information about the used proxy (type, address, port, username, password):
SocketHttpConnectionProvider scp = new SocketHttpConnectionProvider();
scp.useProxy(ProxyInfo.httpProxy("proxy_url", 1090, null, null));
HttpResponse response = HttpRequest
.get("http://jodd.org/")
.withConnectionProvider(scp)
.send();
Jodd supports HTTP, SOCKS4 and SOCKE5 proxy types.
See the documentation.
Related
Hi there I am writing an OpenSource Springboot microservice to get issues from SonarQube
I use SonarQube is installed in a Docker container
From the browser I call successfully after logging in :
http://localhost:9001/api/issues/search?componentKeys=za.co.nico:RabbitMqPoc
I am unit testing a Java class that I can call the same URL and getting a 401
failing Authentication where I need it to work
package za.co.nico.poc.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsClientFactories;
import org.sonarqube.ws.client.WsResponse;
import org.springframework.stereotype.Service;
/**
*
* https://www.baeldung.com/java-http-request
*
*/
#Service
public class SonarServiceImpl implements SonarService {
private static final Logger log = LoggerFactory.getLogger(SonarServiceImpl.class);
private final String TOKEN="2ce06b3585c34141beeeb4005235337ba2bd135d";
/**
* https://programtalk.com/java-api-usage-examples/org.sonarqube.ws.client.WsClient/
*/
#Override
public String getData(String restUrl,String sonarEndPoint) {
log.debug(" restUrl : "+restUrl+" sonarEndPoint : "+sonarEndPoint); // restUrl : http://localhost:9001/ sonarEndPoint : api/components/search_projects
String login="admin";
String password="admin";
WsClient wsClient = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder().url(restUrl).credentials(login, password).build());
WsResponse response = wsClient.wsConnector().call(new GetRequest("api/authentication/validate"));
String content = response.content();
log.debug(""+response.isSuccessful());
log.debug(""+response.code()); //200
response = wsClient.wsConnector().call(new GetRequest("api/components/search_projects"));
log.debug(""+response.isSuccessful());
content = response.content();
log.debug(""+response.code()); //401
wsClient = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder().url(restUrl).credentials("admin", "admin").build());
response = wsClient.wsConnector().call(new GetRequest("local_ws_call/require_permission"));
log.debug(""+response.isSuccessful());
log.debug(""+response.code()); // 200
wsClient = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder().url(restUrl).credentials(login, password).build());
response = wsClient.wsConnector().call(new GetRequest("api/rules/search"));
log.debug(""+response.isSuccessful());
log.debug(""+response.code()); // 401
return "";
}
}
Please advise how to fix this
A 401 error simply means that the authentication credentials you are providing did not match what was expected. It appears you are providing a username and password of "admin" and "admin", but I also see that you defined a "TOKEN" constant, which is unreferenced. We would have no idea how you configured your sonarqube instance, or what credentials are actually required. In my experience, it's best for automation scripts to use the "token" authentication system, which you appear to have been intending to use, but you're simply not passing it correctly.
I want to consume a SOAP Web service which requires an OAuth2 authentication with client_credentials grant type.
From the documentation (http://cxf.apache.org/docs/jax-rs-oauth2.html#JAX-RSOAuth2-AdvancedOAuth2clientapplications) , I have found the BearerAuthSupplier which could be usefull. So I tried
#Bean
public CustomName customName()
{
final JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
factoryBean.setServiceClass(CustomName.class);
factoryBean.setAddress("");
final CustomName serviceClient = (CustomName ) factoryBean.create();
// Get the underlying Client object from the proxy object of service interface
final org.apache.cxf.endpoint.Client proxy = ClientProxy.getClient(serviceClient);
final HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
final BearerAuthSupplier supplier = new BearerAuthSupplier();
supplier.setAccessTokenServiceUri("");
supplier.setConsumer(new Consumer("client-id", "client-secret"));
supplier.setRefreshEarly(true);
conduit.setAuthSupplier(supplier);
return serviceClient;
}
In the Authorization Header I had a Basic assertion (I wanted a Bearer). Plus, I had no possibility to set the scope of the token. I think there is something I missed ...
To get this working, I had to extend BearerAuthSupplier to somethink like this
public class CustomAuthSupplier extends BearerAuthSupplier {
private String accessTokenServiceUri;
public String getAuthorization(AuthorizationPolicy authPolicy,
URI currentURI,
Message message,
String fullHeader) {
ClientCredentialsGrant clientCredentialsGrant = new ClientCredentialsGrant("scope_needed");
clientCredentialsGrant.setClientId(this.getConsumer().getClientId());
clientCredentialsGrant.setClientSecret(this.getConsumer().getClientSecret());
WebClient wc = WebClient.create(this.accessTokenServiceUri, Collections.singletonList(new OAuthJSONProvider()));
ClientAccessToken at = OAuthClientUtils.getAccessToken(wc,clientCredentialsGrant);
this.setClientAccessToken(at);
return super.getAuthorization(authPolicy, currentURI, message, fullHeader);
}
public void setAccessTokenServiceUri(String uri) {
this.accessTokenServiceUri = uri;
super.setAccessTokenServiceUri(uri);
}
So far it works well, but I find it a bit complicated (and I'm not really sure of what i am doing). My question is : How to perform client credential grant with CXF when calling a Soap WS ?
I am recording rest api's with wiremock... in my case for SharePoint.
So I set up a recorder:
java -jar wiremock-standalone-2.18.0.jar
Now I go to http://localhost:8080/__admin/recorder/ and I enable recording for my http://sharepointhost.
Now I make some requests to sharepoint rest apis through http://localhost:8080.
But the rest api responses still reference the http://sharepointhost.
Is there a way to turn on some sort of reverse proxy or URL pattern string replace so I can avoid this issue? What is the way to do that in my case? Do I need to use the Java variety of the recorder instead of using the standalone?
WireMock supports "Extensions." And there are some pre-packaged extension types called "Transformers."
There is an extension type that allows you to intercept responses of http requests. Here you can then replace contents of responses.
See http://wiremock.org/docs/extending-wiremock/
I created a GitHub repository with a response body URL rewrite extension:
https://github.com/nddipiazza/wiremock-response-body-url-rewriter
public class ResponseBodyUrlRewriteTransformer extends ResponseTransformer {
final int wiremockPort;
final String wiremockBindAddress;
final private List<String> urlsToReplace;
public ResponseBodyUrlRewriteTransformer(String wiremockBindAddress, int wiremockPort, List<String> urlsToReplace) {
this.urlsToReplace = urlsToReplace;
this.wiremockBindAddress = wiremockBindAddress;
this.wiremockPort = wiremockPort;
}
private String replaceUrlsInBody(String bodyText) {
for (String urlToReplace : urlsToReplace) {
bodyText = bodyText.replaceAll(Pattern.quote(urlToReplace),
"http://" + wiremockBindAddress + ":" + wiremockPort);
}
return bodyText;
}
#Override
public Response transform(Request request, Response response, FileSource files, Parameters parameters) {
if (response.getStatus() == 200) {
ContentTypeHeader contentTypeHeader = response.getHeaders().getContentTypeHeader();
if (contentTypeHeader != null && contentTypeHeader.mimeTypePart().contains("xml")) {
return Response.response()
.body(replaceUrlsInBody(response.getBodyAsString()))
.headers(response.getHeaders())
.status(response.getStatus())
.statusMessage(response.getStatusMessage())
.fault(response.getFault())
.chunkedDribbleDelay(response.getChunkedDribbleDelay())
.fromProxy(response.isFromProxy())
.build();
}
}
return response;
}
#Override
public String getName() {
return "ResponseBodyUrlRewriteTransformer";
}
}
Yes. You can launch WireMock as a proxy with automatic record mode. The command you need is this:
java -jar wiremock-standalone-2.18.0.jar --port 8787 --print-all-network-traffic --verbose --enable-browser-proxying --record-mappings
The important params there are enable-browser-proxying and record-mappings
The proxy is running on port 8787 and you have to configure your browser to use proxy localhost:8787
Now you can browse any web site, and all the trafic will be recorded.
I have a scenario where I want to store session information across multiple sessions in Application # 2. We have two applications deployed on a tomcat server. Our use case is as follows:
A. Web Application # 1 makes a HTTP Post request to Application # 2 using a HTTP Rest Client. POST request contains a JSON http request body encapsulating the data to be send to Application # 2. The code block is as follows:
RestTemplate template = new RestTemplate();
final SearchCustomer customer = new SearchCustomer();
restTemplate.execute(
SEND_CUSTOMER_PROFILE, HttpMethod.POST,
new SearchRequestCallback(searchCustomer), null);
The request callback function is
static class SearchRequestCallback implements RequestCallback {
/**
* Write a JSON response to the request body.
*/
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
}
}
The second application has a Spring controller with the following set up
#Controller
public class SearchCustomerController {
/**
* Builds customer profile knowledge graph.
*
* <p>This is invoked as an synchronous request.
*/
#RequestMapping(value="/searchProfilePayload.go", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void constructSearchCustomerProfileKnowledgeGraph(
#RequestBody final SearchCustomer customer, HttpServletRequest request) {
UserContext userContext =
(UserContext) request.getSession().getAttribute("userContext");
if (userContext == null) {
// Perform heavy operation to fetch user session.
userContext = UserContextHelper.getUserContext(request);
request.getSession("userContext", userContext)
}
userContext.setCustomerProfile(customer);
}
}
When I make a call to another URI within the application # 2 say via browser, I want it done in such as way that the session attributes are retained when making this call. Is there a way to do that?
I know about URL rewriting that stores JSESSIONIDin the cookie, but I don't think how you can set the value when making a rest call, and using the same JESSIONID to maintain session attributes.
Is there a better way to do this? These have no answers. I have looked at these links, but none seem to answer my question.
HTTP and Sessions
comparison of ways to maintain state
jraahhali is spot on.
Set the cookie header with the value of JSESSIONID=${sessionId} or use it directly in the url as per the URL rewriting link.
First step is to retrieve the JSESSIONID from the initial response (this will depend on how you decide to set the session id - URL or Cookies, lets assume by cookie for now)
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
ClientHttpResponse response = request.execute();
String sessionId = response.getHeaders().get(HttpHeaders.SET_COOKIE).split(":")[1].trim(); // I didnt test this, will prolly get a NPE :P
this.sessionId = sessionId;
}
Then in subsequent requests (ie from the app #1 or a browser or whatever)
if (this.sessionId != null && !this.sessionId.equals(""))
httpHeaders.set(HttpHeaders.COOKIE, "JSESSIONID=" + this.sessionId);
// ...
request.execute();
Note if you really want to use a browser as the other client then I would use the URL rewriting method for ease of use ...
I need to be able to set an entity on an OPTIONS call but looks like HttpClient does not support it. HttpPost and HttpPut extend from HttpEntityEnclosingRequestBase, while HttpOptions does not.
Anyone know the reason for this, or if there is a way around this?
The HTTP specification states
If the OPTIONS request includes an entity-body (as indicated by the
presence of Content-Length or Transfer-Encoding), then the media type
MUST be indicated by a Content-Type field. Although this specification
does not define any use for such a body, future extensions to HTTP
might use the OPTIONS body to make more detailed queries on the
server. A server that does not support such an extension MAY discard
the request body.
The Apache Http Client team probably decided that there was no use case that would warrant a request body in a OPTIONS request.
In case anyone needs this, here is how did this for HttpClient.
#Autowired
HttpClient httpClient;
public HttpResponse execute(String url, String json, String accessToken) {
HttpOptionsWithBody httpOptionsWithBody = new HttpOptionsWithBody(url);
httpOptionsWithBody.setEntity(new StringEntity(json));
return httpClient.execute(httpOptionsWithBody);
}
private static class HttpOptionsWithBody extends HttpEntityEnclosingRequestBase {
public static final String METHOD_NAME = "OPTIONS";
#Override
public String getMethod() {
return METHOD_NAME;
}
public HttpOptionsWithBody(final String uri) {
super();
setURI(URI.create(uri));
}
}
I got the idea on how to do this from HttpDelete with body