Skip to content

Commit

Permalink
add oauth client credentials to connectivity model
Browse files Browse the repository at this point in the history
Signed-off-by: Dominik Guggemos <dominik.guggemos@bosch.io>
  • Loading branch information
dguggemos committed Oct 28, 2021
1 parent 1d989d7 commit 283cfaa
Show file tree
Hide file tree
Showing 15 changed files with 434 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ abstract class JsonFields {
registerDeserializer(SshPublicKeyCredentials.TYPE, SshPublicKeyCredentials::fromJson);
registerDeserializer(UserPasswordCredentials.TYPE, UserPasswordCredentials::fromJson);
registerDeserializer(HmacCredentials.TYPE, HmacCredentials::fromJson);
registerDeserializer(OAuthClientCredentials.TYPE, OAuthClientCredentials::fromJson);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,13 @@ public interface CredentialsVisitor<T> {
* @since 2.1.0
*/
T hmac(HmacCredentials credentials);

/**
* Evaluate OAuth Client Credentials.
*
* @param credentials The OAuth Client Credentials.
* @return evaluation result.
* @since 2.2.0
*/
T oauthClientCredentials(OAuthClientCredentials credentials);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.connectivity.model;

import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull;

import java.util.Objects;

import javax.annotation.concurrent.Immutable;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;

/**
* Credentials used to retrieve a new access token using client credentials flow with the given
* client id, secret and scope.
*
* @since 2.2.0
*/
@Immutable
public final class OAuthClientCredentials implements Credentials {

/**
* Credential type name.
*/
public static final String TYPE = "oauth-client-credentials";

private final String tokenEndpoint;
private final String clientId;
private final String clientSecret;
private final String scope;

private OAuthClientCredentials(final String tokenEndpoint, final String clientId, final String clientSecret,
final String scope) {
this.tokenEndpoint = tokenEndpoint;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.scope = scope;
}

@Override
public <T> T accept(final CredentialsVisitor<T> visitor) {
return visitor.oauthClientCredentials(this);
}

/**
* @return the token endpoint
*/
public String getTokenEndpoint() {
return tokenEndpoint;
}

/**
* @return the client id
*/
public String getClientId() {
return clientId;
}

/**
* @return the client secret
*/
public String getClientSecret() {
return clientSecret;
}

/**
* @return the scope
*/
public String getScope() {
return scope;
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final OAuthClientCredentials that = (OAuthClientCredentials) o;
return tokenEndpoint.equals(that.tokenEndpoint) && clientId.equals(that.clientId) &&
clientSecret.equals(that.clientSecret) && scope.equals(that.scope);
}

@Override
public int hashCode() {
return Objects.hash(tokenEndpoint, clientId, clientSecret, scope);
}

@Override
public String toString() {
return getClass().getSimpleName() + " [" +
"tokenEndpoint=" + tokenEndpoint +
", clientId=" + clientId +
", clientSecret=" + clientSecret +
", scope=" + scope +
"]";
}

@Override
public JsonObject toJson() {
final JsonObjectBuilder jsonObjectBuilder = JsonFactory.newObjectBuilder();
jsonObjectBuilder.set(Credentials.JsonFields.TYPE, TYPE);
jsonObjectBuilder.set(JsonFields.TOKEN_ENDPOINT, tokenEndpoint, Objects::nonNull);
jsonObjectBuilder.set(JsonFields.CLIENT_ID, clientId, Objects::nonNull);
jsonObjectBuilder.set(JsonFields.CLIENT_SECRET, clientSecret, Objects::nonNull);
jsonObjectBuilder.set(JsonFields.SCOPE, scope, Objects::nonNull);
return jsonObjectBuilder.build();
}

static OAuthClientCredentials fromJson(final JsonObject jsonObject) {
final Builder builder = newBuilder();
jsonObject.getValue(JsonFields.TOKEN_ENDPOINT).ifPresent(builder::tokenEndpoint);
jsonObject.getValue(JsonFields.CLIENT_ID).ifPresent(builder::clientId);
jsonObject.getValue(JsonFields.CLIENT_SECRET).ifPresent(builder::clientSecret);
jsonObject.getValue(JsonFields.SCOPE).ifPresent(builder::scope);
return builder.build();
}

/**
* Create empty credentials with no certificates.
*
* @return empty credentials.
*/
public static OAuthClientCredentials empty() {
return newBuilder().build();
}

/**
* Create a new builder initialized with fields of this object.
*
* @return a new builder.
*/
public Builder toBuilder() {
return new Builder().clientId(clientId).clientSecret(clientSecret).tokenEndpoint(tokenEndpoint).scope(scope);
}

/**
* Create an empty builder.
*
* @return a new builder.
*/
public static Builder newBuilder() {
return new Builder();
}

/**
* Builder of {@code X509Credentials}.
*/
public static final class Builder {

private String tokenEndpoint;
private String clientId;
private String clientSecret;
private String scope;

/**
* @param tokenEndpoint the token endpoint
* @return this builder
*/
public Builder tokenEndpoint(final String tokenEndpoint) {
this.tokenEndpoint = checkNotNull(tokenEndpoint, "tokenEndpoint");
return this;
}

/**
* @param clientId the clientId
* @return this builder
*/
public Builder clientId(final String clientId) {
this.clientId = checkNotNull(clientId, "clientId");
;
return this;
}

/**
* @param clientSecret the clientSecret
* @return this builder
*/
public Builder clientSecret(final String clientSecret) {
this.clientSecret = checkNotNull(clientSecret, "clientSecret");
;
return this;
}

/**
* @param scope the scope
* @return this builder
*/
public Builder scope(final String scope) {
this.scope = checkNotNull(scope, "scope");
;
return this;
}

/**
* Build a new {@code OAuthClientCredentials}.
*
* @return the credentials.
*/
public OAuthClientCredentials build() {
return new OAuthClientCredentials(tokenEndpoint, clientId, clientSecret, scope);
}
}

/**
* JSON field definitions.
*/
public static final class JsonFields extends Credentials.JsonFields {

/**
* JSON field definition of OAuth token endpoint.
*/
public static final JsonFieldDefinition<String> TOKEN_ENDPOINT = JsonFieldDefinition.ofString("tokenEndpoint");

/**
* JSON field definition of client ID.
*/
public static final JsonFieldDefinition<String> CLIENT_ID = JsonFieldDefinition.ofString("id");

/**
* JSON field definition of client secret.
*/
public static final JsonFieldDefinition<String> CLIENT_SECRET = JsonFieldDefinition.ofString("secret");

/**
* JSON field definition of scope.
*/
public static final JsonFieldDefinition<String> SCOPE = JsonFieldDefinition.ofString("scope");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.connectivity.model;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf;
import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable;

import org.junit.Test;

import nl.jqno.equalsverifier.EqualsVerifier;

/**
* Tests {@link org.eclipse.ditto.connectivity.model.OAuthClientCredentials}.
*/
public final class OAuthClientCredentialsTest {

@Test
public void testHashCodeAndEquals() {
EqualsVerifier.forClass(OAuthClientCredentials.class).verify();
}

@Test
public void assertImmutability() {
assertInstancesOf(OAuthClientCredentials.class, areImmutable());
}

@Test
public void testJsonSerialization() {
final Credentials original = OAuthClientCredentials.newBuilder().clientId("clientId").clientSecret(
"clientSecret").scope("scope").tokenEndpoint("http://localhost/token").build();
final Credentials deserialized = Credentials.fromJson(original.toJson());
assertThat(deserialized).isEqualTo(original);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.ditto.connectivity.model.CredentialsVisitor;
import org.eclipse.ditto.connectivity.model.HmacCredentials;
import org.eclipse.ditto.connectivity.model.MessageSendingFailedException;
import org.eclipse.ditto.connectivity.model.OAuthClientCredentials;
import org.eclipse.ditto.connectivity.model.SshPublicKeyCredentials;
import org.eclipse.ditto.connectivity.model.UserPasswordCredentials;
import org.eclipse.ditto.connectivity.service.config.Amqp10Config;
Expand Down Expand Up @@ -89,12 +90,18 @@ public AmqpConnectionSigning hmac(final HmacCredentials credentials) {
}
}

@Override
public AmqpConnectionSigning oauthClientCredentials(final OAuthClientCredentials credentials) {
return NoOpSigning.INSTANCE;
}

/**
* The extension ID.
*/
public static final class Id extends AbstractExtensionId<AmqpConnectionSigningExtension> {

private static AmqpConnectionSigningFactory instantiate(final ExtendedActorSystem system, final String className) {
private static AmqpConnectionSigningFactory instantiate(final ExtendedActorSystem system,
final String className) {
final ClassTag<AmqpConnectionSigningFactory> tag =
scala.reflect.ClassTag$.MODULE$.apply(AmqpConnectionSigningFactory.class);
return system.dynamicAccess().createInstanceFor(className, List$.MODULE$.empty(), tag).get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.ditto.connectivity.model.CredentialsVisitor;
import org.eclipse.ditto.connectivity.model.HmacCredentials;
import org.eclipse.ditto.connectivity.model.MessageSendingFailedException;
import org.eclipse.ditto.connectivity.model.OAuthClientCredentials;
import org.eclipse.ditto.connectivity.model.SshPublicKeyCredentials;
import org.eclipse.ditto.connectivity.model.UserPasswordCredentials;
import org.eclipse.ditto.connectivity.service.config.DittoConnectivityConfig;
Expand Down Expand Up @@ -90,6 +91,11 @@ public HttpRequestSigning hmac(final HmacCredentials credentials) {
}
}

@Override
public HttpRequestSigning oauthClientCredentials(final OAuthClientCredentials credentials) {
return NoOpSigning.INSTANCE;
}

/**
* The extension ID.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.ditto.connectivity.model.ClientCertificateCredentials;
import org.eclipse.ditto.connectivity.model.CredentialsVisitor;
import org.eclipse.ditto.connectivity.model.HmacCredentials;
import org.eclipse.ditto.connectivity.model.OAuthClientCredentials;
import org.eclipse.ditto.connectivity.model.SshPublicKeyCredentials;
import org.eclipse.ditto.connectivity.model.UserPasswordCredentials;

Expand Down Expand Up @@ -108,4 +109,10 @@ public KeyManagerFactory sshPublicKeyAuthentication(final SshPublicKeyCredential
public KeyManagerFactory hmac(final HmacCredentials credentials) {
throw new UnsupportedOperationException("HMAC is not supported on certificate credentials authentication");
}

@Override
public KeyManagerFactory oauthClientCredentials(final OAuthClientCredentials credentials) {
throw new UnsupportedOperationException("OAuth client credentials is not supported on certificate credentials" +
" authentication");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.ditto.connectivity.model.ClientCertificateCredentials;
import org.eclipse.ditto.connectivity.model.CredentialsVisitor;
import org.eclipse.ditto.connectivity.model.HmacCredentials;
import org.eclipse.ditto.connectivity.model.OAuthClientCredentials;
import org.eclipse.ditto.connectivity.model.SshPublicKeyCredentials;
import org.eclipse.ditto.connectivity.model.UserPasswordCredentials;

Expand Down Expand Up @@ -70,4 +71,9 @@ public KeyPair sshPublicKeyAuthentication(final SshPublicKeyCredentials credenti
public KeyPair hmac(final HmacCredentials credentials) {
throw new UnsupportedOperationException("HMAC not supported");
}

@Override
public KeyPair oauthClientCredentials(final OAuthClientCredentials credentials) {
throw new UnsupportedOperationException("OAuthClientCredentials not supported");
}
}

0 comments on commit 283cfaa

Please sign in to comment.