Adding attributes to a jar file's manifest using Gradle - java

I'd like to bundle some jar files built with Gradle 1.6 as part of a Java webstart application.
I can currently sign the jars correctly with a certificate and specify the codebase and permissions attributes for the produced artifacts by using the standard jar task like so:
jar {
manifest.attributes provider: 'tribe7.net'
manifest.attributes permissions: 'all-permissions'
manifest.attributes codebase: '*'
}
This is because the latest Java webstart version in Oracle's JDK/JRE makes these attributes mandatory or else it complains to the user about the application's security.
Preventing RIAs from Being Repurposed
However, my artifact jars have third party dependencies (for example, slf4j) and I have yet to find an intuitive way to include these atributes in such third party jars. With this in mind, my final webstart application structure looks sort of like this:
./build/webstart/my.jnlp
./build/webstart/lib/myartifactA-1.00.jar
./build/webstart/lib/myartifactB-1.00.jar
./build/webstart/lib/myartifactC-1.00.jar
./build/webstart/lib/slf4j-api-1.7.5.jar
The result is that at runtime, webstart doesn't complain about my artifacts but does so for the third party jars because they obviously don't have the attributes in their manifest file:
Missing Codebase manifest attribute for: file:/C:/build/webstart/lib/slf4j-api-1.7.5.jar
Missing Permissions manifest attribute for: file:/C:/build/webstart/lib/slf4j-api-1.7.5.jar
Missing Codebase manifest attribute for: file:/C:/build/webstart/lib/slf4j-simple-1.7.5.jar
Missing Permissions manifest attribute for: file:/C:/build/webstart/lib/slf4j-simple-1.7.5.jar
Since I don't directly control the manifest generation for the third party jars I have to somehow modify the manifest files present inside the build/webstart/lib directory to explicitly include those attributes in order to make webstart happy.
Is there a way to add attributes to a jar file's manifest with Gradle? In case anyone's interested, this is my Gradle build script:
build.gradle
Thanks for your time and help!
UPDATE
Peter's answer worked! This is the updated code:
ant.jar(destfile: it, update: true) {
delegate.manifest {
attribute(name: 'permissions', value: 'all-permissions')
attribute(name: 'codebase', value: '*')
}
}
ant.signjar(
destDir: webstartSignedLibPath,
alias: project.getProperty('jarsign.keystore.alias'),
jar: it,
keystore: project.getProperty('jarsign.keystore.path'),
storepass: project.getProperty('jarsign.keystore.password'),
preservelastmodified: 'true'
)
Thanks!

To set these attributes, you'll have to unpack the Jars, edit the manifests (using Groovy), and repack the Jars. Alternatively, you could try to overwrite the manifests with ant.jar(update = true), although overwriting a file (without adding a duplicate) doesn't seem to be supported (see duplicate attribute in the Ant docs). Merging the Jars (in one way or another) might be another option.

Related

OpenJDK11: Security provider setup

In java 8 to setup a security provider I just needed to add the provider to the java.security file and add the provider external library to lib/ext. Since external libraries are not allowed in further versions how can I add a provider on jdk11?
Until now I tried to add the provider to the java.security file in conf/security folder.
security.provider.1=nCipherKM
I inserted the new provider on top of the list but when I try to .getInstance("providerExample") I still get a NoSuchProviderException.
java.security.NoSuchProvidIrException: no such provider: nCipherKM
The lib jar itself, I do not know where do I have to put or how can I include it to be recognized. If I create a lib/ext folder he says to use -classpath instead but also have no clue on that.
Thank you
EDIT: To complete my question I forgot to mention that im using thorntail and maven 3.6.1 to build the project. The error I get is related to this line:
KeyStore.getInstance("ncipher.sworld", "nCipherKM");
As I said before, when I had java 8 I only had to add the security.provider to the java.security and the nCipherKM.jar to $JAVA_HOME/lib/ext folder.

Gradle remove version number from the dependency name

