com.atlassian.asap.performance.Benchmark Maven / Gradle / Ivy
package com.atlassian.asap.performance;
import java.net.URI;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
import com.atlassian.asap.api.Jwt;
import com.atlassian.asap.api.JwtBuilder;
import com.atlassian.asap.api.SigningAlgorithm;
import com.atlassian.asap.api.client.http.AuthorizationHeaderGenerator;
import com.atlassian.asap.api.exception.AuthenticationFailedException;
import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
import com.atlassian.asap.api.exception.InvalidTokenException;
import com.atlassian.asap.api.server.http.RequestAuthenticator;
import com.atlassian.asap.core.client.http.AuthorizationHeaderGeneratorImpl;
import com.atlassian.asap.core.server.http.RequestAuthenticatorImpl;
import com.atlassian.asap.core.validator.JwtValidator;
import com.atlassian.asap.core.validator.JwtValidatorImpl;
import com.google.common.base.Stopwatch;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import static com.atlassian.asap.core.client.SimpleClientRunner.AUDIENCE_SYSPROP;
import static com.atlassian.asap.core.client.SimpleClientRunner.ISSUER_SYSPROP;
import static com.atlassian.asap.core.client.SimpleClientRunner.KEYID_SYSPROP;
import static com.atlassian.asap.core.client.SimpleClientRunner.PRIVATE_KEY_SYSPROP;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
/**
* A main program that runs basic performance checking of the ASAP library, both the client side (signing
* and serialising tokens) and the server side (parsing and verifying signatures).
*/
public class Benchmark
{
private static final String ALGORITHM_SYSPROP = "asap.client.algorithm";
private static final String PUBLIC_KEY_SERVER_SYSPROP = "asap.public.key.repo.url";
/**
* A high value for repetitions is recommended, as cryptographic operations are highly influenced by runtime optimizations.
* A high repetition value allows sufficient time for the effect of such optimizations to plateau
*/
private static final String REPETITIONS_SYSPROP = "asap.benchmark.repetitions";
private static final String DEFAULT_PUBLIC_KEY_SERVER_URL = "https://s3-ap-southeast-2.amazonaws.com/keymaker.syd.dev.atlassian.io/";
/**
* Main function to run the benchmark test.
* @param args command line arguments
*/
public static void main(String[] args)
{
long repetitions = Long.parseLong(defaultIfBlank(System.getProperty(REPETITIONS_SYSPROP), "200000"));
SigningAlgorithm algorithm = SigningAlgorithm.valueOf(defaultIfBlank(System.getProperty(ALGORITHM_SYSPROP), "RS256"));
String issuer = defaultIfBlank(System.getProperty(ISSUER_SYSPROP), "issuer1");
String keyId = defaultIfBlank(System.getProperty(KEYID_SYSPROP), "issuer1/rsa-key-for-tests");
String audience = defaultIfBlank(System.getProperty(AUDIENCE_SYSPROP), "audience");
String publicKeyBaseUrl = defaultIfBlank(System.getProperty(PUBLIC_KEY_SERVER_SYSPROP), DEFAULT_PUBLIC_KEY_SERVER_URL);
URI privateKeyBaseUrl = URI.create(defaultIfBlank(System.getProperty(PRIVATE_KEY_SYSPROP), "classpath:/privatekeys/"));
Jwt jwt = createJwt(algorithm, issuer, keyId, audience);
System.out.println("============== Benchmark Start ===============");
System.out.printf("Client test using key %s and %s algorithm with %d repetitions...%n", keyId, algorithm, repetitions);
clientTest(repetitions, jwt, privateKeyBaseUrl);
System.out.printf("Server test using key %s and %s algorithm with %d repetitions...%n", keyId, algorithm, repetitions);
serverValidTest(repetitions, jwt, publicKeyBaseUrl, privateKeyBaseUrl);
System.out.println("============== Benchmark End ================");
}
private static void clientTest(long repetitions, Jwt jwt, URI privateKeyBaseUrl)
{
AuthorizationHeaderGenerator authorizationHeaderGenerator =
AuthorizationHeaderGeneratorImpl.createDefault(privateKeyBaseUrl);
Stopwatch stopwatch = Stopwatch.createUnstarted();
try
{
stopwatch.start();
for (long i = 0; i < repetitions; i++)
{
authorizationHeaderGenerator.generateAuthorizationHeader(jwt);
}
stopwatch.stop();
}
catch (InvalidTokenException | CannotRetrieveKeyException e)
{
e.printStackTrace();
System.exit(1);
}
System.out.printf("Elapsed time: %d ms. Throughput: %f requests/sec%n",
stopwatch.elapsed(TimeUnit.MILLISECONDS),
1000.0 * repetitions / stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
private static void serverValidTest(long repetitions, Jwt jwt, String publicKeyBaseUrl, URI privateKeyBaseUrl)
{
String firstAudience = jwt.getClaims().getAudience().iterator().next();
JwtValidator jwtValidator = JwtValidatorImpl.createDefault(firstAudience, publicKeyBaseUrl);
RequestAuthenticator requestAuthenticator = new RequestAuthenticatorImpl(jwtValidator);
Stopwatch stopwatch = Stopwatch.createUnstarted();
AuthorizationHeaderGenerator authorizationHeaderGenerator =
AuthorizationHeaderGeneratorImpl.createDefault(privateKeyBaseUrl);
SummaryStatistics stats = new SummaryStatistics();
try
{
stopwatch.start();
final String authorizationHeader = authorizationHeaderGenerator.generateAuthorizationHeader(jwt);
for (long i = 0; i < repetitions; i++)
{
long startTime = System.nanoTime();
requestAuthenticator.authenticateRequest(authorizationHeader);
stats.addValue(TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS));
}
stopwatch.stop();
}
catch (InvalidTokenException | CannotRetrieveKeyException | AuthenticationFailedException e)
{
e.printStackTrace();
System.exit(1);
}
System.out.printf("Elapsed time: %d ms. Throughput: %f requests/sec%n",
stopwatch.elapsed(TimeUnit.MILLISECONDS),
1000.0 * repetitions / stopwatch.elapsed(TimeUnit.MILLISECONDS));
// the latency between server receiving a verification request and then completing the verification with a public key retrieved from key server.
System.out.printf("Server-side Token Verification Latency min/avg/max/stddev = %f/%f/%f/%f ms%n",
stats.getMin(), stats.getMean(), stats.getMax(), stats.getStandardDeviation());
}
private static Jwt createJwt(SigningAlgorithm algorithm, String issuer, String keyId, String audience)
{
return JwtBuilder.newJwt()
.algorithm(algorithm)
.issuer(issuer)
.audience(audience)
.keyId(keyId)
.expirationTime(Instant.now().plus(59, ChronoUnit.MINUTES)) // allow enough time for benchmark
.build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy