Retrieving data from a site through a secured proxy - vba

My client will access my company's site to retrieve data information, using a sub I am working on. This has to be done using a secured proxy, since his company blocks access to some sites. I can't test my sub on his computer and obviously he cannot send the proxy information (ie.:Username, passoword, ip, port...)
Sub login_sub()
url = "http://localhost/php004/loginExcelAddin.php?username=" + username + "&password=" + password
Dim httpObject As Object
Dim response As String
Set httpObject = CreateObject("WinHttp.WinHttpRequest.5.1")
httpObject.Open "GET", url, False
httpObject.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, proxyIP + ":" + proxyPortNumber
httpObject.send
response = httpObject.responseText
On Error GoTo errorHandler
If response = True Then
loggedIn = True
MsgBox "You are logged in"
End If
Application.Calculate
Exit Sub
errorHandler:
MsgBox "Login has failed"
End Sub
(Username, password, proxyPortNumber, proxyIP are public variables filled in a form)
I am struggled with this issue for a while. Anyone could tell me if I am going to the right direction, can I send this code for the client?
Thanks

Ah, I've been through this before many times in my career. From a test strategy perspective (rather than a review of your code above), there are several possible combinations of ways to test all this out:
The client's IT department should be able to provide you with specifications on how their proxy expects client identification information to be included in the outbound request. Some proxies may use alternative authentication information data in the request headers; you need to know exactly how the client's proxy requires the authentication data to be passed (this can get troublesome on Enterprise proxies that may use Active Directory/LDAP as intermediaries).
The ideal first stage of testing is to setup inside your own company a test authenticating proxy in as close as possible the same make, version, and configuration as the client's. Put your Excel code onto a laptop, and connect the laptop to the "outside" of this test proxy. This will allow you to test the code to work out bugs with accessing a similar proxy under your control.
Of course, its quite possible that the client's proxy may not behave quite like your test proxy, so even after doing step 2, there may still be problems once you give it to the client. If the client is allowed to use window sharing services like WebEx, you could then set up a WebEx session with the client, and have them share their screen with you while they are using your code for the first time. If it fails, you can talk them though a debugging session with Excel's debugger while you are watching the debugging results.
3a. If the client's IT Dept will allow a more comprehensive sharing tool that allows YOU to remotely control the client's desktop (while they are watching) that would even be more ideal. But if the client's IT Dept is already doing outbound proxying, they are likely too paranoid to allow this.
If a WebEx-like session is not allowed, then you could add diagnostic outputs into a log file which they could then send you, or verbally tell you in a telecon. This is not an optimal way to accomplish the debugging.
4a. Again if WebEx-like method is not allowed, but if the client has an Excel expert and an IT expert, you can get them to do the testing with you on a telecon. Again not optimal but is better than 3 because you are not talking with a clueless client.
Finally and worst-case, you may have to travel to the client's site to do final testing on their own computers (under of course the supervision of the client).

Related

Is there a simple way to use VB.NET to read a SharePoint Online file without logging in?

