Categories
Atbash Core Profile JAX-RS

Run your Jakarta Application without Runtime

Java EE and now Jakarta EE have the packaging requirements that your application needs to be bundled in a WAR or EAR file and executed by your runtime.
Traditionally, that was the application server that was already configured and running and you deploy the WAR file, containing your application, to it.

These days, with an application runtime, you can launch the runtime and at the same time deploy and run the application by specifying the WAR file location at the command. This makes use of the executable JAR file functionality within Java.

An example of Payara Micro

java -jar payara-micro.jar /path/to/myapplication.war

But now with the addition of the Java SE Bootstrap API to JAX-RS 3.1, this might change. And maybe you don’t need a runtime anymore.

Java SE Bootstrap API

The idea of the Java SE Bootstrap API is that you can start the JAX-RS implementation from the public static void main method. Some of the implementations already had support for this in the past, but it is now available within the JAX-RS specification and thus useable with any certified implementation.

You might wonder how that this is possible without using a servlet container?

When your application or server has REST endpoints that can be called by the client (application), you indeed need to capture the HTTP request. Most of the time, this is done using a servlet container and a specific servlet was responsible to call the correct JAX-RS method depending on the URL.

But actually, you don’t need a servlet for that. Any piece of code that listens on a socket can perform this operation. You don’t need a servlet for this task.

There is even a simple HTTP server within the JDK itself, since Java SE 6, that can be used for this purpose. But also other libraries and products like Netty can be used.

REST without server

Now that you have an API to start your JAX-RS server from within your code, like from within your main method, you can have your application respond to user requests.

The following snippet shows what is needed to realise that.

   SeBootstrap.Configuration.Builder configBuilder = SeBootstrap.Configuration.builder();
   configBuilder.property(SeBootstrap.Configuration.PROTOCOL, "HTTP")
                .property(SeBootstrap.Configuration.HOST, "localhost")
                .property(SeBootstrap.Configuration.PORT, 8080);


   SeBootstrap.start(new DemoApplication(), configBuilder.build());

The DemoApplication class is the class that extends the JAX-RS Application class and provides all JAX-RS resource classes through the getClasses() method.

But you probably need more than just the JAX-RS support of Jakarta EE. What about CDI, JSON handling, etc …

Jersey has already an artefact where they integrate Weld, a CDI implementation that also can be started from pure Java SE since CDI 2.0 ‘Java EE 8, and the JSON support, JSON-P and JSON-P, by adding the Jersey media support modules for JSON.

So, you have already all the specifications that make up the Jakarta EE Core Profile, available without the need for any server. An example of such a project can be found in this example project.

Note that this option is different from the embedded server support some vendors provide. There is no specific glue code or additional functionality from the vendor in this case in action. Just some minimal linking between the different specifications.

Really, no server?

Yes, this is now possible and might be the right choice for your situation. It allows you to run your optimised combination of the specifications that you need for the application, right from your main method in Java. Similar to Spring Boot, Jakarta EE can now be used in a truly modular way and no longer require the potentially large set of specifications provided by the runtime that you don’t need.

But you might need to write some classes to better integrate some specification implementations beyond the ones of the Core Profile.

Atbash Runtime

And that is also the goal of the Atbash Runtime, a limited set of code to integrate the specifications seemingness but keep the modular aspect.

That is the reason for the addition of the JakartaRunner class that can be used to start your application from the main method. But at the same time use the module loader of Atbash Runtime so that all specification implementations that are on the classpath are integrated automatically, just like the case with Spring Boot.

It also adds a logging module on top so that you have already one concern less to make your application production worthy.

You can find an example of this approach in this project.

Conclusion

With the addition of the Java SE Bootstrap API to JAX-RS, it becomes now possible to create your own custom, modular runtime that can be started from the main method. This avoids the overhead of potentially many specifications and functionality from the runtime that are not needed for your case.

Atbash Runtime also supports this mode by providing an easy-to-use API that starts the module system of the product behind the scenes and seemingness integrates the different specifications that are found on the classpath.

Want to lean more about Jakarta EE 10 Core Profile?

This topic was discussed during my JakartaOne LiveStream event of 2022. Have a look at the presentation if you want to know more about the Core Profile “Explore the new Jakarta EE Core Profile“.

Atbash Training and Support

Do you need a specific training session on Jakarta or MicroProfile? Or do you need some help in getting up and running with your next project? Have a look at the training support that I provide on the page https://www.atbash.be/training/ and contact me for more information.

Enjoy

Categories
Atbash JAX-RS MicroProfile

MicroProfile Rest Client for Java SE

Introduction

One of the cool specifications produced by the MicroProfile group is the Rest Client for MicroProfile  available from MP release 1.3.

