Chapter 6. Changes in Eclipse Vert.x authentication and authorization The following sections describe the changes in Eclipse Vert.x authentication and authorization. The Eclipse Vert.x authentication module has major updates in Eclipse Vert.x 4. The io.vertx.ext.auth.AuthProvider interface has been split into two new interfaces: io.vertx.ext.auth.authentication.AuthenticationProvider Important Authentication feature is provided as Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. See Technology Preview Features Support Scope on the Red Hat Customer Portal for information about the support scope for Technology Preview features. io.vertx.ext.auth.authorization.AuthorizationProvider This update enables any provider to independently perform either authentication and authorization. 6.1. Migrating the authentication applications The authentication mechanism has changed at the result level. In earlier releases, the result was a User object, which was provider specific. In Eclipse Vert.x 4, the result is a common implementation of io.vertx.ext.auth.User . The following example shows how a user was authenticated in Eclipse Vert.x 3.x releases. JsonObject authInfo = new JsonObject() .put("username", "john") .put("password", "superUSDecret"); // omitting the error handling for brevity provider.authenticate(authInfo, res -> { if (res.succeeded()) { // may require type casting for example on Oauth2 User user = res.result(); } }); The following example shows how to authenticate a user in Eclipse Vert.x 4. JsonObject authInfo = new JsonObject() .put("username", "john") .put("password", "superUSDecret"); // omitting the error handling for brevity provider.authenticate(authInfo, res -> { if (res.succeeded()) { // Never needs type casting User user = res.result(); } }); 6.2. Migrating the authorization applications Authorization is a new feature in Eclipse Vert.x 4. In earlier releases, you could only check if a user was authorized to perform the tasks on the User object. This meant that the provider was responsible for both authentication and authorization of the user. In Eclipse Vert.x 4, the User object instances are not associated with a particular authentication provider. So you can authenticate and authorize a user using different providers. For example, you can authenticate a user using OAuth2 and perform authorization checks against MongoDB or SQL database. The following example shows how an application checks if a user can use Printer #1234 in Eclipse Vert.x 3.x releases. // omitting the error handling for brevity user.isAuthorized("printers:printer1234", res -> { if (res.succeeded()) { boolean hasAuthority = res.result(); if (hasAuthority) { System.out.println("User can use the printer"); } else { System.out.println("User cannot use the printer"); } } }); This authorization worked for JDBC and MongoDB. However it did not work for providers such as OAuth2, because the provider did not perform authorization checks. From Eclipse Vert.x 4, it is possible to perform such authorization checks by using different providers. // omitting the error handling for brevity provider.getAuthorizations(user, res -> { if (res.succeeded()) { if (PermissionBasedAuthorization.create("printer1234").match(user)) { System.out.println("User can use the printer"); } else { System.out.println("User cannot use the printer"); } } }); You can check authorizations on roles, permissions, logic operations, wildcards and any other implementation you add. 6.3. Changes in key management In Eclipse Vert.x 4, there are major updates in handling keys. The most important change is that when a key loads, there is no distinction between public buffer and private buffer. The following classes have been updated: io.vertx.ext.auth.KeyStoreOptions used to work with jce keystores io.vertx.ext.auth.SecretOptions used to handle symmetric secrets io.vertx.ext.auth.PubSecKeyOptions used to handle public secret keys The following section describes the changes in key management. 6.3.1. Secret options class is no longer available The SecretOptions class is no longer available. Use the new PubSecKeyOptions class instead to work with a cryptographic key. The following example shows how methods of SecretOptions class were used in Eclipse Vert.x 3.x releases. new SecretOptions() .setType("HS256") .setSecret("password") The following example shows how methods of PubSecKeyOptions class should be used in Eclipse Vert.x 4. new PubSecKeyOptions() .setAlgorithm("HS256") .setSecretKey("password") 6.3.2. Updates in public secret keys management In Eclipse Vert.x 3.x, the configuration object in public secret key management assumed that: Keys are configured as key-pairs. Key data is a PKCS8 encoded string without standard delimiters. The following example shows how to configure key pair in Eclipse Vert.x 3.x. new PubSecKeyOptions() .setPublicKey( // remove the PEM boundaries pubPemString .replaceAll("-----BEGIN PUBLIC KEY----") .replaceAll("-----END PUBLIC KEY----")) .setSecretKey( // remove the PEM boundaries secPemString .replaceAll("-----BEGIN PUBLIC KEY----") .replaceAll("-----END PUBLIC KEY----")); In Eclipse Vert.x 4, you must specify both the public and private key. The following example shows how to configure key pair in Eclipse Vert.x 4. PubSecKeyOptions pubKey = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(pubPemString); PubSecKeyOptions secKey = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(secPemString); You can now handle X509 certificates using PubSecKeyOptions . PubSecKeyOptions x509Certificate = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(x509PemString); 6.3.3. Changes in keystore management In Eclipse Vert.x 3.x, KeyStoreOptions assumes that the keystore format is jceks , and the stored password is the same as the password of the key. As jceks is a proprietary format, it is recommended to use a standard format, such as JDK, instead. When you use KeyStoreOptions in Eclipse Vert.x 4, you can specify a store type. For example, store types such as PKCS11, PKCS12, and so on can be set. The default store type is jceks . In Eclipse Vert.x 3.x, all keystore entries would share the same password, that is, the keystore password. In Eclipse Vert.x 4, each keystore entry can have a dedicated password. If you do not want to set password for each keystore entry, you can configure the keystore password as the default password for all entries. The following example shows how to load a jceks keystore in Eclipse Vert.x 3.x. new KeyStoreOptions() .setPath("path/to/keystore.jks") .setPassword("keystore-password"); In Eclipse Vert.x 4, the default format is assumed to be the default format configured by JDK. The format is PKCS12 in Java 9 and above. The following example shows how to load a jceks keystore in Eclipse Vert.x 4. new KeyStoreOptions() .setPath("path/to/keystore.jks") // Modern JDKs use `jceks` keystore. But this type is not the default // If the type is not set to `jceks` then probably `pkcs12` will be used .setType("jceks") .setPassword("keystore-password") // optionally if your keys have different passwords // and if a key specific id is not provided it defaults to // the keystore password .putPasswordProtection("key-id", "key-specific-password"); 6.4. Deprecated and removed authentication and authorization methods The following sections list methods deprecated and removed for authentication and authorization. 6.4.1. List of removed authentication and authorization methods The following methods have been removed: Removed methods Replacing methods OAuth2Auth.createKeycloak() KeycloakAuth.create(vertx, JsonObject) () OAuth2Auth.create(Vertx, OAuth2FlowType, OAuth2ClientOptions)() OAuth2Auth.create(vertx, new OAuth2ClientOptions().setFlow(YOUR_DESIRED_FLOW)) OAuth2Auth.create(Vertx, OAuth2FlowType) OAuth2Auth.create(vertx, new OAuth2ClientOptions().setFlow(YOUR_DESIRED_FLOW)) User.isAuthorised() User.isAuthorized() User.setAuthProvider() No replacing method AccessToken.refreshToken() AccessToken.opaqueRefreshToken() io.vertx.ext.auth.jwt.JWTOptions data object io.vertx.ext.jwt.JWTOptions data object Oauth2ClientOptions.isUseAuthorizationHeader() No replacing method Oauth2ClientOptions.scopeSeparator() No replacing method 6.4.2. List of deprecated authentication and authorization methods The following methods have been deprecated: Deprecated methods Replacing methods OAuth2Auth.decodeToken() AuthProvider.authenticate() OAuth2Auth.introspectToken() AuthProvider.authenticate() OAuth2Auth.getFlowType() No replacing method OAuth2Auth.loadJWK() OAuth2Auth.jwkSet() Oauth2ClientOptions.isUseAuthorizationHeader() No replacing method 6.4.3. List of deprecated authentication and authorization classes The following classes have been deprecated: Deprecated class Replacing class AbstractUser Create user objects using the ` User.create(JsonObject)` method. AuthOptions No replacing class JDBCAuthOptions JDBCAuthenticationOptions for authentication and JDBCAuthorizationOptions for authorization JDBCHashStrategy No replacing class OAuth2RBAC AuthorizationProvider Oauth2Response Recommended to use WebClient class KeycloakHelper No replacing class