I would like to use derbyrun.jar created by the Apache Derby project in my application in order to run a derby database as a Windows or Linux service.
The problem is that derbyrun.jar references in its manifest other derby jars without any version number in their names, like Class-Path: derby.jar derbyclient.jar derbytools.jar derbynet.jar. While my application (with many subprojects) uses "maven/gradle" format derby-10.13.1.1.jar, derbyclient-10.13.1.1.jar, etc..
Is there a simple way in gradle to name those derby jars without a version number, like
compile("org.apache.derby:derby:10.11.1.1") {
artifact {
name = 'derby'
}
}
that should result in just derby.jar.
I do not like an idea of renaming derby-10.13.1.1.jar into derby.jar in a separate task as we reference those artifact names in many places using configurations.runtime, etc. (e.g. when deploying or creating manifest files for our own jars). And this renaming approach seems to complicate the script unnecessary (+ all the future maintenance effort when the derby version will be changed).
Is there a better way to achieve this? Sure, the mentioned above artifact { name = 'derby' } does not remove the version number from the jar's file name.

BouncyCastle 1.51 loading in war on Wildfly 8.0

Background
I am trying to use bouncy castle library to decrypt private keys in my war. Now I tested the code first in a standalone app and it worked fine. Now when I am testing it as a webapp in Wildfly8.0 am facing some issues with Bouncy castle.
The Wildfly 8.0 am using has bouncy castle provider module installed. The BC version being used in v1.46.
The code that I have developed uses v1.51.
I have followed the steps mentioned here:
https://developer.jboss.org/thread/175395
bouncycastle + JBoss AS7: JCE cannot authenticate the provider BC - Specifically followed instructions provided in For a specific deployment (preferred)
Already tried
Installing the JCE policy files.
Adding to the provider list.
Problem
The error I am getting is :
unable to read encrypted data: JCE cannot authenticate the provider BC
And the code which triggers the above error, in as follows :
PKCS8EncryptedPrivateKeyInfo kp = (PKCS8EncryptedPrivateKeyInfo) keyPair;
InputDecryptorProvider pkcs8dec = new JceOpenSSLPKCS8DecryptorProviderBuilder()
.setProvider(new BouncyCastleProvider())
.build("somepass".toCharArray());
PrivateKeyInfo pko = kp.decryptPrivateKeyInfo(pkcs8dec);<-- ##Error here
Also to add the details,in my pom.xml I have added the jar with compile scope, so the libs are copied into the war and get installed in WEB-INF/lib.
Any tips to fix the above problem?
I. Combining the idea of Peter (#comment) and https://developer.jboss.org/thread/175395, create "your own bc version" with a custom name:
Create an 'my.bouncycastle' module in the following manner:
Under $JBOSS_HOME/modules, create directory 'my/bouncycastle/main'. Directory 'my' might not be there. ;)
Copy bcprov-[your-version].jar into my/bouncycastle/main
Create file 'bcprov-[your-version].jar.index' in my/bouncycastle/main, which is basically the output of a jar -tf command without the ".class" lines. (pipe&edit...)
I put a blank line at the top because these .index files always seem to have one. I have attached this file as "bcprov-jdk16-1.46.jar.index".
Create a file called "module.xml", also in my/bouncycastle/main, which will point to the jar file and reference module "javax.api" as a dependency.
I have attached this file as 'module.xml'.
The module is complete.
Since I am deploying in an EAR file, I had to add a module dependency entry to my EAR's META-INF/jboss-deployment-structure.xml file, under the section, like so:
(the statement also applies to WAR files, when deployed on top-level, use the custom name as module reference)
<deployment><dependencies><module name="my.bouncycastle" slot="main" export="true"/>
Make certain that the ear's /lib directory does NOT contain bcprov-[your-version].jar. (actually II.)
Notes:
The 'slot="main" and 'export="true" parameters are very important in the jboss-dependency-structure.xml file...
II. Adjust your maven dependency(ies) to:
<scope>provided</scope>
Note: Don't change the maven dependecy(ies group artifacts) to "my.bouncycastle", only the scope, this will ensure you a nice compile-time-behavior by the most IDE's AND will prevent your (maven-)war/jar/ear-plugin from packaging it into libs! (And which would be anyway the correct scope for a dependency like this.)

Java EE server independent way to locate JAR containing javax.persistence classes

