44 */
55package com .oracle .bmc .auth .sasl ;
66
7+ import com .google .common .base .Preconditions ;
78import com .google .protobuf .ByteString ;
89import com .google .protobuf .InvalidProtocolBufferException ;
910import com .oracle .bmc .auth .BasicAuthenticationDetailsProvider ;
1415import com .oracle .bmc .identity .auth .sasl .messages .OciSaslMessages .Key ;
1516import com .oracle .bmc .identity .auth .sasl .messages .OciSaslMessages .Response ;
1617import java .io .IOException ;
18+ import java .io .InputStream ;
1719import java .nio .ByteBuffer ;
1820import java .nio .charset .StandardCharsets ;
1921import java .security .interfaces .RSAPrivateKey ;
3133import javax .security .sasl .SaslClient ;
3234import javax .security .sasl .SaslClientFactory ;
3335import javax .security .sasl .SaslException ;
36+ import lombok .RequiredArgsConstructor ;
3437
3538/**
3639 * Implementation of a {@link SaslClient} for the OCI SASL mechanism.
@@ -49,6 +52,8 @@ public class OciSaslClient implements SaslClient {
4952 private final BasicAuthenticationDetailsProvider authProvider ;
5053 private final String intent ;
5154
55+ private OciPrivateKey currentPrivateKey = null ;
56+
5257 private State state = State .KEY_ID ;
5358
5459 private enum State {
@@ -89,22 +94,36 @@ public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
8994 }
9095
9196 private Key generateKeyMessage () {
92- // Get new token for each new key exchange to prevent stale keys
93- if (authProvider instanceof RefreshableOnNotAuthenticatedProvider ) {
94- ((RefreshableOnNotAuthenticatedProvider ) authProvider ).refresh ();
95- }
97+ // Because the authProvider might be used across multiple clients,
98+ // we need to protect its access while we generate and retrieve a new private key
99+ synchronized (authProvider ) {
100+ // Get a new token for each new key exchange to prevent stale keys
101+ if (authProvider instanceof RefreshableOnNotAuthenticatedProvider ) {
102+ ((RefreshableOnNotAuthenticatedProvider ) authProvider ).refresh ();
103+ }
96104
97- return Key .newBuilder ().setKeyId (authProvider .getKeyId ()).setIntent (intent ).build ();
105+ currentPrivateKey =
106+ new OciPrivateKey (
107+ authProvider .getKeyId (),
108+ authProvider .getPrivateKey (),
109+ authProvider .getPassphraseCharacters ());
110+
111+ return Key .newBuilder ().setKeyId (currentPrivateKey .keyId ).setIntent (intent ).build ();
112+ }
98113 }
99114
100115 private Response signChallenge (byte [] serializedChallenge ) throws SaslException {
101116
117+ Preconditions .checkArgument (currentPrivateKey != null );
118+
102119 final Challenge challenge = getAndValidateChallenge (serializedChallenge );
103120 final long epoch = OffsetDateTime .now ().toEpochSecond ();
104121
105122 final PEMFileRSAPrivateKeySupplier keySupplier =
106123 new PEMFileRSAPrivateKeySupplier (
107- authProvider .getPrivateKey (), authProvider .getPassphraseCharacters ());
124+ currentPrivateKey .privateKey , currentPrivateKey .passphraseCharacters );
125+
126+ currentPrivateKey = null ;
108127
109128 final RSAPrivateKey privateKey =
110129 keySupplier
@@ -285,4 +304,11 @@ static BasicAuthenticationDetailsProvider get(String key) {
285304 return authProvidersCache .get (key );
286305 }
287306 }
307+
308+ @ RequiredArgsConstructor
309+ private static final class OciPrivateKey {
310+ private final String keyId ;
311+ private final InputStream privateKey ;
312+ private final char [] passphraseCharacters ;
313+ }
288314}
0 commit comments