It builds on top of the Client API of JAX-RS and allows you to use type-safe access to your endpoints without the need to programmatic interact with the Client API.

MicroProfile compliant server implementations need to implement this specification, but nothing says we cannot expand the usage into other environments (with a proper implementation) like use in Java SE (JavaFX seems must useful here) and plain Java EE.

Atbash has created an implementation of the specification so that it can be used in these environments and will use it within Octopus framework to propagate authentication and authorization information automatically in calls to JAX-RS endpoints.

The specification

A few words about the specification itself. JAX-RS 2.x contains a client API which allows you to access any ‘Rest’ endpoint in a uniform way.

Client client = ClientBuilder.newClient();
WebTarget employeeWebTarget = client.target("http://localhost:8080/demo/data").path("employees");
employeeWebTarget.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Employee>>() {
});

This client API is great because we can use it to call any endpoint, not even limited to Java ones. As long as they behave in a standard way.

But things can be improved, by moving away from the programmatic way of performing these calls, into a more declarative way.

If we could define some kind of interface like this

@Path("/employees")
public interface EmployeeService {

@GET
@Produces(MediaType.APPLICATION_JSON)
List<Employee> getAll();
}

And we just could ask an implementation of this interface which performs the required steps of creating the Client, WebTarget and invoke it for us in the background. This would make it much easier for the developer and makes it much more type-safe.

Creating the implementation of that interface is what MicroProfile Rest Client is all about.

The interface defined above can then be injected in any other CDI bean (need to add the @RegisterRestClient on the interface and preferably a CDI scope like @ApplicationScoped) and by calling the method, we actually perform a call to the endpoint and retrieve the result.

@Inject
@RestClient
private EmployeeService employeeService;

public void doSomethingWithEmployees() {
....
... employeeService.getAll();
....
}

Atbash Rest Client

The specification also allows for a programmatic retrieval of the implementation, for those scenarios where no CDI is available.
However, remember that if we are running inside a CDI container, we can always retrieve some CDI bean by using

CDI.current().select();

from within any method.

The programmatic retrieval is thus an ideal candidate to use it in other environments or frameworks like JavaFX (basically every Java SE program), Spring, Kotlin, etc …

The programmatic retrieval starts from the RestClientBuilder with the newBuilder() method.

EmployeeService employeeService = RestClientBuilder.newBuilder()
    .baseUrl(new URL("https://localhost:8080/server/data"))
    .build(EmployeeService.class);

The above retrieves also an implementation for the Employee retrieval endpoint we used earlier on in this text.

For more information about the features like Exception handling, adding custom providers and more, look at the specification document.

The Atbash Rest Client is an implementation in Java 7 which can run on Java SE. It is created mainly for the Octopus Framework to propagate the user authentication (like username) and authorization information (like permissions) to JAX-RS endpoints in a transparent, automatically way.

A ClientRequestFilter is created in Octopus which creates a JWT token (compatible with MicroProfile JWT auth specification) containing username and permissions of the current user and this Filter can then be added as a provider to the MicroProfile Rest Client to have this security information available within the header of the call.

Since the current Octopus version is still based on Java SE 7, no other existing implementation could be used (MicroProfile is Java SE 8 based). The implementation is based on the DeltaSpike Proxy features and uses any Client API compatible implementation which is available at runtime.

Compliant, not certified.

Since all the MicroProfile specifications are Java 8 based, the API is also converted to Java SE 7. Except for a few small incompatibilities, the port is 100% interchangeable.

The most notable difference is creating the builder with the newBuilder() method. In the original specification, this is a static method of an interface which is not allowed in Java 7. For that purpose, an abstract class is created, AbstractRestClientBuilder which contains the method.

Other than that, class and method names should be identical, which makes the switch from Atbash Rest Client to any other implementation using Java 8 very smooth.

The Maven dependency has following coordinates (available on Maven Central):

<dependency>
   <groupId>be.atbash.mp.rest-client</groupId>
   <artifactId>atbash-rest-client-impl</artifactId>
   <version>0.5</version>
</dependency>

If you are running on Java 8, you can use the Apache CXF MicroProfile Rest client

<dependency>
   <groupId>org.apache.cxf</groupId>
   <artifactId>cxf-rt-rs-mp-client</artifactId>
   <version>3.2.4</version>
</dependency>

Which also can be used in a plain Java SE environment. Other implementations like the ones within Liberty and Payara Micro aren’t useable standalone in Java SE.

Remark

This first release of Atbash Rest Client is a pre-release, meaning that not all features of the specification are completely implemented. It is just a bare minimum for the a POC within Octopus.
For example, the handling of exceptions (because the endpoint returned a status in the range 4xx or 5xx) isn’t completely covered yet.

The missing parts will be implemented or improved in a future version.

Conclusion

