I can successfully reach following OData-service using different browsers and also using Postman even so I am behind a proxy:
String SERVICE_ROOT = http://services.odata.org/V4/TripPinService/
However, using Apache Olingo in Java I am not able to access this service.
JVM parameters like -Dhttp.proxySet=true -Dhttp.proxyHost=http-proxy.example.com -Dhttp.proxyPort=8080 allow me to perform basic URL functions, like retrieving HTTP status codes (google returns 200). Nevertheless, access of the OData-Service using an ODataClient is not possible (code below). No errors are thrown.
ODataClient client = ODataClientFactory.getClient();
ODataServiceDocumentRequest request = client.getRetrieveRequestFactory().getServiceDocumentRequest(SERVICE_ROOT);
ODataRetrieveResponse<ClientServiceDocument> response = request.execute();
I tried using the proxy capabilities within Olingo, however without any success:
client.getConfiguration().setHttpClientFactory(new ProxyWrappingHttpClientFactory(URI.create("http://http-proxy.example.com:8080")));
What am I doing wrong, what options do I have left?
Thank you very much.
If you are behind an NTLM proxy you can try with NTLMAuthHttpClientFactory.
NTLMAuthHttpClientFactory ntlm = new NTLMAuthHttpClientFactory(username, password, workstation, domain);
client.getConfiguration().setHttpClientFactory(ntlm);
In case that doesn't work, you can try with cntlm. Install it, change username, password, domain and proxy in C:\Program Files (x86)\Cntlm\cntlm.ini and then invoke net start cntlm.
Use this for Olingo:
client.getConfiguration().setHttpClientFactory(new ProxyWrappingHttpClientFactory(URI.create("http://localhost:3128")));
URI uri;
String scheme = "http";
try {
uri = new URI (scheme,null,host,port,null,null,null);
} catch (URISyntaxException e) {
throw(e);
}
HttpClientFactory clientProxy = new ProxyWrappingHttpClientFactory(uri,userName,password );
client.getConfiguration().setHttpClientFactory(clientProxy);
I somehow solved the problem by myself. Within VM arguments I now only have
-Djava.net.preferIPv4Stack=true
Further I defined a proxy config only within the application:
client = ODataClientFactory.getClient();
client.getConfiguration().setHttpClientFactory(
new ProxyWrappingHttpClientFactory(URI.create("http-prox.example.com:8080")));
This worked for me. :)
Related
In our project we need to access the Blob Storage through a Proxy Server (squid).
We are planning to use the Microsoft Azure Storage SDK for Java version 2.2.0.
But it looks like setting the proxy is not provided by the API.
The only way I could make it go through the proxy is by setting the System properties
System.setProperty("http.proxyHost", "127.0.0.1");
System.setProperty("http.proxyPort", "3128");
But this affect all services that are running on my JVM which harms other services that not supposed to go via the Proxy.
Looking at the java code it looks like
com.microsoft.azure.storage.core.BaseRequest.createURLConnection(URI, RequestOptions, UriQueryBuilder, OperationContext). Is calling java.net.URL.openConnection() without proxy.
While using java.net.URL.openConnection(Proxy) could provide the required support?
It looks wired to me that this is not supported?
Do I miss something here?
UPDATE: I opened an issue on this in azure-storage-java git, I would be happy to get your input as I want to suggest a pull request for this.
So far there have been no Java SDK API support access directly Azure Storage through proxy server, because BaseRequest Class miss "url.openConnection(proxy)" in the function "public static HttpConnection createURLConnection(...)".
Per my experience, there are two ways to help you implement the access function.
The one is that you can use Azure Storage REST API through the java.net.Proxy Class to access storage service.
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
URLConnection conn = url.openConnection(proxy);
And if you should be authorize proxy user & password, you can do it as the follows:
//Proxy-Authorization: Basic <Base64.encode(user:password)>
String headerKey = "Proxy-Authorization";
String headerValue = "Basic " + Base64.encode(user+":"+password);
conn.setRequestProperty(headerKey, headerValue);
The last one is that you can modify Azure SDK API and overwrite the method “createURLConnection” in Class “BaseRequest” to implement accessing. The Azure Storage SDK v2.2.0 project on GitHub is https://github.com/Azure/azure-storage-java/tree/v2.2.0/.
Note:
public static HttpURLConnection createURLConnection(final URI uri, final RequestOptions options, UriQueryBuilder builder, final OperationContext opContext, java.net.Proxy proxy)
and
final HttpURLConnection retConnection = (HttpURLConnection) resourceUrl.openConnection(proxy);
public static HttpURLConnection createURLConnection(final URI uri, final RequestOptions options, UriQueryBuilder builder, final OperationContext opContext, java.net.Proxy proxy) throws IOException, URISyntaxException, StorageException {
if (builder == null) {
builder = new UriQueryBuilder();
}
final URL resourceUrl = builder.addToURI(uri).toURL();
final HttpURLConnection retConnection = (HttpURLConnection) resourceUrl.openConnection(proxy);
if (options.getTimeoutIntervalInMs() != null && options.getTimeoutIntervalInMs() != 0) {
builder.add(TIMEOUT, String.valueOf(options.getTimeoutIntervalInMs() / 1000));
}
// Note: ReadTimeout must be explicitly set to avoid a bug in JDK 6.
// In certain cases, this bug causes an immediate read timeout exception to be thrown even if ReadTimeout is not set.
retConnection.setReadTimeout(Utility.getRemainingTimeout(options.getOperationExpiryTimeInMs(), options.getTimeoutIntervalInMs()));
// Note : accept behavior, java by default sends Accept behavior as text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
retConnection.setRequestProperty(Constants.HeaderConstants.ACCEPT, Constants.HeaderConstants.XML_TYPE);
retConnection.setRequestProperty(Constants.HeaderConstants.ACCEPT_CHARSET, Constants.UTF8_CHARSET);
// Note : Content-Type behavior, java by default sends Content-type behavior as application/x-www-form-urlencoded for posts.
retConnection.setRequestProperty(Constants.HeaderConstants.CONTENT_TYPE, Constants.EMPTY_STRING);
retConnection.setRequestProperty(Constants.HeaderConstants.STORAGE_VERSION_HEADER,
Constants.HeaderConstants.TARGET_STORAGE_VERSION);
retConnection.setRequestProperty(Constants.HeaderConstants.USER_AGENT, getUserAgent());
retConnection.setRequestProperty(Constants.HeaderConstants.CLIENT_REQUEST_ID_HEADER,
opContext.getClientRequestID());
return retConnection;
}
By the way, You need to call above method in every CloudXXXClient(CloudBlobClient, etc) Class.
Following the issue-48 opened by me based on this question and additional one opened by strazh issue-65, The proxy support was improved in version 4.2.0 see here.
Added support for setting a library-wide proxy. The default proxy can
be set on OperationContext.
See the JUnits for full example
https://github.com/Azure/azure-storage-java/blob/master/microsoft-azure-storage-test/src/com/microsoft/azure/storage/GenericTests.java
Look for testDefaultProxy and testProxy
Azure Storage team has released a new SDK (v10), where the Proxy is now supported through the HttpPipeline. You can share the pipeline across all operations by passing it to StorageURL or just use in a single Blob by passing it to the BlobURL object.
AnonymousCredentials creds = new AnonymousCredentials();
// Use PipelineOptions to define a retry strategy and a proxy - you can also pass your own HttpClient to this if you like
PipelineOptions po = new PipelineOptions();
// Proxy configuration shown here as a sample
HttpClientConfiguration configuration = new HttpClientConfiguration(
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888)), false); //pass true if the Proxy endpoint is HTTPS
po.client = HttpClient.createDefault(configuration);
// Create a URI with SAS token, and pass it to the PageBlobURL with an HttpPipeline created by createPipeline method
URL u = new URL("https://myaccount.blob.core.windows.net/mycontainer/myfile?sv=2017-04-17&sr=b&si=14169767-6354-41ed-a99b-c9db8dcc66bc&sig=8NUr%2BSpmRH%2BB2z%2FpQZDPDquTQ7rbgWfE9a6AePLlFT0%3D");
PageBlobURL blobURL = new PageBlobURL(u, PageBlobURL.createPipeline(creds, po));
I created the jar from the WSDL for my client using the wsdl2java command. Now, I need to know how I can authenticate my client in order to complete an operation?
I am using CXF 2.7.16. I created my service using the generated class MyApp_Service, I am struggling with this. Isn't there a simple way to tell my client the credentials it should use to gain access to the web service?
I read about the Spring configuration, however I am unable to figure out if it applies to my case and how if yes. I tried to cast the MyApp_Service class to BindingProvider in order to use the method which consist to put the USERNAME and PASSWORD properties in the context with a value. However, MyApp_Service cannot be cast to BindingProvider.
This is my first web service client application ever. So, any help will be welcomed.
Update 2015-05-28: I tried to define the AuthenticationPolicy but is seems not working. Here is the code:
Client client = JaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl);
ClientImpl clt = (ClientImpl) client;
HTTPConduit cc = (HTTPConduit) clt.getConduit();
org.apache.cxf.configuration.security.ObjectFactory secOF = new org.apache.cxf.configuration.security.ObjectFactory();
AuthorizationPolicy ap = secOF.createAuthorizationPolicy();
ap.setUserName(usagerWS);
ap.setPassword(mdpWS);
ap.setAuthorizationType("Basic");
cc.setAuthorization(ap);
Sniffing with WireShark, the Authorization header is clearly missing in the HTTP request.
What is missing?
Problem solved, here is the solution:
MyApp_Service service = new MyApp_Service(wsdlUrl, new QName(namespace, serviceName));
MyApp port = service.getMyApp();
// Set credentials
Map<String, Object> reqCtxt = ((javax.xml.ws.BindingProvider) port).getRequestContext();
reqCtxt.put(javax.xml.ws.BindingProvider.USERNAME_PROPERTY, username);
reqCtxt.put(javax.xml.ws.BindingProvider.PASSWORD_PROPERTY, password);
No more usage of the dynamic client. Only the classes generated with wsdl2java are used.
I want to export data from VersionOne into my own Java application. Please help me retrieve this data from it. I used the following code but it is not working.
V1APIConnector dataConnector = new V1APIConnector("http://www10.v1host.com/loxvo/rest-1.v1/", "username", "password");
V1APIConnector metaConnector = new V1APIConnector("http://www10.v1host.com/loxvo/meta.v1/");
metaModel = new MetaModel(metaConnector);
services = new Services(metaModel, dataConnector);
It seems there is some problem from with my URL. Please tell me what will be proper URL here as my company URL is https://www10.v1host.com/loxvo/
You have the correct form of the URL in your post, but not in your sample code. All hosted instances use https as you have shown at the end, but your code has http. While a browser will simply accept a redirect and take you from http to https, the API Client code does not; it simply fails to establish a connection.
I have an app that makes http requests to a remote server. I do this with the following code:
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("myURL");
try {
ArrayList<BasicNameValuePair> postVariables = new ArrayList<BasicNameValuePair>(2);
postVariables.add(new BasicNameValuePair("key","value"));
httpPost.setEntity(new UrlEncodedFormEntity(postVariables));
HttpResponse response = httpClient.execute(httpPost);
String responseString = EntityUtils.toString(response.getEntity());
if (responseString.contains("\"success\":true")){
//this means the request succeeded
} else {
//failed
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
This goes really well, but one of our customers has set up an APN that requires requests to go via a certain proxy server. If I add the following to the request this works, the request gets rerouted via the proxy to the server:
HttpHost httpHost = new HttpHost("proxyURL",8080);
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, httpHost);
So far so good, however, I use a library that makes some http requests as well. The library's code is not accesible for me, so I can't add those two lines to the code. I contacted the creators of that library, and they told me it should be possible to set up the android environment so that all requests will automatically go through the proxy. Is there something like that? I didn't find anything on google.
I'm basically looking for a way to set the above two lines as a standard for all http requests. Please note that the APN does not set the proxy as a default for the entire phone, so apps will have to do this manually (and yes that means the majority of the apps don't work on that customer's phone).
It's been a year or two since I've needed to use it, but if I remember correctly, you can use the System.setProperty(String, String) in order to set an environment-wide setting for your application to route all HTTP traffic through a proxy. The properties that you should need to set are "http.proxyHost" and "http.proxyPort" and then use your HttpClient normally without specifying a proxy because the VM will handle routing requests.
Docs for more information about what I'm talking about can be found here: ProxySelector (just so you know what keys to use) and here for documentation about the actual System.setProperty(String, String) function
If that doesn't work for you, let me know and I'll try to dig out my old code that set a system-level proxy. BTW, it's really only "system-level" since each app runs in it's own Dalvik so you won't impact other app's network communications.
I'm working on building an android application which requires different levels of authentication, and I would like to do so using Active Directory.
From what I've read, using Kerberos is the way Microsoft suggests. How do I do this for Android? I see the javax.security.auth doc, but it doesn't tell me too much.
I also saw a note somewhere that Kerberos does not contain user groups - is this true? In that case, would I have to somehow combine LDAP as well?
EDIT
The main goal here is achieving an LDAP connection to the active directory in order to authenticate and give the user correct permissions for the enterprise Android application. The real barrier here is the fact that Google left out many of the Java Web Services API from it's port to android. (i.e. javax.naming) Also, many of the connection mechanisms in the Android jar seem to be only included as legacy code, and they in fact actually do nothing.
For that you might be better off just staying completely within LDAP and don't venture into the kerberos. Kerberos gives you advantage of Single Sign On, but since your android app doesn't have any credentials already in place it doesn't really help you. I guess google had their own reasons not to include the javax.naming into the distro. It is pretty heavy stuff.
You might be able to either port the stuff yourself from java runtime library sources, or might be better off using native LDAP library. For example this one.
Just remember to use secure LDAP connection or at least secure authentication method. More info about this is here.
I found the documentation here to be really useful when I was writing my code to authenticate with my Kerberos server. Here's how I authenticate with my kerberos server, but you might need to tweak it for yours (hence me including the link):
public static final int REGISTRATION_TIMEOUT = 30 * 1000; // ms
private static DefaultHttpClient httpClient;
private static final AuthScope SERVER_AUTH_SCOPE =
new AuthScope("urls to kerberos server", AuthScope.ANY_PORT);
public static DefaultHttpClient getHttpClient(){
if(httpClient == null){
httpClient = new DefaultHttpClient();
final HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT);
ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT);
}
return httpClient;
}
public static boolean authenticate(String username, String password)
{
UsernamePasswordCredentials creds =
new UsernamePasswordCredentials(username, password);
DefaultHttpClient client = getHttpClient();
client.getCredentialsProvider().setCredentials(SERVER_AUTH_SCOPE, creds);
boolean authWorked = false;
try{
HttpGet get = new HttpGet(AUTH_URI);
HttpResponse resp = client.execute(get);
authWorked = resp.getStatusLine().getStatusCode() != 403
}
catch(IOException e){
Log.e("TAG", "IOException exceptions");
//TODO maybe do something?
}
return authWorked;
}
Have you looked at using JCIFS? Based on these questions [1] [2] and this site, JCIFS works under Android. The JCIFS site has a simple NTLM Authenticator example that could help get you started. However, based on this Samba list message, you will need to use LDAP and custom code to get the user's groups.
Try this tutorial from Oracle. My code likes a charm. Hopefully everything is included in Android's VM distro.