Skip to content

Commit

Permalink
token-auth: add vault support
Browse files Browse the repository at this point in the history
Signed-off-by: Dominik Pinsel <dominik.pinsel@daimler.com>
  • Loading branch information
DominikPinsel committed Jun 28, 2022
1 parent 385be86 commit 0895729
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ in the detailed section referring to by linking pull requests or issues.
* Refactored query capabilities for `Asset` (#1459)
* Refactored query capabilities for `ContractDefinition` (#1458)
* Refactored state machine and in-memory persistence (#1511)
* Token based Authentication can retrieve key from vault (#1537)

#### Removed

Expand Down
19 changes: 19 additions & 0 deletions extensions/api/auth-tokenbased/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Token Based Authentication Service

The token based authentication service extension is used to secure connector APIs. These APIs are not protected by the `AuthenticationService` by default. To find out how a specific API is protected please consolidate its documentation.

APIs, protected by this extension, require a client to authenticate by adding a authentication key to the request header.

Authentication Header Example:
```
curl <url> --header "X-API-Key: <key>"
```

## Configuration

| Key | Description | Required |
|:---|:---|:---|
| edc.api.auth.key | API Key Header Value | false |
| edc.api.auth.key.alias | Secret name of the API Key Header Value, stored in the vault | false |

If no authentication key is defined, a random value is generated and printed out into the logs.
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
*
* Contributors:
* Microsoft Corporation - initial API and implementation
* Mercedes-Benz Tech Innovation GmbH - add README.md; authentication key can be retrieved from vault
*
*/

package org.eclipse.dataspaceconnector.api.auth;

import org.eclipse.dataspaceconnector.spi.EdcSetting;
import org.eclipse.dataspaceconnector.spi.security.Vault;
import org.eclipse.dataspaceconnector.spi.system.Inject;
import org.eclipse.dataspaceconnector.spi.system.Provides;
import org.eclipse.dataspaceconnector.spi.system.ServiceExtension;
import org.eclipse.dataspaceconnector.spi.system.ServiceExtensionContext;
Expand All @@ -27,11 +31,30 @@
*/
@Provides(AuthenticationService.class)
public class TokenBasedAuthenticationExtension implements ServiceExtension {

@EdcSetting
private static final String AUTH_SETTING_APIKEY = "edc.api.auth.key";

@EdcSetting
private static final String AUTH_SETTING_APIKEY_ALIAS = "edc.api.auth.key.alias";

@Inject
private Vault vault;

@Override
public void initialize(ServiceExtensionContext context) {
var apiKey = context.getSetting(AUTH_SETTING_APIKEY, UUID.randomUUID().toString());

String apiKey = null;

var apiKeyAlias = context.getSetting(AUTH_SETTING_APIKEY_ALIAS, null);

if (apiKeyAlias != null) {
apiKey = vault.resolveSecret(apiKeyAlias);
}

if (apiKey == null) {
apiKey = context.getSetting(AUTH_SETTING_APIKEY, UUID.randomUUID().toString());
}

context.getMonitor().info(format("API Authentication: using static API Key '%s'", apiKey));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2022 Mercedes-Benz Tech Innovation GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Mercedes-Benz Tech Innovation GmbH - initial implementation
*
*/

package org.eclipse.dataspaceconnector.api.auth;

import org.eclipse.dataspaceconnector.spi.monitor.Monitor;
import org.eclipse.dataspaceconnector.spi.security.Vault;
import org.eclipse.dataspaceconnector.spi.system.ServiceExtensionContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class TokenBasedAuthenticationExtensionTest {

private TokenBasedAuthenticationExtension extension;
private static final String REFLECTION_VAULT_FIELD_NAME = "vault";

private static final String AUTH_SETTING_APIKEY = "edc.api.auth.key";

private static final String AUTH_SETTING_APIKEY_ALIAS = "edc.api.auth.key.alias";

private static final String VAULT_KEY = "foo";

private Vault vaultMock = Mockito.mock(Vault.class);
private ServiceExtensionContext serviceExtensionContextMock = Mockito.mock(ServiceExtensionContext.class);

@BeforeEach
public void setUp()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
extension = new TokenBasedAuthenticationExtension();

var monitorMock = Mockito.mock(Monitor.class);

Mockito.when(serviceExtensionContextMock.getMonitor()).thenReturn(monitorMock);
Mockito.when(vaultMock.resolveSecret(VAULT_KEY))
.thenReturn("foo");

// "inject" vault
var field = TokenBasedAuthenticationExtension.class.getDeclaredField(REFLECTION_VAULT_FIELD_NAME);
field.setAccessible(true);
field.set(extension, vaultMock);
}

@Test
public void testPrimaryMethod_LoadKeyFromVault() {
setAuthSettingApiKeyAlias(VAULT_KEY);
setAuthSettingApiKey("bar");

extension.initialize(serviceExtensionContextMock);

Mockito.verify(serviceExtensionContextMock, Mockito.never())
.getSetting(Mockito.eq(AUTH_SETTING_APIKEY), Mockito.anyString());

Mockito.verify(serviceExtensionContextMock, Mockito.times(1))
.getSetting(AUTH_SETTING_APIKEY_ALIAS, null);

Mockito.verify(vaultMock, Mockito.times(1)).resolveSecret(VAULT_KEY);
}

@Test
public void testSecondaryMethod_LoadKeyFromConfig() {

setAuthSettingApiKeyAlias(null);
setAuthSettingApiKey("bar");

extension.initialize(serviceExtensionContextMock);

Mockito.verify(serviceExtensionContextMock, Mockito.times(1))
.getSetting(Mockito.eq(AUTH_SETTING_APIKEY), Mockito.anyString());

Mockito.verify(serviceExtensionContextMock, Mockito.times(1))
.getSetting(AUTH_SETTING_APIKEY_ALIAS, null);

Mockito.verify(vaultMock, Mockito.times(0)).resolveSecret(Mockito.anyString());
}

private void setAuthSettingApiKey(String value) {
Mockito.when(serviceExtensionContextMock.getSetting(Mockito.eq(AUTH_SETTING_APIKEY), Mockito.anyString()))
.thenReturn(value);
}

private void setAuthSettingApiKeyAlias(String value) {
Mockito.when(serviceExtensionContextMock.getSetting(Mockito.eq(AUTH_SETTING_APIKEY_ALIAS), Mockito.isNull()))
.thenReturn(value);
}
}

0 comments on commit 0895729

Please sign in to comment.