Skip to content

Commit

Permalink
Merge pull request #78 from boschglobal/feature-76
Browse files Browse the repository at this point in the history
feature(SDK): Add Support for Authentication
  • Loading branch information
Chrylo authored Feb 27, 2024
2 parents 26118f7 + bc36d30 commit 5b92b2b
Show file tree
Hide file tree
Showing 32 changed files with 832 additions and 276 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
retention-days: 14

- name: Run 'test' with Gradle Wrapper
run: ./gradlew test -Dkotest.tags="!Secure"
run: ./gradlew test -Dkotest.tags="!CustomDatabroker"

- name: Upload Test Reports
uses: actions/upload-artifact@v3
Expand Down
23 changes: 0 additions & 23 deletions .run/kuksa-sdk_IntegrationSecureTests.run.xml

This file was deleted.

3 changes: 2 additions & 1 deletion .run/kuksa-sdk_IntegrationTests.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
<option value=":kuksa-sdk:testDebugUnitTest" />
</list>
</option>
<option name="vmOptions" value="-Dkotest.tags=&quot;Integration &amp; !Secure&quot;" />
<option name="vmOptions" value="-Dkotest.tags=&quot;Integration &amp; DefaultDatabroker&quot;" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package org.eclipse.kuksa.testapp.databroker;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

Expand All @@ -29,114 +28,48 @@
import org.eclipse.kuksa.DataBrokerConnector;
import org.eclipse.kuksa.DisconnectListener;
import org.eclipse.kuksa.PropertyListener;
import org.eclipse.kuksa.TimeoutConfig;
import org.eclipse.kuksa.VssSpecificationListener;
import org.eclipse.kuksa.model.Property;
import org.eclipse.kuksa.proto.v1.KuksaValV1.GetResponse;
import org.eclipse.kuksa.proto.v1.KuksaValV1.SetResponse;
import org.eclipse.kuksa.proto.v1.Types;
import org.eclipse.kuksa.proto.v1.Types.Datapoint;
import org.eclipse.kuksa.testapp.databroker.model.Certificate;
import org.eclipse.kuksa.testapp.databroker.connection.DataBrokerConnectorFactory;
import org.eclipse.kuksa.testapp.databroker.model.ConnectionInfo;
import org.eclipse.kuksa.vsscore.model.VssSpecification;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

import io.grpc.ChannelCredentials;
import io.grpc.Grpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.TlsChannelCredentials;

