I'm using code from a demo program using Devart's MyDac component using Delphi 2009 to connect to a remote database using SSL.
I have made and verified the certificates and keys and set the connection parameters in MyDAC to use them eg
MyConnection.protocol := 'mpSSL';
MyConnection.SSLOptions.CACert := 'C:\ca-cert.pem';
MyConnection.SSLOptions.Cert := 'C:\client-cert.pem';
MyConnection.SSLOptions.Key := 'C:\client-key.pem';
MyConnection.SSLOptions.Chipherlist := 'All';
When I tell MyConnection to connect (after setting the user name / password etc) it connects to the database with no problems.
However as a test I deliberately put in an invalid key name of 'C:\XXXclient-key.pem and it still connected OK so maybe it wasn't using SSL at all.
So my question is:
How can I use Delphi to detect if a connection is really using SSL or not?
I think I'll close this question myself as it seem far more complex than I thought it was and I need much more information before this question makes sense. It appears that the sql statement;
SHOW STATUS LIKE 'Ssl_cipher'
can help as its value will be empty if its not using ssl or will contain an value if it is.
The touble was the Mysql server I was using (ISP Nativespace) did not even have a variable name called Ssl_cipher so it looks like it doesn't support ssl anyway. Trying the same thing using another ISP I did see the variable name but it had no value, showing that was also not using ssl even I though it could do it.
It now appears that there is much more that needs doing before a ssl connection can be set up. Creating a new user on the db that only ever uses ssl, setting up permissions for them, running code on the server etc.
Not at all as simple as Devart's web page on securebridge leads one to believe!
"It is enough to place several components on the form and specify the
server address and the user login information to establish a secure
connection."
Err... not quite!
Related
As far as I can tell, this is the process to create an HTTPS request using Indy:
Create a TIdHTTP object
Use a TIdSSLIOHandlerSocketOpenSSL object as its IOHandler
Set up this TIdSSLIOHandlerSocketOpenSSL object's SSLOptions and SSLContext to get the proper behaviour before starting the request
However, Indy's documentation is quite minimal as for the possible values for these two SSLOptions and SSLContext objects, even to achieve what seems to me to be pretty standard behaviour.
In particular, I would like to know how to do the following:
Validate the certificate against either (depending on what is more straightforward) :
The local system's trust store
A list of root certificates provided with the application
Drop the connection if the certificate has not been correctly validated.
It seems to me to be the most basic behaviour for an application that needs to call base once in a while: you want to make sure you're really speaking to your own back-end, but still leave you the possibility of changing CAs if you ever need it.
I guess the SSLContext's field rootCertFile should be used, however:
Nowhere is it said in what format the rootCertFile should be provided (pem? der? pkcs something?)
It is in no way obvious how one should process to configure several alternatives root certificates.
Can someone provide the method, and if possible, some sample code on how this behaviour can be achieved?
Our Delphi application is trying to connect to our website via IdFTP on a client machine using a proxy server, and I always get a 'read timed out' message. I don't know how to fix it.
My code:
IdFTP1.Host :=Website_address;
IdFTP1.Username :=Website_user;
IdFTP1.Password :=Website_password;
IdFTP1.TransferType:=ftBinary;
IdFTP1.ProxySettings.ProxyType:=fpcmNone;
IdFTP1.ProxySettings.Host :=Proxy_server;
IdFTP1.ProxySettings.Port :=Proxy_port;
IdFTP1.ProxySettings.Username :=Proxy_username;
IdFTP1.ProxySettings.Password :=Proxy_password;
IdFTP1.Connect;
...which returns a 'read timed out' exception.
Having looked on the web for possible solutions, I have tried various combinations of the following with no joy (although there might be a combination that might work, I just don't really know what I'm doing):
IdFTP1.IOHandler :=TIdSSLIOHandlerSocketOpenSSL.Create
(IdFTP1);
IdFTP1.UseTLS :=utUseExplicitTLS;
IdFTP1.NATKeepAlive.UseKeepAlive:=True;
IdFTP1.NATKeepAlive.IdleTimeMS :=100000;
IdFTP1.DataPortProtection :=ftpdpsPrivate;
The frustrating thing is I can't test it on my machine, I have to compile a new version of the application, copy it to their machine, and then see if it works.
There is nothing complex about the installation on the client side as far as I can tell. They have given me the proxy host address, and the proxy username and password are blank.
Other bits of the application connect to the same website via HTTP and the proxy server, and this works perfectly. So my logic is that it can't be firewalls or anything like that.
IdHTTP1.HandleRedirects :=True;
IdHTTP1.ProxyParams.BasicAuthentication:=True;
IdHTTP1.ProxyParams.ProxyServer :=Proxy_server;
IdHTTP1.ProxyParams.ProxyPort :=Proxy_port;
IdHTTP1.ProxyParams.ProxyUsername :=Proxy_username;
IdHTTP1.ProxyParams.ProxyPassword :=Proxy_password;
I am using Delphi XE8.
They have created a virtual server for our testing, it runs Windows 7 64 bit.
Update
Remy, is this the right idea? One problem I am having is the TIdConnectThroughHttpProxy component, what must be in the uses clause for this? Delphi is not recognizing it.
var
TempIO : TIdIOHandlerStack;
TempProxy : TIdConnectThroughHttpProxy;
......
TempIO :=TIdIOHandlerStack.Create;
TempProxy :=TIdConnectThroughHttpProxy.Create;
TempProxy.Host :=Proxy_host;
TempIO.TransparentProxy:=TempProxy;
IdFTP1.IOHandler :=TempIO;
IdFTP1.Connect;
Update 2
A point of clarity: the HTTP request that is successfully reaching the web server through the proxy server goes to a different web address than the FTP request. In other words, they both go through the same proxy server, but the destination addresses are different. Just in case this is of use.
I have now tried using Fiddler to find the problem, not sure if this is a great idea? My understanding is is that Fiddler acts as a proxy server, so I thought I would see if I encountered the same problem. Sure enough, can't connect.
To be clear about my steps:
Run Fiddler, and check the box that says 'Capture FTP requests'.
Update my IdHTTP component:
IdHTTP1.ProxyParams.ProxyServer:='127.0.0.1';
IdHTTP1.ProxyParams.ProxyPort :=Fiddler port;
Update my IdFTP component:
IdFTP1.ProxySettings.Host:='127.0.0.1';
IdFTP1.ProxySettings.Port:=Fiddler port;
So now I have removed the client setup completely, I am mirroring the problem from my local machine using Fiddler as far as I can tell. If I don't use Fiddler, everything works great. If I use Fiddler as described above, then the HTTP request works correctly, but the FTP request can't connect.
Any ideas as to what I can do to try and solve this? I'm sure it is something really stupid that I'm doing wrong.
IdFTP1.ProxySettings.ProxyType:=fpcmNone
This tells TIdFTP not to communicate with an FTP-aware proxy. If you want to use the TIdFTP.ProxySettings properties, you need to set the ProxyType so TIdFTP.Connect() will connect to the ProxySettings.Host and TIdFTP.Login() will know what kind of commands it needs to send to login to the proxy and request a connection to the next host.
Note that TIdFTP.ProxySettings only works with FTP proxies. If you need to connect to a different type of proxy, before you call TIdFTP.Connect() you will have to assign a TIdIOHandler-derived component to the TIdFTP.IOHandler property, and then assign a TIdCustomTransparentProxy-derived component to the TIdIOHandler.TransparentProxy property. To connect to an HTTP proxy (which it sounds like you need, since that is what TIdHTTP.ProxyParams works with), use TIdConnectThroughHttpProxy. To connect to a SOCKS proxy, use TIdSocksInfo.
This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Delphi Client-Server Application using Firebird 2.5 embedded connection error
I have got a lengthy question to ask. First of all Im still very new when it comes to Delphi programming and my experience has beem mostly developing small single user database applications using ADO and an Access database.
I need to take the transition now to a client server application and this is where the problem starts. I decided to use Firebird 2.5 embeded as my database, as it is open source, and it is can be used with the interbase components in Delphi and that multiple clients can access the database simultanously. So I followed the interbase tutorial in Delphi. I managed to connect the client to the server and see the data in the example (While both are running on my pc), but when i tried to move the client to another pc, keeping the server on mine and running it to see if I can connect to the server it gave me the following error.
Exception EIdSocketError in module clientDemo.exe at 0029DCAC. Socket Error # 10061 Connection refused.
I understand that this might be because the host is defined as localhost in the client. But here is my first question. In the TSQLConncetion you can set die hostname under Driver->Hostname. The thing I want to know is how do you do this at run time, as I cannot get the property when I try and make an edit box to allow the user to enter the value and then set it via code like for example:
SQLConncetion1.Driver.Hostname := edtHost.text;
The thing is there is not such property to set, so how do you set the hostname at run time?
Im using Delphi XE2
There is still a lot of questions to come especially when it comes to deployment, but I will take this piece by piece and I appreciate the advice.
That means that the server: port your program is trying to connect to
is refusing your connection. Could be a firewall related issue on
either your server or your own machine.
Try using telent to connect to the server. If that succeeds you know it a problem with your machine's configuration.
Check these links for more information :
How TO Fix Socket Error 10061 Connection Refused Easily
Problem Loading (python blocked by firewall)
I have got a lengthy question to ask. First of all Im still very new when it comes to Delphi programming and my experience has beem mostly developing small single user database applications using ADO and an Access database.
I need to take the transition now to a client server application and this is where the problem starts. I decided to use Firebird 2.5 embeded as my database, as it is open source, and it is can be used with the interbase components in Delphi and that multiple clients can access the database simultanously. So I followed the interbase tutorial in Delphi. I managed to connect the client to the server and see the data in the example (While both are running on my pc), but when i tried to move the client to another pc, keeping the server on mine and running it to see if I can connect to the server it gave me the following error.
Exception EIdSocketError in module clientDemo.exe at 0029DCAC. Socket Error # 10061 Connection refused.
I understand that this might be because the host is defined as localhost in the client. But here is my first question. In the TSQLConncetion you can set die hostname under Driver->Hostname. The thing I want to know is how do you do this at run time, as I cannot get the property when I try and make an edit box to allow the user to enter the value and then set it via code like for example:
SQLConncetion1.Driver.Hostname := edtHost.text;
This cannot be done this way and the only way I see you can set the hostname is with the object inspector, but that is not available at runtime and I need to set the hostname on the client when the program is running the first time, so how do you set the hostname/IP address at runtime?
Im using Delphi XE2
There is still a lot of questions to come especially when it comes to deployment, but I will take this piece by piece and I appreciate the advice.
Embedded can't be used by multiple users at the same time (even if it's two applications on the same machine). See here for information on the differences between the three versions. There's also information in another SO question that might help.
As far as specifying a server at runtime, this may help:
procedure TForm1.Button1Click(Sender: TObject);
var
Conn: TSQLConnection;
begin
Conn := TSQLConnection.Create(Self);
try
Conn.DriverName := 'FirebirdConnection';
Conn.Params.Add('User_Name=SYSDBA');
Conn.Params.Add('Password=masterkey');
// Replace the dbname in the next line with the
// value obtained at runtime, as in
// Conn.Params.Add('Database=' + YourNewPathAndDBName);
Conn.Params.Add('Database=C:\FireBirdData\YourDB.fdb');
Conn.Open;
if Conn.Connected then
ShowMessage('Connection successfully made to DB');
finally
Conn.Free;
end;
end;
We use stateful DataSnap servers for some business logic tasks and also to provide clientdataset data.
If we have to update the server to modify a business rule, we copy the new version into a new empty folder and register it (depending on the Delphi version, just by launching or by running the TRegSvr utility).
We can do this even while the old server instance is running. However, after registering the new version, all new client connections will still use the currently running (old) server instance. All clients have to disconnect first, then the new server will be used for the next clients.
Is there a way to direct all new client connections to the new server, immediately after registering?
(I know that new or changed method signatures will also require a change and restart of the clients but this question is about internal modifications which do not affect the interface)
We are using Socket connections, and all clients share the same server application (only one application window is open). In the early days we have used a different configuration of the remote datamodule which resulted in one app window per client. Maybe this could be a solution? (because every new client will launch the currently registered executable)
Update: does Delphi XE offer some support for 'hot deployment' (of updated servers)? We use Delphi 2009 at the moment but would upgrade to XE if it offers easier implementation of 'hot deployment'.
you could separate your appserver into 2 new servers, one being a simple proxy object redirecting all methods (and optionally containing state info if any) to the second one actually implementing your business logic. you also need to implement "silent reconnect" feature within your proxy server in order not to disturb connected clients if you decide to replace business appserver any time you want. never did such design myself before but hope the idea is clear
Have you tried renaming the current server and placing the new in the same location with the correct name (versus changing the registry location). I have done this for COM libraries before with success. I am not sure if it would apply to remote launch rules through as it may look for an existing instance to attach to instead of a completely fresh server.
It may be a bit hackish but you would have the client call a method on the server indicating that a newer version is available. This would allow it to perform any necessary cleanup so it doesn't end up talking to both the existing server instance and new server instance at the same time.
There is probably not a simple answer to this question, and I suspect that you will have to modify the client. The simplest solution I can think of is to have a flag (a property or an out parameter on some commonly called method) on the server that the client checks periodically that tells the client to disconnect and reconnect (called something like ImBeingRetired).
It's also possible to write callbacks under certain circumstances for datasnap (although I've never done this). This would allow the server to inform the client that it should restart or reconnect.
The last option I can think of (that hasn't already been mentioned) would be to make the client/server stateless, so that every time the client wants something it connects, gets what it wants then disconnects.
Unfortunately none of these options are the answer you want to your question, but might give you some ideas.
(optional) set up vmware vSphere, ESX, or find a hosting service that already has one.
Store the session variables in db.
Prepare 2 web boxes with 2 distinct IP address and deploy your stuff.
Set up DNS, firewall, load balancer, or BSD vm so name "example.com" resolves to web box 1.
Deploy new version to web box 2.
Switch over to web box 2 using whatever routing method you chose.
Deploy new version to web box 1 if things look ok.
Using DNS is probably easiest, but it takes time for the mapping to propagate to the client (if the client is outside your LAN) and also two clients may see different results. Some firewalls have IP address mapping feature that you can map public IP address and internal IP address. The ideal way is to use load balancer and configure it to 50:50 and change it to 100:0 when you want to do upgrade, but it costs money. A cheaper alternative is to run software load balancer on BSD vm, but it probably requires some work.
Edit: What I meant to say is session variables, not session. You said the server is stateful. If it contains some business logic that uses session variable, it needs to get stored externally to be preserved across reconnection during switch over. Actual DataSnap session will be lost, so when you shutdown web box 1 during upgrade, the client will get "Session {some-uuid} is not found" error by web box 1, and it will reconnect to web box 2.
Also you could use 3 IP addresses (1 public and 2 private) so the client always sees 1 address , which is better method.
I have done something similar by having a specific table which held my "data version". Each time I would update the server or change a system wide global setting, I would increment this field. When a client starts it always checks this value, and will check again before any transactions/queries. If the value was ever different from when I first started, then I needed to go through my re-initialization logic, which could easily include a re-login to an updated server.
I was using IIS to publish my app servers, so the data that would change would be the path to the app server. I kept the old ones available, to respond to any existing transactions that were in play. Eventually these would be removed once I knew there were no more client connections to that version.
You could easily handle knowing what versions to keep around if you log what server the client last connected too (and therefore would know about).
For newer versions (Delphi 2010 and up), there is an interesting solution
for systems using the HTTP transport:
Implementing Failover and Load Balancing in DataSnap 2010 by Andreano Lanusse
and a related question for the TCP/IP transport:
How to direct DataSnap client connections to various DS Servers?