I inherited a program written in VB.NET. I want to host the installer and documentation for the program in a SharePoint Online library. The SPO library allows View/Read-only access to "Everyone except external users" but it does not allow anonymous access. I want the program to check the SPO library for an updated version when it launches.
I envisioned a simple function like this:
Private Function getVersion() As String
Using client As New WebClient
getVersion = client.DownloadString("https://companyname.sharepoint.com/site/library/version.txt")
End Using
End Function
where version.txt contains nothing but the current version number.
However, this function throws an IOException stating that the connection was forcibly closed by the remote host. I think this is because the SPO site requires authentication.
I don't want to add a user login step solely for this one thing. This probably means an SPO site that requires authentication is not the ideal place for my version.txt file to reside, but I'm also trying to avoid solutions that require me to jump through hoops and involve others to get it to work. I'm the only developer for this program, so I'd like to be able to publish an update without having to wait for someone else to do something (like update a web server that I don't have access to).
Suggestions for a simple technique to achieve my goal?
In your Using block, before the line with DownloadString, set the Credentials of your WebClient:
Private Function getVersion() As String
Using client As New WebClient
client.Credentials = CredentialCache.DefaultCredentials
getVersion = client.DownloadString("https://companyname.sharepoint.com/site/library/version.txt")
End Using
End Function
The DefaultCredentials will be the credentials of the currently logged in Windows user.
See the docs on System.Net.WebClient.

Communication between third-User and my Server

I am looking for the best way to setup communication between user who uses my application and my own server.
The thing is that I am creating application with licensing and I have to receive information by third-User when he connected and IP addresses he connected from.
But, I don't know should I use one more connection string and send those information to my MS SQL Server I have in my company from his workplace or I should upload .txt files on my web server? What is the best way to make this communication possible?
While the requirements are a bit vague, based on what seem to need I would approach this with a web service. This WS would provide the means to communicate with your SQL server without exposing SQL itself to the internet.
Your web service could, for example, have a call which accepts the following information:
Product being requested
Information needed from the local client (machine name, etc.)
Existing authentication ticket previously issued (if required)
Your method could then take this information, process it in SQL, and then return whether or not a license is available along with an authentication ticket (if needed).
On the client side, if your application only needs to hit this service once then you can just call it on connection/load. Otherwise if you need to periodically hit the licensing WS you could use a Timer.
Dim licenseCheck As New Timer
licenseCheck.Interval = 60000 ' Check every minute.
AddHandler licenseCheck.Tick AddressOf CheckLicense
Private Sub CheckLicense(sender As Object, e As EventArgs)
' Call license web service and act accordingly.
End Sub

Socket.io Rooms in a Hostile Network Environment?

I have a very frustrating problem with a client's network environment, and I'm hoping someone can lend a hand in helping me figure this out...
They have an app that for now is written entirely inside of VBA for Excel. (No laughing.)
Part of my helping them improve their product and user experience involved converting their UI from VBA form elements to a single WebBrowser element that houses a rich web app which communicates between Excel and their servers. It does this primarily via a socket.io server/connection.
When the user logs in, a connection is made to a room on the socket server.
Initial "owner" called:
socket.on('create', function (roomName, userName) {
socket.username = userName;
socket.join(roomName);
});
Followup "participant" called:
socket.on('adduser', function (userName, roomName){
socket.username = userName;
socket.join(roomName);
servletparam = roomName;
var request = require('request');
request(bserURL + servletparam, function (error, response, body) {
io.sockets.to(roomName).emit('messages', body);
});
servletparam = roomName + '|' + userName;
request( baseURL + servletparam, function (error, response, body) {
io.sockets.to(roomName).emit('participantList', body);
});
});
This all worked beautifully well until we got to the point where their VBA code would lock everything up causing the socket connection to get lost. When the client surfaces form it's forced VBA induced pause (that lasts anywhere from 20 seconds to 3 minutes), I try to join the room again by passing an onclick to an HTML element that triggers a script to rejoin. Oddly, that doesn't work. However if I wait a few seconds and click the object by hand, it does rejoin the room. Yes, the click is getting received from the Excel file... we see the message to the socket server, but it doesn't allow that call to rejoin the room.
Here's what makes this really hard to debug. There's no ability to see a console in VBA's WebBrowser object, so I use weinre as a remote debugger, but a) it seems to not output logs and errors to the console unless I'm triggering them to happen in the console, and b) it loses its connection when socket.io does, and I'm dead in the water.
Now, for completeness, if I remove the .join() calls and the .to() calls, it all works like we'd expect it to minus all messages being written into a big non-private room. So it's an issue with rejoining rooms.
As a long-time user of StackOverflow, I know that a long question with very little code is frowned upon, but there is absolutely nothing special about this setup (which is likely part of the problem). It's just simple emits and broadcasts (from the client). I'm happy to fill anything in based on followup questions.
To anyone that might run across this in the future...
The answer is to manage your room reconnection on the server side of things. If your client can't make reliable connections, or is getting disconnected a lot, the trick it to keep track of the rooms on the server side and join them when they do a connect.
The other piece of this that was a stumper was that the chat server and the web UI weren't on the same domain, so I couldn't share cookies to know who was connecting. In their case there wasn't a need to have them hosted in two different places, so I merged them, had Express serve the UI, and then when the client surfaced after a forced disconnect, I'd look at their user ID cookie, match them to the rooms they were in that I kept track of on the server, and rejoined them.

Terrible Performance with WCF and certificates (mutual authentication)

