Task #1767
closedRun on Windows
100%
Description
Now when you want to execute caw on Windows in git-bash you are not able to get the response nor response code from the bash script.
So the issue is we are not able to run bash script on windows and get the output from it.
In module we are creating new process via ProcessBuilder.
Tried solutions in crt module in win driver:
command is just path to bash script
Runtime run = Runtime.getRuntime();
return run.exec(new String[]{"\"C:\\Program Files\\Git\\git-bash.exe\"", "-c", command});
ProcessBuilder pb = new ProcessBuilder();
pb.command("\"C:\\Program Files\\Git\\git-bash.exe\"", "-c", command);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
return pb.start();
ProcessBuilder pb = new ProcessBuilder("cmd.exe");
pb.inheritIO().command("\"C:\\Program Files\\Git\\git-bash.exe\"", "-c", command);
Some links with examples to ProcessBuilder
https://www.mkyong.com/java/java-processbuilder-examples/
https://stackoverflow.com/questions/14165517/processbuilder-forwarding-stdout-and-stderr-of-started-processes-without-blocki
http://www.javasavvy.com/execute-shell-script-java-using-process-builder/
Updated by Petr Fišer almost 5 years ago
This seems to be a bit of a quirk of the git-bash.exe executable. The binary itself starts a new window and has some "problems" with stdout/in/err redirection (it does not do any).
When you use the plain bash.exe from the bin directory then it works fine. But, interestingly enough, when calling bash.exe from windows cmd, it seems to have some problems IIRC. :)
Anyway I changed the call to use bash.exe and it seems to be working fine (also confirmed this works when I found it mentioned on some Node.js / SO post).
My setup:
package hnojiste;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
public class WinRunner {
public static void main(String[] args) throws Exception {
Runtime run = Runtime.getRuntime();
Process p = run.exec("C:\\Program Files\\Git\\bin\\bash.exe -c '/c/caw/caw list-certs'");
InputStream stderr = p.getErrorStream();
InputStream stdout = p.getInputStream();
String resultERR = new BufferedReader(new InputStreamReader(stderr)).lines().collect(Collectors.joining("\n"));
String resultOUT = new BufferedReader(new InputStreamReader(stdout)).lines().collect(Collectors.joining("\n"));
System.out.println("STDERR:");
System.out.println(resultERR);
System.out.println();
System.out.println("STDOUT:");
System.out.println(resultOUT);
}
}
Built and run on windows machine from hand:
Administrator@TEST MINGW64 ~ $ javac hnojiste/WinRunner.java Administrator@TEST MINGW64 ~ $ java hnojiste.WinRunner STDERR: STDOUT: V 191020145321Z B93A76B3017EDBBD40F93AEF9FFC35B0 unknown /C=CZ/ST=Czech Republic/L=Prague/O=BCV/OU=TEST/CN=user.test.bcv R 191020145351Z 190723073307Z,keyCompromise B93A76B3017EDBBD40F93AEF9FFC35B1 unknown /C=CZ/ST=Czech Republic/L=Prague/O=BCV/OU=TEST/CN=user.test.bcv ... etc ...
Updated by Tomáš Doischer almost 5 years ago
I tried using Runtime and it's probably the best way since it actually runs the script.
private Process executeInternal(String command, String[] parameters) throws IOException {
// BEWARE, dont log parameters - password in plain text
LOG.debug("Execute this command [{}]", command);
String completePath = "C:\\Program Files\\Git\\bin\\bash.exe -c '/c/caw/caw ";
StringBuilder sb = new StringBuilder();
for(String p : parameters) {
sb.append(p);
sb.append(" ");
}
String parameter = sb.toString();
parameter = parameter.trim();
String completeCommand = completePath + parameter + "'";
Runtime run = Runtime.getRuntime();
Process p = run.exec(completeCommand);
return p;
}
This still doesn't quite work, IdM will not create a request (only a concept) and shows the following error in log:
org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [eu.bcvsolutions.idm.crt.api.domain.CrtResultCode]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [eu.bcvsolutions.idm.crt.api.domain.CrtResultCode]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1311) at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1299) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119) at eu.bcvsolutions.idm.crt.driver.caw.winCawDriver.execute(winCawDriver.java:470) at eu.bcvsolutions.idm.crt.driver.caw.winCawDriver.generate(winCawDriver.java:161) at eu.bcvsolutions.idm.crt.service.DefaultCertificateManager.generate(DefaultCertificateManager.java:220) at eu.bcvsolutions.idm.crt.service.DefaultCertificateManager$$FastClassBySpringCGLIB$$d6deedce.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) at eu.bcvsolutions.idm.core.security.service.impl.EnabledAspect.checkBeanEnabled(EnabledAspect.java:52) at sun.reflect.GeneratedMethodAccessor152.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ...
We'll look into it in more details tomorrow.
Updated by Tomáš Doischer almost 5 years ago
- Assignee changed from Petr Fišer to Tomáš Doischer
Updated by Tomáš Doischer almost 5 years ago
- Status changed from New to In Progress
Updated by Tomáš Doischer almost 5 years ago
We tried both RunTime and ProcessBuilder; one of the problems was to parse the input data in a format such that CAW can read it. This was fixed (in both cases). RunTime turned out to have a problem with concurrency so we tried ProcessBuilder which also had this issue. We now run the ProcessBuilder in a new thread which fixed the problem.
As of now, we can create new certificates, revoke them, and upload from a pem file. We cannot renew a certificate and generate it from a csr file. This is probably due to strange input coming in the getCertificate method. Once the testing environment is available again, I'll try to fix that. Also, right now, the paths to git-bash.exe and CAW are hardwired in the winCawDrive class, this is for testing purposes only. New configuration will be created.
The code can be found here:
https://git.bcvsolutions.eu/modules/crt/tree/personal/tomasdoischer/16065_winCawDriver
Updated by Tomáš Doischer over 4 years ago
- % Done changed from 0 to 80
I managed to fix renewing certificates, generating from a csr file and validating certificates. Everything seems to function properly, only the driver configuration has a small problem (which is probably caused by the state of the running IdM rather than the CRT module itself) and shows one item twice. The code still needs some refactoring but it works.
Updated by Tomáš Doischer over 4 years ago
I refactored the code a little bit and added documentation to wiki:
Updated by Vít Švanda over 4 years ago
- Status changed from In Progress to Needs feedback
- Assignee changed from Tomáš Doischer to Vít Švanda
- Target version set to 1.4.0
Updated by Tomáš Doischer over 4 years ago
- File caw.zip added
Here is a CAW folder which works on Windows.
Updated by Vít Švanda over 4 years ago
- Status changed from Needs feedback to In Progress
- Assignee changed from Vít Švanda to Tomáš Doischer
We discovered problem on Windows, when CAW is call with paramters where value has diacritic characters, then exception "No such file or directory" is returned.
Updated by Vít Švanda over 4 years ago
- WinCawConfiguration should extends the CawConfiguration.
- WinCawDriver could extends the CawDriver. For this extends must be CawDriver changed (may be this is way: "public class CawDriver<C extends CawConfiguration> extends AbstractDriver<C>").
- In many methods in WinCawDriver you only added CawPath parameter. So you can create some parent method in CawDriver and "only" this method can be overriden in the WinCawDriver (may be "executeInternal" method can be overrided?).
- Method isProcessFailed is not correct. Caw can return more then 0 or 1 (for example 127 in problem with diacritic char .. this is new for me to). This method should return false only if Caw return 0. I know, you only copied this method, but please fix it :-).
private boolean isProcessFailed(Process process) {
if (0 == (process.exitValue())) {
return false;
}
return true;
}
Updated by Petr Fišer over 4 years ago
- Assignee changed from Tomáš Doischer to Petr Fišer
I tried to fiddle with string_mask setting in openssl (nombstr --> utf8only; plus some tweaking). On linux (CentOS7), this works fine. Even better, this probably solves displaying diacritic in the certificates in idm (not verified yet).
However on windows this causes problems when generating CSRs: Openssl reports invalid characters when ASN.1 parsing the utf8 string. It could be caused by openssl version. The MinGW uses 1.0.2o which is a LTS branch of 1.0.2 but I think this is the older branch to 1.0.1j/1.1.1 LTS branches. I will look into this tomorrow.
Updated by Petr Fišer over 4 years ago
- The original behavior still persists when using utf8. Adding nameopts has no effect:
utf8 = yes string_mask = utf8only name_opt = multiline,utf8
- When changed to default or nombstr, I am able to create CSR but ASN.1 parse shows that datatype of CN is T61String. This probably causes unicode characters to be skewed (they become single-byte nonsense, usually a control char).
- When using utf8only,utf8=yes with 1.1.1c and disabled MinGW path conversion using MSYS2_ARG_CONV_EXCL="*" env variable, I was able to nudge unicode sequences into the CN in CSR in the form of "xAB" or "\\xAB" but not in the form "\xAB" we need. So this does not work either.
When I was positive that this is something in openssl binary, the internet search started to give some results. Mainly https://github.com/openssl/openssl/issues/8317 which is exactly what we are experiencing. Jumped on the discussion and will be trying to resolve it directly with openssl guys.
Until this is resolved, we have a limitation for running CRT/caw on Windows -> Just ASCII chars. No known way around that, sorry.
This means to strip diacritics in the win-caw-driver, I already discussed it with @doischert and we are ready to implement this. None of us likes it and we hope this is just a temporary solution.
- Tomas: implement diacritics stripping, test the CA
- Petr: review CAW changes made during the debugging of this ticket, release new version of CAW if suitable
- Petr: resolve this with openssl upstream
- Also, a ticket to actually look into it when upstream is fixed would be nice.
Updated by Petr Fišer over 4 years ago
Problem 1:
- On Windows MinGW seems to be converting UTF-8 chars (the commandline) into UTF-16 chars (program parameters, ABI).
- It does the conversion in a weird way - some characters seem to be garbled (Š --> \xffffff9a). On some characters, MinGW strips diacritics (ě --> e; ť --> t).
- OpenSSL has problems with handling wide chars (aka UTF-16). That's why all supposed UTF-8 characters are broken.
- Contact mingw devs and ask about the shell behavior.
- Contact openssl devs about the UTF16 support.
- I tried to completely change the invocation using generated php script:
$ cat gencsr.php <?php shell_exec('openssl req -utf8 -new -out tmp.GV7gq46zU0 -keyout tmp.iVgK4InrKQ -passout pass:password -subj "/countryName=CZ/stateOrProvinceName=Czech Republic/localityName=Prague/organizationName=BCV/organizationalUnitName=Example1/commonName=Anděl Šťastný/emailAddress=stastny.andel@domain.tld/"'); ?>
- I built small C binary (built on windows using gcc from mingw) which prints out received arguments and also a HEXdump of them. Notice the garbles when passing string with diacritics:
#include <stdio.h> #include <string.h> int main(int argc, char **argv) { for (int i = 0; i < argc; ++i) { if (i == 0) continue; printf("argv[%d]: %s\n", i, argv[i]); int m = strlen(argv[i]); char keyword[m]; for (int j = 0; j < strlen(argv[i]); j++){ keyword[j] = argv[i][j]; printf("argv[%d][%d]=\\x%x\n",i,j,keyword[j]); } printf("\n"); } }
- Outputs from the binary:
Administrator@host MINGW64 /c/caw-pokusy $ ./paramdump.exe stastny argv[1]: stastny argv[1][0]=\x73 argv[1][1]=\x74 argv[1][2]=\x61 argv[1][3]=\x73 argv[1][4]=\x74 argv[1][5]=\x6e argv[1][6]=\x79 Administrator@host MINGW64 /c/caw-pokusy $ ./paramdump.exe šťastný argv[1]: ▒tastn▒ argv[1][0]=\xffffff9a argv[1][1]=\x74 argv[1][2]=\x61 argv[1][3]=\x73 argv[1][4]=\x74 argv[1][5]=\x6e argv[1][6]=\xfffffffd
Updated by Vít Švanda over 4 years ago
- Assignee changed from Petr Fišer to Tomáš Doischer
I did review for WinCawDriver. Works correctly, good work (only diacritics characters missing :-) ). I successed tried to generating, validation, renew, revocation certificate.
There is no tests for WinCawDriver. I know create tests for this driver on Windows is hard, but should be created. We have only tests for CawDriver working under Linux now and these tests doesn't work under Windows (from the logic reason).
Code looks nice (there is minimal redundant code now, thanks for that), but I found some formal issues:
- Why did you removed czechidm-crt/test/localization/Localization-test.js?
- Do not use "+" for join a Strings (user MessageFormat or builder instead).
- "-----BEGIN CERTIFICATE-----" .. should be final static variable.
- Some private static methods still exists in WinCawDriver. Plese remove static.
- There is unused method "assembleEscapedString", please remove it.
Updated by Petr Fišer over 4 years ago
I believe the diacritics is not only openssl issue. The MinGW also works in mysterious ways. :-/
Reported here: https://github.com/openssl/openssl/issues/8317#issuecomment-529411089 . Now we'll wait for the analysis review.
Then I will take this (probably) to the MinGW developers.
- Trying to invoke the CSR generation from PHP does not work well either:
$ file gencsr.php gencsr.php: PHP script, UTF-8 Unicode text $ cat gencsr.php <?php shell_exec('openssl req -utf8 -new -out tmp.GV7gq46zU0 -keyout tmp.iVgK4InrKQ -passout pass:password -subj "/countryName=CZ/stateOrProvinceName=Czech Republic/localityName=Prague/organizationName=BCV/organizationalUnitName=Example1/commonName=Anděl Šťastný/emailAddress=stastny.andel@domain.tld/"'); ?>
Updated by Petr Fišer over 4 years ago
According to the comment https://github.com/openssl/openssl/issues/8317#issuecomment-529422504 openssl has some way to cope with windows.
One has to explicitly set the env variable OPENSSL_WIN32_UTF8=1 and then the CSR generation seems to be working correctly:
$ OPENSSL_WIN32_UTF8=1 MSYS2_ARG_CONV_EXCL="*" openssl req -utf8 -new -out tmp.GV7gq46zU0 -keyout tmp.iVgK4InrKQ -passout pass:password -subj '/countryName=CZ/stateOrProvinceName=Czech Republic/localityName=Prague/organizationName=BCV/organizationalUnitName=Example1/commonName=Anděl Šťastný/emailAddress=stastny.andel@domain.tld/' $ openssl asn1parse -in tmp.GV7gq46zU0 | grep -A1 -i commonname 106:d=5 hl=2 l= 3 prim: OBJECT :commonName 111:d=5 hl=2 l= 17 prim: UTF8STRING :Anděl Šťastný $ openssl req -in tmp.GV7gq46zU0 -text | grep -i subject: Subject: C = CZ, ST = Czech Republic, L = Prague, O = BCV, OU = Example1, CN = And\C4\9Bl \C5\A0\C5\A5astn\C3\BD, emailAddress = stastny.andel@domain.tld
I will adjust the caw configuration and do some testing. Also, I would like to make string_mask=utf8only and utf8=yes default on both Linux and Windows. I recall there was some ill effect on displaying CNs in the IdM and this could solve it.
Updated by Petr Fišer over 4 years ago
- @doischert will now correct some string handling a will do a few other tests (this "bug" happenned because we misunderstood each other, sorry!).
- I will release new CAW version we can deploy.
- I will update our wiki pages so that they no longer contain a warning about incorrect diacritics on Windows.
Then, we have correctly functioning CA for both Linux and Windows.
Also, reported to openssl that proposed solution works https://github.com/openssl/openssl/issues/8317#issuecomment-532238680 .
Updated by Tomáš Doischer over 4 years ago
- Assignee changed from Tomáš Doischer to Vít Švanda
- % Done changed from 80 to 90
@svandav
I created the test and added support for diacritics, can you please check the code?
As for the code review, I corrected mistakes:
Why did you removed czechidm-crt/test/localization/Localization-test.js? No idea, I put it back.
Do not use "+" for join a Strings (user MessageFormat or builder instead). I used StringBuilder.
"-----BEGIN CERTIFICATE-----" .. should be final static variable. I added it as a static variable.
Some private static methods still exists in WinCawDriver. Plese remove static. Removed.
There is unused method "assembleEscapedString", please remove it. This method now converts the text to UTF-8. I instead removed removeDiacritics which is no longer needed.
There is (and was) a potential problem in the test where testValidateCertificate will fail if the authority becomes expired. I added a comment about this to the code but still.
Updated by Vít Švanda over 4 years ago
- Status changed from In Progress to Needs feedback
Updated by Vít Švanda over 4 years ago
- Status changed from Needs feedback to In Progress
- Assignee changed from Vít Švanda to Tomáš Doischer
- % Done changed from 90 to 100
I did review. Works correctly, finally with diacritics. I am glad for tests on Windows. Thanks for that.
- Version in the pom should be 1.4.0-SNAPSHOT.
- You have 13 "bugs" in the Sonar. https://sonar.bcvsolutions.eu/project/issues?id=eu.bcvsolutions.idm%3Aidm-crt&resolved=false&sinceLeakPeriod=true&types=BUG
- Remove unused import java.text.Normalizer;
- FindFileRecursively.java - Author and javadoc missing.
Updated by Tomáš Doischer over 4 years ago
- Status changed from In Progress to Resolved
I implemented code-review findings, the branch was merged to develop.
Updated by Radek Tomiška over 4 years ago
- Status changed from Resolved to Closed