Commands:
JsonObject authInfo = new JsonObject() .put("username", "john") .put("password", "superUSDecret"); // omitting the error handling for brevity provider.authenticate(authInfo, res -> { if (res.succeeded()) { // may require type casting for example on Oauth2 User user = res.result(); } });
JsonObject authInfo = new JsonObject() .put("username", "john") .put("password", "superUSDecret"); // omitting the error handling for brevity provider.authenticate(authInfo, res -> { if (res.succeeded()) { // Never needs type casting User user = res.result(); } });
// omitting the error handling for brevity user.isAuthorized("printers:printer1234", res -> { if (res.succeeded()) { boolean hasAuthority = res.result(); if (hasAuthority) { System.out.println("User can use the printer"); } else { System.out.println("User cannot use the printer"); } } });
// omitting the error handling for brevity provider.getAuthorizations(user, res -> { if (res.succeeded()) { if (PermissionBasedAuthorization.create("printer1234").match(user)) { System.out.println("User can use the printer"); } else { System.out.println("User cannot use the printer"); } } });
new SecretOptions() .setType("HS256") .setSecret("password")
new PubSecKeyOptions() .setAlgorithm("HS256") .setSecretKey("password")
new PubSecKeyOptions() .setPublicKey( // remove the PEM boundaries pubPemString .replaceAll("-----BEGIN PUBLIC KEY----") .replaceAll("-----END PUBLIC KEY----")) .setSecretKey( // remove the PEM boundaries secPemString .replaceAll("-----BEGIN PUBLIC KEY----") .replaceAll("-----END PUBLIC KEY----"));
PubSecKeyOptions pubKey = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(pubPemString); PubSecKeyOptions secKey = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(secPemString);
PubSecKeyOptions x509Certificate = new PubSecKeyOptions() // the buffer is the exact contents of the PEM file and had boundaries included in it .setBuffer(x509PemString);
new KeyStoreOptions() .setPath("path/to/keystore.jks") .setPassword("keystore-password");
new KeyStoreOptions() .setPath("path/to/keystore.jks") // Modern JDKs use `jceks` keystore. But this type is not the default // If the type is not set to `jceks` then probably `pkcs12` will be used .setType("jceks") .setPassword("keystore-password") // optionally if your keys have different passwords // and if a key specific id is not provided it defaults to // the keystore password .putPasswordProtection("key-id", "key-specific-password");