openrtb3-adscert-verifier

Core library offering Digital Signature Verification (via OpenRTB 3.0 object or Digest or Map of key-values)

License

License

Categories

Categories

Net
GroupId

GroupId

net.media
ArtifactId

ArtifactId

openrtb3-adscert-verifier
Last Version

Last Version

1.1
Release Date

Release Date

Type

Type

jar
Description

Description

openrtb3-adscert-verifier
Core library offering Digital Signature Verification (via OpenRTB 3.0 object or Digest or Map of key-values)
Project URL

Project URL

https://github.com/media-net/ads-cert-openrtb3-verifier/tree/master/
Source Code Management

Source Code Management

https://github.com/media-net/ads-cert-openrtb3-verifier/tree/master

Download openrtb3-adscert-verifier

How to add to project

<!-- https://jarcasting.com/artifacts/net.media/openrtb3-adscert-verifier/ -->
<dependency>
    <groupId>net.media</groupId>
    <artifactId>openrtb3-adscert-verifier</artifactId>
    <version>1.1</version>
</dependency>
// https://jarcasting.com/artifacts/net.media/openrtb3-adscert-verifier/
implementation 'net.media:openrtb3-adscert-verifier:1.1'
// https://jarcasting.com/artifacts/net.media/openrtb3-adscert-verifier/
implementation ("net.media:openrtb3-adscert-verifier:1.1")
'net.media:openrtb3-adscert-verifier:jar:1.1'
<dependency org="net.media" name="openrtb3-adscert-verifier" rev="1.1">
  <artifact name="openrtb3-adscert-verifier" type="jar" />
</dependency>
@Grapes(
@Grab(group='net.media', module='openrtb3-adscert-verifier', version='1.1')
)
libraryDependencies += "net.media" % "openrtb3-adscert-verifier" % "1.1"
[net.media/openrtb3-adscert-verifier "1.1"]

Dependencies

provided (1)

Group / Artifact Type Version
org.openjdk.jmh : jmh-generator-annprocess jar 1.12

test (5)

Group / Artifact Type Version
junit : junit jar 4.12
org.powermock : powermock-module-junit4 jar 2.0.0
org.powermock : powermock-api-mockito jar 1.7.4
org.ehcache : ehcache jar 3.7.0
org.bouncycastle : bcprov-jdk15on jar 1.54

Project Modules

There are no modules declared in this project.

build_status

Verification Service for Signed Bid Requests

Ad Fraud has always been a big problem in the ad industry. Inventory spoofing is a problem that still exists where a request can be modified by any entity in the supply chain to pose it as premium inventory. This is the problem which ads.cert tries to solve.

How ads.cert works?

  • The publisher or the signing authority maintains the private key
  • A small set of essential fields (DsMap) and values in the request is used to generate the digest
  • The Signing Service generates the Digital Signature (ds) using the digest and the private key
  • The request is sent to the Exchanges/DSPs including the Digital Signature, DsMap and other fields
  • The Signature Verification Service creates a new digest from the request it receives using the fields present in the DsMap and the respective values
  • The digest and the public key (hosted on publisher domain) are then used to verify the Digital Signature present in the OpenRTB request using ECDSA SHA 256 algorithm

N|Solid

Read about Ads.Cert - Signed Bid Requests here: IAB Ads.Cert

Goal of this library:

To allow for fast-track on-boarding for ads.cert, media.net is offering the verification service as an open-source solution. Following are the features supported:

  • Digital Signature Verification (via OpenRTB 3.0 object or Digest or Map of key-values)
  • Sampling
  • Message Expiry checks
  • Offline Verification
  • Reporting hooks
  • In-memory caching to minimize latencies

Build Notes

Maven

In your project's pom, add the following dependency:

<dependency>
   <groupId>net.media.adscert</groupId>
   <artifactId>openrtb-ads-cert-verification</artifactId>
   <version>1.0</version>
</dependency>

Usage Guidelines

Instantiate an object of VerificationService to access the methods for verifying the request. The output of verification is an object of type Result whose field, status indicates whether the verification succeeded or not. Note that status can have any of these values- SUCCESS, FAILURE and SAMPLED. In case of FAILURE, appropriate message and exception can be retrieved from message and exception fields, respectively. For status = SAMPLED, refer to Sampling.

The class VerificationService is thread-safe and can be used as a singleton.