I have a Java EE application where you can define variables of a certain type. To validate that the value expression is valid for it's type, I create a string containing a small class:
public class CompilableExpression {
private <type> expression = <expression>;
}
.. and try to compile it using JavaCompiler:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
Iterable<? extends JavaFileObject> compilationUnits =
Arrays.asList(stringContainingCompilableExpression);
CompilationTask task = compiler.getTask(
null, null, diagnostics, options, null, compilationUnits
);
task.call();
This works fine if you are using type: String and expression: "my string", or type: Integer and expression: 10.
I also want to validate types using the #Entity annotation.
When I try to do so I get an error:
Cannot find annotation method name() in type javax.persistence.Table: class file for javax.persistence.Table not found
So, I need to add a JAR containing javax.persistence classes to the class path somehow. Is there a generic way to find this JAR? I'm using GlassFish, and don't want to build a GlassFish only solution.
Or is adding it to my project as a normal (non provided) dependency the way to go?
Update
I'm trying to at least find the location in GlassFish (at ~/glassfish-4.1/glassfish):
find ./ -name '*ee*.jar'
./lib/javaee.jar
./modules/security-ee.jar
./modules/amx-javaee.jar
./modules/javaee-kernel.jar
./modules/autostart/osgi-javaee-base.jar
./modules/autostart/osgi-ee-resources.jar
./modules/deployment-javaee-full.jar
./modules/deployment-javaee-core.jar
./modules/glassfish-ee-api.jar
./modules/javax.management.j2ee-api.jar
My best guess is to use ./lib/javaee.jar, but when I check the contents it's almost empty:
$JAVA_HOME/bin/jar tf ./lib/javaee.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/maven/
META-INF/maven/org.glassfish.main.extras/
META-INF/maven/org.glassfish.main.extras/javaee/
META-INF/maven/org.glassfish.main.extras/javaee/pom.xml
META-INF/maven/org.glassfish.main.extras/javaee/pom.properties
Does anyone know where (in the GlassFish installation) to get the JAR including the javax.persistence classes?
The JAR you are looking for is in $GLASSFISH_HOME/glassfish/modules/javax.persistence.jar
If you are deploying to a JavaEE App Server, the JAR with the #Entity annotation will already be in your application's runtime classpath. You shouldn't have to load any JAR files in code (as you described in your comment).
During development you typically configure your App Server in your IDE and that process should include the JAR with the annotation into your compilation classpath.
You might need to manually include it in the project compile classpath / application server libraries classpath depending on how your IDE handles this. For Glassfish all the API JARs are where you were looking in the modules directory.
Even though this ties your project to finding the JAR for compilation in a specific location relative to the app server install I find it's still a better approach then copying JARs into you project for compilation. This ensures you are compiling against the correct JARs that are deployed to the app server and so long as these are JavaEE APIs your application will deploy fine into any app server.
You could also set up your project to use Maven, include the required deps for the persistence APIs and it will find the compile time deps in your maven cache.
Also you might want to check out Jar Explorer which lets you search for classes etc inside JARs, folders of JARs etc. Its pretty convenient for finding these things.

How to get jar library name and version from String library name?

I have many jar files in my directory:
some-lib-2.0.jar
some-lib-2.1-SNAPSHOT.jar
some-lib-3.RELEASE.jar
some-lib-R8.jar
some-lib-core-1.jar
some-lib-2.patch2.jar
some-lib-2-alpha-4.jar
some-lib.jar
some-lib2-4.0.jar
How can I get library name and version from file name?
Is regex ((?:(?!-\d)\S)+)-(\S*\d\S*(?:-SNAPSHOT)?).jar$ valid for extract name and version?
The version number in the JAR file name is merely a convention and a default for Maven-built JARs. It may have been overridden, and it is not always reliable reading the version number from just the file name.
A more reliable way for reading version number from JAR is to look inside the JAR file. Here you have a couple of options depending on how the JAR was built:
look at META-INF/maven/.../pom.properies and pom.xml and read the version from that - this should be present for Maven-built binaries
sometimes version number if present in META-INF/MANIFEST.MF under Specification-Version or Implementation-Version properties
If this fails, then fall back to reading version number from the JAR name since there is no other information available.
Naming policy could differ across different libraries, so you aren't able to extract name/version from package name using one rule, for details you should check project docs.
In case of Maven you are able to configure the final name of built artifact with finalName pom.xml configuration option. Maven docs provide nice introduction into pom structure. Below is the example from docs:
<build>
...
<finalName>${artifactId}-${version}</finalName>
...
</build>

Categories