With the MicroProfile Rest Client specification, it becomes easy to call some JAX-RS endpoints in a type-safe way. By using a declarative method, calling some endpoint becomes as easy as calling any other method within the JVM.

And since micro-services need to be called at some point from non-micro-service code, Java SE executable implementation is very important. It makes it possible to call it from plain Java EE, Java SE, any other framework or a JVM based language.

Have fun.

Categories
JAX-RS Security

Http Signatures for End-To-End protection

Introduction

In a distributed system, it is not enough to know who called you, but you also need to make sure the data which you receive are not altered in transit.
The use of tokens (like Bearer JWT tokens according to the OpenId Connect or MicroProfile JWT Auth specifications) can be captured and briefly used to send fake request to your endpoints.
And SSL (like using HTTPS connections) cannot guarantee that your message isn’t read or altered by someone due to the possibilities of SSL Proxy termination or even Man In The Middle Intermediates who fakes correct SSL.

Encryption or protection

The solution is that your processes somehow make sure that the communication between them is ‘safe’. If the processes themselves (your client and your server application) perform these tasks and not some network layer (SSL, in fact, doesn’t fit in any OSI based network layer) of your (virtual) machine.

When your process is performing these tasks, it is possible to create a security context between the 2 processes and then each process can ensure or detect that the message is unaltered or can’t be read, regardless of any Proxy or Man In The Middle.

Whether you need encryption of the message (because you have confidential data) or signing (sensitive data) depends on the data. But at least you need the signing of the message so that we can guarantee the message is actually sent by someone we trust and isn’t altered.

Http Signatures

There is a standard created to have a mechanism to implement this kind of End To End Protection. It is called ‘HTTP Signatures’ and designed by the IETF. https://tools.ietf.org/id/draft-cavage-http-signatures-09.html

It is very HTTP friendly as it adds an additional header to the request. Within this header, enough information is placed so that the target process can verify if the message was altered or not.

This header is called Signature

Signature : keyId="rsa-key-1",algorithm="rsa-sha256",headers="(request-target) date digest content-length",signature="Base64(RSA-SHA256(signing string))"

The specification defines the structure and framework how the header should be created and the verification process must be performed but leaves a lot of freedom to the developer to tailor this protection to his/her needs.

The idea is that there is a signature calculated based on some parameters which are mostly just other headers. And by calculating them on the receiving side, we can verify if these values are changed.

These parameters are described within the headers parameter, and in the example, the following headers are used (request-target) date digest content-length

The values of these headers are concatenated (there exist a few rules about how to do it) and for this string, the cryptographic hash is calculated the signature.
The calculation is done using the value specified by the algorithm parameter (rsa-sha256 in our example above) and from the key with id rsa-key-1 is used for this in our example.
There are a number of crypto algorithms allowed, but RSA keys are the most popular ones.
This signature value is a binary, so a BASE64 encoded value is placed within the header.

In theory, all headers can be used but some of them are more interesting than other ones.
For example

  • (request-target) is a pseudo header value containing the concatenation of the http method and the path of the URL. If you like to include also the hostname (which can be interesting if you want to make sure that a request for the test environments never hits production, you can add the host header in the set of headers which needs to be used for the calculation of the signature value.
  • date header contains the timestamp when the request is created. This allows is to reject ‘old’ requests.
  • digest is very interesting when there is a payload send to the endpoint (like with put and post). This header contains then the hash value of the payload and is a key point in the end to end protection we are discussing here.

On the receiving side, the headers which are specified within the signature parameter are checked. Like

  • date is verified to be within a skew value from the system time
  • digest is verified to see if the header value is the same as the calculated hash value from the payload.

And of course, the signature is verified. Here we decode the signature value with the public key defined in the keyId parameter, using the algorithm specified.
And that value should match the calculated value from the headers.

Using Http Signatures

I have created a Proof Of Concept how this can be integrated with JAX-RS, client and server side.

For the server side, it is quite simple since you can add filters and interceptors easily by annotating them with @Provider. By just then indicating if this interceptor and filters should need to do their work, verification of the HTTP Signature, you are set to go.

@Path("/order")
@RestSignatureCheck
public class OrderController {

On the client side, you can register the required filters and WriterInterceptor manually with the Client. Something like this

Client client = ClientBuilder.newClient();
client.register(SignatureClientRequestFilter.class);
client.register(SignatureWriterInterceptor.class);

One thing is on the roadmap is to integrate it with the MicroProfile Rest Client way of working so that you can register the Signatures Feature and you’re done.

The initial code can be found on Github.

Conclusion

With the Http Signatures specification, you can add a header which can be used to verify if the message is changed or not. This is a nice non-intrusive way of having an End-To-End protection implement which can complement the SSL features to be sure that no intermediary party changes the message.

Have fun.