Examples

  • Verification via Open RTB object

    OpenRTB3_X openRTB = ...  // Construct open RTB object 
    VerificationService service = new VerificationService();
    // Approach 1: Non-Debug Mode (Digest will be created using fields present 
    // in dsMap present at openrtb.request.source.dsmap).
    Result result = service.verifyRequest(openRTB); // or service.verifyRequest(openRTB, true);
    // Approach 2: Debug Mode: Digest present at openrtb.request.source.digest
    // will be used. DsMap will not be used for digest creation.
    Result result = service.verifyRequest(openRTB, false);
    // Approach 3: If Public Key object is already available for verification.
    Result result = service.verifyRequest(openRTB, false, publicKey);
  • Verification via key-value map of fields

    In this case, the entire open RTB object need not be created. Simply pass, in a map, values against field names for creating digest and running verification. Along with this map, dsMap must be passed to enforce the order in which the fields from the map will be processed.

    Map<String, String> map = new LinkedHashMap<>(); 
    // Put values
    map.put("domain", "newsite.com");
    map.put("ft", "d");
    map.put("tid", "ABC7E92FBD6A");
    
    String dsMap = "domain=&ft=&tid=";
    String publicKeyUrl = "http://www.newsite.com/ads.cert";
    String ds = ... // digital signature to be verified.
     
    VerificationService service = new VerificationService();
    // Approach 1: Using Public Key URL.
    Result result = service.verifyRequest(publicKeyUrl, dsMap, ds, map);
    // Approach 2: If Public Key object is already available for verification.
    Result result = service.verifyRequest(publicKey, dsMap, ds, map);

Note

  • service.verifyRequest can throw an exception for certain types of failure. See Exception Handling.

  • Only the following fields are supported:

Key Spec Object Example Value Comments
tid OpenRTB Source ABC7E92FBD6A
ts OpenRTB Source
cert OpenRTB Source ads-cert.1.txt
domain AdCOM Site newsite.com
bundle AdCOM App
consent AdCOM User
ft AdCOM - vd
ip AdCOM Device 192.168.1.1
ipv6 AdCOM Device
ifa AdCOM Device
ua AdCOM Device
w AdCOM VideoPlacement 480 The video placement under first item is considered.
h AdCOM VideoPlacement 360 The video placement under first item is considered.

Features

Sampling

Aditionally, a sampling percentage can be provided during instantiation to control the percentage of requests for which verification is desired. For instance, sampling percentage of 30 means that verification would be run for 30% of the requests, and for the remaining 70%, service.verifyRequest will return Result with status = SAMPLED without running any kind of verification.

Please note that the default value of sampling percentage is 100, which means that all requests will be verified.

// Sampling Percentage is 30. This means that verification would be run for only 30% of the requests!
int samplingPercentage = 30; 

VerificationService service = new VerificationService(samplingPercentage);

OpenRTB3_X openRTB = ...  // Construct open RTB object 

// There is a 30% chance that verification would be run! 
// If the verification does not run, then result with status = SAMPLED is returned.
Result result = service.verifyRequest(openRTB);

Message Expiry

Support has also been provided to optionally check message expiry. The timestamp in OpenRTB is assumed to be the time elapsed since UTC epoch. If the difference between timestamp in the OpenRTB request and current system timestamp exceeds a pre-defined margin, the service will fail the verification.

int samplingPercentage = 50; // Sampling Percentage is 50.
long messageExpiryTimeInMillis = 2000l; // Message should be received under 2 seconds.
VerificationService service = new VerificationService(samplingPercentage, messageExpiryTimeInMillis);
service.verifyRequest(openRTB, debug, checkMessageExpiry);

Metrics and Reporting

A reporting hook through MetricsManager has been provided for collecting and pushing metrics to a suitable data sink. One can pass an implementation of MetricsManager to the constructor of VerificationService as below:

MetricsManager metricsManager = ....;
VerificationService service = new VerificationServiceJCache(metricsManager);
MetricsManager metricsManager = ...;
// with custom sampling and message expiry time
int samplingPercentage = 50; // Sampling Percentage is 50.
long messageExpiry = 2000l; // Value should be in milliseconds. In this case, message should be received under 2 seconds. 
VerificationService service = new VerificationService(samplingPercentage, messageExpiry, metricsManager);

MetricsManager has a method, pushMetrics() which accepts a map (where key is the metric name) and a result object whose status field can have values - SUCCESS, FAILURE and SAMPLED. It is this method that is internally referred during verification using dsMap. Note that the map passed to pushMetrics() will contain all the entries of dsMap.

Cache

