-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from project-kessel/RHCLOUD-32406-Java-client-…
…client-credentials-flow Rhcloud 32406 java client client credentials flow
- Loading branch information
Showing
21 changed files
with
1,652 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
src/main/java/org/project_kessel/relations/client/authn/CallCredentialsFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.project_kessel.relations.client.authn; | ||
|
||
import io.grpc.CallCredentials; | ||
import org.project_kessel.relations.client.Config; | ||
import org.project_kessel.relations.client.authn.oidc.client.OIDCClientCredentialsCallCredentials; | ||
|
||
public class CallCredentialsFactory { | ||
|
||
private CallCredentialsFactory() { | ||
|
||
} | ||
|
||
public static CallCredentials create(Config.AuthenticationConfig authnConfig) throws CallCredentialsCreationException { | ||
if (authnConfig == null) { | ||
throw new CallCredentialsCreationException("AuthenticationConfig is required to create CallCredentials and must not be null."); | ||
} | ||
|
||
try { | ||
switch (authnConfig.mode()) { | ||
case DISABLED: return null; | ||
case OIDC_CLIENT_CREDENTIALS: return new OIDCClientCredentialsCallCredentials(authnConfig); | ||
} | ||
} catch (OIDCClientCredentialsCallCredentials.OIDCClientCredentialsCallCredentialsException e) { | ||
throw new CallCredentialsCreationException("Failed to create OIDCClientCredentialsCallCredentials.", e); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public static class CallCredentialsCreationException extends Exception { | ||
public CallCredentialsCreationException(String message) { | ||
super(message); | ||
} | ||
|
||
public CallCredentialsCreationException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
...oject_kessel/relations/client/authn/oidc/client/OIDCClientCredentialsCallCredentials.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package org.project_kessel.relations.client.authn.oidc.client; | ||
|
||
import io.grpc.Metadata; | ||
import io.grpc.Status; | ||
import org.project_kessel.relations.client.Config; | ||
|
||
import java.util.Optional; | ||
import java.util.concurrent.Executor; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
public class OIDCClientCredentialsCallCredentials extends io.grpc.CallCredentials { | ||
static final Metadata.Key<String> authorizationKey = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER); | ||
|
||
private final Config.OIDCClientCredentialsConfig clientCredentialsConfig; | ||
private final OIDCClientCredentialsMinter minter; | ||
|
||
private final AtomicReference<OIDCClientCredentialsMinter.BearerHeader> storedBearerHeaderRef = new AtomicReference<>(); | ||
|
||
public OIDCClientCredentialsCallCredentials(Config.AuthenticationConfig authnConfig) throws OIDCClientCredentialsCallCredentialsException { | ||
this.clientCredentialsConfig = validateAndExtractConfig(authnConfig); | ||
|
||
Optional<String> minterImpl = clientCredentialsConfig.oidcClientCredentialsMinterImplementation(); | ||
try { | ||
if(minterImpl.isPresent()) { | ||
this.minter = OIDCClientCredentialsMinter.forName(minterImpl.get()); | ||
} else { | ||
this.minter = OIDCClientCredentialsMinter.forDefaultImplementation(); | ||
} | ||
} catch (OIDCClientCredentialsMinter.OIDCClientCredentialsMinterException e) { | ||
throw new OIDCClientCredentialsCallCredentialsException("Couldn't create GrpcCallCredentials because minter impl not instantiated.", e); | ||
} | ||
} | ||
|
||
OIDCClientCredentialsCallCredentials(Config.OIDCClientCredentialsConfig clientCredentialsConfig, OIDCClientCredentialsMinter minter) { | ||
this.clientCredentialsConfig = clientCredentialsConfig; | ||
this.minter = minter; | ||
} | ||
|
||
@Override | ||
public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) { | ||
appExecutor.execute(() -> { | ||
try { | ||
synchronized (storedBearerHeaderRef) { | ||
if (storedBearerHeaderRef.get() == null || storedBearerHeaderRef.get().isExpired()) { | ||
storedBearerHeaderRef.set(minter.authenticateAndRetrieveAuthorizationHeader(clientCredentialsConfig)); | ||
} | ||
|
||
Metadata headers = new Metadata(); | ||
headers.put(authorizationKey, storedBearerHeaderRef.get().getAuthorizationHeader()); | ||
applier.apply(headers); | ||
} | ||
} catch (Exception e) { | ||
applier.fail(Status.UNAUTHENTICATED.withCause(e)); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* For unusual cases where stored credentials (i.e. token), which may be long-lived, is bad and needs to be flushed. | ||
*/ | ||
public void flushStoredCredentials() { | ||
synchronized (storedBearerHeaderRef) { | ||
storedBearerHeaderRef.set(null); | ||
} | ||
} | ||
|
||
/* We don't know that smallrye config validation will be used by clients, so do some validation here. */ | ||
static Config.OIDCClientCredentialsConfig validateAndExtractConfig(Config.AuthenticationConfig authnConfig) throws OIDCClientCredentialsCallCredentialsException { | ||
if (authnConfig.clientCredentialsConfig().isEmpty()) { | ||
throw new OIDCClientCredentialsCallCredentialsException("ClientCredentialsConfig is required for OIDC client credentials authentication method."); | ||
} | ||
if(authnConfig.clientCredentialsConfig().get().issuer() == null) { | ||
throw new OIDCClientCredentialsCallCredentialsException("ClientCredentialsConfig Issuer must not be null."); | ||
} | ||
if(authnConfig.clientCredentialsConfig().get().clientId() == null) { | ||
throw new OIDCClientCredentialsCallCredentialsException("ClientCredentialsConfig Client id must not be null."); | ||
} | ||
if(authnConfig.clientCredentialsConfig().get().clientSecret() == null) { | ||
throw new OIDCClientCredentialsCallCredentialsException("ClientCredentialsConfig Client secret must not be null."); | ||
} | ||
|
||
return authnConfig.clientCredentialsConfig().get(); | ||
} | ||
|
||
public static class OIDCClientCredentialsCallCredentialsException extends Exception { | ||
public OIDCClientCredentialsCallCredentialsException(String message) { | ||
super(message); | ||
} | ||
|
||
public OIDCClientCredentialsCallCredentialsException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.