Authenticate against MongoDB using DelphiMongoDB from Grijjy - mongodb

I am using DelphiMongoDB from Grijjy (DelphiMongoDB) which is working pretty cool so far. But I can't find any functions to authenticate against a MongoDB. Did anybody getting this work or figured out how to do it?
Thanks and best regards

Update: The most up to date version of the Grijjy driver now supports TLS, X.509 client certificate authentication, SCRAM SHA-1 and SHA-256 authentication. We have also tested it against MongoDB Atlas instance at Azure.
Here is a simple example of how to use the authentication.
var
Settings: TgoMongoClientSettings;
Client: IgoMongoClient;
Database: IgoMongoDatabase;
Collection: IgoMongoCollection;
Doc: TgoBsonDocument;
begin
Settings := TgoMongoClientSettings.Create;
Settings.Secure := True;
Settings.AuthMechanism := TgoMongoAuthMechanism.SCRAM_SHA_1;
Settings.AuthDatabase := 'admin';
Settings.Username := 'username';
Settings.Password := 'password';
//Settings.QueryFlags := [TgoMongoQueryFlag.SlaveOk];
Client := TgoMongoClient.Create('my.mongodb.server.com', 27017, Settings);
Database := Client.GetDatabase('mydatabase');
Collection := Database.GetCollection('mycollection');
for Doc in Collection.Find() do
Writeln(Doc.ToJson(TgoJsonWriterSettings.Pretty));
end;
Legacy: Yes, the published Grijjy driver does not support authentication, but we have tested it internally and may add this ability in the near future to Github. You are also welcome to make a pull request if you want to adapt the following changes:
MongoDB currently supports 2 types of authentication, SCRAM and x.509 Certificate Authentication. Internally we have tested the x.509 Certificate Authentication, but the current driver on Github does not reflect this ability. We have not experimented with SCRAM yet.
To make it work with the MongoDB driver we published on Github, you may have to make a couple of changes.
You need to create a self-signed CA and certificate for your MongoDB server.
You need to configure your MongoDB server to use certs.
You need to create a self-signed certificate for your MongoDB client or clients. You can use the same cert for all clients.
You need to enable SSL/TLS connections and use your client certificate with the MongoDB driver.
1 To create all the certificates, you need an existing CA or create a self-signed CA. You can use the openssl.exe binary to do most of this:
Create root certificate authority (ca.pem and privkey.pem):
openssl req -out ca.pem -new -x509 -days 3650 -subj "/C=US/ST=California/O=Company/CN=root/emailAddress=root#domain.com"
To create a self-signed certificate for your MongoDB server (server.pem):
openssl genrsa -out server.key 2048
openssl req -key server.key -new -out server.req -subj "/C=US/ST=California/O=Company/CN=db.myserver.com/emailAddress=user#domain.com"
openssl x509 -req -in server.req -CA ca.pem -CAkey privkey.pem -CAcreateserial -out server.crt -days 3650
type server.key server.crt > server.pem
openssl verify -CAfile ca.pem server.pem
2 To configure MongoDB to use certs on the Windows version (similar on other versions), edit the c:\data\mongod.cfg:
systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db
net:
port: 27017
bindIp: 127.0.0.1
ssl:
mode: requireSSL
PEMKeyFile: c:\data\server.pem
CAFile: c:\data\ca.pem
{allowConnectionsWithoutCertificates: true }
{allowInvalidHostnames: true }
You may need allowInvalidHostnames to True if you are using a self signed certificate.
3 To create a self-signed certificate for your MongoDB client (client1.pem):
openssl genrsa -out client1.key 2048
openssl req -key client1.key -new -out client1.req -subj "/C=US/ST=California/O=Company/CN=client1/emailAddress=user#domain.com"
openssl x509 -req -in client1.req -CA ca.pem -CAkey privkey.pem -CAserial ca.srl -out client1.crt -days 3650
type client1.key client1.crt > client1.pem
openssl verify -CAfile ca.pem client1.pem
Note: You will also need to use the client certificate in whatever tool you are using to admin the MongoDB server.
4 To enable SSL/TLS connections for MongoDB driver you may have to change the source files. Our unit Grijjy.Http shows how to enable the driver for ‘https’. Essentially you need to do 2 things to the Connection inside the Grijjy.MongoDB.Protocol unit probably within the method TgoMongoProtocol.Connect :
Set Connection.SSL := True;
Set the Connection.Certificate to the client1.pem you created.
You will have to do some testing, but I hope it points you in the correct direction to make it work. Would love your contribution to the open source project if you can.

As far as I can understand the sources, https://github.com/grijjy/DelphiMongoDB/ doesn't support authentication.
Also from the source, https://github.com/stijnsanders/TMongoWire doesn't either.
FireDAC Mongo uses the C Mongo client library, which supports authentication.
Our Open Source SynMongoDB.pas supports authentication, FPC and almost all Delphi versions (even pre-Unicode). Using variant late-binding to access the BSON/JSON content, it is pretty easy to work with it. Just check the corresponding documentation pages. You can write for instance:
var doc: variant;
...
doc := Coll.FindOne(5);
writeln('Name: ',doc.Name);
writeln('Number: ',doc.Number);
or
var docs: TVariantDynArray;
...
Coll.FindDocs(docs);
for i := 0 to high(docs) do
writeln('Name: ',docs[i].Name,' Number: ',docs[i].Number);
The TMongoClient.OpenAuth method supports both old/deprecated MONGODB-CR method, and the new SCRAM-SHA-1 method:
Client := TMongoClient.Create('localhost',27017);
try
DB := Client.OpenAuth('mydb','mongouser','mongopwd');
...
Note that even if it is part of the mORMot framework, this unit is stand-alone: you don't need to use the ORM, SOA, or MVC parts of the framework - even if it works very well with the ORM, and is able to convert SQL-like statements into MongoDB pipelines, which is a unique very powerful feature. Another unique feature is proper Decimal128 support.
Over a network, also ensure that you use a TLS connection to the server. SynMongoDB.pas can do that under Windows, with no external OpenSSL library needed (it uses the raw Windows SO API).

Related

Keycloak does not have all the Keys available in the storage

I have created a realm and added new keystore(RS384) in the Providers section
When I tried authenticate using postman. I am getting below error in Keycloak console
PublicKey wasn't found in the storage. Requested kid: 'Y3RDLAudovJPEU3Z9BMJL3OyuzqsgAj4424CpxnJqkI' . Available kids: '[]'
Kid is available in the Keys section for the Realm. I am not sure what is causing that. Any help on this is so much appreciated
Edit
Client Authentication
Added JWKS keys from certs endpoint
In Postman made call to token endpoint with client_assertion which has signed JWT and got response back "Invalid client: Unable to load Public key "
I think you gave wrong a value(or format) of "Private RSA Key" and "X509 Certificate" file when you add the key-store at Keycloak UI.
it is possible to get the public Key for RS384 by Postman and UI.
I demoed with Keycloak 18.0.0 with "ssh-keygen" & "openssl" on Ubuntu.
Generate RS384 private key and public key and certification file
ssh-keygen -t rsa -b 4096 -E SHA384 -m PEM -P "" -f RS384.key
openssl req -new -x509 -key RS384.key -out RS384-cert.pem -days 360
it will create three files
RS384-cert.pem <- certification file
RS384.key <- private key
RS384.key.pub <- public key
Add Keystore with 1.'s files
New Keystore will be created
Can get Key by Postman
can compare public key between UI and openssl generated it.
you can check API call value and JWT creator web site
with KID and public key
https://russelldavies.github.io/jwk-creator/
The issue is I did not add "use":"sig" in the JWKS that is kid is not available

Is there a way to check if a certificate is client cert or server cert?

