1 package com.atlassian.asap.performance;
2
3 import com.atlassian.asap.api.Jwt;
4 import com.atlassian.asap.api.JwtBuilder;
5 import com.atlassian.asap.api.SigningAlgorithm;
6 import com.atlassian.asap.api.client.http.AuthorizationHeaderGenerator;
7 import com.atlassian.asap.api.exception.AuthenticationFailedException;
8 import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
9 import com.atlassian.asap.api.exception.InvalidTokenException;
10 import com.atlassian.asap.api.server.http.RequestAuthenticator;
11 import com.atlassian.asap.core.client.http.AuthorizationHeaderGeneratorImpl;
12 import com.atlassian.asap.core.server.http.RequestAuthenticatorImpl;
13 import com.atlassian.asap.core.validator.JwtValidator;
14 import com.atlassian.asap.core.validator.JwtValidatorImpl;
15 import com.google.common.base.Stopwatch;
16 import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
17
18 import java.net.URI;
19 import java.time.Instant;
20 import java.time.temporal.ChronoUnit;
21 import java.util.concurrent.ExecutorService;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.TimeUnit;
24
25 import static com.atlassian.asap.core.client.SimpleClientRunner.AUDIENCE_SYSPROP;
26 import static com.atlassian.asap.core.client.SimpleClientRunner.ISSUER_SYSPROP;
27 import static com.atlassian.asap.core.client.SimpleClientRunner.KEYID_SYSPROP;
28 import static com.atlassian.asap.core.client.SimpleClientRunner.PRIVATE_KEY_SYSPROP;
29
30
31
32
33
34 public class Benchmark {
35 private static final SigningAlgorithm ALGORITHM = SigningAlgorithm.valueOf(System.getProperty("asap.client.algorithm", "RS256"));
36
37
38
39
40
41 private static final long REPETITIONS = Long.getLong("asap.benchmark.repetitions", 200000L);
42
43 private static final int NUM_THREADS = Integer.getInteger("asap.benchmark.threads", 1);
44
45 private static final String ISSUER = System.getProperty(ISSUER_SYSPROP, "issuer1");
46 private static final String KEY_ID = System.getProperty(KEYID_SYSPROP, "issuer1/rsa-key-for-tests");
47 private static final String AUDIENCE = System.getProperty(AUDIENCE_SYSPROP, "audience");
48
49 private static final URI PRIVATE_KEY_BASE_URL = URI.create(System.getProperty(PRIVATE_KEY_SYSPROP,
50 "classpath:/privatekeys/"));
51 private static final String PUBLIC_KEY_BASE_URL = System.getProperty("asap.public.key.repo.url",
52 "https://s3-ap-southeast-2.amazonaws.com/keymaker.syd.dev.atlassian.io/");
53
54
55
56
57
58
59
60 public static void main(String[] args) throws Exception {
61 Jwt jwtPrototype = JwtBuilder.newJwt()
62 .algorithm(ALGORITHM)
63 .issuer(ISSUER)
64 .audience(AUDIENCE)
65 .keyId(KEY_ID)
66 .expirationTime(Instant.now().plus(59, ChronoUnit.MINUTES))
67 .build();
68
69 System.out.println("============== Benchmark Start ===============");
70 clientTest(REPETITIONS, jwtPrototype, PRIVATE_KEY_BASE_URL);
71 serverValidTest(REPETITIONS, jwtPrototype, PUBLIC_KEY_BASE_URL, PRIVATE_KEY_BASE_URL);
72 System.out.println("============== Benchmark End ================");
73
74 }
75
76 private static void clientTest(long repetitions, Jwt jwtPrototype, URI privateKeyBaseUrl)
77 throws InterruptedException {
78 System.out.printf("Client test using key %s and %s algorithm with %d repetitions and %d threads...%n", KEY_ID, ALGORITHM, repetitions, NUM_THREADS);
79 ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
80
81 AuthorizationHeaderGenerator authorizationHeaderGenerator =
82 AuthorizationHeaderGeneratorImpl.createDefault(privateKeyBaseUrl);
83 Runnable runnableJob = () -> {
84 try {
85 SummaryStatistics stats = new SummaryStatistics();
86 for (long i = 0; i < repetitions; i++) {
87 long startTime = System.nanoTime();
88
89 Jwt jwt = JwtBuilder.copyJwt(jwtPrototype).build();
90 authorizationHeaderGenerator.generateAuthorizationHeader(jwt);
91 stats.addValue(System.nanoTime() - startTime);
92 }
93 System.out.printf("Client-side token generation min/avg/max/stddev = %f/%f/%f/%f ms%n",
94 nanosToMillis(stats.getMin()), nanosToMillis(stats.getMean()),
95 nanosToMillis(stats.getMax()), nanosToMillis(stats.getStandardDeviation()));
96 } catch (InvalidTokenException | CannotRetrieveKeyException e) {
97 e.printStackTrace();
98 System.exit(1);
99 }
100 };
101
102 Stopwatch stopwatch = Stopwatch.createUnstarted();
103 stopwatch.start();
104 for (int job = 0; job < NUM_THREADS; job++) {
105 executorService.execute(runnableJob);
106 }
107 executorService.shutdown();
108 executorService.awaitTermination(1, TimeUnit.HOURS);
109 stopwatch.stop();
110
111 System.out.printf("Elapsed time: %d ms. Throughput: %f requests/sec%n",
112 stopwatch.elapsed(TimeUnit.MILLISECONDS),
113 1000.0 * repetitions * NUM_THREADS / stopwatch.elapsed(TimeUnit.MILLISECONDS));
114
115 }
116
117 private static void serverValidTest(long repetitions, Jwt jwtPrototype, String publicKeyBaseUrl, URI privateKeyBaseUrl)
118 throws CannotRetrieveKeyException, InvalidTokenException, AuthenticationFailedException {
119 System.out.printf("Server test using key %s and %s algorithm with %d repetitions...%n", KEY_ID, ALGORITHM, repetitions);
120 String firstAudience = jwtPrototype.getClaims().getAudience().iterator().next();
121 JwtValidator jwtValidator = JwtValidatorImpl.createDefault(firstAudience, publicKeyBaseUrl);
122 RequestAuthenticator requestAuthenticator = new RequestAuthenticatorImpl(jwtValidator);
123 Stopwatch stopwatch = Stopwatch.createUnstarted();
124 AuthorizationHeaderGenerator authorizationHeaderGenerator =
125 AuthorizationHeaderGeneratorImpl.createDefault(privateKeyBaseUrl);
126 SummaryStatistics stats = new SummaryStatistics();
127
128
129 final String authorizationHeader = authorizationHeaderGenerator.generateAuthorizationHeader(jwtPrototype);
130
131 stopwatch.start();
132 for (long i = 0; i < repetitions; i++) {
133 long startTime = System.nanoTime();
134 requestAuthenticator.authenticateRequest(authorizationHeader);
135 stats.addValue(TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS));
136
137 }
138 stopwatch.stop();
139
140 System.out.printf("Elapsed time: %d ms. Throughput: %f requests/sec%n",
141 stopwatch.elapsed(TimeUnit.MILLISECONDS),
142 1000.0 * repetitions / stopwatch.elapsed(TimeUnit.MILLISECONDS));
143
144 System.out.printf("Server-side Token Verification Latency min/avg/max/stddev = %f/%f/%f/%f ms%n",
145 stats.getMin(), stats.getMean(), stats.getMax(), stats.getStandardDeviation());
146 }
147
148 private static double nanosToMillis(double nanos) {
149 return nanos / 1_000_000;
150 }
151 }