14141515package com .rabbitmq .stream .oauth2 ;
1616
17+ import static org .junit .jupiter .api .Assertions .fail ;
18+
19+ import com .sun .net .httpserver .HttpHandler ;
20+ import com .sun .net .httpserver .HttpServer ;
21+ import com .sun .net .httpserver .HttpsConfigurator ;
22+ import com .sun .net .httpserver .HttpsServer ;
23+ import java .io .IOException ;
24+ import java .math .BigInteger ;
25+ import java .net .InetSocketAddress ;
26+ import java .net .ServerSocket ;
27+ import java .security .KeyPair ;
28+ import java .security .KeyPairGenerator ;
29+ import java .security .KeyStore ;
30+ import java .security .SecureRandom ;
31+ import java .security .cert .X509Certificate ;
32+ import java .security .spec .ECGenParameterSpec ;
1733import java .time .Duration ;
34+ import java .time .Instant ;
35+ import java .time .temporal .ChronoUnit ;
36+ import java .util .Date ;
37+ import java .util .function .Supplier ;
38+ import javax .net .ssl .KeyManagerFactory ;
39+ import javax .net .ssl .SSLContext ;
40+ import org .bouncycastle .asn1 .x500 .X500NameBuilder ;
41+ import org .bouncycastle .asn1 .x500 .style .BCStyle ;
42+ import org .bouncycastle .cert .X509CertificateHolder ;
43+ import org .bouncycastle .cert .jcajce .JcaX509CertificateConverter ;
44+ import org .bouncycastle .cert .jcajce .JcaX509v3CertificateBuilder ;
45+ import org .bouncycastle .operator .jcajce .JcaContentSignerBuilder ;
1846
1947public final class OAuth2TestUtils {
2048
49+ private static final char [] KEY_STORE_PASSWORD = "password" .toCharArray ();
50+
2151 private OAuth2TestUtils () {}
2252
2353 public static String sampleJsonToken (String accessToken , Duration expiresIn ) {
@@ -32,4 +62,144 @@ public static String sampleJsonToken(String accessToken, Duration expiresIn) {
3262 return json .replace ("{accessToken}" , accessToken )
3363 .replace ("{expiresIn}" , expiresIn .toSeconds () + "" );
3464 }
65+
66+ public static int randomNetworkPort () throws IOException {
67+ ServerSocket socket = new ServerSocket ();
68+ socket .bind (null );
69+ int port = socket .getLocalPort ();
70+ socket .close ();
71+ return port ;
72+ }
73+
74+ public static Duration waitAtMost (
75+ Duration timeout ,
76+ Duration waitTime ,
77+ CallableBooleanSupplier condition ,
78+ Supplier <String > message )
79+ throws Exception {
80+ if (condition .getAsBoolean ()) {
81+ return Duration .ZERO ;
82+ }
83+ Duration waitedTime = Duration .ZERO ;
84+ Exception exception = null ;
85+ while (waitedTime .compareTo (timeout ) <= 0 ) {
86+ Thread .sleep (waitTime .toMillis ());
87+ waitedTime = waitedTime .plus (waitTime );
88+ try {
89+ if (condition .getAsBoolean ()) {
90+ return waitedTime ;
91+ }
92+ exception = null ;
93+ } catch (Exception e ) {
94+ exception = e ;
95+ }
96+ }
97+ String msg ;
98+ if (message == null ) {
99+ msg = "Waited " + timeout .getSeconds () + " second(s), condition never got true" ;
100+ } else {
101+ msg = "Waited " + timeout .getSeconds () + " second(s), " + message .get ();
102+ }
103+ if (exception == null ) {
104+ fail (msg );
105+ } else {
106+ fail (msg , exception );
107+ }
108+ return waitedTime ;
109+ }
110+
111+ public static Duration waitAtMost (
112+ Duration timeout , Duration waitTime , CallableBooleanSupplier condition ) throws Exception {
113+ return waitAtMost (timeout , waitTime , condition , null );
114+ }
115+
116+ public static HttpServer startServer (int port , String path , HttpHandler handler ) {
117+ return startServer (port , path , null , handler );
118+ }
119+
120+ public static HttpServer startServer (
121+ int port , String path , KeyStore keyStore , HttpHandler handler ) {
122+ HttpServer server ;
123+ try {
124+ if (keyStore != null ) {
125+ KeyManagerFactory keyManagerFactory =
126+ KeyManagerFactory .getInstance (KeyManagerFactory .getDefaultAlgorithm ());
127+ keyManagerFactory .init (keyStore , KEY_STORE_PASSWORD );
128+ SSLContext sslContext = SSLContext .getInstance ("TLS" );
129+ sslContext .init (keyManagerFactory .getKeyManagers (), null , null );
130+ server = HttpsServer .create (new InetSocketAddress (port ), 0 );
131+ ((HttpsServer ) server ).setHttpsConfigurator (new HttpsConfigurator (sslContext ));
132+ } else {
133+ server = HttpServer .create (new InetSocketAddress (port ), 0 );
134+ }
135+ server .createContext (path , handler );
136+ server .start ();
137+ return server ;
138+ } catch (Exception e ) {
139+ throw new RuntimeException (e );
140+ }
141+ }
142+
143+ public static KeyStore generateKeyPair () {
144+ try {
145+ KeyStore keyStore = KeyStore .getInstance (KeyStore .getDefaultType ());
146+ keyStore .load (null , KEY_STORE_PASSWORD );
147+
148+ KeyPairGenerator kpg = KeyPairGenerator .getInstance ("EC" );
149+ ECGenParameterSpec spec = new ECGenParameterSpec ("secp521r1" );
150+ kpg .initialize (spec );
151+
152+ KeyPair kp = kpg .generateKeyPair ();
153+
154+ JcaX509v3CertificateBuilder certificateBuilder =
155+ new JcaX509v3CertificateBuilder (
156+ new X500NameBuilder ().addRDN (BCStyle .CN , "localhost" ).build (),
157+ BigInteger .valueOf (new SecureRandom ().nextInt ()),
158+ Date .from (Instant .now ().minus (10 , ChronoUnit .DAYS )),
159+ Date .from (Instant .now ().plus (10 , ChronoUnit .DAYS )),
160+ new X500NameBuilder ().addRDN (BCStyle .CN , "localhost" ).build (),
161+ kp .getPublic ());
162+
163+ X509CertificateHolder certificateHolder =
164+ certificateBuilder .build (
165+ new JcaContentSignerBuilder ("SHA256withECDSA" ).build (kp .getPrivate ()));
166+
167+ X509Certificate certificate =
168+ new JcaX509CertificateConverter ().getCertificate (certificateHolder );
169+
170+ keyStore .setKeyEntry (
171+ "localhost" , kp .getPrivate (), KEY_STORE_PASSWORD , new X509Certificate [] {certificate });
172+
173+ return keyStore ;
174+ } catch (Exception e ) {
175+ throw new RuntimeException (e );
176+ }
177+ }
178+
179+ public static <A , B > Pair <A , B > pair (A v1 , B v2 ) {
180+ return new Pair <>(v1 , v2 );
181+ }
182+
183+ public interface CallableBooleanSupplier {
184+ boolean getAsBoolean () throws Exception ;
185+ }
186+
187+ public static class Pair <A , B > {
188+
189+ private final A v1 ;
190+ private final B v2 ;
191+
192+ private Pair (A v1 , B v2 ) {
193+ this .v1 = v1 ;
194+ this .v2 = v2 ;
195+ }
196+
197+ public A v1 () {
198+ return this .v1 ;
199+ }
200+
201+ public B v2 () {
202+ return this .v2 ;
203+ }
204+ }
35205}
0 commit comments