Open PeerWitthoeft opened 2 years ago
Hi @PeerWitthoeft, I'm unclear as to if you are reporting a bug, or what specifically you are asking for. What you're proposing sounds like it should "just work", Cypress doesn't do anything special to block the browser process from accessing peripherals. Can you clarify the ask?
Hi @flotwig, sorry to make in more complicated than it is ;) For our tests in production, we need certificates from the microsoft certificate store. These are unavailable with cypress. I assume, cypress uses another (maybe own generated) store for certificates instead. Is it possible to make the use of the default certificate store configurable?
Hi @PeerWitthoeft! Currently we support configuring the certificate authority and client certificates. Does this address your issue?
Hey @rachelruderman , unfortunately this solution is not possible in our environment, as we don't have access to any pfx- or pem-files.
Thanks for the clarification, @PeerWitthoeft! I've consulted with the team and have some follow-ups for ya:
I assume, cypress uses another (maybe own generated) store for certificates instead.
We don't use another certificate store; we do disable SSL verification in the browser, but if I understand correctly, you're not talking about SSL certificates
For our tests in production, we need certificates from the microsoft certificate store. These are unavailable with cypress.
When you say, "These are unavailable with cypress", do you mean regular Chrome has what you need, but Cypress doesn't? Can you share some test code that doesn't work?
Resources that may help:
--use-mock-keychain
seems kind of suspect. Can you try omitting this arg and let me know if that helps? Cypress doc on how to modify browser launch argsUnfortunately we have to close this issue due to inactivity. Please comment if there is new information to provide concerning the original issue and we can reopen.
Hello again, sorry for the late answer. We made a few more researches and got the following results:
With Chrome and without Cypress:
The Browser shows the client certificate dialog:
the Browser accesses the certificate store files to show the usable certificates:
With Chrome and Cypress
The Browser does not show the client certificate dialog, but tries to authenticate with null certificate
The browser only uses files in cypress path:
Sorry for censor almost half of the screenshots. Our company is very strict with security-issues ;) For the same reason, i am not allowed to share test-code here. It consists only of 3 steps:
then the selection for the certificate pops up. I hope this helps to analyze our issue!
@PeerWitthoeft @rachelruderman had suggested this in a comment above:
- The full list of CLI opts we pass to Chrome. --use-mock-keychain seems kind of suspect. Can you try omitting this arg and let me know if that helps? Cypress doc on how to modify browser launch args
Were you able to give that a try?
@tbiethman Yes, i tried it, but without any changes in behavior
@PeerWitthoeft I see, thanks for double checking that. Without more specifics, it is difficult to try and reproduce this issue. Is there any way for you to provide a minimal reproduction that exhibits the issues you're seeing?
For your screenshot above regarding "The browser only uses files in cypress path:":
What application is that/how are your viewing that data? I apologize, I'm unfamiliar with Windows certificate management.
@tbiethman I am currently trying to get permission to share some test code here.
For the screenshot: is used the process monitor of sysinternals tool suite, available here: https://docs.microsoft.com/en-us/sysinternals/downloads/procmon. This tool documents almost all activities of all processes running in windows. Filtering the correct entries is quite... lets call it "interesting" ;)
I have the permission to share some of our testcode:
it('should be able to use log in', () => { cy.visit('apps.datev.de/km-kalkulation'); cy.get('#label_secure18').click(); cy.get('#btn_MethodNext').click(); })
The popup for the certificate should show, if the user has an client-certificate in his own certificates in microsoft certificate store
Having site under test does help give some context, thank you. Have you explored using Chrome's AutoSelectCertificateForUrls policy? I'm unfamiliar with how dynamic the smartcard cert data/locations are, but it seems like that might be the best way to avoid the certificate popup altogether, which would be necessary for Cypress to test your application. The certificate selection popup is shown by the browser, not by your app, and thus you cannot interact with it using Cypress commands in an automated fashion.
@PeerWitthoeft, This seems like a limitation with cypress today. I've converted this to a feature request.
@tbiethman , i tried the AutoSelectCertificateForUrls policy, but with no other outcome. The browser still won't use any certificates from the store. I know about the fact, that Cypress can't handle browser dialogs, but we have some ideas for this problem.
Hello, it's been some time since the last comment.. any updates on this?
Hi @Arachnatur. No updates yet. I do not see this work being prioritized by the team and might be a good opportunity for an open source contribution if any is up for the task!
Totally agree! I also need this feature as the AutoSelectCertificateForUrls policy doesn't work (I perform a task with Selenium inside Cypress project to perform a login for some tests with AutoSelectCertificateForUrls policy and it's working)
Right now, if you need a workaround for some of your tests that need login via smartcards, here the steps:
cypress.config.js
on('task', {
loginSmartCard: async (pin) => {
driver = new Builder()
.setChromeOptions(chromeCapabilities)
.forBrowser('chrome')
.build()
await driver.switchTo().window(driver.getWindowHandle())
await driver.get('https://mywebsite.com/login')
const button = driver.findElement(By.xpath("//button[contains(text(), 'LOGIN')]"))
driver.executeScript("arguments[0].click();", button)
await new Promise((resolve, reject) => {
const child = spawn('powershell.exe', ['-ExecutionPolicy', 'ByPass', '-File', process.cwd() + "\\utils\\login.ps1", '-pin', pin])
child.on('close', (code) => {
if (code === 0) {
resolve()
} else {
reject(new Error(`Child process exited with code ${code}`))
}
})
})
......
login.ps1
param (
[Parameter(Mandatory=$true)][string]$pin
)
Start-Sleep -Milliseconds 2000
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('Title of the Window - Google Chrome')
Start-Sleep -Milliseconds 500
$wshell.SendKeys('{ENTER}')
Start-Sleep -Milliseconds 2000
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('Windows Security')
Start-Sleep -Milliseconds 500
$wshell.SendKeys($pin)
$wshell.SendKeys('{ENTER}')
@meshuggahbobo Thank you very much for the workaround. Doesn't work for me, unfortunately, because the system is very restrictive (no selenium driver for me..). Still, nice work, thanks 👍 @AtofStryker Thanks for your reply - If I can find the time, I'll take your challenge - seems kind of sad that cypress can't do this, it's such an amazing framework otherwise! I realize it's probably not an important feature for most people, because in the wild you can use more comfortable logins. Still, there are some of us who must do testing on somewhat old-fashioned and/or restrictive corporate systems.
@AtofStryker @mjhenkes @flotwig @Arachnatur This would need to be implemented at the Cypress proxy level, just like the file-based clientCertificates support.
Basically the differences between smartcard-based client certificates and file-based client certificates are:
Cypress is using node.js' 'tls' module under the hood, so instead of passing the 'cert' or 'pfx' options to tls.connect(), you would instead pass the 'clientCertEngine', 'privateKeyEngine' options with the name of an OpenSSL engine that communicates with the HSM, as well as pass the 'privateKeyIdentifier' option with the PKCS#11 URI pointing to the smart card and slot to use. See https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions for a list of the securecontextoptions for tls.connect().
You'll also need to bundle the "OpenSSL engine that communicates with the HSM" mentioned earlier. An example would be the libp11 engine from the OpenSC team, and the underlying OpenSC library. If setup and configured with the default config mentioned on the libp11 page, the engine name you pass to tls.connect() would be 'pkcs11', and you would pass the PIN as the 'pin-value' attribute of the PKCS#11 URI.
HSM-based (smartcard-based) client certificates are fundamentally more secure than storing them in the file system, especially when the current Cypress implementation doesn't have a way to get the passphrase protecting the keys at runtime, instead the passphrase must be stored in plain text on the file system as well.
I hope that the Cypress team will seriously consider adding this support.
So, to summarize, unless I'm missing something, to implement this, Cypress would need to:
The user would then just set 'smartcardURI' as a valid PKCS#11 URI pointing to the desired HSM device and slot. (and, as optionally noted above, set 'cert' to a certificate file that goes with the private key on the HSM))
What would you like?
Hello,
i would like to use certificates provided by an secure smartcard.
Why is this needed?
Our Applications uses a secure smartcard with stored certifikate for authentifikation. For login, the user has to select his certificate in the browser. In our test environment this is handled by softcertificates (pfx-files). Due to security this is not allowed in production, where we would like to create some monitoring-like tests with cypress. So we need to use the "real" certificate from a hardware smartcard.
Other
No response