We have also provided the functionality to fetch and cache the Public Keys for different domains, thus saving time required for verification. Cache will expire after a preconfigured time (default 30 days). Two different cache implementations, using JCache and Guava, are provided for VerificationService. The corresponding classes are VerificationServiceJCache and VerificationServiceGuavaCache.

Additionally, default implementations for both caches are also provided. Either can be used or a custom cache object can be passed to the constructor.

JCache:

To run the code with a JSR - 107 compliant cache, a suitable dependency must be added first. Here are a few examples:

  • EHCache

    <dependency>
       <groupId>org.ehcache</groupId>
       <artifactId>ehcache</artifactId>
       <version>${version.ehcache}</version>
    </dependency>
  • Infinispan

    <dependency>
      <groupId>org.infinispan</groupId>
      <artifactId>infinispan-jcache</artifactId>
      <version>${version.infinispan}</version>
    </dependency>
Cache<String, PublicKey> cache = DefaultJCacheBuilder.newBuilder()
                                       .setExpiryForAccess(...)
                                       .setExpiryForCreation(...)
                                       .setExpiryForUpdate(...)
                                       .setCacheLoader(...)
                                       .build();
// without sampling and message expiry                                       
VerificationServiceJCache service = new VerificationServiceJCache(cache);

// with custom sampling
int samplingPercentage = 50; // Sampling Percentage is 50.
VerificationServiceJCache serviceWithCustomSampling = new VerificationServiceJCache(cache, samplingPercentage);

// with custom message expiry
long messageExpiryTimeInMillis = 2000l; // Message should be received under 2 seconds.
VerificationServiceJCache serviceWithCustomSamplingAndExpiry = new VerificationServiceJCache(cache, samplingPercentage, messageExpiryTimeInMillis);

// with Metrics Manager
MetricsManager metricsManager = new MetricsManager();
VerificationServiceJCache serviceWithMetricSupport = new VerificationServiceJCache(cache, samplingPercentage, messageExpiryTimeInMillis, metricsManager);

Closing Cache and CacheManager is the responsibility of the user.

Guava:

Cache<String, PublicKey> cache = DefaultGuavaCacheBuilder.newBuilder()
                                        .setMaximumSize(...)
                                        .setExpireAfterAccess(...)
                                        .setExpireAfterWrite(...)
                                        .build();

VerificationServiceGuavaCache service = new VerificationServiceGuavaCache(cache);

// with custom sampling
int samplingPercentage = 50; // Sampling Percentage is 50.
VerificationServiceGuavaCache serviceWithCustomSampling = new VerificationServiceJCache(cache, samplingPercentage);

// with custom message expiry
long messageExpiryTimeInMillis = 2000l; // Message should be received under 2 seconds.
VerificationServiceGuavaCache serviceWithCustomSamplingAndExpiry = new VerificationServiceJCache(cache, samplingPercentage, messageExpiryTimeInMillis);

// with Metrics Manager
MetricsManager metricsManager = new MetricsManager();
VerificationServiceGuavaCache serviceWithMetricSupport = new VerificationServiceGuavaCache(cache, samplingPercentage, messageExpiryTimeInMillis, metricsManager);

Both the default cache builders have default values set for fields. For example, one can write DefaultGuavaCacheBuilder.newBuilder().build() and it will return a cache created with parameters set to default values.

Offline Bulk verification

Bulk verification can be performed by passing the path to the input file containing JSONs of OpenRTB requests (each line has complete json of one request), along with the path to the file to which output should be written.

FileVerificationService.verify("input.txt", "output.txt");

Assumptions

  • Comments in the ads.cert file are not supported
  • Metric collection and reporting are not supported in debug mode (i.e. when the supplied digest is used for verification instead of creating it)

Exception Handling

Scenario Exception Comment
openrtb.request.source.digest == null InvalidDataException: OpenRtb.source.digest: may not be null Raised only in debug mode
validation of dsmap in Open RTB fails InvalidDataException: OpenRtb.source.dsmap: bad dsmap provided Raised only when the verification is run on open RTB object
dsmap validation fails when executed only on map of fields to values InvalidDataException: bad dsmap provided Raised only when the verification is run on the map of fields to values
Message has expired ProcessException: Message has expired. Time Difference (in millis):...
openrtb == null InvalidDataException: OpenRTB object is null
openrtb.request == null InvalidDataException: OpenRTB.Request object is null
openrtb.request.source == null InvalidDataException: OpenRTB.Request.Source is null

Requirements

Java 8

net.media

Media.Net

Fastest growing AdTech company in the world

Versions

Version
1.1
1.0