3030import static org .apache .ignite .internal .util .CollectionUtils .setListAtIndex ;
3131import static org .awaitility .Awaitility .await ;
3232import static org .hamcrest .MatcherAssert .assertThat ;
33+ import static org .hamcrest .Matchers .anyOf ;
3334import static org .hamcrest .Matchers .equalTo ;
3435import static org .hamcrest .Matchers .is ;
3536
3637import com .fasterxml .jackson .core .JsonProcessingException ;
3738import com .fasterxml .jackson .databind .ObjectMapper ;
39+ import com .typesafe .config .Config ;
40+ import com .typesafe .config .ConfigFactory ;
3841import java .io .File ;
3942import java .io .IOException ;
4043import java .net .URI ;
4750import java .nio .file .Path ;
4851import java .util .ArrayList ;
4952import java .util .Arrays ;
53+ import java .util .Base64 ;
5054import java .util .Collections ;
5155import java .util .HashSet ;
5256import java .util .List ;
6165import org .apache .ignite .IgniteServer ;
6266import org .apache .ignite .InitParameters ;
6367import org .apache .ignite .InitParametersBuilder ;
68+ import org .apache .ignite .client .BasicAuthenticator ;
6469import org .apache .ignite .client .IgniteClient ;
70+ import org .apache .ignite .client .IgniteClientAuthenticator ;
6571import org .apache .ignite .internal .Cluster .ServerRegistration ;
6672import org .apache .ignite .internal .logger .IgniteLogger ;
6773import org .apache .ignite .internal .logger .Loggers ;
@@ -94,6 +100,7 @@ public class IgniteCluster {
94100 private volatile boolean stopped = false ;
95101
96102 private final ClusterConfiguration clusterConfiguration ;
103+ private @ Nullable IgniteClientAuthenticator authenticator ;
97104
98105 IgniteCluster (ClusterConfiguration clusterConfiguration ) {
99106 this .clusterConfiguration = clusterConfiguration ;
@@ -236,36 +243,29 @@ public void initEmbedded(List<ServerRegistration> nodeRegistrations, Consumer<In
236243 * Initializes the cluster using REST API on the first node with default settings.
237244 */
238245 public void init (Consumer <InitParametersBuilder > initParametersConfigurator ) {
239- init (new int [] { 0 }, initParametersConfigurator );
246+ int [] cmgNodes = { 0 };
247+ InitParameters initParameters = initParameters (cmgNodes , initParametersConfigurator );
248+
249+ authenticator = authenticator (initParameters );
250+
251+ init (initParameters );
240252 }
241253
242254 /**
243255 * Initializes the cluster using REST API on the first node with specified Metastorage and CMG nodes.
244- *
245- * @param cmgNodes Indices of the CMG nodes (also used as Metastorage group).
246256 */
247- void init (int [] cmgNodes , Consumer < InitParametersBuilder > initParametersConfigurator ) {
257+ private void init (InitParameters initParameters ) {
248258 // Wait for the node to start accepting requests
249259 await ()
250260 .ignoreExceptions ()
251261 .timeout (30 , TimeUnit .SECONDS )
252262 .until (
253263 () -> send (get ("/management/v1/node/state" )).body (),
254- hasJsonPath ("$.state" , is (equalTo ("STARTING" )))
264+ hasJsonPath ("$.state" , anyOf (equalTo ("STARTING" ), equalTo ( "STARTED " )))
255265 );
256266
257267 // Initialize the cluster
258- List <String > metaStorageAndCmgNodes = Arrays .stream (cmgNodes )
259- .mapToObj (this ::nodeName )
260- .collect (toList ());
261-
262- InitParametersBuilder builder = InitParameters .builder ()
263- .metaStorageNodeNames (metaStorageAndCmgNodes )
264- .clusterName (clusterConfiguration .clusterName ());
265-
266- initParametersConfigurator .accept (builder );
267-
268- sendInitRequest (builder .build ());
268+ sendInitRequest (initParameters );
269269
270270 // Wait for the cluster to be initialized
271271 await ()
@@ -280,6 +280,20 @@ void init(int[] cmgNodes, Consumer<InitParametersBuilder> initParametersConfigur
280280 stopped = false ;
281281 }
282282
283+ private InitParameters initParameters (int [] cmgNodes , Consumer <InitParametersBuilder > initParametersConfigurator ) {
284+ List <String > metaStorageAndCmgNodes = Arrays .stream (cmgNodes )
285+ .mapToObj (this ::nodeName )
286+ .collect (toList ());
287+
288+ InitParametersBuilder builder = InitParameters .builder ()
289+ .metaStorageNodeNames (metaStorageAndCmgNodes )
290+ .clusterName (clusterConfiguration .clusterName ());
291+
292+ initParametersConfigurator .accept (builder );
293+
294+ return builder .build ();
295+ }
296+
283297 private void sendInitRequest (InitParameters initParameters ) {
284298 ObjectMapper mapper = new ObjectMapper ();
285299 String requestBody ;
@@ -304,7 +318,17 @@ private void sendInitRequest(InitParameters initParameters) {
304318 * @return Ignite client instance.
305319 */
306320 public IgniteClient createClient () {
307- return IgniteClient .builder ().addresses ("localhost:" + clusterConfiguration .baseClientPort ()).build ();
321+ return createClient (authenticator );
322+ }
323+
324+ private IgniteClient createClient (@ Nullable IgniteClientAuthenticator authenticator ) {
325+ IgniteClient .Builder builder = IgniteClient .builder ().addresses ("localhost:" + clusterConfiguration .baseClientPort ());
326+
327+ if (authenticator != null ) {
328+ builder .authenticator (authenticator );
329+ }
330+
331+ return builder .build ();
308332 }
309333
310334 /**
@@ -413,8 +437,26 @@ private HttpRequest get(String path) {
413437 return newBuilder (path ).build ();
414438 }
415439
440+ private HttpRequest get (String path , int nodeIndex ) {
441+ return newBuilder (path , nodeIndex ).build ();
442+ }
443+
444+ private Builder newBuilder (String path , int nodeIndex ) {
445+ Builder builder = HttpRequest .newBuilder (URI .create ("http://localhost:" + port (nodeIndex ) + path ));
446+
447+ if (authenticator instanceof BasicAuthenticator ) {
448+ builder .header ("Authorization" , basicAuthenticationHeader ((BasicAuthenticator ) authenticator ));
449+ }
450+
451+ return builder ;
452+ }
453+
416454 private Builder newBuilder (String path ) {
417- return HttpRequest .newBuilder (URI .create ("http://localhost:" + clusterConfiguration .baseHttpPort () + path ));
455+ return newBuilder (path , 0 );
456+ }
457+
458+ private int port (int nodeIndex ) {
459+ return clusterConfiguration .baseHttpPort () + nodeIndex ;
418460 }
419461
420462 private HttpResponse <String > send (HttpRequest request ) {
@@ -495,4 +537,41 @@ private static File getArgsFile(ProjectConnection connection, String igniteVersi
495537
496538 return constructArgFile (connection , dependenciesListNotation , false );
497539 }
540+
541+ private static String basicAuthenticationHeader (BasicAuthenticator authenticator ) {
542+ String valueToEncode = authenticator .identity () + ":" + authenticator .secret ();
543+ return "Basic " + Base64 .getEncoder ().encodeToString (valueToEncode .getBytes ());
544+ }
545+
546+ /**
547+ * Parses the cluster configuration and returns {@link BasicAuthenticator} if there is a user with "system" role.
548+ *
549+ * @see ClusterSecurityConfigurationBuilder
550+ */
551+ private static @ Nullable IgniteClientAuthenticator authenticator (InitParameters initParameters ) {
552+ if (initParameters .clusterConfiguration () == null ) {
553+ return null ;
554+ }
555+
556+ Config cfg = ConfigFactory .parseString (initParameters .clusterConfiguration ());
557+
558+ if (!cfg .hasPath ("ignite.security.enabled" )
559+ || !cfg .getBoolean ("ignite.security.enabled" )
560+ || !cfg .hasPath ("ignite.security.authentication.providers" )) {
561+ return null ;
562+ }
563+
564+ return cfg .getConfigList ("ignite.security.authentication.providers" )
565+ .stream ()
566+ .filter (provider -> "basic" .equalsIgnoreCase (provider .getString ("type" )))
567+ .flatMap (provider -> provider .getConfigList ("users" ).stream ())
568+ .filter (user -> user .getStringList ("roles" ).contains ("system" ))
569+ .findAny ()
570+ .map (user -> BasicAuthenticator .builder ()
571+ .username (user .getString ("username" ))
572+ .password (user .getString ("password" ))
573+ .build ()
574+ )
575+ .orElseThrow ();
576+ }
498577}
0 commit comments