I received a new keystore .jks file for ssl connection to replace an old, but working, .jks keystore file, but I got "unexpected handshake message: serve_hello" error. I was told to make sure the keystore contains a client cert, so I used keytool to export its cert to a pem file, then use openssl to check the purpose. The result shows
Certificate purposes:
SSL client : No
SSL client CA : No
SSL server : Yes
SSL server CA : No
...
However when I applied the same process to check the old but working jks file I got the same result. Wonder if this is the right way to verify the certificate? And how to troubleshooting this handshake error with the new jks file?
Thanks!
The extended key usage extension contains OIDs which define the purpose:
id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
-- TLS WWW server authentication
-- Key usage bits that may be consistent: digitalSignature,
-- keyEncipherment or keyAgreement
id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
-- TLS WWW client authentication
-- Key usage bits that may be consistent: digitalSignature
-- and/or keyAgreement
https://datatracker.ietf.org/doc/html/rfc5280 Page 44
See: https://oidref.com/1.3.6.1.5.5.7.3.1 and https://oidref.com/1.3.6.1.5.5.7.3.2
When opening a certificate on Windows you can see the extension here:

Self signed SSL certificate generated by New-SelfSignedCertificateEx isn't trusted in Ubuntu

I used this tool in this link to generate a self-signed certificate for a Windows webserver.
The command to generate the cert is like following
New-SelfSignedCertificateEx -Subject "CN=192.168.56.111" -SAN "192.168.56.111" -IsCA $true -EKU "Server Authentication", "Client Authentication" -KeyLength 2048 -KeySpec "Signature" -KeyUsage "DigitalSignature" -FriendlyName "192.168.56.111" -NotAfter $([datetime]::now.AddYears(5)) -StoreLocation "LocalMachine" -Exportable
After installing the certificate with IIS, and add the certificate to the trusted root CA store in a Windows 10 client, I was able to browse the website with no certificate errors.
However when I try to do the same in a ubuntu 18.04 client by installing the cert to the CA certs store and test using cURL, it doesn't work
Install cert to Ubuntu ca-certificates
openssl s_client -connect 192.168.56.111:443 -showcerts > out.txt
#then use vim to edit out.txt and save the cert to 192.168.56.111.crt
sudo cp 192.168.56.111.crt /usr/local/share/ca-certificates
sudo update-ca-certificates
Test the connection using cURL
curl https://192.168.56.111
And got the error message
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
When adding the cert to the Chrome Certifiates store, Chrome shows NET::ERR_CERT_INVALID
So my question is, why does it work in Windows client but not in Ubuntu 18.04? I can't see any error indicating what's wrong with the certificate in Ubuntu so I'm stuck at the moment.
Your openssl command is not correct:
jonathan.muller#jonathan-muller-C02ZC4EPLVDQ$ openssl s_client -connect drylm.org:443 -showcerts
CONNECTED(00000005)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = blog.drylm.org
verify return:1
---
Certificate chain
0 s:/CN=blog.drylm.org
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
-----BEGIN CERTIFICATE-----
MIIFUzCCBDugAwIBAgISA0xYp5ZHU+NGF1EW/RcUuV0fMA0GCSqGSIb3DQEBCwUA
...
you have a lot of noise in the output.
Here is how to extract the certificate:
echo | openssl s_client -connect 192.168.56.111:443 2>/dev/null | openssl x509 > 192.168.56.111.pem
and you can copy this pem file to the truststore.
Edit:
I just made the exercise by creating a self sign certificate on this website
in my shell:
john#kona$ curl https://test.drylm.org
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
then
john#kona$ echo | openssl s_client -connect test.drylm.org:443 2>/dev/null | openssl x509 > test.drylm.org.crt
sudo cp test.drylm.org.crt /usr/local/share/ca-certificates/
john#kona$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
Adding debian:test.drylm.org.pem
done.
done.
and finally:
john#kona$ curl https://test.drylm.org
Path : ~
No more error message with curl.

How do I connect to MongoDB with SSL in Scala?