Guys / Gals we are having terrible performance with our website that uses WCF as the application later. We are using message level security and certificates (mutual authentication). We are caching the channel factory in the application object:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
Dim loChannelFactor As New ChannelFactory(Of OurReference.IWCFChannel)("ClientEndpoint")
loChannelFactor.Open()
Application.Add("ChannelFactory", loChannelFactor)
End Sub
In every page that we need data we do the following:
Dim Proxy = DirectCast(voWebApp("ChannelFactory"), ChannelFactory(Of OurInfoReference.IOurInfoChannel)).CreateChannel
Proxy.DataCall()
If roWCFService IsNot Nothing Then
CType(roWCFService, ICommunicationObject).Close()
roWCFService = Nothing
End If
Also i have set establishsecuritycontext = true.
We are not wanting to cache the proxy because of having to mess with a faulted proxy state. As far as i know caching the channel stack should be enough anyways. When i turn on tracking i'm seeing a bunch of SCT commands instead of just for the first call like i would expect. Does anyone know whats going on. Are we caching the channel factory incorrectly?
thanks,
Ncage
Looks like you could solve it using a certificate from a ceritificate authority:
"MakeCert is a tool provided by Microsoft to create test certificates that can be used during the development of a product (For developing and testing purposes only). These certificates have also performance problems, certain cryptographic operations may perform slowly when they are used. Certificates issued from a true Certificate Authority do not have this problem, and it is a know issue."
http://weblogs.asp.net/cibrax/archive/2006/08/08/Creating-X509-Certificates-for-WSE-or-WCF.aspx
Edit: May be the extra activity is due to initial handshake when creating of a session. WCF default is per call, that is a new session is created for each call. You could try marking your contract with:
[ServiceContract(Session = true)]
That may maintain the session and avoid the initial handshake.
I remember a similar issue however it was a good 18 months ago. I found this whilst having a quick look for how i resolved the issue. It may help, I will edit my response when I find what I was looking for!
The additional SCT/RST calls are establishing the security context. If you recreate the proxy on each call, a security context is unneccesary overhead. Turn it off.
The way you use the factory is fine. However, your error handling and closing of the proxy is not. Make sure that you close or abort the proxy in any case. Check msdn for the recommended pattern.
Also can you provide some figures about how bad performance is?

System.DirectoryServices pegs my processor when multi-threaded - can I lower the burden?

My application takes the currently logged-in user and uses an a DirectoryServices.DirectorySearcher to pull a few additional detail about them (some properties we have stored in a few custom AD fields, as well as their email address). This works great, though I've always though it was a little slow - my single-threaded code could only make about 2-3 requests/second to AD.
The real problem came when I moved this code to a web server. With multiple simultaneous users, the number of requests/second jumps greatly, and the LSASS.EXE process pegs on my server. I've checked the domain controllers, and they're just fine - the bottleneck is clearly on the application side. I suspect that what's slowing my down is the NTLM/Kerberos challenge/response, and the number of simultaneous requests pegs even the multi-core processor.
Our network policy doesn't allow anonymous reads from AD, so that choice is out. Also, I've tried every member of "AuthenticationTypes" (in the example, I'm using .FastBind), but they all seem to have about the same throughput rate with the same load on the processor.
Does anybody have an idea for how I might work around this restriction and lower my demands on the processor?
Here is the code I'm using - pretty straightforward:
Dim sPath As String = "LDAP://" & stringUserDN
Dim entry As New DirectoryEntry(sPath)
entry.AuthenticationType = AuthenticationTypes.FastBind
For Each stringADNumber As String In entry.Properties(_ADPROP_EMPLOYEENUMBER)
'return first item
Return Convert.ToInt32(stringADNumber)
Next
Return String.Empty
I don't have a ton of experience with looking up items in AD. However, one suggestion is that you might want to check in the HttpContext for the request. There is some basic information for the current user that is making the request, such as groups, SID, and token information. I don't beleive there is an email address field by default, but you might be able to use the User.Name property + "#your.domain" to build an email address.
In order for this data to show up, you will need IIS to be requiring authentication for requests. Anonymous users will not have this data populated. The accessor for this data is HttpContext.Current.Request.LogonUserIdentity or, alternatively, within the code behind for your page, you can call this.Request.LogonUserIdentity for short.
Hopefully this helps. Good luck.