ebourg / jsign

Java implementation of Microsoft Authenticode for signing Windows executables, installers & scripts
https://ebourg.github.io/jsign
Apache License 2.0
250 stars 107 forks source link

Error message: Log4j2 could not find a logging implementation #148

Closed GunArm closed 4 months ago

GunArm commented 1 year ago

I tried to upgrade from 3.1 to 4.2. My build script did well to sign several dlls, exes, and a ps1. When it got to signing an msi, something went wrong. But there was apparently a problem outputting the error message, as I got: ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console... There was nothing before or after it.

It was before outputting anything like "Adding authenticode signature to..."

Reverting back to 3.1 made the problem go away.

ebourg commented 1 year ago

What build tool do you use? Did you get a build failure or an invalid signature on the MSI file ?

GunArm commented 1 year ago

I was running the CLI jar file with java through powershell, same context between the two versions. My build failed but sadly because of the complexity of the CI setup I don't have a lot of confidence except to say signing failed somehow and the only output was the above message about Log4j2.

I wasn't so much needing to solve the MSI signage as reporting the "logging" error. I thought it might be low hanging fruit since jsign is otherwise able to write things to the console like "Adding authenticode signature to {xyz}" so maybe there would be an inconsistent use of the logger that might stick out.

I'll try to poke at it a bit more on monday but it will be a non-trivial (potentially several hour to multi-day) project to get into a context with the credentials where I can try to repro it interactively, and (I hate to be that guy but) while I have other things that need attention the previous version is still working for me.

If there were some kind of --verbose flag I could turn on that would help narrow where in the process the Log4j2 message is coming out, that would be relatively easy to add, but I don't see an option like that in the help. It would also not be too hard for me to just try previous versions and see which do and don't have this behavior.

ebourg commented 1 year ago

If you ran java -jar jsign.jar in the PowerShell script you have to add -Dlog4j2.loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory to remove the log4j warning.

log4j is used by Apache POI when parsing the MSI file. But even if the warning is displayed a parsing error will still result in a exception visible on the console.

GunArm commented 1 year ago

I tried previous versions and the behavior is only on 4.1 and later (not 4.0).

If you ran java -jar jsign.jar in the PowerShell script you have to add -Dlog4j2.loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory to remove the log4j warning.

Thank you for that. That is (essentially) how I'm running it. I tried adding that to my java command and got Error: Could not find or load main class .loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory

Edit: this was wrong After much trial and error I found that I needed to download the log4j-core jar file and put it with jsign and then run with a command like

java `
  -cp path/to/log4j-core-2.20.0.jar;path/to/jsign-4.2.jar `
  -Dlog4j2.loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory `
  -jar path/to/jsign-4.2.jar `
  -etc `
  -etc `

I was surprised that this not only prevented the log4j error message, but allowed the msi signing to complete successfully. I expected that once past the log4j error, log4j would out an actual error message of something going wrong in signing. But it seems it was simply the initialization of log4j that was causing me problems.

Is it expected to need to have log4j-core along with the jsign jar now? IE is jsign no longer meant to be a standalone jar fie? Atleast when signing MSIs?

ebourg commented 1 year ago

jsign.jar should contain everything needed, including log4j. That said, I just checked and you are right, the -Dlog4j.loggerContextFactory parameter doesn't remove the warning. But this doesn't prevent the file from being signed.

GunArm commented 1 year ago

Ok I've got more of a handle on this now. First of all, I was wrong in my last reply, embarrassingly after about 30 test pipeline runs, the one that "worked" was because I ran the wrong branch. Setting classpath to that log4j jar did not help.

This is probably not useful, but for posterity here are the results of a small subset of things I tried.

I was strucky by your referring to "the warning", and wasn't 100% if you were referring to the line about log4j, since it doesn't say "warning", and you seemed to be expecting it to continue past that (like one would expect with a warning) but what I was seeing was something that says "ERROR" and aborting my pipeline immediately.

I finally managed to get into the build environment to experiment. First thing I did was run the command and it worked. It did show the log4j line, but continued on and signed the MSI (like it is a warning, just one that is logged at the ERROR level)

Then I put the sign command into a foreach-object -Parallel loop like it is in the build script. It still showed the log4j line and signed the file, but this time the log4j line was in red. This means it's on stderr. (It's up to someone better with powershell than me to explain why this is only turning red in the foreach-object -Parallel loop and not when run directly, and also not in a non-parallel foreach-object loop.)

In the past I have run into different versions of powershell reacting when $ErrorActionPreference = "Stop" set to abort on cmdlet exceptions, and then anything is written to stderr.

I disabled $ErrorActionPreference = "Stop" and reran the pipeline and it succeeded.

So the issue, for me, was that this warning is being written at an ERROR level and written to stderr, and as soon as that text is returned to powershell it detects that as an error and aborts the script.

ebourg commented 1 year ago

Reopening to remind me that the log4j configuration isn't right yet. I don't understand why the -Dlog4j2.loggerContextFactory parameter has no effect.