Overview

For any MYDATA-enabled system, a so-call "Policy Enforcement Point" (PEP) has to be integrated into the system. Its main purpose is to intercept or monitor events within the system, fetch a policy decision from the Policy Decision Point (PDP), and to modify the event according to the provided decision.

Whether an event can can be intercepted or monitored depends on the system. The main difference is that some events can be seen by a PEP (i.e., monitored), but it cannot be prevented that the event is further executed.

In a nutshell, PEPs work as follows:

  1. At some point in the application, the PEP receives an event (e.g., message, event on a bus) or is programmatically called.

  2. The PEP transforms it into the Event structure, which consists of an event name, a timestamp and a key-value list of parameters (primitives or Java objects)

  3. The PEP sends serializes the event and sends it to the PDP

  4. The PEP receives an AuthorizationDecision with instructions based on the currently deployed policies

  5. The PEP modifies the event, deserializes it and replaces the original event with the modified event. If the event should be inhibited, the PEP throws an InhibitException.

PEP
Figure 1. Basic PEP-PDP Communication

PEP Structure

A PEP is composed of two basic subcomponents: Decision Enforcers and Modifiers. By default, our SDK offers a Decision Enforcer that works on Json and a set of generic modifiers.

Decision Enforcers

The Decision Enforcers task is to enforce any decision on the given event. The JsonPathDecisionEnforcer is a concrete implementation of a DecisionEnforcer coming with our SDK. The JsonPathDecisionEnforcer enforces the authorization decision on parameters using JsonPath. For a custom implementation, the DecisionEnforcer interface must be implemented and provided during PEP initialization. Decision Enforcer also knows which modifier methods are registered.

Modifiers

One of the key features of MYDATA is the ability to modify events. Is is implemented by so-called Modifiers that are used for changing the value of certain parameters of the event. By default, several generic modifiers are available, e.g.:

  • Delete: Delete an event parameter or parts of a complex parameter using JsonPath

  • Replace: Replaces an event parameter or parts of a complex parameter using JsonPath

  • Anagram: Rearranges the letters of an event parameter or parts of a complex parameter using JsonPath

  • Append: Appends prefix or suffix to an event parameter or parts of a complex parameter using JsonPath

Custom modifiers can be developed by implementing the ModifierMethod interface. The following example shows the AnagramModifier:

public class AnagramModifierMethod implements ModifierMethod {
    public AnagramModifierMethod() {
    }

    public DocumentContext doModification(DocumentContext documentContext, String expression, ParameterList parameterList) {
        Object percentage = parameterList.getParameterValueForName("percentage");
        int percentageParam = percentage != null?Integer.parseInt(String.valueOf(percentage)):0;
        return this.anagram(documentContext, expression, percentageParam);
    }

    @ActionDescription(description =
    	  "Jumbles up the letters of the word so string does not make any sense",
        pepSupportedType = String.class
    )
    public DocumentContext Anagram(DocumentContext documentContext, String expression, @ActionParameterDescription(name = "percentage", description = "percentage of String to be modified (value between 0 and 100)", mandatory = true) int percentage) {
        final MapFunction blur = (o, configuration) -> this.scramble(o.toString(), percentage);
        return documentContext.map(expression, blur);
    }

    public String getDisplayName() {
        return "anagram";
    }

    private String scramble(String inputString, int count) {
        Random random = new Random();
        char[] a = inputString.toCharArray();

        final int limit = Math.round((a.length * (Math.min(count, 100) / 100f)));

		  for (int i = 0; i < Math.min(a.length - 1, limit); i++) {
        	  final int j = random.nextInt(Math.min(a.length - 1, limit));
        	  final char temp = a[i];
      		  a[i] = a[j];
      		  a[j] = temp;
    	  }
    	  final String result = new String(a);

    	  return result;
    }
}

Explanation of the above example:

  • doModification is the method that is called to modify an object using the following parameters

    • DocumentContext is the compiled version of the object from JsonPath in JSON format

    • parameterList contains parameters that are specified in the policy

    • expression is the JsonPath expression that is specified in the policy

  • getDisplayName denotes the name of modifier that is visible during policy specification

  • @ActionDescription is used by the PEP to describe what this modifier method would do. Its attribute description specifies what it does and pepSupportedType specifies which data types are supported by this modifier

  • @ActionParameterDescription specifies details of parameters that can be specified in the policy and passed in AuthorizationDecision. If the name attribute is not specified, then it takes the name of the parameter.

Specification & Registration

During initialization, the PEP needs to know which Decision Enforcer, interface descriptor and modifiers are used. Using that information, the PEP has to be registered with the Policy Management Point (PMP). All information regarding modifiers, interfaces and object structures (passed to the PDP) are passed to the PMP. This information is used for policy specification. Using java reflection, all this information is automatically registered. Details of this process are clarified in this page.

To register a PEP, add a maven dependency in the pom file:

<dependency>
  <groupId>de.fraunhofer.iese.ind2uce</groupId>
  <artifactId>sdk</artifactId>
  <version>${ind2uce.version}</version>
</dependency>

In addition to these dependencies, one needs to add another dependency depending on the protocol used. MYDATA by default uses HTTP protocol & following dependency is to be used for connection.

<dependency>
    <groupId>de.fraunhofer.iese.ind2uce</groupId>
    <artifactId>connectors.rest</artifactId>
    <version>${ind2uce.version}</version>
</dependency>

A DocumentationAPI interface must be specified for registering it with the PMP. A sample interface may look as follows:

@PEPServiceDescription(componentId = "urn:component:cs4:pep:reactivePEP")
@ProvidedModifiers(className = {
    AppendModifierMethod.class, ReplaceModifierMethod.class, AnagramModifierMethod.class, DeleteModifierMethod.class
})
public interface RxPEPDocumentationAPI {

}

