This repository contains utility libraries for GXF java applications.
The library makes it possible to configure OAUTH Kafka authentication using environment variables
OAuth is enabled by setting the kafka-oauth profile.
The following environment variables are required:
AZURE_CLIENT_ID: client id of the oauth serverAZURE_AUTHORITY_HOST: url of the oauth server (ex: http://oauth-server.com/)AZURE_TENANT_ID: Tenant id of the oauth resourceAZURE_FEDERATED_TOKEN_FILE: File containing the oauth token.OAUTH_SCOPE: Scope of the oauth client
Library containing a Kafka serializer and deserializer for avro objects.
It can be configured with the encoder / decoder of a specific object using:
new DefaultKafkaConsumerFactory(
kafkaProperties.buildConsumerProperties(),
ErrorHandlingDeserializer(AvroSerializer(AvroMessage.getEncoder())),
ErrorHandlingDeserializer(AvroDeserializer(AvroMessage.getDecoder()))
)Library for signing Kafka messages and for verification of signed Kafka messages.
Two variations of signing messages are supported:
- The signature is set as a
signatureheader on the KafkaProducerRecord. - The signature is set on a field of the message, via
FlexibleSignableMessageWrapper;
Also, you can choose to use the MessageSigner class directly or use one of the message signing Kafka ProducerInterceptors that sign messages automatically when sent.
For verification, you always need to use the MessageSigner class directly.
Wrapping messages is required when using the 'sign using field' method.
Here's how to wrap your message in FlexibleSignableMessageWrapper:
class MyMessage(val body: String, var sig: ByteBuffer? = null)
val myMessage = MyMessage(body = "Hello, GXF!")
val wrapped : FlexibleSignableMessageWrapper<MyMessage> = FlexibleSignableMessageWrapper(
myMessage,
messageGetter = { msg -> ByteBuffer.wrap(msg.body.toByteArray()) },
signatureGetter = { msg -> msg.sig },
signatureSetter = { msg, sig -> msg.sig = sig }
)The MessageSigner class is used for both signing and verifying a signature.
To sign messages automatically when producing messages to Kafka, you can use one of these beans for producer properties in the Kafka configuration (use @Qualifier to select the correct one):
producerPropertiesForByteArrayRecordsproducerPropertiesForAvroRecords
@Bean
fun producerFactory(
@Qualifier("producerPropertiesForByteArrayRecords") producerProperties: Map<String, Any>,
): ProducerFactory<String, ByteArray> =
DefaultKafkaProducerFactory(
producerProperties,
StringSerializer(),
ByteArraySerializer(),
)To sign a message using the MessageSigner class directly, use one of MessageSigner's sign methods:
signUsingField(...)using theFlexibleSignableMessageWrapperto wrap your Avro object;signUsingHeader(...)to add the signature to the Avro object's header.
To verify a signature, use one of MessageSigner's verify methods:
verifyUsingField(...)using theFlexibleSignableMessageWrapperto wrap your Avro object;verifyUsingHeader(...)to read the signature from the Avro object's header.
You can configure the settings in your application.yaml (or properties), for example:
message-signing:
signing-enabled: true
strip-avro-header: true
signature-algorithm: SHA256withRSA
signature-provider: SunRsaSign
key-algorithm: RSA
private-key-file: classpath:rsa-private.pem
public-key-file: classpath:rsa-public.pemYou can create your own MessageSigningProperties object and use MessageSigner.newMessageSigner(props).
Spring Boot users can extend the MessageSigningProperties to add @ConfigurationProperties capabilities and/or to
support multiple configurations.
If you want to support multiple keys, you also have to instantiate multiple MessageSigner beans.
Auto configuration (see above) will see when you defined your own MessageSigner or MessageSigningProperties bean and will not auto-create one.
@ConfigurationProperties(prefix = "your-app.your-message-signing")
class YourMessageSigningProperties extends MessageSigningProperties {
}
@Configuration
class MessageSigningConfiguration {
@Bean
public MessageSigner yourMessageSigner(YourMessageSigningProperties yourMessageSigningProperties) {
return new MessageSigner(yourMessageSigningProperties);
}
}To generate a public/private keypair, use these two commands:
openssl genrsa -out rsa-private.pem 2048
openssl rsa -in rsa-private.pem -pubout -out rsa-public.pemThe private key (PKCS#8) and public key can then be set in the configuration as shown above. To view the generated files, you can use
openssl rsa -noout -text -in rsa-private.pem
openssl rsa -noout -text -pubin -in rsa-public.pemLibrary that easily configures the msal4j oauth token provider.
The client requires the following properties:
# If not set to true no other configuration is required
oauth.client.enabled=true
oauth.client.token-endpoint=https://localhost:56788/token
oauth.client.client-id=client-id
oauth.client.scope=client-scope
# Resources
oauth.client.private-key=classpath:keys/private-key.key
oauth.client.certificate=classpath:keys/certificate.crtLibrary for signing OSLP messages and for verification of signed OSLP messages with two methods:
- createSignature() to create a signature for an OSLP message based on the private key
- verifySignature() to verify the signature of an OSLP message based on the public key
The keys can be provided through the KeyProvider interface, which can be implemented to provide custom key retrieval logic.
The SigningUtil class use the security provider SunRsaSign and the algorithm SHA256withRSA as defaults.
Autoconfiguration is available for Spring Boot applications to change these defaults.