public class JavaDataBrokerEngine implements DataBrokerEngine {
private static final String TAG = JavaDataBrokerEngine.class.getSimpleName();
private static final long TIMEOUT_CONNECTION = 5;

@Nullable
private DataBrokerConnection dataBrokerConnection = null;

private final DataBrokerConnectorFactory connectorFactory = new DataBrokerConnectorFactory();
private final Set<DisconnectListener> disconnectListeners = new HashSet<>();

// Too many to usefully handle: Checked Exceptions: IOE, RuntimeExceptions: UOE, ISE, IAE, ...
@SuppressWarnings("TooGenericExceptionCaught")
public void connect(
@NonNull Context context,
@NonNull ConnectionInfo connectionInfo,
@NonNull CoroutineCallback<DataBrokerConnection> callback
) {
if (connectionInfo.isTlsEnabled()) {
connectSecure(context, connectionInfo, callback);
} else {
connectInsecure(connectionInfo, callback);
}
}

private void connectInsecure(
@NonNull ConnectionInfo connectInfo,
@NonNull CoroutineCallback<DataBrokerConnection> callback
) {
try {
ManagedChannel managedChannel = ManagedChannelBuilder
.forAddress(connectInfo.getHost(), connectInfo.getPort())
.usePlaintext()
.build();

connect(managedChannel, callback);
} catch (IllegalArgumentException e) {
callback.onError(e);
}
}

private void connectSecure(
@NotNull Context context,
@NotNull ConnectionInfo connectInfo,
@NotNull CoroutineCallback<DataBrokerConnection> callback
) {
Certificate certificate = connectInfo.getCertificate();

ChannelCredentials tlsCredentials;
try {
InputStream rootCertFile = context.getContentResolver().openInputStream(certificate.getUri());
if (rootCertFile == null) return;

tlsCredentials = TlsChannelCredentials.newBuilder()
.trustManager(rootCertFile)
.build();
} catch (IOException e) {
Log.w(TAG, "Could not find file for certificate: " + certificate);

return;
}

try {
ManagedChannelBuilder<?> channelBuilder = Grpc
.newChannelBuilderForAddress(connectInfo.getHost(), connectInfo.getPort(), tlsCredentials);

String overrideAuthority = certificate.getOverrideAuthority().trim();
boolean hasOverrideAuthority = !overrideAuthority.isEmpty();
if (hasOverrideAuthority) {
channelBuilder.overrideAuthority(overrideAuthority);
}

ManagedChannel managedChannel = channelBuilder.build();
connect(managedChannel, callback);
} catch (IllegalArgumentException e) {
DataBrokerConnector connector = connectorFactory.create(context, connectionInfo);
connect(connector, callback);
} catch (Exception e) {
callback.onError(e);
}
}

private void connect(
@NonNull ManagedChannel managedChannel,
@NonNull DataBrokerConnector connector,
@NonNull CoroutineCallback<DataBrokerConnection> callback
) {
DataBrokerConnector connector = new DataBrokerConnector(managedChannel);
connector.setTimeoutConfig(new TimeoutConfig(TIMEOUT_CONNECTION, TimeUnit.SECONDS));
connector.connect(new CoroutineCallback<>() {
@Override
public void onSuccess(@Nullable DataBrokerConnection result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,106 +21,45 @@ package org.eclipse.kuksa.testapp.databroker

import android.content.Context
import androidx.lifecycle.LifecycleCoroutineScope
import io.grpc.ChannelCredentials
import io.grpc.Grpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import io.grpc.TlsChannelCredentials
import kotlinx.coroutines.launch
import org.eclipse.kuksa.CoroutineCallback
import org.eclipse.kuksa.DataBrokerConnection
import org.eclipse.kuksa.DataBrokerConnector
import org.eclipse.kuksa.DataBrokerException
import org.eclipse.kuksa.DisconnectListener
import org.eclipse.kuksa.PropertyListener
import org.eclipse.kuksa.TimeoutConfig
import org.eclipse.kuksa.VssSpecificationListener
import org.eclipse.kuksa.model.Property
import org.eclipse.kuksa.proto.v1.KuksaValV1.GetResponse
import org.eclipse.kuksa.proto.v1.KuksaValV1.SetResponse
import org.eclipse.kuksa.proto.v1.Types.Datapoint
import org.eclipse.kuksa.testapp.databroker.connection.DataBrokerConnectorFactory
import org.eclipse.kuksa.testapp.databroker.model.ConnectionInfo
import org.eclipse.kuksa.vsscore.model.VssSpecification
import java.io.IOException

@Suppress("complexity:TooManyFunctions")
class KotlinDataBrokerEngine(
private val lifecycleScope: LifecycleCoroutineScope,
) : DataBrokerEngine {
override var dataBrokerConnection: DataBrokerConnection? = null

private val connectorFactory = DataBrokerConnectorFactory()
private val disconnectListeners = mutableSetOf<DisconnectListener>()

// Too many to usefully handle: Checked Exceptions: IOE, RuntimeExceptions: UOE, ISE, IAE, ...
@Suppress("TooGenericExceptionCaught")
override fun connect(
context: Context,
connectionInfo: ConnectionInfo,
callback: CoroutineCallback<DataBrokerConnection>,
) {
if (connectionInfo.isTlsEnabled) {
connectSecure(context, connectionInfo, callback)
} else {
connectInsecure(connectionInfo, callback)
}
}

private fun connectInsecure(
connectInfo: ConnectionInfo,
callback: CoroutineCallback<DataBrokerConnection>,
) {
try {
val managedChannel = ManagedChannelBuilder
.forAddress(connectInfo.host, connectInfo.port)
.usePlaintext()
.build()

connect(managedChannel, callback)
} catch (e: IllegalArgumentException) {
callback.onError(e)
}
}

private fun connectSecure(
context: Context,
connectInfo: ConnectionInfo,
callback: CoroutineCallback<DataBrokerConnection>,
) {
val certificate = connectInfo.certificate

val tlsCredentials: ChannelCredentials
try {
val rootCertFile = context.contentResolver.openInputStream(certificate.uri)
tlsCredentials = TlsChannelCredentials.newBuilder()
.trustManager(rootCertFile)
.build()
} catch (e: IOException) {
val connector: DataBrokerConnector = try {
connectorFactory.create(context, connectionInfo)
} catch (e: Exception) {
callback.onError(e)
return
}

try {
val host = connectInfo.host.trim()
val port = connectInfo.port
val channelBuilder = Grpc
.newChannelBuilderForAddress(host, port, tlsCredentials)

val overrideAuthority = certificate.overrideAuthority.trim()
val hasOverrideAuthority = overrideAuthority.isNotEmpty()
if (hasOverrideAuthority) {
channelBuilder.overrideAuthority(overrideAuthority)
}

val managedChannel = channelBuilder.build()
connect(managedChannel, callback)
} catch (e: IllegalArgumentException) {
callback.onError(e)
}
}

private fun connect(managedChannel: ManagedChannel, callback: CoroutineCallback<DataBrokerConnection>) {
val connector = DataBrokerConnector(managedChannel).apply {
timeoutConfig = TimeoutConfig(TIMEOUT_CONNECTION_SEC)
}

lifecycleScope.launch {
try {
dataBrokerConnection = connector.connect()
Expand Down Expand Up @@ -206,8 +145,4 @@ class KotlinDataBrokerEngine(
disconnectListeners.remove(listener)
dataBrokerConnection?.disconnectListeners?.unregister(listener)
}

companion object {
const val TIMEOUT_CONNECTION_SEC = 5L
}
}
Loading

0 comments on commit 5b92b2b

Please sign in to comment.