Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

564818 API revision | conditions | key keepers review #282

Merged
merged 5 commits into from
Jul 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
public interface DigestExpectation {

/**
* @return is there is any expectation at all
* @return {@code true} if there is any expectation at all, {@code false} if
* digest is not intended to be used for a key verification
*/
boolean expected();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@
import java.nio.file.Paths;

import org.eclipse.passage.lic.api.LicensingConfiguration;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension.LicenseDecrypted;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension.LicenseEncrypted;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension.PublicKey;
import org.eclipse.passage.lic.internal.base.io.FileNameFromLicensedProduct;
import org.eclipse.passage.lic.internal.base.io.LicensingFolder;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension;
import org.eclipse.passage.lic.internal.base.io.PathFromLicensedProduct;
import org.eclipse.passage.lic.internal.base.io.PathFromLocalUrl;

Expand All @@ -39,17 +37,17 @@ public final class LicensingPaths {
public static final String FOLDER_LICENSING_BASE = ".passage"; //$NON-NLS-1$

/**
* @deprecated use {@link LicenseDecrypted}
* @deprecated use {@link PassageFileExtension.LicenseDecrypted}
*/
@Deprecated
public static final String EXTENSION_LICENSE_DECRYPTED = ".lic"; //$NON-NLS-1$
/**
* @deprecated use {@link LicenseEncrypted}
* @deprecated use {@link PassageFileExtension.LicenseEncrypted}
*/
@Deprecated
public static final String EXTENSION_LICENSE_ENCRYPTED = ".licen"; //$NON-NLS-1$
/**
* @deprecated use {@link PublicKey}
* @deprecated use {@link PassageFileExtension.PublicKey}
*/
@Deprecated
public static final String EXTENSION_PRODUCT_PUBLIC = ".pub"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@
*******************************************************************************/
package org.eclipse.passage.lic.internal.base.io;

import java.util.Objects;
import java.util.function.Supplier;

import org.eclipse.passage.lic.internal.api.LicensedProduct;

public final class FileNameFromLicensedProduct implements Supplier<String> {

private final LicensedProduct product;
private final String extension;
private final PassageFileExtension extension;

public FileNameFromLicensedProduct(LicensedProduct product, String extension) {
public FileNameFromLicensedProduct(LicensedProduct product, PassageFileExtension extension) {
Objects.requireNonNull(product, "FileNameFromLicensedProduct::product"); //$NON-NLS-1$
Objects.requireNonNull(extension, "FileNameFromLicensedProduct::extension"); //$NON-NLS-1$
this.product = product;
this.extension = extension;
}
Expand All @@ -31,7 +34,7 @@ public String get() {
return String.format("%s_%s%s", //$NON-NLS-1$
product.identifier(), //
product.version(), //
extension);
extension.get());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
*******************************************************************************/
package org.eclipse.passage.lic.equinox.io;

import static org.eclipse.passage.lic.base.io.LicensingPaths.*;
import static org.eclipse.passage.lic.base.io.LicensingPaths.EXTENSION_PRODUCT_PUBLIC;
import static org.eclipse.passage.lic.base.io.LicensingPaths.composeFileName;

import java.io.FileNotFoundException;
import java.io.IOException;
Expand All @@ -26,12 +27,16 @@
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;

/**
* @deprecated use internal (1.0) BundleKeyKeeper
*/
@Deprecated
public class BundleKeyKeeper implements KeyKeeper {

protected static final String PATH_DEFAULT = "OSGI-INF/"; //$NON-NLS-1$

private ComponentContext componentContext;

@Activate
public void activate(ComponentContext context) {
this.componentContext = context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public class EquinoxMessages extends NLS {
public static String ComponentConfigurationResolver_error_invalid_component_rt;
public static String ComponentRequirements_error_no_resource;
public static String ComponentRequirements_requirement_for_resource;
public static String BundleKeyKeeper_failed_to_find_file;

public static String BundleKeyKeeper_failed_to_open_stream;

public static String BundleRequirements_error_bundle_context;
public static String BundleRequirements_no_context;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ComponentConfigurationResolver_error_invalid_bundle_context=Unable to extract co
ComponentConfigurationResolver_error_invalid_component_rt=Unable to extract configuration requirements: invalid ServiceComponentRuntime
ComponentRequirements_error_no_resource=Unable to extract configuration requirements: invalid {0}
ComponentRequirements_requirement_for_resource={0} for {1} OSGi-component
BundleKeyKeeper_failed_to_find_file=Failed to find public key for product [%s] in path [%s] of bundle [%s]
BundleKeyKeeper_failed_to_open_stream=Failed to open a stream from public key for product [%s] by url [%s]
BundleRequirements_no_context=Bundle context for {0} OSGi-component
BundleRequirements_error_bundle_context=Unable to extract configuration requirements: invalid BundleContext
BundleVendor_unknown_vendor=Unknown vendor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.internal.equinox.io;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

import org.eclipse.passage.lic.internal.api.LicensedProduct;
import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.api.io.KeyKeeper;
import org.eclipse.passage.lic.internal.base.io.FileNameFromLicensedProduct;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension;
import org.eclipse.passage.lic.internal.equinox.i18n.EquinoxMessages;
import org.osgi.framework.Bundle;

/**
* Look for the product's public key into OSGI-INF folder of the configured
* bundle.
*/
@SuppressWarnings("restriction")
public final class BundleKeyKeeper implements KeyKeeper {

private final Supplier<LicensedProduct> product;
private final Bundle bundle;

public BundleKeyKeeper(Supplier<LicensedProduct> product, Bundle bundle) {
Objects.requireNonNull(product, "BundleKeyKeeper::product"); //$NON-NLS-1$
Objects.requireNonNull(bundle, "BundleKeyKeeper::bundle"); //$NON-NLS-1$
this.product = product;
this.bundle = bundle;
}

@Override
public LicensedProduct id() {
return product.get();
}

@Override
public InputStream productPublicKey() throws LicensingException {
URL resource = resource(Paths.get("OSGI-INF").resolve(keyFile())); //$NON-NLS-1$
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have PassageBundlePath later to encapsulate a way to find the info like this?
We may want to store the licensing information under a subfolder later, like they store bundle properties under OSGI-INF/l10n

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about that, but lots of questions arised. This implementation sticks to the current functionality to keep status quo where it's possible. Let's do it when we actually will need it.

try {
return resource.openStream();
} catch (IOException e) {
throw new LicensingException(String.format(//
EquinoxMessages.BundleKeyKeeper_failed_to_open_stream, //
product.get(), //
resource.toString()));
}
}

/**
* Either returns functional URL for the given {@code path} under the configured
* {@code bundle}, or fails with properly explained
* {@linkplain LicensingException}
*/
private URL resource(Path path) throws LicensingException {
Optional<URL> url = Optional.ofNullable(bundle.getResource(path.toString()));
if (!url.isPresent()) {
throw new LicensingException(String.format(//
EquinoxMessages.BundleKeyKeeper_failed_to_find_file, //
product.get(), //
path.toString(), //
bundle.getSymbolicName()));
}
return url.get();
}

private String keyFile() {
return new FileNameFromLicensedProduct(product.get(), new PassageFileExtension.PublicKey()).get();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;

/**
* @deprecated use internal.api.io StreamCodecRegistry
*/
@Deprecated
@Component
public class EquinoxKeyKeeperRegistry extends BaseKeyKeeperRegistry implements KeyKeeperRegistry {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;

/**
* @deprecated use internal.api.io StreamCodecRegistry
*/
@Deprecated
@Component
public class EquinoxStreamCodecRegistry extends BaseStreamCodecRegistry implements StreamCodecRegistry {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.eclipse.passage.lic.internal.api.conditions.mining.ContentType;
import org.eclipse.passage.lic.internal.api.conditions.mining.MinedConditions;
import org.eclipse.passage.lic.internal.api.conditions.mining.MinedConditionsRegistry;
import org.eclipse.passage.lic.internal.api.io.KeyKeeper;
import org.eclipse.passage.lic.internal.api.io.KeyKeeperRegistry;
import org.eclipse.passage.lic.internal.api.io.StreamCodec;
import org.eclipse.passage.lic.internal.api.io.StreamCodecRegistry;
import org.eclipse.passage.lic.internal.api.registry.Registry;
Expand All @@ -30,10 +32,13 @@
import org.eclipse.passage.lic.internal.api.requirements.ResolvedRequirementsRegistry;
import org.eclipse.passage.lic.internal.base.registry.ReadOnlyRegistry;
import org.eclipse.passage.lic.internal.bc.BcStreamCodec;
import org.eclipse.passage.lic.internal.equinox.io.BundleKeyKeeper;
import org.eclipse.passage.lic.internal.equinox.requirements.BundleRequirements;
import org.eclipse.passage.lic.internal.equinox.requirements.ComponentRequirements;
import org.eclipse.passage.lic.internal.hc.remote.impl.RemoteConditions;
import org.eclipse.passage.lic.internal.json.tobemoved.JsonConditionTransport;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

@SuppressWarnings("restriction")
final class SealedAccessCycleConfiguration implements AccessCycleConfiguration {
Expand All @@ -42,6 +47,7 @@ final class SealedAccessCycleConfiguration implements AccessCycleConfiguration {
private final Registry<StringServiceId, MinedConditions> conditions;
private final Registry<ContentType, ConditionTransport> transports;
private final Registry<LicensedProduct, StreamCodec> codecs;
private final Registry<LicensedProduct, KeyKeeper> keys;

SealedAccessCycleConfiguration(Supplier<LicensedProduct> product) {
requirements = new ReadOnlyRegistry<>(Arrays.asList(//
Expand All @@ -50,14 +56,16 @@ final class SealedAccessCycleConfiguration implements AccessCycleConfiguration {
));
conditions = new ReadOnlyRegistry<>(Arrays.asList(//
new RemoteConditions(product, transports())//
// FIXME: path condition minders require codecs
));
transports = new ReadOnlyRegistry<>(Arrays.asList(//
new JsonConditionTransport()//
));
codecs = new ReadOnlyRegistry<>(Arrays.asList(//
new BcStreamCodec(product) //
));
keys = new ReadOnlyRegistry<>(Arrays.asList(//
new BundleKeyKeeper(product, bundle()) //
));
}

@Override
Expand All @@ -74,8 +82,18 @@ private ConditionTransportRegistry transports() {
return () -> transports;
}

@SuppressWarnings("unused") // Under development: required for condition mining
private StreamCodecRegistry codecs() {
return () -> codecs;
}

@SuppressWarnings("unused") // Under development: required for condition mining
private KeyKeeperRegistry keys() {
return () -> keys;
}

private Bundle bundle() {
return FrameworkUtil.getBundle(getClass());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This test .pub file
emulates public key file
for a product [fake-product]
of version [1.0.0]
for test BundleKeyKeeperTest.

Totally fake.

Illustrates, after all,
that the format is not checked
on an input stream opening.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.internal.equinox.io;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.io.InputStream;

import org.eclipse.passage.lic.internal.api.LicensedProduct;
import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.base.BaseLicensedProduct;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

/**
* Integration test: demands OSGi running
*/
@SuppressWarnings("restriction")
public final class BundleKeyKeeperTest {

@Test
public void exisgingKeyFileFound() throws IOException {
try {
InputStream stream = new BundleKeyKeeper(this::productWithKey, bundle()).productPublicKey();
assertNotNull(stream);
stream.close();
} catch (LicensingException e) {
fail("Public key file stream retrieval is not supposed to fail on valid data"); //$NON-NLS-1$
}
}

@SuppressWarnings("resource") // stream is not supposed to be opened
@Test
public void foreignProductKeyIsIgnired() throws IOException {
try {

new BundleKeyKeeper(this::productWithoutKey, bundle()).productPublicKey();
} catch (LicensingException e) {
assertTrue(e.getMessage().contains("find")); //$NON-NLS-1$
return;
}
fail("Public key for the foreign product is not supposed to fit"); //$NON-NLS-1$
}

@Test(expected = NullPointerException.class)
public void productIsMandatory() {
new BundleKeyKeeper(null, bundle());
}

@Test(expected = NullPointerException.class)
public void bundleIsMandatory() {
new BundleKeyKeeper(this::productWithKey, null);
}

private Bundle bundle() {
return FrameworkUtil.getBundle(getClass());
}

private LicensedProduct productWithKey() {
return new BaseLicensedProduct("fake-product", "1.0.0"); //$NON-NLS-1$ //$NON-NLS-2$
}

private LicensedProduct productWithoutKey() {
return new BaseLicensedProduct("another-fake-product", "1.0.0"); //$NON-NLS-1$ //$NON-NLS-2$
}
}