From 722e562d43822768b37b4f0132e9ff5ce0ed37ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondra=20=C5=A0tumpf?= Date: Wed, 21 Jan 2015 21:51:42 +0100 Subject: [PATCH] [ADD] fixes and comments --- .../cuni/mff/d3s/deeco/annotations/Allow.java | 7 +- .../d3s/deeco/annotations/AllowMultiple.java | 2 +- .../mff/d3s/deeco/annotations/HasRole.java | 6 +- .../deeco/annotations/HasRoleMultiple.java | 2 +- .../mff/d3s/deeco/annotations/Rating.java | 6 +- .../d3s/deeco/annotations/RatingsProcess.java | 2 +- .../d3s/deeco/annotations/RoleDefinition.java | 3 +- .../mff/d3s/deeco/annotations/RoleParam.java | 10 +- .../processor/AnnotationProcessor.java | 24 ++-- .../mff/d3s/deeco/integrity/PathRating.java | 5 +- .../d3s/deeco/integrity/RatingsChangeSet.java | 46 ++++++- .../d3s/deeco/integrity/RatingsHolder.java | 47 ++++++- .../d3s/deeco/integrity/RatingsManager.java | 51 +++++++- .../deeco/integrity/RatingsManagerImpl.java | 57 ++++++++- .../integrity/ReadonlyRatingsHolder.java | 19 ++- .../deeco/knowledge/BaseKnowledgeManager.java | 51 ++++++++ .../d3s/deeco/knowledge/KnowledgeManager.java | 50 +++++++- .../knowledge/ReadOnlyKnowledgeManager.java | 16 ++- .../network/DefaultKnowledgeDataManager.java | 3 +- .../mff/d3s/deeco/network/RatingsData.java | 2 +- .../d3s/deeco/network/RatingsMetaData.java | 2 +- .../deeco/security/KnowledgeEncryptor.java | 119 ++++++++++++++---- .../deeco/security/LocalSecurityChecker.java | 51 ++++++-- .../security/ModelSecurityValidator.java | 58 ++++++++- .../d3s/deeco/security/RatingsEncryptor.java | 38 +++++- .../deeco/security/RemoteSecurityChecker.java | 14 ++- .../mff/d3s/deeco/security/RoleHelper.java | 42 ++++++- .../d3s/deeco/security/SecurityHelper.java | 102 ++++++++++++++- .../deeco/security/SecurityKeyManager.java | 36 +++++- .../security/SecurityKeyManagerImpl.java | 31 ++++- .../deeco/security/SecurityTagCollection.java | 43 ++++++- .../cuni/mff/d3s/deeco/task/EnsembleTask.java | 8 ++ .../cuni/mff/d3s/deeco/task/ProcessTask.java | 2 +- .../processor/input/samples/CorrectC4.java | 10 +- .../processor/input/samples/CorrectC5.java | 2 +- .../processor/input/samples/WrongC10.java | 10 +- .../processor/input/samples/WrongC11.java | 2 +- .../processor/input/samples/WrongC12.java | 2 +- .../input/samples/WrongC4WithSecurity.java | 12 +- .../processor/input/samples/WrongC8.java | 6 +- .../processor/input/samples/WrongC9.java | 4 +- .../security/KnowledgeEncryptorTest.java | 6 +- .../d3s/deeco/security/RoleHelperTest.java | 20 ++- .../security/SecurityKeyManagerImplTest.java | 20 +-- .../runtime/SecurityRuntimeModel.java | 6 +- 45 files changed, 919 insertions(+), 136 deletions(-) diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Allow.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Allow.java index 5719300fd..cb2d8ff59 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Allow.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Allow.java @@ -8,8 +8,9 @@ /** - * Used to decorate a knowledge field with access restrictions - * + * Used to decorate a knowledge field with access restrictions. The parameter + * is the security interface, i.e. interface decorated with {@link RoleDefinition} with possible parameters {@link RoleParam}. + * This annotation can be used multiple times on the same field. * @author Ondřej Štumpf * */ @@ -18,5 +19,5 @@ @Target(ElementType.FIELD) @Repeatable(value=AllowMultiple.class) public @interface Allow { - Class roleClass(); + Class value(); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/AllowMultiple.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/AllowMultiple.java index 7d30c463a..68a89c8ec 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/AllowMultiple.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/AllowMultiple.java @@ -7,7 +7,7 @@ /** - * Used to decorate a knowledge field with access restrictions + * Container of {@link Allow} annotations, required by Java to enable repeatable annotations. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRole.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRole.java index 049960c85..411c8ce6e 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRole.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRole.java @@ -8,7 +8,9 @@ /** - * Used to decorate a component with desired roles + * Used to decorate a component with desired roles. The parameter + * is the security interface, i.e. interface decorated with {@link RoleDefinition} with possible parameters {@link RoleParam}. + * This annotation can be used multiple times on the same component. * * @author Ondřej Štumpf * @@ -18,5 +20,5 @@ @Target(ElementType.TYPE) @Repeatable(value=HasRoleMultiple.class) public @interface HasRole { - Class roleClass(); + Class value(); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRoleMultiple.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRoleMultiple.java index a78416890..a394e9e0f 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRoleMultiple.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/HasRoleMultiple.java @@ -7,7 +7,7 @@ /** - * Used to decorate a component with desired roles + * Container of {@link HasRole} annotations, required by Java to enable repeatable annotations. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Rating.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Rating.java index 7050bc8f2..d52c99da0 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Rating.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/Rating.java @@ -5,8 +5,12 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import cz.cuni.mff.d3s.deeco.integrity.RatingsHolder; +import cz.cuni.mff.d3s.deeco.integrity.ReadonlyRatingsHolder; + /** - * Marks a method parameter to contain a ranking for specified knowledge path. + * Used to decorate a rating process argument as a source of rating information. + * The only allowed types for such parameter are {@link RatingsHolder} and {@link ReadonlyRatingsHolder}. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RatingsProcess.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RatingsProcess.java index c43b1325a..cc6abc4b6 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RatingsProcess.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RatingsProcess.java @@ -6,7 +6,7 @@ import java.lang.annotation.Target; /** - * Used to mark a method that performs an integrity check on component instance. + * Used to mark a method that performs an the rating in a component definition. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleDefinition.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleDefinition.java index 826e9f423..eead1e4b3 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleDefinition.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleDefinition.java @@ -7,7 +7,8 @@ /** - * Used to mark an interface as a security role + * Used to mark an interface as a security role. + * Only such interfaces can be used as arguments for {@link Allow} and {@link HasRole} annotations. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleParam.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleParam.java index b4629e9f2..a2dc4b10a 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleParam.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/RoleParam.java @@ -5,9 +5,17 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import cz.cuni.mff.d3s.deeco.model.runtime.api.AbsoluteSecurityRoleArgument; +import cz.cuni.mff.d3s.deeco.model.runtime.api.BlankSecurityRoleArgument; + /** - * Used to mark a field within a role definition as a role parameter. Such field must be of type String, static and final. + * Used to mark a field within a security interface (interface decorated with {@link RoleDefinition} as a role parameter. + * Such field must be static and final. + * The field can have following values: + * - null, then {@link BlankSecurityRoleArgument} is created. This signals "any value is allowed". + * - String in the format "[knowledge.path]" (including the brackets). The {@link PathSecurityRoleArgument}, which signals that the value of knowledge.path is used as a value of the parameter. + * - any other object (including String not in the format above). Then {@link AbsoluteSecurityRoleArgument} with the object value is created. * * @author Ondřej Štumpf * diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/processor/AnnotationProcessor.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/processor/AnnotationProcessor.java index df5db9f1f..789d8d6fd 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/processor/AnnotationProcessor.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/annotations/processor/AnnotationProcessor.java @@ -418,12 +418,12 @@ ComponentInstance createComponentInstance(Object obj) throws AnnotationProcessor Set> roles = new HashSet<>(); for (HasRole role : clazz.getDeclaredAnnotationsByType(HasRole.class)) { - if (roles.contains(role.roleClass())) { + if (roles.contains(role.value())) { throw new AnnotationProcessorException("The same role cannot be assigned multiply to a component."); } - SecurityRole securityRole = createRoleFromClassDefinition(role.roleClass(), km, true); + SecurityRole securityRole = createRoleFromClassDefinition(role.value(), km, true); componentInstance.getRoles().add(securityRole); - roles.add(role.roleClass()); + roles.add(role.value()); } callExtensions(ParsingEvent.ON_COMPONENT_CREATION, componentInstance, getUnknownAnnotations(clazz)); @@ -458,7 +458,7 @@ private cz.cuni.mff.d3s.deeco.model.runtime.api.RatingsProcess createRatingsProc } /** - * Parses the class used as a role definition + * Parses the class used as a role definition and returns the {@link SecurityRole} created from the class. * @param roleClass the class from annotation * @return * @throws AnnotationProcessorException @@ -472,15 +472,18 @@ private SecurityRole createRoleFromClassDefinition(Class roleClass, Knowledge SecurityRole securityRole = factory.createSecurityRole(); securityRole.setRoleName(roleClass.getName()); + // create parent roles recursively for (Class iface : roleClass.getInterfaces()) { securityRole.getConsistsOf().add(createRoleFromClassDefinition(iface, knowledgeManager, false)); } + // select only fields decorated with @RoleParam List fieldParameters = Arrays.stream(roleClass.getFields()) .filter(field -> field.getAnnotationsByType(RoleParam.class).length > 0) .collect(Collectors.toList()); for (Field field : fieldParameters) { + // check if the field is not overriden by another field if (!isValidForRole(field, fieldParameters, securityRole)) { continue; } @@ -495,9 +498,12 @@ private SecurityRole createRoleFromClassDefinition(Class roleClass, Knowledge throw new AnnotationProcessorException("Cannot read path from security role argument "+field.getName(), e); } + // create appropriate argument from the field value SecurityRoleArgument argument = createSecurityRoleArgument(field, fieldValue); securityRole.getArguments().add(argument); + + // override argument values in parent roles for (SecurityRole role : securityRole.getConsistsOf()) { overrideArgument(argument, role); } @@ -597,7 +603,7 @@ private void overrideArgument(SecurityRoleArgument argument, SecurityRole securi } /** - * Checks whether the given field is an applicable argument for the role + * Checks whether the given field is an applicable argument for the role (not being overriden). * @param field * @param fieldParameters * @param securityRole @@ -639,14 +645,14 @@ private void addSecurityTags(Class clazz, KnowledgeManager km, ChangeSet init Set> roleClasses = new HashSet<>(); for (Allow allow : allows) { - if (roleClasses.contains(allow.roleClass())) { - throw new AnnotationProcessorException("Cannot assign the same role " + allow.roleClass().getSimpleName() + " multiple times."); + if (roleClasses.contains(allow.value())) { + throw new AnnotationProcessorException("Cannot assign the same role " + allow.value().getSimpleName() + " multiple times."); } KnowledgeSecurityTag tag = factory.createKnowledgeSecurityTag(); - tag.setRequiredRole(createRoleFromClassDefinition(allow.roleClass(), km, true)); + tag.setRequiredRole(createRoleFromClassDefinition(allow.value(), km, true)); km.addSecurityTag(kp, tag); - roleClasses.add(allow.roleClass()); + roleClasses.add(allow.value()); } } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/PathRating.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/PathRating.java index d3d36f66e..3edf5db3a 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/PathRating.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/PathRating.java @@ -1,7 +1,10 @@ package cz.cuni.mff.d3s.deeco.integrity; +import cz.cuni.mff.d3s.deeco.annotations.RatingsProcess; + /** - * + * Possible states of knowledge data. Components can use {@link RatingsProcess} and {@link RatingsHolder} to assign + * any of these values to a knowledge path. * @author Ondřej Štumpf * */ diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsChangeSet.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsChangeSet.java index bf4fbb0f2..0c87a3efd 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsChangeSet.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsChangeSet.java @@ -11,18 +11,27 @@ import cz.cuni.mff.d3s.deeco.model.runtime.meta.RuntimeMetadataFactory; /** - * + * Represents a single change in the rating container. * @author Ondřej Štumpf * */ public class RatingsChangeSet implements Serializable { + /** The Constant serialVersionUID. */ private static final long serialVersionUID = 2415324270333544655L; - private String authorComponentId, targetComponentId; + /** ID of the component that issued the rating. */ + private String authorComponentId; + + /** ID of the component whose knowledge is rated. */ + private String targetComponentId; + + /** The knowledge path that is rated. */ private KnowledgePath knowledgePath; - private PathRating rating; + /** The actual rating for the knowledge path. */ + private PathRating rating; + public RatingsChangeSet(String authorComponentId, String targetComponentId, KnowledgePath knowledgePath, PathRating rating) { this.authorComponentId = authorComponentId; this.targetComponentId = targetComponentId; @@ -30,29 +39,50 @@ public RatingsChangeSet(String authorComponentId, String targetComponentId, Know this.rating = rating; } + /** + * Gets the ID of the component that issued the rating. + * + * @return ID of the component + */ public String getAuthorComponentId() { return authorComponentId; } + + /** + * Gets the target component id. + * + * @return the target component id + */ public String getTargetComponentId() { return targetComponentId; } + /** + * Gets the knowledge path that is rated. + * + * @return the knowledge path + */ public KnowledgePath getKnowledgePath() { return knowledgePath; } + /** + * Gets the actual rating for the knowledge path. + * + * @return the path rating + */ public PathRating getPathRating() { return rating; } - + private void writeObject(ObjectOutputStream oos) throws IOException { oos.writeUTF(getAuthorComponentId()); oos.writeUTF(getTargetComponentId()); oos.writeUTF(getKnowledgePath().toString()); oos.writeObject(getPathRating()); } - + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { RuntimeMetadataFactory factory = new RuntimeMetadataFactoryExt(); authorComponentId = ois.readUTF(); @@ -69,6 +99,9 @@ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IO knowledgePath = kp; } + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ @Override public boolean equals(Object obj) { if (this == obj) @@ -109,6 +142,9 @@ public boolean equals(Object obj) { return true; } + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ @Override public String toString() { return String.format("RatingsChangeSet: author=%s, target=%s, knowledge path=%s, rating=%s", authorComponentId, targetComponentId, knowledgePath, rating); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsHolder.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsHolder.java index a66646b0e..60a85c9fd 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsHolder.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsHolder.java @@ -2,18 +2,33 @@ import java.util.Map; - +import cz.cuni.mff.d3s.deeco.annotations.Rating; +import cz.cuni.mff.d3s.deeco.annotations.RatingsProcess; +import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; /** - * - * @author Ondřej Štumpf + * Contains rating information about a single {@link KnowledgePath} of a single component. + * This class is passed as an argument to the {@link RatingsProcess} for those arguments that are decorated with {@link Rating} * + * @author Ondřej Štumpf */ public class RatingsHolder extends ReadonlyRatingsHolder { private PathRating oldRating, newRating; private final String askingComponentId, targetComponentId; + /** + * Instantiates a new ratings holder. + * + * @param askingComponentId + * the ID of the component that asked for this holder (and later becomes author of the rating) + * @param targetComponentId + * the ID of the component whose knowledge is being rated + * @param rating + * the old rating + * @param ratings + * the aggregated ratings from other components + */ protected RatingsHolder(String askingComponentId, String targetComponentId, PathRating rating, Map ratings) { super(ratings); this.oldRating = rating; @@ -22,6 +37,12 @@ protected RatingsHolder(String askingComponentId, String targetComponentId, Path this.targetComponentId = targetComponentId; } + /** + * Sets the rating. + * + * @param rating + * the new rating + */ public void setMyRating(PathRating rating) { this.oldRating = this.newRating; this.newRating = rating; @@ -39,18 +60,38 @@ public void setMyRating(PathRating rating) { } } + /** + * Gets the rating. + * + * @return the rating + */ public PathRating getMyRating() { return newRating; } + /** + * Checks if is dirty (i.e. the new rating is different from the original). + * + * @return true, if is dirty + */ public boolean isDirty() { return oldRating != newRating; } + /** + * Gets the ID of the component that asked for this holder (and later becomes author of the rating). + * + * @return the ID of the component + */ protected String getAskingComponentId() { return askingComponentId; } + /** + * Gets the ID of the component whose knowledge is being rated + * + * @return the ID of the component + */ protected String getTargetComponentId() { return targetComponentId; } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManager.java index 1290cacbc..6d22838d6 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManager.java @@ -6,16 +6,65 @@ import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; /** - * + * Interface for a container of ratings data. * @author Ondřej Štumpf * */ public interface RatingsManager { + + /** + * Creates the {@link ReadonlyRatingsHolder}, which enables component or ensemble to read the rating data, but not modify them. + * + * @param targetComponentId + * the ID of the component whose knowledge is being rated + * @param absolutePath + * the knowledge path that is rated + * @return the read-only ratings holder + */ public ReadonlyRatingsHolder createReadonlyRatingsHolder(String targetComponentId, KnowledgePath absolutePath); + + /** + * Creates the {@link RatingsHolder}, which enables component rating process to read and modify rating data. + * + * @param askingComponentId + * the ID of the component that asked for this holder (and later becomes author of the rating) + * @param targetComponentId + * the ID of the component whose knowledge is being rated + * @param absolutePath + * the knowledge path that is rated + * @return the ratings holder + */ public RatingsHolder createRatingsHolder(String askingComponentId, String targetComponentId, KnowledgePath absolutePath); + + /** + * Creates the list of changes to the central rating data container. This list is later distributed across components. + * + * @param pathRatings + * rating for each knowledge path + * @return the list of change sets + */ public List createRatingsChangeSet(Map pathRatings); + /** + * Updates the container with given change sets. + * + * @param changeSets + * the set of changes (possibly obtained from other component) + */ public void update(List changeSets); + + /** + * Adds the list of change sets to the list of change sets that gets distributed. + * + * @param changeSets + * the change sets + */ public void addToPendingChangeSets(List changeSets); + + /** + * Gets the list of change sets that has not yet been redistributed. + * + * @return the change sets + */ public List getPendingChangeSets(); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManagerImpl.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManagerImpl.java index ead0f1008..a3ce143df 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManagerImpl.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/RatingsManagerImpl.java @@ -12,20 +12,35 @@ import cz.cuni.mff.d3s.deeco.task.KnowledgePathHelper; /** - * - * @author Ondřej Štumpf + * The Class RatingsManagerImpl. * + * @author Ondřej Štumpf */ public class RatingsManagerImpl implements RatingsManager { - private Map>> ratings; // path->target component->claiming component->rating + /** Contains all ratings. path->target component->author component->rating */ + private Map>> ratings; + + /** Changes to the ratings container that had not yet been distributed */ private List pendingChanges; + /** + * Instantiates a new ratings manager. + */ public RatingsManagerImpl() { this.ratings = new HashMap<>(); this.pendingChanges = new ArrayList<>(); } + /** + * Gets the map of ratings, containing ID of the component and the rating this component assigned to the given knowledge in the given component. + * + * @param targetComponentId + * the ID of the component whose knowledge is rated + * @param absolutePath + * the absolute path to the knowledge + * @return the ratings map + */ protected Map getRatings(String targetComponentId, KnowledgePath absolutePath) { if (absolutePath == null || !KnowledgePathHelper.isAbsolutePath(absolutePath)) { throw new IllegalArgumentException("Knowledge path must be not null and absolute."); @@ -41,6 +56,18 @@ protected Map getRatings(String targetComponentId, Knowledge return ratings.get(absolutePath).get(targetComponentId); } + /** + * Sets the rating. + * + * @param authorComponentId + * the ID of the component that issues the rating + * @param targetComponentId + * the ID of the component whose knowledge is rated + * @param absolutePath + * the absolute path to the knowledge + * @param rating + * the rating + */ protected void setRating(String authorComponentId, String targetComponentId, KnowledgePath absolutePath, PathRating rating) { if (absolutePath == null || !KnowledgePathHelper.isAbsolutePath(absolutePath)) { throw new IllegalArgumentException("Knowledge path must be not null and absolute."); @@ -50,6 +77,9 @@ protected void setRating(String authorComponentId, String targetComponentId, Kno targetComponentRatings.put(authorComponentId, rating); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.integrity.RatingsManager#createReadonlyRatingsHolder(java.lang.String, cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ public ReadonlyRatingsHolder createReadonlyRatingsHolder(String targetComponentId, KnowledgePath absolutePath) { if (absolutePath == null || !KnowledgePathHelper.isAbsolutePath(absolutePath)) { throw new IllegalArgumentException("Knowledge path must be not null and absolute."); @@ -65,6 +95,9 @@ public ReadonlyRatingsHolder createReadonlyRatingsHolder(String targetComponentI } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.integrity.RatingsManager#createRatingsHolder(java.lang.String, java.lang.String, cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ public RatingsHolder createRatingsHolder(String askingComponentId, String targetComponentId, KnowledgePath absolutePath) { if (absolutePath == null || !KnowledgePathHelper.isAbsolutePath(absolutePath)) { throw new IllegalArgumentException("Knowledge path must be not null and absolute."); @@ -78,6 +111,9 @@ public RatingsHolder createRatingsHolder(String askingComponentId, String target return new RatingsHolder(askingComponentId, targetComponentId, oldPathRating, pathRating); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.integrity.RatingsManager#createRatingsChangeSet(java.util.Map) + */ public synchronized List createRatingsChangeSet(Map pathRatings) { if (pathRatings == null) return Collections.emptyList(); @@ -92,10 +128,16 @@ public synchronized List createRatingsChangeSet(Map getPendingChangeSets() { return pendingChanges; } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.integrity.RatingsManager#update(java.util.List) + */ public synchronized void update(List changeSets) { if (changeSets == null) return; @@ -104,11 +146,18 @@ public synchronized void update(List changeSets) { } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.integrity.RatingsManager#addToPendingChangeSets(java.util.List) + */ public void addToPendingChangeSets(List changeSets) { pendingChanges.addAll(changeSets); } - + /** + * Groups the individual ratings by the value and counts the number of occurences. + * @param individualRating + * @return + */ private Map aggregateRatings(Map individualRating) { return individualRating.values().stream().collect(Collectors.groupingBy(x -> x, Collectors.counting())); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/ReadonlyRatingsHolder.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/ReadonlyRatingsHolder.java index 1a25d0e78..6f2bc350e 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/ReadonlyRatingsHolder.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/integrity/ReadonlyRatingsHolder.java @@ -2,8 +2,12 @@ import java.util.Map; +import cz.cuni.mff.d3s.deeco.annotations.Rating; +import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; + /** - * + * Contains rating information about a single {@link KnowledgePath} of a single component. + * This class is passed to methods with arguments that are decorated with {@link Rating}. * @author Ondřej Štumpf * */ @@ -11,10 +15,23 @@ public class ReadonlyRatingsHolder { protected Map ratings; + /** + * Instantiates a new read-only ratings holder. + * + * @param ratings + * the ratings from the {@link RatingsManager} + */ public ReadonlyRatingsHolder(Map ratings) { this.ratings = ratings; } + /** + * Gets the number of components that rated the given knowledge with this rating. + * + * @param rating + * the rating + * @return the number of components + */ public long getRatings(PathRating rating) { Long l = ratings.get(rating); return l == null ? 0l : l.longValue(); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/BaseKnowledgeManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/BaseKnowledgeManager.java index 83d1c5f4a..117f28186 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/BaseKnowledgeManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/BaseKnowledgeManager.java @@ -36,6 +36,7 @@ * * @author Rima Al Ali * @author Michal Kit + * @author Ondřej Štumpf * */ @SuppressWarnings("unchecked") @@ -62,16 +63,26 @@ public BaseKnowledgeManager(String id, ComponentInstance component) { this.lockedKnowledgePaths = new HashSet<>(); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getId() + */ @Override public String getId() { return this.id; } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getComponent() + */ @Override public ComponentInstance getComponent() { return component; } + + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getAuthor(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ @Override public String getAuthor(KnowledgePath knowledgePath) { if (!KnowledgePathHelper.isAbsolutePath(knowledgePath)) { @@ -158,6 +169,9 @@ public void unregister(Trigger trigger, } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.KnowledgeManager#update(cz.cuni.mff.d3s.deeco.knowledge.ChangeSet) + */ @Override public void update(final ChangeSet changeSet) throws KnowledgeUpdateException { update(changeSet, getId()); @@ -239,6 +253,10 @@ public void update(final ChangeSet changeSet, String authorId) throws KnowledgeU } } + /** + * Removes authors of the given knowledge paths. + * @param knowledgePaths + */ private void deleteAuthors(Collection knowledgePaths) { List listToRemove = new LinkedList<>(); @@ -255,6 +273,12 @@ private void deleteAuthors(Collection knowledgePaths) { knowledgeAuthors.keySet().removeAll(listToRemove); } + /** + * Sets the author fot the given knowlege path. + * @param updateKP + * @param authorId + * @param updatedAuthors + */ private void updateAuthors(KnowledgePath updateKP, String authorId, Map updatedAuthors) { knowledgeAuthors.put(updateKP, authorId); updatedAuthors.put(updateKP, authorId); @@ -668,6 +692,9 @@ private void revert(Map updated, } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.KnowledgeManager#markAsLocal(java.util.Collection) + */ @Override public void markAsLocal(Collection knowledgePaths) { for (KnowledgePath path : knowledgePaths) { @@ -680,16 +707,25 @@ public void markAsLocal(Collection knowledgePaths) { localKnowledgePaths.addAll(knowledgePaths); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#isLocal(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ @Override public boolean isLocal(KnowledgePath knowledgePath) { return localKnowledgePaths.contains(knowledgePath); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getLocalPaths() + */ @Override public Collection getLocalPaths() { return localKnowledgePaths; } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.KnowledgeManager#addSecurityTag(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath, cz.cuni.mff.d3s.deeco.model.runtime.api.SecurityTag) + */ @Override public void addSecurityTag(KnowledgePath knowledgePath, SecurityTag newSecurityTag) { if (knowledgePath.getNodes().size() != 1) { @@ -708,6 +744,9 @@ public void addSecurityTag(KnowledgePath knowledgePath, SecurityTag newSecurityT securityTags.get(pathNode).add(newSecurityTag); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.KnowledgeManager#setSecurityTags(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath, java.util.Collection) + */ @Override public void setSecurityTags(KnowledgePath knowledgePath, Collection newSecurityTags) { if (knowledgePath.getNodes().size() != 1) { @@ -723,6 +762,9 @@ public void setSecurityTags(KnowledgePath knowledgePath, Collection securityTags.get(pathNode).addAll(newSecurityTags); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getKnowledgeSecurityTags(cz.cuni.mff.d3s.deeco.model.runtime.api.PathNodeField) + */ @Override public List getKnowledgeSecurityTags(PathNodeField pathNodeField) { List result = securityTags.get(pathNodeField); @@ -733,6 +775,9 @@ public List getKnowledgeSecurityTags(PathNodeField pathNod } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#getSecurityTags(cz.cuni.mff.d3s.deeco.model.runtime.api.PathNodeField) + */ @Override public List getSecurityTags(PathNodeField pathNodeField) { List result = securityTags.get(pathNodeField); @@ -743,6 +788,9 @@ public List getSecurityTags(PathNodeField pathNodeField) { } } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.ReadOnlyKnowledgeManager#isLocked(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ @Override public boolean isLocked(KnowledgePath knowledgePath) { if (!KnowledgePathHelper.isAbsolutePath(knowledgePath)) { @@ -751,6 +799,9 @@ public boolean isLocked(KnowledgePath knowledgePath) { return this.lockedKnowledgePaths.contains(knowledgePath); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.knowledge.KnowledgeManager#lockKnowledgePath(cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath) + */ @Override public void lockKnowledgePath(KnowledgePath knowledgePath) { if (!KnowledgePathHelper.isAbsolutePath(knowledgePath)) { diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/KnowledgeManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/KnowledgeManager.java index 0c9ee6893..0c3ca6fea 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/KnowledgeManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/KnowledgeManager.java @@ -2,7 +2,10 @@ import java.util.Collection; +import cz.cuni.mff.d3s.deeco.annotations.Allow; import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; +import cz.cuni.mff.d3s.deeco.model.runtime.api.LocalKnowledgeTag; +import cz.cuni.mff.d3s.deeco.model.runtime.api.SecurityRole; import cz.cuni.mff.d3s.deeco.model.runtime.api.SecurityTag; /** @@ -14,7 +17,7 @@ * are absolute, meaning that they are fully evaluated. * * @author Rima Al Ali - * + * @author Ondřej Štumpf */ public interface KnowledgeManager extends ReadOnlyKnowledgeManager { @@ -28,9 +31,54 @@ public interface KnowledgeManager extends ReadOnlyKnowledgeManager { * thrown when knowledge could not have been updated */ void update(ChangeSet changeSet) throws KnowledgeUpdateException; + + /** + * Updates this knowledge manager with the given {@link ChangeSet} values. + * + * @param changeSet + * update changes. + * @param shadowComponentId + * the ID of the component which owns the change set + * @throws KnowledgeUpdateException + * thrown when knowledge could not have been updated + */ void update(ChangeSet changeSet, String shadowComponentId) throws KnowledgeUpdateException; + + /** + * Marks the knowledge paths as local and assigns them a {@link LocalKnowledgeTag}. + * + * @param knowledgePaths + * the knowledge paths + */ void markAsLocal(Collection knowledgePaths); + + + /** + * Adds the security tag to the given knowledge path. Each security tag corresponds either to {@link Allow} annotation, + * or is an instance of {@link LocalKnowledgeTag} for local knowledge. + * + * @param knowledgePath + * the knowledge path + * @param newSecurityTag + * the new security tag + */ void addSecurityTag(KnowledgePath knowledgePath, SecurityTag newSecurityTag); + + /** + * Sets the security tags for the given knowledge path (i.e. removes any previous). + * + * @param knowledgePath + * the knowledge path + * @param newSecurityTags + * the new security tags + */ void setSecurityTags(KnowledgePath knowledgePath, Collection newSecurityTags); + + /** + * Locks the knowledge path, which signals that it is being used as an parameter for a {@link SecurityRole} and cannot be changed. + * + * @param knowledgePath + * the knowledge path + */ void lockKnowledgePath(KnowledgePath knowledgePath); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/ReadOnlyKnowledgeManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/ReadOnlyKnowledgeManager.java index 041cd9f48..0b996a4af 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/ReadOnlyKnowledgeManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/knowledge/ReadOnlyKnowledgeManager.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.List; +import cz.cuni.mff.d3s.deeco.annotations.Local; import cz.cuni.mff.d3s.deeco.model.runtime.api.ComponentInstance; import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgeSecurityTag; @@ -18,6 +19,7 @@ * absolute, meaning that they are fully evaluated. * * @author Rima Al Ali + * @author Ondřej Štumpf * */ public interface ReadOnlyKnowledgeManager { @@ -63,7 +65,17 @@ public ValueSet get(Collection knowledgeReferenceList) */ public String getId(); + /** + * Checks if the knowledge path has been decorated with the {@link Local} annotation. + * @param knowledgePath + * @return true if the knowledge is local + */ public boolean isLocal(KnowledgePath knowledgePath); + + /** + * Gets the knowledge paths that were decorated with the {@link Local} annotation + * @return the list of knowledge paths + */ public Collection getLocalPaths(); /** @@ -90,14 +102,14 @@ public ValueSet get(Collection knowledgeReferenceList) /** * Returns the ID of the component from which this knowledge path comes. * @param knowledgePath - * @return + * @return the ID of the component */ String getAuthor(KnowledgePath knowledgePath); /** * Returns true if given knowledge path is a parameter of some security role and therefore its value cannot be modified * @param knowledgePath - * @return + * @return true if the knowledge value cannot be modified */ boolean isLocked(KnowledgePath knowledgePath); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/DefaultKnowledgeDataManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/DefaultKnowledgeDataManager.java index 81ff4b14a..1445550f4 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/DefaultKnowledgeDataManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/DefaultKnowledgeDataManager.java @@ -24,7 +24,6 @@ import cz.cuni.mff.d3s.deeco.logging.Log; import cz.cuni.mff.d3s.deeco.model.runtime.api.EnsembleDefinition; import cz.cuni.mff.d3s.deeco.model.runtime.api.KnowledgePath; -import cz.cuni.mff.d3s.deeco.model.runtime.api.PathNodeField; import cz.cuni.mff.d3s.deeco.model.runtime.api.SecurityTag; import cz.cuni.mff.d3s.deeco.model.runtime.custom.RuntimeMetadataFactoryExt; import cz.cuni.mff.d3s.deeco.model.runtime.meta.RuntimeMetadataFactory; @@ -59,7 +58,7 @@ * @see KnowledgeDataSender * @see KnowledgeDataReceiver */ -@SuppressWarnings({"rawtypes", "unchecked"}) +@SuppressWarnings({"unchecked"}) public class DefaultKnowledgeDataManager extends KnowledgeDataManager { // this rssi corresponds to roughly 20m distance diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsData.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsData.java index 3181a1397..7b7195c31 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsData.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsData.java @@ -10,7 +10,7 @@ import javax.crypto.SealedObject; /** - * + * Container of ratings data that is sent across network. * @author Ondřej Štumpf * */ diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsMetaData.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsMetaData.java index 9f5d8beb0..17197ca4e 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsMetaData.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/network/RatingsMetaData.java @@ -4,7 +4,7 @@ import java.util.Arrays; /** - * + * Ratings meta data. * @author Ondřej Štumpf * */ diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptor.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptor.java index 0703c0569..1f871b88c 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptor.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptor.java @@ -12,7 +12,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -34,7 +33,9 @@ import cz.cuni.mff.d3s.deeco.task.KnowledgePathHelper; /** - * @author Ondřej Štumpf + * The class managing encryption and decryption of {@link KnowledgeData}. + * + * @author Ondřej Štumpf */ public class KnowledgeEncryptor { @@ -42,40 +43,63 @@ public class KnowledgeEncryptor { private final SecurityHelper securityHelper; private final RemoteSecurityChecker securityChecker; + /** + * Instantiates a new knowledge encryptor. + * + * @param keyManager + * the private/public key manager + */ public KnowledgeEncryptor(SecurityKeyManager keyManager) { this.keyManager = keyManager; this.securityHelper = new SecurityHelper(); this.securityChecker = new RemoteSecurityChecker(); } - @SuppressWarnings("unchecked") + + /** + * Attempts to decrypt the given {@link KnowledgeData}, using roles available for the given replica. + * + * @param kd + * the knowledge data (as received) + * @param replica + * the replica (the component attempting to access the data) + * @param metaData + * the meta data (as received) + * @return the knowledge data with knowledge and security tags data decrypted (or removed if decryption failed) + */ public KnowledgeData decryptValueSet(KnowledgeData kd, KnowledgeManager replica, KnowledgeMetaData metaData) { if (kd == null) return null; ValueSet decryptedKnowledge = decrypt(kd.getKnowledge(), replica, metaData); ValueSet decryptedSecuritySet = decrypt(kd.getSecuritySet(), replica, metaData); - // replace lists of serializable roles with actual security tags - for (KnowledgePath path : decryptedSecuritySet.getKnowledgePaths()) { - List tags = (List)decryptedSecuritySet.getValue(path); - decryptedSecuritySet.setValue(path, tags); - } - return new KnowledgeData(decryptedKnowledge, decryptedSecuritySet, metaData); } + /** + * Attempts to decrypt the {@link SealedObject} sealed objects present in the given {@link ValueSet}. + * @param valueSet + * the value set to decrypt + * @param replica + * the component attempting to decrypt + * @param metaData + * the meta data containing security information + * @return the value set containing those knowledge paths that either were not encrypted or their decryption succeeded + */ private ValueSet decrypt(ValueSet valueSet, KnowledgeManager replica, KnowledgeMetaData metaData) { ValueSet result = new ValueSet(); for (KnowledgePath kp : valueSet.getKnowledgePaths()) { Object value = valueSet.getValue(kp); if (value instanceof SealedObject) { try { + // attempt to decrypt the knowledge Object decryptedValue = accessValue((SealedObject)value, replica, metaData); result.setValue(kp, decryptedValue); } catch (KnowledgeNotFoundException | SecurityException e) { // do nothing } } else { + // knowledge not encrypted result.setValue(kp, value); } } @@ -83,6 +107,20 @@ private ValueSet decrypt(ValueSet valueSet, KnowledgeManager replica, KnowledgeM return result; } + /** + * Encrypts the value set, i.e. splits it into several {@link KnowledgeData} instances, each encrypted with different key. + * There is a KnowledgeData instance for each {@link KnowledgeSecurityTag} used in the value set. + * + * @param valueSet + * the value set + * @param knowledgeManager + * the knowledge manager + * @param metaData + * the meta data + * @return the list of knowledge data instances + * @throws KnowledgeNotFoundException + * the knowledge not found exception + */ public List encryptValueSet(ValueSet valueSet, KnowledgeManager knowledgeManager, KnowledgeMetaData metaData) throws KnowledgeNotFoundException { if (valueSet == null) return null; @@ -95,8 +133,8 @@ public List encryptValueSet(ValueSet valueSet, KnowledgeManager k throw new IllegalArgumentException("The value set must contain only absolute knowledge paths."); } - List tags = knowledgeManager.getKnowledgeSecurityTags((PathNodeField)kp.getNodes().get(0)).stream() - .filter(t -> t instanceof KnowledgeSecurityTag).map(t -> (KnowledgeSecurityTag)t ).collect(Collectors.toList()); + // get the security tags for the given knowledge path + List tags = knowledgeManager.getKnowledgeSecurityTags((PathNodeField)kp.getNodes().get(0)); securityTagsMap.put(kp, tags); if (tags == null || tags.isEmpty()) { @@ -138,6 +176,17 @@ public List encryptValueSet(ValueSet valueSet, KnowledgeManager k return result; } + /** + * Attempts to decrypt given {@link SealedObject} with roles assigned to the given component. + * @param sealedObject + * the object to decrypt + * @param replica + * the component + * @param metaData + * the metadata as received + * @return + * @throws KnowledgeNotFoundException + */ private Object accessValue(SealedObject sealedObject, KnowledgeManager replica, KnowledgeMetaData metaData) throws KnowledgeNotFoundException { // verify signature on metadata boolean verificationSucceeded = false; @@ -145,18 +194,23 @@ private Object accessValue(SealedObject sealedObject, KnowledgeManager replica, verificationSucceeded = securityHelper.verify(metaData.signature, keyManager.getIntegrityPublicKey(), metaData.componentId, metaData.versionId, metaData.targetRole); } catch (InvalidKeyException | CertificateEncodingException | SignatureException | NoSuchAlgorithmException - | KeyStoreException | SecurityException | IllegalStateException e1) { } + | KeyStoreException | SecurityException | IllegalStateException e1) { + verificationSucceeded = false; + } if (!verificationSucceeded) { throw new SecurityException(); } Object value = null; - boolean encryptionSucceeded = false; + boolean decryptionSucceeded = false; + // gets the roles transitive closure List transitiveRoles = RoleHelper.getTransitiveRoles(replica.getComponent().getRoles()); + // try each role, if it can decrypt the data for (SecurityRole role : transitiveRoles) { + // perform local security check if (!securityChecker.checkSecurity(role, metaData.targetRole, replica.getComponent().getKnowledgeManager())) { continue; } @@ -165,25 +219,27 @@ private Object accessValue(SealedObject sealedObject, KnowledgeManager replica, Map arguments = metaData.targetRole.getRoleArguments(); try { - Key privateKey = keyManager.getPrivateKeyFor(roleName, arguments); + Key privateKey = keyManager.getPrivateKey(roleName, arguments); Key decryptedSymmetricKey = securityHelper.decryptKey(metaData.encryptedKey, metaData.encryptedKeyAlgorithm, privateKey); value = sealedObject.getObject(securityHelper.getSymmetricCipher(Cipher.DECRYPT_MODE, decryptedSymmetricKey)); - encryptionSucceeded = true; - break; // decryption succeeded - we have a value + decryptionSucceeded = true; + break; } catch (InvalidKeyException | ClassNotFoundException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException | IOException | ShortBufferException | CertificateEncodingException | KeyStoreException | SecurityException - | SignatureException | IllegalStateException e) { } + | SignatureException | IllegalStateException e) { + decryptionSucceeded = false; + } } - if (!encryptionSucceeded) { + if (!decryptionSucceeded) { throw new SecurityException(); } return value; } - + private void addToSecurityMap(ValueSet basicValueSet, Map securityMap, KnowledgeSecurityTag tag, KnowledgePath kp) { @@ -193,14 +249,28 @@ private void addToSecurityMap(ValueSet basicValueSet, securityMap.get(tag).setValue(kp, basicValueSet.getValue(kp)); } + /** + * Creates an instance of {@link Cipher} for the given security tag and modifies the given metadata instance accordingly. + * @param knowledgeManager + * the knowledge manager containing data referenced by the security role + * @param tag + * the security tag + * @param metaData + * the metadata + * @return the cipher + */ private Cipher prepareCipher(KnowledgeManager knowledgeManager, KnowledgeSecurityTag tag, KnowledgeMetaData metaData) { try { String roleName = tag.getRequiredRole().getRoleName(); Map arguments = RoleHelper.readRoleArguments(tag.getRequiredRole(), knowledgeManager); - Key publicKey = keyManager.getPublicKeyFor(roleName, arguments); + // get the public key for the given role + Key publicKey = keyManager.getPublicKey(roleName, arguments); + + // create random symmetric key Key symmetricKey = securityHelper.generateKey(); + // encrypt the symmetric key using the public key byte[] encryptedKey = securityHelper.encryptKey(symmetricKey, publicKey); metaData.encryptedKey = encryptedKey; @@ -219,7 +289,14 @@ private Cipher prepareCipher(KnowledgeManager knowledgeManager, KnowledgeSecurit } } - private void seal(ValueSet values, Cipher cipher) throws KnowledgeNotFoundException { + /** + * Replaces each value in the value set with its encrypted version. + * @param values + * the values to encrypt + * @param cipher + * the cipher to use for encryption + */ + private void seal(ValueSet values, Cipher cipher) { try { for (KnowledgePath kp : values.getKnowledgePaths()) { Object plainKnowledge = values.getValue(kp); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/LocalSecurityChecker.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/LocalSecurityChecker.java index 9c83451fd..698772a21 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/LocalSecurityChecker.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/LocalSecurityChecker.java @@ -22,26 +22,43 @@ import cz.cuni.mff.d3s.deeco.task.KnowledgePathHelper.PathRoot; /** - * + * Performs security checks before knowledge exchange between two local components. * @author Ondřej Štumpf */ public class LocalSecurityChecker { - /** - * Reference to the corresponding {@link KnowledgeManagerContainer} - */ + /** Reference to the corresponding {@link KnowledgeManagerContainer}. */ KnowledgeManagerContainer kmContainer; - /** - * Reference to the corresponding {@link EnsembleController} - */ + /** Reference to the corresponding {@link EnsembleController}. */ EnsembleController ensembleController; + /** + * Instantiates a new local security checker. + * + * @param ensembleController + * the ensemble controller + * @param kmContainer + * the km container + */ public LocalSecurityChecker(EnsembleController ensembleController, KnowledgeManagerContainer kmContainer) { this.ensembleController = ensembleController; this.kmContainer = kmContainer; } + /** + * Checks if all knowledge paths used in the membership and knowledge + * exchange are secured in such way which enables the local component to + * access them. + * + * @param localRole + * the role of the local component (member/coord) + * @param shadowKnowledgeManager + * the shadow knowledge manager + * @return true if the local component has such roles that allow it to access the knowledge + * @throws TaskInvocationException + * the task invocation exception + */ public boolean checkSecurity(PathRoot localRole, ReadOnlyKnowledgeManager shadowKnowledgeManager) throws TaskInvocationException { boolean canAccess; @@ -69,12 +86,23 @@ public boolean checkSecurity(PathRoot localRole, ReadOnlyKnowledgeManager shadow return canAccess && compromitationErrors.isEmpty(); } + /** + * Checks if the set of knowledge paths is secured in such way which enables the local component to + * access them. + * @param localRole + * the role of the local component (member/coord) + * @param paths + * the knowledge paths + * @param shadowKnowledgeManager + * the shadow knowledge manager + * @return true if the local component has such roles that allow it to access the knowledge + */ private boolean canAccessKnowledge(PathRoot localRole, Collection paths, ReadOnlyKnowledgeManager shadowKnowledgeManager) { - // shadowKnowledgeManager is actually local and therefore has associated knowledge security tags KnowledgeManager localKnowledgeManager = ensembleController.getComponentInstance().getKnowledgeManager(); boolean canAccessAll = true; + // verify each of the paths for (KnowledgePath kp : paths) { Map securityTagManager = new HashMap<>(); SecurityTagCollection securityTagCollection = SecurityTagCollection.getSecurityTags(localRole, kp, localKnowledgeManager, shadowKnowledgeManager, securityTagManager); @@ -98,6 +126,9 @@ private boolean canAccessKnowledge(PathRoot localRole, Collection return canAccessAll; } + /** + * Checks whether the local component has role to access the given security tag. + */ private boolean canAccessTag(KnowledgeSecurityTag securityTag, ReadOnlyKnowledgeManager localKnowledgeManager, ReadOnlyKnowledgeManager shadowKnowledgeManager, Map securityTagManager) { ReadOnlyKnowledgeManager accessingKnowledgeManager, protectingKnowledgeManager; @@ -110,9 +141,11 @@ private boolean canAccessTag(KnowledgeSecurityTag securityTag, ReadOnlyKnowledge accessingKnowledgeManager = localKnowledgeManager; } + // get the roles transitive closure List localRoles = RoleHelper.getTransitiveRoles(accessingKnowledgeManager.getComponent().getRoles()); boolean canAccessTag = false; + // try each of the roles for (SecurityRole role : localRoles) { try { String roleName = role.getRoleName(); @@ -123,7 +156,7 @@ private boolean canAccessTag(KnowledgeSecurityTag securityTag, ReadOnlyKnowledge canAccessTag = canAccessTag || (roleName.equals(tagName) && RoleHelper.roleArgumentsMatch(roleArguments, tagArguments)); } catch (KnowledgeNotFoundException e) { - + // do nothing } } return canAccessTag; diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/ModelSecurityValidator.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/ModelSecurityValidator.java index d5ebd5d62..028a372b6 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/ModelSecurityValidator.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/ModelSecurityValidator.java @@ -23,12 +23,19 @@ import cz.cuni.mff.d3s.deeco.task.KnowledgePathHelper.PathRoot; /** - * - * @author Ondřej Štumpf + * Helper class for validating security compromise. * + * @author Ondřej Štumpf */ public class ModelSecurityValidator { + /** + * Validates all processes in the given component. + * + * @param component + * the component + * @return the list of potential errors + */ public static List validate(ComponentInstance component) { List errorList = new ArrayList<>(); @@ -42,12 +49,22 @@ public static List validate(ComponentInstance component) { return errorList; } + /** + * Validates the component process. + * + * @param process + * the process + * @return the list of potential errors + */ public static List validate(ComponentProcess process) { List errorList = new ArrayList<>(); + // get all input parameters List inputParameters = process.getParameters().stream() .filter(param -> param.getKind() == ParameterKind.IN || param.getKind() == ParameterKind.INOUT) .collect(Collectors.toList()); + + // get all output parameters List outputParameters = process.getParameters().stream() .filter(param -> param.getKind() == ParameterKind.OUT || param.getKind() == ParameterKind.INOUT) .collect(Collectors.toList()); @@ -69,6 +86,19 @@ public static List validate(ComponentProcess process) { return errorList; } + /** + * Validates the knowledge exchange method. + * + * @param pathRoot + * the path root + * @param exchange + * the exchange method + * @param component + * the local component + * @param shadowKnowledgeManager + * the shadow knowledge manager + * @return the list of potential errors + */ public static List validate(PathRoot pathRoot, Exchange exchange, ComponentInstance component, ReadOnlyKnowledgeManager shadowKnowledgeManager) { List errorList = new ArrayList<>(); @@ -100,26 +130,44 @@ public static List validate(PathRoot pathRoot, Exchange exchange, Compon } + /** + * Checks if the security of output is more or equally restrictive than the security of the input. + * + * @param out + * the output security (DNF) + * @param in + * the input security (DNF) + * @return true, if is more restrictive + */ public static boolean isMoreRestrictive(SecurityTagCollection out, SecurityTagCollection in) { + // if output has no security tags and input does if (out.isEmpty() && !in.isEmpty()) { return false; } + + // if output has some security tags and input does not if (in.isEmpty() && !out.isEmpty()) { return true; } + + // each conjunction from the output must override some conjunction from the input return out.stream().allMatch(conjunction -> satisfiesConjunction(conjunction, in)); } private static boolean satisfiesConjunction(List outConjunction, SecurityTagCollection in) { + // any of the conjunctions in the input must be overriden by the output conjunction return in.stream().anyMatch(inConjunction -> satisfiesConjunction(outConjunction, inConjunction)); } private static boolean satisfiesConjunction(List outConjunction, List inConjunction) { + // either an output conjunction contains local knowledge + // or each tag in the input conjunction is overriden in the output return outConjunction.stream().anyMatch(outTag -> outTag instanceof LocalKnowledgeTag) || inConjunction.stream().allMatch(inTag -> tagPresentOrOverriden(inTag, outConjunction)); } private static boolean tagPresentOrOverriden(SecurityTag inTag, List outConjunction) { + // any of the output tags must override the input tag return outConjunction.stream().anyMatch(outTag -> satisfies(inTag, outTag)); } @@ -131,6 +179,7 @@ private static boolean satisfies(SecurityTag inTag, SecurityTag outTag) { List transitiveRoles = RoleHelper.getTransitiveRoles(Arrays.asList(outKnowledgeTag.getRequiredRole())); boolean roleMatched = false; + // the role of the output role must be more restrictive than the role of the input for (SecurityRole outRole : transitiveRoles) { boolean namesMatch = inKnowledgeTag.getRequiredRole().getRoleName().equals(outRole.getRoleName()); boolean argumentsMatch = inKnowledgeTag.getRequiredRole().getArguments().stream().allMatch(inArgument -> @@ -147,12 +196,17 @@ private static boolean satisfies(SecurityTag inTag, SecurityTag outTag) { private static boolean satisfies(SecurityRoleArgument inArgument, SecurityRoleArgument outArgument) { boolean namesMatch = inArgument.getName().equals(outArgument.getName()); + // blank argument overrides anything if (inArgument instanceof BlankSecurityRoleArgument) { return namesMatch; } + + // path arguments must share both names and paths if (inArgument instanceof PathSecurityRoleArgument && outArgument instanceof PathSecurityRoleArgument) { return namesMatch && ((PathSecurityRoleArgument)inArgument).getKnowledgePath().equals(((PathSecurityRoleArgument)outArgument).getKnowledgePath()); } + + // absolute arguments must share names and values if (inArgument instanceof AbsoluteSecurityRoleArgument && outArgument instanceof AbsoluteSecurityRoleArgument) { Object inValue = ((AbsoluteSecurityRoleArgument)inArgument).getValue(); Object outValue = ((AbsoluteSecurityRoleArgument)outArgument).getValue(); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RatingsEncryptor.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RatingsEncryptor.java index a23b666f7..814f6c909 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RatingsEncryptor.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RatingsEncryptor.java @@ -22,7 +22,7 @@ import cz.cuni.mff.d3s.deeco.network.RatingsMetaData; /** - * + * Class used to encrypt ratings data (IDs of the components, the knowledge paths and ratings). * @author Ondřej Štumpf * */ @@ -30,23 +30,44 @@ public class RatingsEncryptor { private final SecurityKeyManager keyManager; private final SecurityHelper securityHelper; + /** + * Instantiates a new ratings encryptor. + * + * @param keyManager + * the key manager + */ public RatingsEncryptor(SecurityKeyManager keyManager) { this.keyManager = keyManager; this.securityHelper = new SecurityHelper(); } + /** + * Encrypts ratings data and modifies given metadata accordingly. + * + * @param ratings + * the ratings + * @param ratingsMetaData + * the meta data + * @return the list of sealed objects + */ public List encryptRatings(List ratings, RatingsMetaData ratingsMetaData) { List result = new ArrayList<>(); try { + // get special well-known public key for this purpose Key publicKey = keyManager.getIntegrityPublicKey(); + + // generate random symmetrical key Key symmetricKey = securityHelper.generateKey(); + + // encrypt the symmetrical key with the public key and send it with data byte[] encryptedKey = securityHelper.encryptKey(symmetricKey, publicKey); Cipher symmetricCipher = securityHelper.getSymmetricCipher(Cipher.ENCRYPT_MODE, symmetricKey); ratingsMetaData.encryptedKey = encryptedKey; ratingsMetaData.encryptedKeyAlgorithm = symmetricKey.getAlgorithm(); + // use the cipher to encrypt everything in the list for (RatingsChangeSet changeSet : ratings) { SealedObject encryptedChangeSet = new SealedObject((Serializable) changeSet, symmetricCipher); @@ -59,6 +80,15 @@ public List encryptRatings(List ratings, Ratings return result; } + /** + * Decrypts ratings data. + * + * @param ratings + * the encrypted ratings + * @param ratingsMetaData + * the meta data + * @return the decrypted list + */ public List decryptRatings(List ratings, RatingsMetaData ratingsMetaData) { List result = new ArrayList<>(); @@ -66,16 +96,18 @@ public List decryptRatings(List ratings, Ratings Key decryptedSymmetricKey = null; try { + // use well-known private key for decryption of the key from metadata privateKey = keyManager.getIntegrityPrivateKey(); decryptedSymmetricKey = securityHelper.decryptKey(ratingsMetaData.encryptedKey, ratingsMetaData.encryptedKeyAlgorithm, privateKey); } catch (InvalidKeyException | CertificateEncodingException | NoSuchAlgorithmException | KeyStoreException | SecurityException | SignatureException | IllegalStateException | NoSuchPaddingException | ShortBufferException | IllegalBlockSizeException | BadPaddingException | IOException e1) { - e1.printStackTrace(); + // do nothing } if (decryptedSymmetricKey != null) { + // decrypt everything in the list for (SealedObject sealedObject : ratings) { try { RatingsChangeSet ratingsChangeSet = (RatingsChangeSet) sealedObject.getObject(securityHelper.getSymmetricCipher(Cipher.DECRYPT_MODE, decryptedSymmetricKey)); @@ -84,7 +116,7 @@ public List decryptRatings(List ratings, Ratings | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException | IOException e) { - e.printStackTrace(); + } } } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RemoteSecurityChecker.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RemoteSecurityChecker.java index 83018c7db..095e4471f 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RemoteSecurityChecker.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RemoteSecurityChecker.java @@ -8,11 +8,23 @@ import cz.cuni.mff.d3s.deeco.network.KnowledgeSecurityAnnotation; /** - * + * Class used to verification of access when exchanging knowledge between a local and a remote component. * @author Ondřej Štumpf * */ public class RemoteSecurityChecker { + + /** + * Checks if the local component has a role which allows it to read remote's component data. + * @param securityRole + * the role of the local component + * @param securityAnnotation + * the role required to read the data + * @param accessingKnowledgeManager + * the local knowledge manager + * @return true if the conditions are met + * @throws KnowledgeNotFoundException + */ public boolean checkSecurity(SecurityRole securityRole, KnowledgeSecurityAnnotation securityAnnotation, ReadOnlyKnowledgeManager accessingKnowledgeManager) throws KnowledgeNotFoundException { Map roleArguments = RoleHelper.readRoleArguments(securityRole, accessingKnowledgeManager); boolean namesMatch = securityRole.getRoleName().equals(securityAnnotation.getRoleName()); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RoleHelper.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RoleHelper.java index b7a9e6984..f624e294f 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RoleHelper.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/RoleHelper.java @@ -18,18 +18,26 @@ import cz.cuni.mff.d3s.deeco.model.runtime.api.SecurityRoleArgument; /** - * + * Helper class providing functionality for working with roles and their parameters. * @author Ondřej Štumpf */ public class RoleHelper { + + /** + * Checks if the arguments of the role contain such values that they correspond to the arguments + * of the security tag. + * + * @param roleArguments + * the role arguments + * @param tagArguments + * the tag arguments + * @return true, if successful + */ public static boolean roleArgumentsMatch(Map roleArguments, Map tagArguments) { - if (!roleArguments.keySet().equals(tagArguments.keySet())) { - return false; - } - boolean match = true; + // each of the tag parameters must be matched for (Entry entry : tagArguments.entrySet()) { Object roleArgumentValue = roleArguments.get(entry.getKey()); match = match && ((roleArgumentValue == null) || (entry.getValue() != null && entry.getValue().equals(roleArgumentValue))); @@ -40,6 +48,13 @@ public static boolean roleArgumentsMatch(Map roleArguments, Map< return match; } + /** + * Gets the transitive closure of the given roles. + * + * @param roles + * the roles + * @return the transitive closure + */ public static List getTransitiveRoles(List roles) { List result = new LinkedList<>(); result.addAll(roles); @@ -47,13 +62,27 @@ public static List getTransitiveRoles(List roles) { return result; } + /** + * Reads role arguments values from the given knowledge manager. + * + * @param requiredRole + * the role with the arguments + * @param knowledgeManager + * the knowledge manager from which to read the data + * @return the map knowledge path -> value + * @throws KnowledgeNotFoundException + * the knowledge not found exception + */ public static Map readRoleArguments(SecurityRole requiredRole, ReadOnlyKnowledgeManager knowledgeManager) throws KnowledgeNotFoundException { Map arguments = new HashMap<>(); + + // get the knowledge paths used in the parameters List knowledgePaths = requiredRole.getArguments().stream() .filter(arg -> arg instanceof PathSecurityRoleArgument) .map(arg -> ((PathSecurityRoleArgument)arg).getKnowledgePath()) .collect(Collectors.toList()); + // load the knowledge from the manager ValueSet argumentsValueSet = null; if (!knowledgePaths.isEmpty()) { argumentsValueSet = knowledgeManager.get(knowledgePaths); @@ -61,11 +90,14 @@ public static Map readRoleArguments(SecurityRole requiredRole, R for (SecurityRoleArgument argument : requiredRole.getArguments()) { if (argument instanceof PathSecurityRoleArgument) { + // get the value from value set KnowledgePath argumentPath = ((PathSecurityRoleArgument)argument).getKnowledgePath(); arguments.put(argument.getName(), argumentsValueSet.getValue(argumentPath)); } else if (argument instanceof BlankSecurityRoleArgument) { + // set null arguments.put(argument.getName(), null); } else if (argument instanceof AbsoluteSecurityRoleArgument) { + // set the actual value of the parameter arguments.put(argument.getName(), ((AbsoluteSecurityRoleArgument)argument).getValue() ); } else throw new KnowledgeNotFoundException(); } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityHelper.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityHelper.java index 3b093b8d5..b80c8257b 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityHelper.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityHelper.java @@ -27,6 +27,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; /** + * Helper class containing low-level functionality for working with security keys. * @author Ondřej Štumpf */ public class SecurityHelper { @@ -38,6 +39,15 @@ public class SecurityHelper { Security.addProvider(new BouncyCastleProvider()); } + /** + * Encrypts the symmetric key using the public key. + * + * @param symmetricKey + * the symmetric key + * @param publicKey + * the public key + * @return the encrypted symmetric key + */ public byte[] encryptKey(Key symmetricKey, Key publicKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, IOException { Cipher publicCipher = getAsymmetricCipher(Cipher.ENCRYPT_MODE, publicKey); byte[] input = symmetricKey.getEncoded(); @@ -45,6 +55,17 @@ public byte[] encryptKey(Key symmetricKey, Key publicKey) throws InvalidKeyExcep return transform(input, publicCipher); } + /** + * Decrypts the symmetric key with specified algorithm using given private key. + * + * @param encryptedKey + * the encrypted key + * @param algorithm + * the algorithm + * @param privateKey + * the private key + * @return the decrypted key + */ public Key decryptKey(byte[] encryptedKey, String algorithm, Key privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, IOException { Cipher publicCipher = getAsymmetricCipher(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedKey = transform(encryptedKey, publicCipher); @@ -52,6 +73,15 @@ public Key decryptKey(byte[] encryptedKey, String algorithm, Key privateKey) thr return new SecretKeySpec(decryptedKey, algorithm); } + /** + * Transforms (encrypts/decrypts) the array of bytes using given cipher. + * + * @param data + * the data + * @param cipher + * the cipher + * @return the transformed data + */ public byte[] transform(byte[] data, Cipher cipher) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException, IOException { byte[] buffer = new byte[BLOCK_SIZE]; int noBytes = 0; @@ -80,22 +110,54 @@ public byte[] transform(byte[] data, Cipher cipher) throws ShortBufferException, return outputStream.toByteArray(); } + /** + * Gets the symmetric cipher for the given symmetric key. + * + * @param opmode + * the operation mode {@link Cipher} + * @param symmetricKey + * the symmetric key + * @return the symmetric cipher + */ public Cipher getSymmetricCipher(int opmode, Key symmetricKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { Cipher cipher = Cipher.getInstance(symmetricKey.getAlgorithm()); cipher.init(opmode, symmetricKey); return cipher; } - public Cipher getAsymmetricCipher(int opmode, Key publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { - Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); - cipher.init(opmode, publicKey); + /** + * Gets the asymmetric cipher for the given key. + * + * @param opmode + * the operation mode {@link Cipher} + * @param assymetricKey + * the public/private key + * @return the asymmetric cipher + */ + public Cipher getAsymmetricCipher(int opmode, Key assymetricKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(assymetricKey.getAlgorithm()); + cipher.init(opmode, assymetricKey); return cipher; } + /** + * Generates random AES key of size 128b. WARNING: raising the key size requries the JCE to be installed!!. + * + * @return AES key of size 128b + */ public Key generateKey() throws NoSuchAlgorithmException { return generateKey("AES", 128); } + /** + * Generates new symmetric key. + * + * @param algorithm + * the algorithm of the key + * @param keySize + * the key size + * @return the key + */ public Key generateKey(String algorithm, int keySize) throws NoSuchAlgorithmException { KeyGenerator generator = KeyGenerator.getInstance(algorithm); generator.init(keySize); @@ -103,16 +165,39 @@ public Key generateKey(String algorithm, int keySize) throws NoSuchAlgorithmExce return generator.generateKey(); } + /** + * Generates new key pair with the RSA algorithm and 1024b key size. + * + * @return the key pair + */ public KeyPair generateKeyPair() throws NoSuchAlgorithmException { return generateKeyPair("RSA", 1024); } + /** + * Generates new key pair. + * + * @param algorithm + * the algorithm + * @param keySize + * the key size + * @return the key pair + */ public KeyPair generateKeyPair(String algorithm, int keySize) throws NoSuchAlgorithmException { KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithm); generator.initialize(keySize, secureRandom); return generator.generateKeyPair(); } + /** + * Sign the given data using the private key. + * + * @param key + * the key + * @param data + * the data + * @return the signature + */ public byte[] sign(PrivateKey key, Object... data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, SignatureException { if (data == null || data.length == 0) { throw new IllegalArgumentException("No data to sign."); @@ -127,6 +212,17 @@ public byte[] sign(PrivateKey key, Object... data) throws NoSuchAlgorithmExcepti return signature.sign(); } + /** + * Verify the signature. + * + * @param signatureHash + * the signature hash + * @param key + * the key + * @param data + * the data + * @return true, if successful + */ public boolean verify(byte[] signatureHash, PublicKey key, Object... data) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { if (data == null || data.length == 0) { throw new IllegalArgumentException("No data to verify."); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManager.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManager.java index 62e2f4cba..9ad677806 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManager.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManager.java @@ -10,15 +10,45 @@ import java.util.Map; /** - * @author Ondřej Štumpf + * The manager of certificates and public/private key pairs. + * + * @author Ondřej Štumpf */ public interface SecurityKeyManager { - PublicKey getPublicKeyFor(String roleName, Map arguments) throws KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SecurityException, SignatureException, IllegalStateException; + /** + * Gets the public key for the given role and concrete argument values. + * + * @param roleName + * the role name + * @param arguments + * the arguments + * @return the public key + */ + PublicKey getPublicKey(String roleName, Map arguments) throws KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SecurityException, SignatureException, IllegalStateException; - PrivateKey getPrivateKeyFor(String roleName, Map arguments) throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException; + /** + * Gets the private key for the given role and concrete argument values. + * + * @param roleName + * the role name + * @param arguments + * the arguments + * @return the private key + */ + PrivateKey getPrivateKey(String roleName, Map arguments) throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException; + /** + * Gets the private key used for signatures and ratings decryption. + * + * @return the private key + */ PrivateKey getIntegrityPrivateKey() throws InvalidKeyException, CertificateEncodingException, NoSuchAlgorithmException, KeyStoreException, SecurityException, SignatureException, IllegalStateException; + /** + * Gets the public key used for signatures and ratings decryption. + * + * @return the public key + */ PublicKey getIntegrityPublicKey() throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException; } diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImpl.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImpl.java index e0cd05cc6..92d7aae92 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImpl.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImpl.java @@ -24,17 +24,30 @@ /** - * @author Ondřej Štumpf + * The security key manager. + * + * @author Ondřej Štumpf */ public class SecurityKeyManagerImpl implements SecurityKeyManager { + /** storage of the certificates */ private KeyStore keyStore; + + /** storage of the private keys */ private Map privateKeys; + + /** secure random number generator */ private SecureRandom secureRandom; + + /** Security helper instance */ private SecurityHelper securityHelper; private final Integer INTEGRITY_KEY = 95423814; + /** + * Instantiates a new security key manager. + * + */ public SecurityKeyManagerImpl() throws KeyStoreException { this.keyStore = KeyStore.getInstance("JKS"); this.secureRandom = new SecureRandom(); @@ -53,8 +66,11 @@ private void initialize() throws NoSuchAlgorithmException, CertificateException, keyStore.load(null, null); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.security.SecurityKeyManager#getPublicKey(java.lang.String, java.util.Map) + */ @Override - public PublicKey getPublicKeyFor(String roleName, Map arguments) throws KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SecurityException, SignatureException, IllegalStateException { + public PublicKey getPublicKey(String roleName, Map arguments) throws KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SecurityException, SignatureException, IllegalStateException { Integer roleKey = getRoleKey(roleName, arguments); if (!keyStore.containsAlias(roleKey.toString())) { @@ -64,8 +80,11 @@ public PublicKey getPublicKeyFor(String roleName, Map arguments) return keyStore.getCertificate(roleKey.toString()).getPublicKey(); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.security.SecurityKeyManager#getPrivateKey(java.lang.String, java.util.Map) + */ @Override - public PrivateKey getPrivateKeyFor(String roleName, Map arguments) throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { + public PrivateKey getPrivateKey(String roleName, Map arguments) throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { Integer roleKey = getRoleKey(roleName, arguments); if (!keyStore.containsAlias(roleKey.toString())) { @@ -75,6 +94,9 @@ public PrivateKey getPrivateKeyFor(String roleName, Map argument return privateKeys.get(roleKey); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.security.SecurityKeyManager#getIntegrityPrivateKey() + */ @Override public PrivateKey getIntegrityPrivateKey() throws InvalidKeyException, CertificateEncodingException, NoSuchAlgorithmException, KeyStoreException, SecurityException, SignatureException, IllegalStateException { if (!keyStore.containsAlias(INTEGRITY_KEY.toString())) { @@ -84,6 +106,9 @@ public PrivateKey getIntegrityPrivateKey() throws InvalidKeyException, Certifica return privateKeys.get(INTEGRITY_KEY); } + /* (non-Javadoc) + * @see cz.cuni.mff.d3s.deeco.security.SecurityKeyManager#getIntegrityPublicKey() + */ @Override public PublicKey getIntegrityPublicKey() throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { if (!keyStore.containsAlias(INTEGRITY_KEY.toString())) { diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityTagCollection.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityTagCollection.java index 355dcaa77..f91866494 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityTagCollection.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/security/SecurityTagCollection.java @@ -20,7 +20,8 @@ import cz.cuni.mff.d3s.deeco.task.KnowledgePathHelper.PathRoot; /** - * + * Represents a formula securing a knowledge path. The formula has a DNF form, i.e. disjunction of conjunctions. The literals + * are security tags. * @author Ondřej Štumpf * */ @@ -28,25 +29,39 @@ public class SecurityTagCollection extends ArrayList> { private static final long serialVersionUID = -246404371591456723L; + /** + * Gets the formula protecting the given (possibly non-absolute) knowledge path. + * @param knowledgePath + * the knowledge path + * @param knowledgeManager + * the knowledge manager that contains security information about the path + * @return instance of {@link SecurityTagCollection} + */ public static SecurityTagCollection getSecurityTags(KnowledgePath knowledgePath, ReadOnlyKnowledgeManager knowledgeManager) { SecurityTagCollection result = new SecurityTagCollection(); Iterator iterator = knowledgePath.getNodes().iterator(); + + // check if the path is empty if (!iterator.hasNext()) { throw new IllegalArgumentException("The knowledge path contains no nodes."); } + // first node must be either ID or field name PathNode firstNode = iterator.next(); if (!(firstNode instanceof PathNodeField) && !(firstNode instanceof PathNodeComponentId)) { throw new IllegalArgumentException("The knowledge path must refer to a field."); } + // get security tags associated directly with the field List tags = (firstNode instanceof PathNodeField) ? knowledgeManager.getSecurityTags((PathNodeField)firstNode) : null; if (tags == null) { tags = new LinkedList<>(); } + // convert list of elements into list of lists of elements result.addAll(tags.stream().map(tag -> Arrays.asList(tag)).collect(Collectors.toList())); + // recursively build the DNF while (iterator.hasNext()) { PathNode node = iterator.next(); if (node instanceof PathNodeMapKey) { @@ -59,16 +74,32 @@ public static SecurityTagCollection getSecurityTags(KnowledgePath knowledgePath, return result; } + /** + * Gets the formula protecting the given (possibly non-absolute) knowledge path. + * @param localRole + * the local component role coord/member + * @param knowledgePath + * the knowledge path + * @param localKnowledgeManager + * the local knowledge manager + * @param shadowKnowledgeManager + * the shadow knowledge manager + * @param securityTagManager + * mapping between security tags and knowledge managers that contain them, possibly null + * @return instance of {@link SecurityTagCollection} + */ public static SecurityTagCollection getSecurityTags(PathRoot localRole, KnowledgePath knowledgePath, ReadOnlyKnowledgeManager localKnowledgeManager, ReadOnlyKnowledgeManager shadowKnowledgeManager, Map securityTagManager) { SecurityTagCollection result = new SecurityTagCollection(); + // check if the path is empty Iterator iterator = knowledgePath.getNodes().iterator(); if (!iterator.hasNext()) { throw new IllegalArgumentException("The knowledge path contains no nodes."); } PathNode firstNode = iterator.next(); + // determine the knowledge manager to use ReadOnlyKnowledgeManager relevantKnowledgeManager; if (firstNode instanceof PathNodeCoordinator) { if (localRole == PathRoot.COORDINATOR) { @@ -86,22 +117,27 @@ public static SecurityTagCollection getSecurityTags(PathRoot localRole, Knowledg throw new IllegalArgumentException("The knowledge path must start with member/coordinator."); } + // second node must be either ID or field name PathNode secondNode = iterator.next(); if (!(secondNode instanceof PathNodeField) && !(secondNode instanceof PathNodeComponentId)) { throw new IllegalArgumentException("The knowledge path must refer to a field."); } + // get security tags associated directly with the field List tags = (secondNode instanceof PathNodeField) ? relevantKnowledgeManager.getSecurityTags((PathNodeField)secondNode) : null; if (tags == null) { tags = new LinkedList<>(); } + // map the tag to its knowledge manager if (securityTagManager != null) { tags.stream().forEach(tag -> securityTagManager.put(tag, relevantKnowledgeManager)); } + // convert list of elements into list of lists of elements result.addAll(tags.stream().map(tag -> Arrays.asList(tag)).collect(Collectors.toList())); + // recursively build the DNF while (iterator.hasNext()) { PathNode node = iterator.next(); if (node instanceof PathNodeMapKey) { @@ -114,6 +150,11 @@ public static SecurityTagCollection getSecurityTags(PathRoot localRole, Knowledg return result; } + /** + * Merge the two DNF formulas. + * @param other + * @return + */ public SecurityTagCollection mergeWith(SecurityTagCollection other) { SecurityTagCollection result = new SecurityTagCollection(); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/EnsembleTask.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/EnsembleTask.java index bc3b3f265..7f1d76df4 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/EnsembleTask.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/EnsembleTask.java @@ -514,6 +514,12 @@ private boolean performExchange(PathRoot localRole, ReadOnlyKnowledgeManager sha return true; } + /** + * Invokes the method marked with the {@link RatingsProcess} annotation. + * @param shadowComponentId + * the ID of the shadow component + * @throws TaskInvocationException + */ private void invokeRatingsProcess(String shadowComponentId) throws TaskInvocationException { ComponentInstance component = ensembleController.getComponentInstance(); KnowledgeManager knowledgeManager = component.getKnowledgeManager(); @@ -541,6 +547,7 @@ private void invokeRatingsProcess(String shadowComponentId) throws TaskInvocatio String.format("Knowledge path (%s) could not be resolved.", e.getNotFoundPath()), e); } + // only IN and RATING params are allowed if (paramDir == ParameterKind.IN) { inPaths.add(absoluteKnowledgePath); } @@ -597,6 +604,7 @@ private void invokeRatingsProcess(String shadowComponentId) throws TaskInvocatio // Call the rating process method process.getMethod().invoke(null, actualParams); + // update the ratings container and prepare the change set for distribution List changes = ratingsManager.createRatingsChangeSet(ratingsHolders); ratingsManager.update(changes); ratingsManager.addToPendingChangeSets(changes); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/ProcessTask.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/ProcessTask.java index c5441a2c4..643f6453f 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/ProcessTask.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/task/ProcessTask.java @@ -21,7 +21,6 @@ import cz.cuni.mff.d3s.deeco.model.runtime.api.TimeTrigger; import cz.cuni.mff.d3s.deeco.model.runtime.api.Trigger; import cz.cuni.mff.d3s.deeco.scheduler.Scheduler; -import cz.cuni.mff.d3s.deeco.security.ModelSecurityValidator; /** * The implementation of {@link Task} that corresponds to a component process. This class is responsible for (a) registering triggers with the @@ -92,6 +91,7 @@ public ProcessTask(ComponentProcess componentProcess, Scheduler scheduler, Archi * @throws TaskInvocationException signifies a problem in executing the task including the case when parameters cannot be retrieved from / updated in * the knowledge manager. */ + @SuppressWarnings("unchecked") @Override public void invoke(Trigger trigger) throws TaskInvocationException { // Obtain parameters from the knowledge diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC4.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC4.java index 43ecb82ad..6ea23fd02 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC4.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC4.java @@ -13,8 +13,8 @@ */ @Component -@HasRole(roleClass = CorrectC4.Role1.class) -@HasRole(roleClass = CorrectC4.Role2.class) +@HasRole(CorrectC4.Role1.class) +@HasRole(CorrectC4.Role2.class) public class CorrectC4 { @RoleDefinition @@ -43,10 +43,10 @@ public static interface Role3 { public String name; - @Allow(roleClass = Role1.class) - @Allow(roleClass = Role3.class) + @Allow(Role1.class) + @Allow(Role3.class) public Integer capacity; - @Allow(roleClass = Role2.class) + @Allow(Role2.class) public Date time; } diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC5.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC5.java index c2fc662be..fdfc48729 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC5.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/CorrectC5.java @@ -43,7 +43,7 @@ public static interface Role3 extends Role1, Role2 { public static final String fieldRole0 = "value_override"; } - @Allow(roleClass = Role3.class) + @Allow(Role3.class) public String name; public String x,y,z,v; diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC10.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC10.java index 4212ae738..ac77dba4d 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC10.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC10.java @@ -13,8 +13,8 @@ */ @Component -@HasRole(roleClass = WrongC10.Role1.class) -@HasRole(roleClass = WrongC10.Role2.class) +@HasRole(WrongC10.Role1.class) +@HasRole(WrongC10.Role2.class) public class WrongC10 { @RoleDefinition @@ -43,10 +43,10 @@ public static interface Role3 { public String name; - @Allow(roleClass = Role1.class) - @Allow(roleClass = Role3.class) + @Allow(Role1.class) + @Allow(Role3.class) public Integer capacity; - @Allow(roleClass = Role2.class) + @Allow(Role2.class) public Date time; } diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC11.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC11.java index f9e4df12e..009706df6 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC11.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC11.java @@ -21,7 +21,7 @@ public static interface Role1 { } - @Allow(roleClass = Role1.class) + @Allow(Role1.class) public Integer securedCapacity; public Integer capacity; diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC12.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC12.java index 15e90362b..7c7cc034f 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC12.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC12.java @@ -21,7 +21,7 @@ public static interface Role1 { public static String nonexisting_param = "[no_such_parameter]"; } - @Allow(roleClass = Role1.class) + @Allow(Role1.class) public Integer securedCapacity; public Integer capacity; diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC4WithSecurity.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC4WithSecurity.java index 7ba862921..d52b89ef8 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC4WithSecurity.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC4WithSecurity.java @@ -14,8 +14,8 @@ */ @Component -@HasRole(roleClass = WrongC4WithSecurity.Role1.class) -@HasRole(roleClass = WrongC4WithSecurity.Role2.class) +@HasRole(WrongC4WithSecurity.Role1.class) +@HasRole(WrongC4WithSecurity.Role2.class) public class WrongC4WithSecurity { @RoleDefinition @@ -38,13 +38,13 @@ public static interface Role3 { public String name; - @Allow(roleClass = WrongC4WithSecurity.Role1.class) - @Allow(roleClass = WrongC4WithSecurity.Role3.class) + @Allow(WrongC4WithSecurity.Role1.class) + @Allow(WrongC4WithSecurity.Role3.class) public Integer capacity; - @Allow(roleClass = WrongC4WithSecurity.Role2.class) + @Allow(WrongC4WithSecurity.Role2.class) public Date time; - @Allow(roleClass = WrongC4WithSecurity.Role1.class) + @Allow(WrongC4WithSecurity.Role1.class) public String id; } diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC8.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC8.java index 1909f3f37..fc97df2d9 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC8.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC8.java @@ -10,7 +10,7 @@ */ @Component -@HasRole(roleClass = WrongC8.Role1.class) +@HasRole(WrongC8.Role1.class) public class WrongC8 { @RoleDefinition @@ -19,8 +19,8 @@ public static interface Role1 { } // the same role assigned multiply - @Allow(roleClass = Role1.class) - @Allow(roleClass = Role1.class) + @Allow(Role1.class) + @Allow(Role1.class) public Integer capacity; } diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC9.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC9.java index 0a4d425fd..3bb50fa42 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC9.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/annotations/processor/input/samples/WrongC9.java @@ -11,7 +11,7 @@ */ @Component -@HasRole(roleClass = WrongC9.Role1.class) +@HasRole(WrongC9.Role1.class) public class WrongC9 { @RoleDefinition @@ -20,7 +20,7 @@ public static interface Role1 { } // local knowledge cannot be secured - @Allow(roleClass = Role1.class) + @Allow(Role1.class) @Local public Integer capacity; diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptorTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptorTest.java index 099fad590..e31c89958 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptorTest.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/KnowledgeEncryptorTest.java @@ -94,9 +94,9 @@ public void setUp() throws InvalidKeyException, CertificateEncodingException, Ke testrole1PrivateKey = role1Pair.getPrivate(); keyManagerMock = mock(SecurityKeyManager.class); - when(keyManagerMock.getPublicKeyFor(eq("testrole1"), anyObject())).thenReturn(testrole1PublicKey); - when(keyManagerMock.getPrivateKeyFor(eq("testrole1"), anyObject())).thenReturn(testrole1PrivateKey); - when(keyManagerMock.getPublicKeyFor(eq("testrole2"), anyObject())).thenReturn(testrole2PublicKey); + when(keyManagerMock.getPublicKey(eq("testrole1"), anyObject())).thenReturn(testrole1PublicKey); + when(keyManagerMock.getPrivateKey(eq("testrole1"), anyObject())).thenReturn(testrole1PrivateKey); + when(keyManagerMock.getPublicKey(eq("testrole2"), anyObject())).thenReturn(testrole2PublicKey); when(keyManagerMock.getIntegrityPublicKey()).thenReturn(integrityPair.getPublic()); when(keyManagerMock.getIntegrityPrivateKey()).thenReturn(integrityPair.getPrivate()); diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/RoleHelperTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/RoleHelperTest.java index af227da0d..bcf23629c 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/RoleHelperTest.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/RoleHelperTest.java @@ -134,7 +134,7 @@ public void argumentsRoleMatchTest4() { @Test public void argumentsRoleMatchTest5() { - // when key sets are not equal + // when the role contains an extra parameter Map roleArguments = new HashMap<>(); roleArguments.put("x", null); roleArguments.put("y", "y"); @@ -143,9 +143,25 @@ public void argumentsRoleMatchTest5() { Map tagArguments = new HashMap<>(); tagArguments.put("x", null); tagArguments.put("y", "y"); + + // then true is returned + assertTrue(RoleHelper.roleArgumentsMatch(roleArguments, tagArguments)); + } + + @Test + public void argumentsRoleMatchTest6() { + // when the tag contains an extra parameter + Map roleArguments = new HashMap<>(); + roleArguments.put("x", null); + roleArguments.put("y", "y"); + + Map tagArguments = new HashMap<>(); + tagArguments.put("x", null); + tagArguments.put("y", "y"); + tagArguments.put("z", Arrays.asList(1,2,3)); // then false is returned - assertFalse(RoleHelper.roleArgumentsMatch(roleArguments, tagArguments)); + assertTrue(RoleHelper.roleArgumentsMatch(roleArguments, tagArguments)); } @Test diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImplTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImplTest.java index 919868a77..a7ef6aaa2 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImplTest.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/SecurityKeyManagerImplTest.java @@ -33,7 +33,7 @@ public void setUp() throws KeyStoreException { @Test public void getPublicKeyTest1() throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { - assertNotNull(target.getPublicKeyFor("role1", null)); + assertNotNull(target.getPublicKey("role1", null)); } @Test @@ -41,11 +41,11 @@ public void getPublicKeyTest2() throws InvalidKeyException, CertificateEncodingE Map args = new HashMap<>(); args.put("x", "xvalue"); - Key key1 = target.getPublicKeyFor("role1", null); - Key key2 = target.getPublicKeyFor("role1", args); + Key key1 = target.getPublicKey("role1", null); + Key key2 = target.getPublicKey("role1", args); args.put("y", null); - Key key3 = target.getPublicKeyFor("role1", args); + Key key3 = target.getPublicKey("role1", args); assertNotNull(key2); assertNotEquals(key1, key2); @@ -55,12 +55,12 @@ public void getPublicKeyTest2() throws InvalidKeyException, CertificateEncodingE @Test public void getPublicKeyTest3() throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { - assertEquals(target.getPublicKeyFor("role1", null), target.getPublicKeyFor("role1", null)); + assertEquals(target.getPublicKey("role1", null), target.getPublicKey("role1", null)); } @Test public void getPrivateKeyTest1() throws InvalidKeyException, CertificateEncodingException, KeyStoreException, NoSuchAlgorithmException, SecurityException, SignatureException, IllegalStateException { - assertNotNull(target.getPrivateKeyFor("role1", null)); + assertNotNull(target.getPrivateKey("role1", null)); } @Test(expected = Throwable.class) @@ -70,12 +70,12 @@ public void incompatibilityTest() throws NoSuchAlgorithmException, NoSuchPadding Map args = new HashMap<>(); args.put("x", "xvalue"); Cipher decryptCipher = Cipher.getInstance("RSA"); - decryptCipher.init(Cipher.DECRYPT_MODE, target.getPrivateKeyFor("role1", args)); + decryptCipher.init(Cipher.DECRYPT_MODE, target.getPrivateKey("role1", args)); args = new HashMap<>(); args.put("x", null); Cipher encryptCipher = Cipher.getInstance("RSA"); - encryptCipher.init(Cipher.ENCRYPT_MODE, target.getPublicKeyFor("role1", args)); + encryptCipher.init(Cipher.ENCRYPT_MODE, target.getPublicKey("role1", args)); byte[] cipherText = encryptCipher.doFinal(text.getBytes()); byte[] decipheredText = decryptCipher.doFinal(cipherText); @@ -88,10 +88,10 @@ public void compatibilityTest() throws NoSuchAlgorithmException, NoSuchPaddingEx String text = "hello"; Cipher decryptCipher = Cipher.getInstance("RSA"); - decryptCipher.init(Cipher.DECRYPT_MODE, target.getPrivateKeyFor("role1", null)); + decryptCipher.init(Cipher.DECRYPT_MODE, target.getPrivateKey("role1", null)); Cipher encryptCipher = Cipher.getInstance("RSA"); - encryptCipher.init(Cipher.ENCRYPT_MODE, target.getPublicKeyFor("role1", null)); + encryptCipher.init(Cipher.ENCRYPT_MODE, target.getPublicKey("role1", null)); byte[] cipherText = encryptCipher.doFinal(text.getBytes()); byte[] decipheredText = decryptCipher.doFinal(cipherText); diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/runtime/SecurityRuntimeModel.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/runtime/SecurityRuntimeModel.java index 03975fde3..505356415 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/runtime/SecurityRuntimeModel.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/security/runtime/SecurityRuntimeModel.java @@ -77,7 +77,7 @@ public static class VehicleComponent { public String id; public String cityId; - @Allow(roleClass = PoliceInCity.class) + @Allow(PoliceInCity.class) public String secret; public VehicleComponent(String id, String cityId, String secret) { @@ -89,7 +89,7 @@ public VehicleComponent(String id, String cityId, String secret) { } @Component - @HasRole(roleClass = PoliceInCity.class) + @HasRole(PoliceInCity.class) public static class PoliceComponent { public String id; public String cityId; @@ -120,7 +120,7 @@ public static void ratingProcess(@In("cityId") String cityId, @Rating("cityId") } @Component - @HasRole(roleClass = PoliceEverywhere.class) + @HasRole(PoliceEverywhere.class) public static class GlobalPoliceComponent { public String id;