The interface defines the annotation @PEPServiceDescription, which has the PEP componentId as a mandatory attribute. Note: ComponentId should be unique within the whole execution environment.

Annotation @ProvidedModifiers specifies the association with the event, which will be used to register the PEP at the PMP. @ProvidedModifiers will be initialized if it has a default constructor.

Each DocumentationAPI interface is configured as RxPEP using RxPEPFactory and is then used to register with the PMP.

ReactivePEP Registration

Here is an example for RxPEP generation and registration:

The RxPEPFactory.createRxPEP() method of RxPEPFactory is used for generating PEP as shown below:

ReactivePEP<RxPEPDocumentationAPI> rxPEP = RxPEPFactory.createRxPEP(RxPEPDocumentationAPI.class, pmpUri, aliveCheckUri, oauthCredentials);
RxPEPDocumentationAPI rxPepAPI;

If there was no error in the definition of the PEP documentation API (a RuntimeException with a reason is thrown if there were declaration errors), the ReactivePEP<T> is created successfully. pmpUri points to the URI of the PMP hosted in the target system and aliveCheckUri points to the URI of the PEP. The 'oauthCredentials' contain the client_id, client_secret and access_token_uri. This information is provided when the solution is initially created

The next step is to register the PEP at the PMP as shown below:

rxPEP.doRegisterAtPMP().subscribe((b) -> {
      // onNext registration status is pushed to subscription
      if( b.booleanValue())
        rxPepAPI = rxPEP.createInstanceAPI();
    });

The methods specified above will generate an implementation for the specified DocumentationAPI interface and register with the PMP.

Events in ReactivePEP

Once the interfaces have been generated, the PEP needs to provide methods for policy enforcement. Using RxPEP, the return type of an enforcement method is Observable<Event> and by subscribing to that Observable<Event> one can access the decision.

The DocumentationAPI for RxPEP looks as follows:

@PEPServiceDescription(componentId = "urn:component:cs4:pep:ReactivePEP")
@ProvidedModifiers(className = { AppendModifierMethod.class, ReplaceModifierMethod.class })
public interface RxPEPDocumentationAPI {

  // arguments user and address will be used as parameter in event and event id will be "unr:action:cs4:show-user"
  @EventSpecification(scope = "cs4", action = "show-user")
  Observable<Event> enforceUserShow(@EventParameter(name = "user") User user, @EventParameter(name = "address") Address address);

  // arguments user will be used as parameter in event and event id will be "unr:action:cs4:show-project"
  @EventSpecification(scope = "cs4", action = "show-project")
  Observable<Event> enforceProjectShow(@EventParameter(name = "user") User user);
}

Explanation of the above annotations:

  • Annotation @EventSpecification is used for naming any event. It has two attributes: scope and action. These attributes are used to uniquely identify any event within the given system boundary.

  • Annotation @EventParameter is used for naming the object that is passed via the event.

Once these methods are declared, they can be accessed by the rxPepAPI object. The following example shows how the enforceProjectShow() interface method can be used in the target system using a rxPepAPI object

rxPepAPI.enforceProjectShow(getUser())
	.subscribe((event) -> {
		User user = (User) event.getValueForName("user");
		log.info("Modified user name is ", user.getName());
	}, (throwable) -> {
		log.info("Error occurred while processing enforceProjectShow" + throwable.getMessage());
	});

These calls are non-blocking. A blocking call it can be issued with toBlocking() in the following manner:

rxPepAPI.enforceProjectShow(getUser()).toBlocking()
	.subscribe((event) -> {
		User user = (User) event.getValueForName("user");
		log.info("Modified user name is ", user.getName());
	}, (throwable) -> {
		log.info("Error occurred while processing enforceProjectShow" + throwable.getMessage());
	});

Developing a PEP with our Spring SDK

For spring-boot based application, one can autowire RxPEP. DocumentationAPI would remain the same, but registration and initialization is handled by spring auto configuration.

The following dependency is required for adding spring-autoconfiguration along with the SDK:

<dependency>
    <groupId>de.fraunhofer.iese.ind2uce</groupId>
    <artifactId>sdk.spring</artifactId>
    <version>${ind2uce.version}</version>
</dependency>

Basic Configuration

MYDATA uses the default spring autoconfiguration support to configure the PEP registration. Therefore, the following properties must be declared in the application.properties:

ind2uce.component.path=ind2uce
ind2uce.pmpUri=https://localhost:8444/ws
ind2uce.es-id= urn:es:cs4
ind2uce.es-type= urn:es-type:cs4
ind2uce.externalServerUrl=http://localhost:9551

Each property is described in the table below :

Table 1. application properties

ind2uce.component.path

The common url-path used in RestController which is serving PEP requests.

ind2uce.pmpUri

The URI of the PMP to connect to.

ind2uce.es-id

Id of the enforcement scope.

ind2uce.es-type

Enforcement Type

externalServerUrl

URL used to reach the PEP from PMP Service. This URL can be used if PEP and PMP have been deployed to different domains/subnets.

Enabling PEP AutoConfiguration

In order to tell Spring that it shall scan the beans for PEPServices, the Spring Boot Application class or a configuration class of the PEP should be annotated with

@EnableAutoConfiguration
@SpringBootApplication
@EnablePolicyEnforcementPoint(basePackageClasses = MyPEPDocumentationAPI.class)
public class Application extends SpringBootServletInitializer {

}

@EnablePolicyEnforcementPoint loads the configuration to discover interfaces with @PepInterfaceDescription and creates a bean by creating via Factory. As @EnablePolicyEnforcementPoint was defined you can inject the PEP via autowiring and call the defined event enforcement methods:

@Autowired
private MyPEPDocumentationAPI myPepApi;