I'm trying to set up an ssl connection to a mongodb instance I have running in a container on my machine and keep running into,
nioEventLoopGroup-2-4, fatal error: 46: General SSLEngine problem
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I created a self signed .pem for mongo with,
openssl req -x509 -newkey rsa:4096 -keyout mongo.key -out mongo.crt -days 365 -nodes
cat mongo.key mongo.cert > mongo.pem
Moved those into a folder, mounted it as a bind volume in my container and added
--sslMode requireSSL --sslPEMKeyFile /etc/boundfolder/mongo.pem
to the mongo startup. I can connect to this with the mongo client.
I am setting up my mongo client in scala like so,
val hostConf = ClusterSettings.builder().hosts(List(new ServerAddress(hostName)).asJava).build()
val clientSettings = MongoClientSettings.builder()
.streamFactoryFactory(NettyStreamFactoryFactory())
.clusterSettings(hostConf)
val withTLS = clientSettings.sslSettings(
SslSettings.builder()
.enabled(true)
.invalidHostNameAllowed(true)
.build())
MongoClient(withTLS.build())
Lastly, I created a keystore with,
keytool -importcert -trustcacerts -file mongo.crt -keystore mongo.keystore
and am starting the application with the following parameters,
-Djavax.net.ssl.keyStore=/path/to/mongo.keystore -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.debug=SSL
I'm pretty sure the issue is either what, or how, I'm adding the self signed cert to the keystore. Thanks for any help you can give.

Unable to get the new paypal SSL CA certificates to be recognized. Handshake to Sandbox failing

I am testing a sandbox version of the PayPal IPN system that worked previously, but is now not functioning. The IPN simulator says:
"IPN was not sent, and the handshake was not verified. Please review your information."
I reviewed the documentation about the Verisign G5 CA certificate and followed the instructions shown, but the following command:
openssl s_client -connect api-3t.sandbox.paypal.com:443 -showcerts -CApath /etc/ssl/certs/
Still produces this output: (Truncated)
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID: 9E01CD86FA9E600EAD505F17E34C0F9BE07E7894E35B20BAF2946F88596BB047
Session-ID-ctx:
Master-Key: 90F662CD0BD319EB87ACFE89CDACEFED2327AC4C827ED74861166B86423B5404
587A70B65BCEA2FAC23F7DDAAA49F9DC
Key-Arg : None
Start Time: 1445624886
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)
I verified that the G3 certificate is no longer in the certificate store, and even removed and reinstalled the new certificate many times. I have spent the last 10 hours on this with no end in sight.
I own my own servers, so there is no other administrator I can turn to... I need to figure out how to solve this myself, and am at my wits end. I know I do not know as much about SSL and certificate chains as I should, but theres no help for that part lol.
Can anyone who has performed this task give me a kick in the right direction, and/or let me know what additional information I can provide to help solicit a solution?
Thank you very much,
Dave
Here's how I did to import the G5 root cert into openssl:
Obtain a G5 root certificate from Verisign (Symantec) HERE (get it in PEM format, save the file with .pem extension)
Put the file into your openssl base dir (should be like "/usr/lib/ssl" on your server, but you may check the base dir by running openssl version -d)
Run the command to install the cert
openssl verify -CApath <ssl-base-dir>certs server-certificate-file
(replace <ssl-base-dir> with your openssl base dir, and replace server-certificate-file with your .pem file, the command would be something like openssl verify -CApath /usr/lib/ssl/certs G5.pem)
The response would be an G5.pem: OK for the installation
Try again with the connection command
openssl s_client -connect api-3t.sandbox.paypal.com:443 -showcerts -CApath /usr/lib/ssl/certs/
You will see Verify return code: 0 (ok) at the end of the response
I downloaded the VeriSign Class 3 Public Primary Certification Authority - G5.pem certificate file into a local directory, and ran the following command:
openssl s_client -connect api-3t.sandbox.paypal.com:443 -showcerts
-CAfile "ssl\VeriSign Class 3 Public Primary Certification Authority - G5.pem"
Openssl returned a successful result (truncated):
Server certificate
subject=/C=US/ST=California/L=San Jose/O=PayPal, Inc./OU=PayPal Production/CN=api-3t.sandbox.paypal.com
issuer=/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
---
No client certificate CA names sent
---
SSL handshake has read 3379 bytes and written 344 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : ECDHE-RSA-AES256-SHA
Session-ID: 9E01CD86FA9CEB77AD505F17E34C0B9B8A233BD98E30D705F2946F88596F077D
Session-ID-ctx:
Master-Key: 7AC616B7499ED70B6D75FAD3308C332A48B85987685A514365B7507297A3C6A70CD6E7503CE27A9A157045531B54149F
Key-Arg : None
PSK identity: None
PSK identity hint: None
Start Time: 1445867355
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
Note that I used the -CAfile option to directly reference the CA root certificate.