diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin index 26821c8991..6aaa89443e 100644 --- a/AddIns/ICSharpCode.SharpDevelop.addin +++ b/AddIns/ICSharpCode.SharpDevelop.addin @@ -1243,6 +1243,10 @@ + + + + + + + diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AddWebReferenceDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AddWebReferenceDialog.cs index 1756415f37..91b7b0bc5e 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AddWebReferenceDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AddWebReferenceDialog.cs @@ -22,7 +22,8 @@ namespace ICSharpCode.SharpDevelop.Gui { public class AddWebReferenceDialog : System.Windows.Forms.Form { - DiscoveryClientProtocol discoveryClientProtocol; + WebServiceDiscoveryClientProtocol discoveryClientProtocol; + CredentialCache credentialCache = new CredentialCache(); int initialFormWidth; int initialUrlComboBoxWidth; string namespacePrefix = String.Empty; @@ -32,6 +33,7 @@ namespace ICSharpCode.SharpDevelop.Gui delegate DiscoveryDocument DiscoverAnyAsync(string url); delegate void DiscoveredWebServicesHandler(DiscoveryClientProtocol protocol); + delegate void AuthenticationHandler(Uri uri, string authenticationType); public AddWebReferenceDialog(IProject project) { @@ -431,7 +433,6 @@ namespace ICSharpCode.SharpDevelop.Gui Cursor = Cursors.WaitCursor; stopButton.Enabled = true; webServicesView.Clear(); - StartDiscovery(e.Url); } void WebBrowserNavigated(object sender, WebBrowserNavigatedEventArgs e) @@ -439,6 +440,7 @@ namespace ICSharpCode.SharpDevelop.Gui Cursor = Cursors.Default; stopButton.Enabled = false; urlComboBox.Text = webBrowser.Url.ToString(); + StartDiscovery(e.Url); } void WebBrowserCanGoForwardChanged(object sender, EventArgs e) @@ -524,6 +526,11 @@ namespace ICSharpCode.SharpDevelop.Gui /// Starts the search for web services at the specified url. /// void StartDiscovery(Uri uri) + { + StartDiscovery(uri, new DiscoveryNetworkCredential(CredentialCache.DefaultNetworkCredentials, DiscoveryNetworkCredential.DefaultAuthenticationType)); + } + + void StartDiscovery(Uri uri, DiscoveryNetworkCredential credential) { // Abort previous discovery. StopDiscovery(); @@ -532,8 +539,8 @@ namespace ICSharpCode.SharpDevelop.Gui discoveryUri = uri; DiscoverAnyAsync asyncDelegate = new DiscoverAnyAsync(discoveryClientProtocol.DiscoverAny); AsyncCallback callback = new AsyncCallback(DiscoveryCompleted); - discoveryClientProtocol.Credentials = CredentialCache.DefaultCredentials; - IAsyncResult result = asyncDelegate.BeginInvoke(uri.AbsoluteUri, callback, discoveryClientProtocol); + discoveryClientProtocol.Credentials = credential; + IAsyncResult result = asyncDelegate.BeginInvoke(uri.AbsoluteUri, callback, new AsyncDiscoveryState(discoveryClientProtocol, uri, credential)); } /// @@ -542,7 +549,8 @@ namespace ICSharpCode.SharpDevelop.Gui /// void DiscoveryCompleted(IAsyncResult result) { - DiscoveryClientProtocol protocol = (DiscoveryClientProtocol)result.AsyncState; + AsyncDiscoveryState state = (AsyncDiscoveryState)result.AsyncState; + WebServiceDiscoveryClientProtocol protocol = state.Protocol; // Check that we are still waiting for this particular callback. bool wanted = false; @@ -555,10 +563,19 @@ namespace ICSharpCode.SharpDevelop.Gui try { DiscoverAnyAsync asyncDelegate = (DiscoverAnyAsync)((AsyncResult)result).AsyncDelegate; DiscoveryDocument doc = asyncDelegate.EndInvoke(result); + if (!state.Credential.IsDefaultAuthenticationType) { + AddCredential(state.Uri, state.Credential); + } Invoke(handler, new object[] {protocol}); } catch (Exception ex) { - LoggingService.Error("DiscoveryCompleted", ex); - Invoke(handler, new object[] {null}); + if (protocol.IsAuthenticationRequired) { + HttpAuthenticationHeader authHeader = protocol.GetAuthenticationHeader(); + AuthenticationHandler authHandler = new AuthenticationHandler(AuthenticateUser); + Invoke(authHandler, new object[] {state.Uri, authHeader.AuthenticationType}); + } else { + LoggingService.Error("DiscoveryCompleted", ex); + Invoke(handler, new object[] {null}); + } } } } @@ -575,7 +592,7 @@ namespace ICSharpCode.SharpDevelop.Gui } catch (NotImplementedException) {}; discoveryClientProtocol.Dispose(); } - discoveryClientProtocol = new DiscoveryClientProtocol(); + discoveryClientProtocol = new WebServiceDiscoveryClientProtocol(); } } @@ -649,7 +666,10 @@ namespace ICSharpCode.SharpDevelop.Gui MessageService.ShowError(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.AddWebReferenceDialog.InvalidNamespaceError}")); return; } - + + webReference.Name = referenceNameTextBox.Text; + webReference.ProxyNamespace = namespaceTextBox.Text; + DialogResult = DialogResult.OK; Close(); } catch (Exception ex) { @@ -695,5 +715,28 @@ namespace ICSharpCode.SharpDevelop.Gui webServicesTabPage.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.AddWebReferenceDialog.WebServicesTabPageTitle}"); webServicesTabPage.ToolTipText = webServicesTabPage.Text; } + + void AuthenticateUser(Uri uri, string authenticationType) + { + DiscoveryNetworkCredential credential = (DiscoveryNetworkCredential)credentialCache.GetCredential(uri, authenticationType); + if (credential != null) { + StartDiscovery(uri, credential); + } else { + using (UserCredentialsDialog credentialsForm = new UserCredentialsDialog(uri.ToString(), authenticationType)) { + if (DialogResult.OK == credentialsForm.ShowDialog()) { + StartDiscovery(uri, credentialsForm.Credential); + } + } + } + } + + void AddCredential(Uri uri, DiscoveryNetworkCredential credential) + { + NetworkCredential matchedCredential = credentialCache.GetCredential(uri, credential.AuthenticationType); + if (matchedCredential != null) { + credentialCache.Remove(uri, credential.AuthenticationType); + } + credentialCache.Add(uri, credential.AuthenticationType, credential); + } } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AsyncDiscoveryState.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AsyncDiscoveryState.cs new file mode 100644 index 0000000000..3b07f5d935 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/AsyncDiscoveryState.cs @@ -0,0 +1,46 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace ICSharpCode.SharpDevelop.Gui +{ + /// + /// Holds information needed when an async web discovery call has completed. + /// + public class AsyncDiscoveryState + { + WebServiceDiscoveryClientProtocol protocol; + Uri uri; + DiscoveryNetworkCredential credential; + + public WebServiceDiscoveryClientProtocol Protocol { + get { + return protocol; + } + } + + public Uri Uri { + get { + return uri; + } + } + + public DiscoveryNetworkCredential Credential { + get { + return credential; + } + } + + public AsyncDiscoveryState(WebServiceDiscoveryClientProtocol protocol, Uri uri, DiscoveryNetworkCredential credential) + { + this.protocol = protocol; + this.uri = uri; + this.credential = credential; + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/DiscoveryNetworkCredential.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/DiscoveryNetworkCredential.cs new file mode 100644 index 0000000000..7a27da6949 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/DiscoveryNetworkCredential.cs @@ -0,0 +1,43 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Net; + +namespace ICSharpCode.SharpDevelop.Gui +{ + /// + /// Adds an authentication type to the standard NetworkCredential class. + /// + public class DiscoveryNetworkCredential : NetworkCredential + { + public const string DefaultAuthenticationType = "Default"; + + string authenticationType = String.Empty; + + public DiscoveryNetworkCredential(string userName, string password, string domain, string authenticationType) : base(userName, password, domain) + { + this.authenticationType = authenticationType; + } + + public DiscoveryNetworkCredential(NetworkCredential credential, string authenticationType) : this(credential.UserName, credential.Password, credential.Domain, authenticationType) + { + } + + public string AuthenticationType { + get { + return authenticationType; + } + } + + public bool IsDefaultAuthenticationType { + get { + return String.Compare(authenticationType, DefaultAuthenticationType, true) == 0; + } + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/HttpAuthenticationHeader.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/HttpAuthenticationHeader.cs new file mode 100644 index 0000000000..408661a030 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/HttpAuthenticationHeader.cs @@ -0,0 +1,72 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Net; +using System.Text; + +namespace ICSharpCode.SharpDevelop.Gui +{ + /// + /// Represents the WWW-Authenticate HTTP response header. + /// + public class HttpAuthenticationHeader + { + string[] authenticationSchemes; + + public HttpAuthenticationHeader(WebHeaderCollection headers) + { + authenticationSchemes = headers.GetValues("WWW-Authenticate"); + } + + public override string ToString() + { + if (HasAuthenticationSchemes) { + StringBuilder schemes = new StringBuilder(); + foreach (string scheme in authenticationSchemes) { + schemes.Append("WWW-Authenticate: "); + schemes.Append(scheme); + schemes.Append("\r\n"); + } + return schemes.ToString(); + } + return String.Empty; + } + + /// + /// Gets a comma separated list of authentication types. + /// + public string AuthenticationType { + get { + if (HasAuthenticationSchemes) { + int schemesAdded = 0; + StringBuilder authenticationType = new StringBuilder(); + for (int i = 0; i < authenticationSchemes.Length; ++i) { + string scheme = authenticationSchemes[i]; + int index = scheme.IndexOf(' '); + if (index > 0) { + scheme = scheme.Substring(0, index); + } + if (schemesAdded > 0) { + authenticationType.Append(","); + } + authenticationType.Append(scheme); + schemesAdded++; + } + return authenticationType.ToString(); + } + return String.Empty; + } + } + + bool HasAuthenticationSchemes { + get { + return authenticationSchemes != null && authenticationSchemes.Length > 0; + } + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/UserCredentialsDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/UserCredentialsDialog.cs new file mode 100644 index 0000000000..e7ed20e155 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/UserCredentialsDialog.cs @@ -0,0 +1,219 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.Core; +using System; +using System.Drawing; +using System.Net; +using System.Windows.Forms; + +namespace ICSharpCode.SharpDevelop.Gui +{ + public class UserCredentialsDialog : System.Windows.Forms.Form + { + string authenticationType = String.Empty; + + public UserCredentialsDialog(string url, string authenticationType) + { + InitializeComponent(); + this.url.Text = url; + this.authenticationType = authenticationType; + AddStringResources(); + } + + public DiscoveryNetworkCredential Credential { + get { + return new DiscoveryNetworkCredential(userTextBox.Text, passwordTextBox.Text, domainTextBox.Text, authenticationType); + } + } + + #region Windows Forms Designer generated code + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.urlLabel = new System.Windows.Forms.Label(); + this.userNameLabel = new System.Windows.Forms.Label(); + this.passwordLabel = new System.Windows.Forms.Label(); + this.domainLabel = new System.Windows.Forms.Label(); + this.userTextBox = new System.Windows.Forms.TextBox(); + this.passwordTextBox = new System.Windows.Forms.TextBox(); + this.domainTextBox = new System.Windows.Forms.TextBox(); + this.url = new System.Windows.Forms.Label(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.infoLabel = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // urlLabel + // + this.urlLabel.Location = new System.Drawing.Point(10, 59); + this.urlLabel.Name = "urlLabel"; + this.urlLabel.Size = new System.Drawing.Size(91, 23); + this.urlLabel.TabIndex = 0; + this.urlLabel.Text = "Url:"; + this.urlLabel.UseCompatibleTextRendering = true; + // + // userNameLabel + // + this.userNameLabel.Location = new System.Drawing.Point(10, 88); + this.userNameLabel.Name = "userNameLabel"; + this.userNameLabel.Size = new System.Drawing.Size(91, 23); + this.userNameLabel.TabIndex = 1; + this.userNameLabel.Text = "&User name:"; + this.userNameLabel.UseCompatibleTextRendering = true; + // + // passwordLabel + // + this.passwordLabel.Location = new System.Drawing.Point(10, 115); + this.passwordLabel.Name = "passwordLabel"; + this.passwordLabel.Size = new System.Drawing.Size(91, 23); + this.passwordLabel.TabIndex = 3; + this.passwordLabel.Text = "&Password:"; + this.passwordLabel.UseCompatibleTextRendering = true; + // + // domainLabel + // + this.domainLabel.Location = new System.Drawing.Point(10, 142); + this.domainLabel.Name = "domainLabel"; + this.domainLabel.Size = new System.Drawing.Size(91, 23); + this.domainLabel.TabIndex = 5; + this.domainLabel.Text = "&Domain:"; + this.domainLabel.UseCompatibleTextRendering = true; + // + // userTextBox + // + this.userTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.userTextBox.Location = new System.Drawing.Point(93, 85); + this.userTextBox.Name = "userTextBox"; + this.userTextBox.Size = new System.Drawing.Size(187, 21); + this.userTextBox.TabIndex = 2; + // + // passwordTextBox + // + this.passwordTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.passwordTextBox.Location = new System.Drawing.Point(93, 112); + this.passwordTextBox.Name = "passwordTextBox"; + this.passwordTextBox.PasswordChar = '*'; + this.passwordTextBox.Size = new System.Drawing.Size(187, 21); + this.passwordTextBox.TabIndex = 4; + // + // domainTextBox + // + this.domainTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.domainTextBox.Location = new System.Drawing.Point(93, 139); + this.domainTextBox.Name = "domainTextBox"; + this.domainTextBox.Size = new System.Drawing.Size(187, 21); + this.domainTextBox.TabIndex = 6; + // + // url + // + this.url.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.url.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.url.Location = new System.Drawing.Point(93, 57); + this.url.Name = "url"; + this.url.Size = new System.Drawing.Size(187, 21); + this.url.TabIndex = 9; + this.url.UseCompatibleTextRendering = true; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.okButton.Location = new System.Drawing.Point(146, 166); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(64, 26); + this.okButton.TabIndex = 7; + this.okButton.Text = "OK"; + this.okButton.UseCompatibleTextRendering = true; + this.okButton.UseVisualStyleBackColor = true; + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(216, 166); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(64, 26); + this.cancelButton.TabIndex = 8; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseCompatibleTextRendering = true; + this.cancelButton.UseVisualStyleBackColor = true; + // + // infoLabel + // + this.infoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.infoLabel.Location = new System.Drawing.Point(12, 9); + this.infoLabel.Name = "infoLabel"; + this.infoLabel.Size = new System.Drawing.Size(267, 48); + this.infoLabel.TabIndex = 10; + this.infoLabel.Text = "Please supply the credentials to access the specified url."; + this.infoLabel.UseCompatibleTextRendering = true; + // + // UserCredentialsDialog + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(292, 202); + this.Controls.Add(this.infoLabel); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.url); + this.Controls.Add(this.domainTextBox); + this.Controls.Add(this.passwordTextBox); + this.Controls.Add(this.userTextBox); + this.Controls.Add(this.domainLabel); + this.Controls.Add(this.passwordLabel); + this.Controls.Add(this.userNameLabel); + this.Controls.Add(this.urlLabel); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(300, 236); + this.Name = "UserCredentialsDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Discovery Credential"; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Label infoLabel; + private System.Windows.Forms.TextBox passwordTextBox; + private System.Windows.Forms.Label userNameLabel; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Label url; + private System.Windows.Forms.TextBox domainTextBox; + private System.Windows.Forms.TextBox userTextBox; + private System.Windows.Forms.Label domainLabel; + private System.Windows.Forms.Label passwordLabel; + private System.Windows.Forms.Label urlLabel; + #endregion + + void AddStringResources() + { + Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.DialogTitle}"); + infoLabel.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.InformationLabel}"); + urlLabel.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.UrlLabel}"); + userNameLabel.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.UserNameLabel}"); + passwordLabel.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.PasswordLabel}"); + domainLabel.Text = StringParser.Parse("${res:ICSharpCode.SharpDevelop.Gui.Dialogs.UserCredentialsDialog.DomainLabel}"); + cancelButton.Text = StringParser.Parse("${res:Global.CancelButtonText}"); + okButton.Text = StringParser.Parse("${res:Global.OKButtonText}"); + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebReference.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebReference.cs index 6ada4fc3ca..188b3cc25f 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebReference.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebReference.cs @@ -172,6 +172,15 @@ namespace ICSharpCode.SharpDevelop.Gui } } + public string ProxyNamespace { + get { + return proxyNamespace; + } + set { + proxyNamespace = value; + } + } + public List Items { get { if (items == null) { diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebServiceDiscoveryClientProtocol.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebServiceDiscoveryClientProtocol.cs new file mode 100644 index 0000000000..4f671c56b8 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/WebServiceDiscoveryClientProtocol.cs @@ -0,0 +1,50 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Net; +using System.Web.Services.Discovery; + +namespace ICSharpCode.SharpDevelop.Gui +{ + /// + /// Custom DiscoveryClientProtocol that determines whether user authentication + /// is required. + /// + public class WebServiceDiscoveryClientProtocol : DiscoveryClientProtocol + { + HttpWebResponse lastResponseReceived; + + public WebServiceDiscoveryClientProtocol() + { + } + + public HttpAuthenticationHeader GetAuthenticationHeader() + { + if (lastResponseReceived != null) { + return new HttpAuthenticationHeader(lastResponseReceived.Headers); + } + return null; + } + + public bool IsAuthenticationRequired { + get { + if (lastResponseReceived != null) { + return lastResponseReceived.StatusCode == HttpStatusCode.Unauthorized; + } + return false; + } + } + + protected override WebResponse GetWebResponse(WebRequest request) + { + lastResponseReceived = null; + lastResponseReceived = base.GetWebResponse(request) as HttpWebResponse; + return lastResponseReceived; + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/ReferenceFolderNodeCommands.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/ReferenceFolderNodeCommands.cs index f408fb4400..b263268e1a 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/ReferenceFolderNodeCommands.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/ReferenceFolderNodeCommands.cs @@ -53,37 +53,64 @@ namespace ICSharpCode.SharpDevelop.Project.Commands WebReferenceUrl url = (WebReferenceUrl)node.ProjectItem; try { // Discover web services at url. - DiscoveryClientProtocol protocol = new DiscoveryClientProtocol(); - protocol.DiscoverAny(url.UpdateFromURL); - protocol.ResolveOneLevel(); - - // Save web services. - WebReference webReference = new WebReference(url.Project, url.UpdateFromURL, node.Text, url.Project.RootNamespace, protocol); - webReference.Save(); - - // Update project. - WebReferenceChanges changes = webReference.GetChanges(url.Project); - if (changes.Changed) { - foreach (ProjectItem itemRemoved in changes.ItemsRemoved) { - ProjectService.RemoveProjectItem(url.Project, itemRemoved); - FileService.RemoveFile(itemRemoved.FileName, false); - } - foreach (ProjectItem newItem in changes.NewItems) { - ProjectService.AddProjectItem(url.Project, newItem); - FileNode fileNode = new FileNode(newItem.FileName, FileNodeStatus.InProject); - fileNode.AddTo(node); + DiscoveryClientProtocol protocol = DiscoverWebServices(url.UpdateFromURL); + if (protocol != null) { + // Save web services. + WebReference webReference = new WebReference(url.Project, url.UpdateFromURL, node.Text, url.Project.RootNamespace, protocol); + webReference.Save(); + + // Update project. + WebReferenceChanges changes = webReference.GetChanges(url.Project); + if (changes.Changed) { + foreach (ProjectItem itemRemoved in changes.ItemsRemoved) { + ProjectService.RemoveProjectItem(url.Project, itemRemoved); + FileService.RemoveFile(itemRemoved.FileName, false); + } + foreach (ProjectItem newItem in changes.NewItems) { + ProjectService.AddProjectItem(url.Project, newItem); + FileNode fileNode = new FileNode(newItem.FileName, FileNodeStatus.InProject); + fileNode.AddTo(node); + } + ProjectBrowserPad.Instance.ProjectBrowserControl.TreeView.Sort(); + url.Project.Save(); } - ProjectBrowserPad.Instance.ProjectBrowserControl.TreeView.Sort(); - url.Project.Save(); + + // Update code completion. + ParserService.ParseFile(webReference.WebProxyFileName); } - - // Update code completion. - ParserService.ParseFile(webReference.WebProxyFileName); } catch (WebException ex) { MessageService.ShowError(ex, String.Format(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Commands.ProjectBrowser.RefreshWebReference.ReadServiceDescriptionError}"), url.UpdateFromURL)); } } } + + DiscoveryClientProtocol DiscoverWebServices(string url) + { + WebServiceDiscoveryClientProtocol protocol = new WebServiceDiscoveryClientProtocol(); + NetworkCredential credential = CredentialCache.DefaultNetworkCredentials; + bool retry = true; + while (retry) { + try { + protocol.Credentials = credential; + protocol.DiscoverAny(url); + protocol.ResolveOneLevel(); + return protocol; + } catch (WebException ex) { + if (protocol.IsAuthenticationRequired) { + using (UserCredentialsDialog dialog = new UserCredentialsDialog(url, protocol.GetAuthenticationHeader().AuthenticationType)) { + if (dialog.ShowDialog() == DialogResult.OK) { + credential = dialog.Credential; + } else { + retry = false; + } + } + } else { + throw ex; + } + } + } + return null; + } } public class AddWebReferenceToProject : AbstractMenuCommand diff --git a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj index 9246bb2d6e..647e94568d 100644 --- a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj +++ b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj @@ -66,6 +66,7 @@ + diff --git a/src/Main/Base/Test/WebReferences/HttpAuthenticationHeaderTests.cs b/src/Main/Base/Test/WebReferences/HttpAuthenticationHeaderTests.cs new file mode 100644 index 0000000000..dccea3762f --- /dev/null +++ b/src/Main/Base/Test/WebReferences/HttpAuthenticationHeaderTests.cs @@ -0,0 +1,81 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.SharpDevelop.Gui; +using NUnit.Framework; +using System; +using System.Net; + +namespace ICSharpCode.SharpDevelop.Tests.WebReferences +{ + [TestFixture] + public class HttpAuthenticationHeaderTests + { + [Test] + public void IsBasicAuthentication() + { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Basic realm='localhost'"); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual("Basic", authenticationHeader.AuthenticationType); + } + + [Test] + public void NoHeadersAdded() + { + WebHeaderCollection headers = new WebHeaderCollection(); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual(String.Empty, authenticationHeader.AuthenticationType); + } + + [Test] + public void NonStandardAuthenticationHeaderAdded() + { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Foo"); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual("Foo", authenticationHeader.AuthenticationType); + } + + [Test] + public void IsWindowsAuthentication() + { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Negotiate"); + headers.Add(HttpResponseHeader.WwwAuthenticate, "NTLM"); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual("Negotiate,NTLM", authenticationHeader.AuthenticationType); + } + + [Test] + public void ManyAuthenticationSchemesAdded() + { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Negotiate"); + headers.Add(HttpResponseHeader.WwwAuthenticate, "NTLM"); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Basic realm='test'"); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual("Negotiate,NTLM,Basic", authenticationHeader.AuthenticationType); + } + + [Test] + public void DigestAuthenticationSchemeAdded() + { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.WwwAuthenticate, "Digest realm='test'"); + headers.Add(HttpResponseHeader.WwwAuthenticate, "NTLM"); + HttpAuthenticationHeader authenticationHeader = new HttpAuthenticationHeader(headers); + + Assert.AreEqual("Digest,NTLM", authenticationHeader.AuthenticationType); + } + } +} diff --git a/src/Main/StartUp/Project/Resources/StringResources.resources b/src/Main/StartUp/Project/Resources/StringResources.resources index 7ebfa3cad0..ec800d804b 100644 Binary files a/src/Main/StartUp/Project/Resources/StringResources.resources and b/src/Main/StartUp/Project/Resources/StringResources.resources differ