/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.support.wsdl;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.support.CompressionSupport;
import com.eviware.soapui.impl.wsdl.support.PathUtils;
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
import com.eviware.soapui.model.settings.Settings;
import com.eviware.soapui.settings.HttpSettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.swing.SwingWorker;
import com.eviware.soapui.support.types.StringToStringMap;
import com.eviware.x.form.XForm;
import com.eviware.x.form.XFormDialog;
import com.eviware.x.form.XFormDialogBuilder;
import com.eviware.x.form.XFormFactory;
/**
* WsdlLoader for URLs
*
* @author ole.matzura
*/
public class UrlWsdlLoader extends WsdlLoader {
private HttpContext state;
protected HttpGet getMethod;
private boolean aborted;
protected Map<String, byte[]> urlCache = new HashMap<String, byte[]>();
protected boolean finished;
private boolean useWorker;
private ModelItem contextModelItem;
private org.apache.http.HttpResponse httpResponse;
public UrlWsdlLoader(String url) {
this(url, null);
}
public UrlWsdlLoader(String url, ModelItem contextModelItem) {
super(url);
this.contextModelItem = contextModelItem;
state = new BasicHttpContext();
}
public boolean isUseWorker() {
return useWorker;
}
public void setUseWorker(boolean useWorker) {
this.useWorker = useWorker;
}
public InputStream load() throws Exception {
return load(getBaseURI());
}
public synchronized InputStream load(String url) throws Exception {
if (!PathUtils.isHttpPath(url)) {
try {
File file = new File(url.replace('/', File.separatorChar));
if (file.exists()) {
url = file.toURI().toURL().toString();
}
} catch (Exception e) {
}
}
if (urlCache.containsKey(url)) {
setNewBaseURI(url);
return new ByteArrayInputStream(urlCache.get(url));
}
if (url.startsWith("file:")) {
return handleFile(url);
}
log.debug("Getting wsdl component from [" + url + "]");
createGetMethod(url);
if (aborted) {
return null;
}
LoaderWorker worker = new LoaderWorker();
if (useWorker) {
worker.start();
} else {
worker.construct();
}
while (!aborted && !finished) {
Thread.sleep(200);
}
// wait for method to catch up - required in unit tests..
// limited looping to 10 loops because of eclipse plugin which entered
// endless loop without it
int counter = 0;
byte[] content = null;
if (httpResponse != null && httpResponse.getEntity() != null) {
content = EntityUtils.toByteArray(new BufferedHttpEntity(httpResponse.getEntity()));
}
while (!aborted && content == null && counter < 10) {
Thread.sleep(200);
counter++;
}
if (aborted) {
throw new Exception("Load of url [" + url + "] was aborted");
} else {
if (content != null) {
String compressionAlg = HttpClientSupport.getResponseCompressionType(httpResponse);
if (compressionAlg != null) {
content = CompressionSupport.decompress(compressionAlg, content);
}
urlCache.put(url, content);
String newUrl = getMethod.getURI().toString();
if (!url.equals(newUrl)) {
log.info("BaseURI was redirected to [" + newUrl + "]");
}
setNewBaseURI(newUrl);
urlCache.put(newUrl, content);
return new ByteArrayInputStream(content);
} else {
throw new Exception("Failed to load url; " + url + ", "
+ (httpResponse != null ? httpResponse.getStatusLine().getStatusCode() : 0) + " - "
+ (httpResponse != null ? httpResponse.getStatusLine().getReasonPhrase() : ""));
}
}
}
protected InputStream handleFile(String url) throws Exception {
setNewBaseURI(url);
return new URL(url).openStream();
}
protected void createGetMethod(String url) {
getMethod = new HttpGet(url);
getMethod.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, true);
state.setAttribute(ClientContext.CREDS_PROVIDER, new WsdlCredentialsProvider());
if (SoapUI.getSettings().getBoolean(HttpSettings.AUTHENTICATE_PREEMPTIVELY)) {
if (!StringUtils.isNullOrEmpty(getUsername()) && !StringUtils.isNullOrEmpty(getPassword())) {
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(getUsername(), getPassword());
getMethod.addHeader(BasicScheme.authenticate(creds, "utf-8", false));
}
}
}
public final class LoaderWorker extends SwingWorker {
public Object construct() {
HttpClientSupport.SoapUIHttpClient httpClient = HttpClientSupport.getHttpClient();
try {
Settings soapuiSettings = SoapUI.getSettings();
HttpClientSupport.applyHttpSettings(getMethod, soapuiSettings);
httpResponse = httpClient.execute(getMethod, state);
} catch (Exception e) {
return e;
} finally {
finished = true;
}
return null;
}
}
public boolean abort() {
if (getMethod != null) {
getMethod.abort();
}
aborted = true;
return true;
}
public boolean isAborted() {
return aborted;
}
/**
* CredentialsProvider for providing login information during WSDL loading
*
* @author ole.matzura
*/
private static Map<AuthScope, Credentials> cache = new HashMap<AuthScope, Credentials>();
public final class WsdlCredentialsProvider implements CredentialsProvider {
private XFormDialog basicDialog;
private XFormDialog ntDialog;
public WsdlCredentialsProvider() {
}
public Credentials getCredentials(final AuthScope authScope) {
if (authScope == null) {
throw new IllegalArgumentException("Authentication scope may not be null");
}
// if( cache.containsKey( authScope ) )
// {
// return cache.get( authScope );
// }
String pw = getPassword();
if (pw == null) {
pw = "";
}
if (AuthPolicy.NTLM.equalsIgnoreCase(authScope.getScheme())
|| AuthPolicy.SPNEGO.equalsIgnoreCase(authScope.getScheme())) {
String workstation = "";
try {
workstation = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
}
if (hasCredentials()) {
log.info("Returning url credentials");
return new NTCredentials(getUsername(), pw, workstation, null);
}
log.info(authScope.getHost() + ":" + authScope.getPort() + " requires Windows authentication");
if (ntDialog == null) {
buildNtDialog();
}
StringToStringMap values = new StringToStringMap();
values.put("Info", "Authentication required for [" + authScope.getHost() + ":" + authScope.getPort() + "]");
ntDialog.setValues(values);
if (ntDialog.show()) {
values = ntDialog.getValues();
NTCredentials credentials = new NTCredentials(values.get("Username"), values.get("Password"),
workstation, values.get("Domain"));
cache.put(authScope, credentials);
return credentials;
}
} else if (AuthPolicy.BASIC.equalsIgnoreCase(authScope.getScheme())
|| AuthPolicy.DIGEST.equalsIgnoreCase(authScope.getScheme())) {
if (hasCredentials()) {
log.info("Returning url credentials");
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(getUsername(), pw);
cache.put(authScope, credentials);
return credentials;
}
log.info(authScope.getHost() + ":" + authScope.getPort() + " requires authentication with the realm '"
+ authScope.getRealm() + "'");
ShowDialog showDialog = new ShowDialog();
showDialog.values.put("Info",
"Authentication required for [" + authScope.getHost() + ":" + authScope.getPort() + "]");
UISupport.getUIUtils().runInUIThreadIfSWT(showDialog);
if (showDialog.result) {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
showDialog.values.get("Username"), showDialog.values.get("Password"));
cache.put(authScope, credentials);
return credentials;
}
}
return null;
}
private void buildBasicDialog() {
XFormDialogBuilder builder = XFormFactory.createDialogBuilder("Basic Authentication");
XForm mainForm = builder.createForm("Basic");
mainForm.addLabel("Info", "");
mainForm.addTextField("Username", "Username for authentication", XForm.FieldType.TEXT);
mainForm.addTextField("Password", "Password for authentication", XForm.FieldType.PASSWORD);
basicDialog = builder.buildDialog(builder.buildOkCancelActions(), "Specify Basic Authentication Credentials",
UISupport.OPTIONS_ICON);
}
private void buildNtDialog() {
XFormDialogBuilder builder = XFormFactory.createDialogBuilder("NT Authentication");
XForm mainForm = builder.createForm("Basic");
mainForm.addLabel("Info", "");
mainForm.addTextField("Username", "Username for authentication", XForm.FieldType.TEXT);
mainForm.addTextField("Password", "Password for authentication", XForm.FieldType.PASSWORD);
mainForm.addTextField("Domain", "NT Domain for authentication", XForm.FieldType.TEXT);
ntDialog = builder.buildDialog(builder.buildOkCancelActions(), "Specify NT Authentication Credentials",
UISupport.OPTIONS_ICON);
}
private class ShowDialog implements Runnable {
StringToStringMap values = new StringToStringMap();
boolean result;
public void run() {
if (basicDialog == null) {
buildBasicDialog();
}
basicDialog.setValues(values);
result = basicDialog.show();
if (result) {
values = basicDialog.getValues();
}
}
}
public void clear() {
cache.clear();
}
public void setCredentials(AuthScope arg0, Credentials arg1) {
}
}
public void close() {
}
}