Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ public static void initializeClients() throws Exception {
System.out.println("ML version: " + version.getVersionString());
isML11OrHigher = version.getMajor() >= 11;

client = newClientAsUser(OPTIC_USER, OPTIC_USER_PASSWORD);
schemasClient = newClient(getRestServerHostName(), getRestServerPort(), "java-functest-schemas",
newSecurityContext(OPTIC_USER, OPTIC_USER_PASSWORD), null);
client = newDatabaseClientBuilder().build();
schemasClient = newClientForDatabase("java-functest-schemas");
adminModulesClient = newAdminModulesClient();

// Required to ensure that tests using the "/ext/" prefix work reliably. Expand to other directories as needed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClient.ConnectionType;
import com.marklogic.client.DatabaseClientBuilder;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.DatabaseClientFactory.SecurityContext;
import com.marklogic.client.admin.ServerConfigurationManager;
import com.marklogic.client.impl.OkHttpServices;
import com.marklogic.client.impl.RESTServices;
Expand All @@ -48,6 +48,8 @@

public abstract class ConnectedRESTQA {

protected static Properties testProperties = null;

protected static String securityContextType;
protected static String restServerName = null;
private static String restSslServerName = null;
Expand Down Expand Up @@ -2019,45 +2021,64 @@ else if (getSslEnabled().trim().equalsIgnoreCase("false") || getSslEnabled() ==
return bSecurityEnabled;
}

public static DatabaseClientBuilder newDatabaseClientBuilder() {
Map<String, Object> props = new HashMap<>();
testProperties.entrySet().forEach(entry -> props.put((String) entry.getKey(), entry.getValue()));
return new DatabaseClientBuilder(props);
}

public static DatabaseClient newBasicAuthClient(String username, String password) {
return newDatabaseClientBuilder()
.withUsername(username)
.withPassword(password)
.withSecurityContextType("basic")
.build();
}

public static DatabaseClient newClientAsUser(String username, String password) {
return newClient(getRestServerHostName(), getRestServerPort(), null, newSecurityContext(username, password), null);
return newDatabaseClientBuilder()
.withUsername(username)
.withPassword(password)
.build();
}

public static DatabaseClient newAdminModulesClient() {
return newClient(getRestServerHostName(), getRestServerPort(), "java-unittest-modules",
newSecurityContext(getAdminUser(), getAdminPassword()), null);
public static DatabaseClient newClientForDatabase(String database) {
return newDatabaseClientBuilder()
.withDatabase(database)
.build();
}

public static DatabaseClient newBasicAuthClient(String username, String password) {
return newClient(getRestServerHostName(), getRestServerPort(), null,
new DatabaseClientFactory.BasicAuthContext(username, password), null);
public static DatabaseClient newAdminModulesClient() {
return newDatabaseClientBuilder()
.withUsername(getAdminUser())
.withPassword(getAdminPassword())
.withDatabase("java-unittest-modules")
.build();
}

public static DatabaseClient getDatabaseClient(String user, String password, ConnectionType connType)
throws KeyManagementException, NoSuchAlgorithmException, IOException {
return newClient(getRestServerHostName(), getRestServerPort(), null, newSecurityContext(user, password), connType);
return newDatabaseClientBuilder()
.withUsername(user)
.withPassword(password)
.withConnectionType(connType)
.build();
}

/**
* Intent is for every functional test to create a client ultimately via this method so that basePath can be
* applied in one place.
*
* @param host
* @param port
* @param database
* @param securityContext
* @param connectionType
* @return
* Only use this in "slow" functional tests until they're converted over to fast.
*/
public static DatabaseClient newClient(String host, int port, String database,
SecurityContext securityContext, ConnectionType connectionType) {
connectionType = connectionType != null ? connectionType : getConnType();
return DatabaseClientFactory.newClient(host, port, basePath, database, securityContext, connectionType);
}

@Deprecated
public static DatabaseClient getDatabaseClientOnDatabase(String hostName, int port, String databaseName,
String user, String password, ConnectionType connType) {
return newClient(hostName, port, databaseName, newSecurityContext(user, password), connType);
String user, String password, ConnectionType connType) {
return newDatabaseClientBuilder()
.withHost(hostName)
.withPort(port)
.withUsername(user)
.withPassword(password)
.withDatabase(databaseName)
.withConnectionType(connType)
.build();
}

//Return a Server name. For SSL runs returns value in restSslServerName For
Expand Down Expand Up @@ -2090,9 +2111,9 @@ private static void overrideTestPropertiesWithSystemProperties(Properties testPr
if ("true".equals(System.getProperty("TEST_USE_REVERSE_PROXY_SERVER"))) {
System.out.println("TEST_USE_REVERSE_PROXY_SERVER is true, so overriding properties to use reverse proxy server");
testProperties.setProperty("httpPort", "8020");
testProperties.setProperty("fastHttpPort", "8020");
testProperties.setProperty("basePath", "testFunctional");
testProperties.setProperty("securityContextType", "basic");
testProperties.setProperty("marklogic.client.port", "8020");
testProperties.setProperty("marklogic.client.basePath", "testFunctional");
testProperties.setProperty("marklogic.client.securityContextType", "basic");
}
}

Expand All @@ -2110,18 +2131,18 @@ public static void loadGradleProperties() {

overrideTestPropertiesWithSystemProperties(properties);

securityContextType = properties.getProperty("securityContextType");
securityContextType = properties.getProperty("marklogic.client.securityContextType");
restServerName = properties.getProperty("mlAppServerName");
restSslServerName = properties.getProperty("mlAppServerSSLName");

https_port = properties.getProperty("httpsPort");
http_port = properties.getProperty("httpPort");
fast_http_port = properties.getProperty("fastHttpPort");
admin_port = properties.getProperty("adminPort");
basePath = properties.getProperty("basePath");
fast_http_port = properties.getProperty("marklogic.client.port");
admin_port = "8002"; // No need yet for a property for this
basePath = properties.getProperty("marklogic.client.basePath");

// Machine names where ML Server runs
host_name = properties.getProperty("restHost");
host_name = properties.getProperty("marklogic.client.host");
ssl_host_name = properties.getProperty("restSSLHost");

// Users
Expand All @@ -2136,9 +2157,11 @@ public static void loadGradleProperties() {
ml_certificate_password = properties.getProperty("ml_certificate_password");
ml_certificate_file = properties.getProperty("ml_certificate_file");
mlDataConfigDirPath = properties.getProperty("mlDataConfigDirPath");
isLBHost = Boolean.parseBoolean(properties.getProperty("lbHost"));
isLBHost = "gateway".equalsIgnoreCase(properties.getProperty("marklogic.client.connectionType"));
PROPERTY_WAIT = Integer.parseInt(isLBHost ? "15000" : "0");

testProperties = properties;

System.out.println("For 'slow' tests, will connect to: " + host_name + ":" + http_port + "; basePath: " + basePath +
"; auth: " + securityContextType);
System.out.println("For 'fast' tests, will connect to: " + host_name + ":" + fast_http_port + "; basePath: " + basePath +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
securityContextType=digest
# Standard properties for constructing a DatabaseClient
marklogic.client.host=localhost
marklogic.client.port=8014
marklogic.client.securityContextType=digest
marklogic.client.username=opticUser
marklogic.client.password=0pt1c
marklogic.client.basePath=
marklogic.client.type=direct

# Custom properties used by ConnectedRESTQA
restSSLset=false
restHost=localhost
restSSLHost=localhost
mlAdminUser=admin
mlAdminPassword=admin
mlRestReadUser=rest-reader
mlRestReadPassword=x
mlAppServerName=REST-Java-Client-API-Server
mlAppServerSSLName=REST-Java-Client-API-SSL-Server

# Used by "slow" functional tests that don't use the test-app's application
httpPort=8011
# For fastfunctest tests
fastHttpPort=8014
httpsPort=8013
adminPort=8002
basePath=
lbHost=false

ml_certificate_password=welcome
ml_certificate_file=user.p12

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Copyright (c) 2022 MarkLogic Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.marklogic.client;

import com.marklogic.client.impl.DatabaseClientPropertySource;

import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
* Intended to support programmatically building a {@code DatabaseClient} via chained "with" methods for setting
* each possible input allowed for connecting to and authenticating with MarkLogic. While the
* {@code DatabaseClientFactory.Bean} class is intended for use in a context such as a Spring container, it requires
* that a user have already assembled the appropriate {@code DatabaseClientFactory.SecurityContext}. This builder
* instead is intended for a more dynamic environment - in particular, one where the desired authentication strategy is
* not known until runtime. A client can then collect inputs from a user at runtime and call the appropriate methods on
* this builder. The builder will handle constructing the correct {@code DatabaseClientFactory.SecurityContext} and
* using that to construct a {@code DatabaseClient}.
*
* @since 6.1.0
*/
public class DatabaseClientBuilder {

public final static String PREFIX = "marklogic.client.";
private final Map<String, Object> props;

public DatabaseClientBuilder() {
this.props = new HashMap<>();
}

/**
* Initialize the builder with the given set of properties.
*
* @param props
*/
public DatabaseClientBuilder(Map<String, Object> props) {
this();
this.props.putAll(props);
}

/**
* @return a {@code DatabaseClient} based on the inputs that have been provided via the "with" builder methods
* and any inputs provided via this instance's constructor
*/
public DatabaseClient build() {
return DatabaseClientFactory.newClient(getPropertySource());
}

/**
* @return an instance of {@code DatabaseClientFactory.Bean} based on the inputs that have been provided via
* the "with" builder methods and any inputs provided via this instance's constructor
*/
public DatabaseClientFactory.Bean buildBean() {
return new DatabaseClientPropertySource(getPropertySource()).newClientBean();
}

/**
* @return a function that acts as a property source, specifically for use with the
* {@code DatabaseClientFactory.newClient} method that accepts this type of function.
*/
private Function<String, Object> getPropertySource() {
return propertyName -> props.get(propertyName);
}

public DatabaseClientBuilder withHost(String host) {
props.put(PREFIX + "host", host);
return this;
}

public DatabaseClientBuilder withPort(int port) {
props.put(PREFIX + "port", port);
return this;
}

public DatabaseClientBuilder withBasePath(String basePath) {
props.put(PREFIX + "basePath", basePath);
return this;
}

public DatabaseClientBuilder withDatabase(String database) {
props.put(PREFIX + "database", database);
return this;
}

public DatabaseClientBuilder withUsername(String username) {
props.put(PREFIX + "username", username);
return this;
}

public DatabaseClientBuilder withPassword(String password) {
props.put(PREFIX + "password", password);
return this;
}

public DatabaseClientBuilder withSecurityContext(DatabaseClientFactory.SecurityContext securityContext) {
props.put(PREFIX + "securityContext", securityContext);
return this;
}

public DatabaseClientBuilder withSecurityContextType(String type) {
props.put(PREFIX + "securityContextType", type);
return this;
}

public DatabaseClientBuilder withConnectionType(DatabaseClient.ConnectionType type) {
props.put(PREFIX + "connectionType", type);
return this;
}

public DatabaseClientBuilder withCloudApiKey(String cloudApiKey) {
props.put(PREFIX + "cloud.apiKey", cloudApiKey);
return this;
}

public DatabaseClientBuilder withCertificateFile(String file) {
props.put(PREFIX + "certificate.file", file);
return this;
}

public DatabaseClientBuilder withCertificatePassword(String password) {
props.put(PREFIX + "certificate.password", password);
return this;
}

public DatabaseClientBuilder withKerberosPrincipal(String principal) {
props.put(PREFIX + "kerberos.principal", principal);
return this;
}

public DatabaseClientBuilder withSAMLToken(String token) {
props.put(PREFIX + "saml.token", token);
return this;
}

public DatabaseClientBuilder withSSLContext(SSLContext sslContext) {
props.put(PREFIX + "sslContext", sslContext);
return this;
}

public DatabaseClientBuilder withSSLProtocol(String sslProtocol) {
props.put(PREFIX + "sslProtocol", sslProtocol);
return this;
}

public DatabaseClientBuilder withTrustManager(X509TrustManager trustManager) {
props.put(PREFIX + "trustManager", trustManager);
return this;
}

public DatabaseClientBuilder withSSLHostnameVerifier(DatabaseClientFactory.SSLHostnameVerifier sslHostnameVerifier) {
props.put(PREFIX + "sslHostnameVerifier", sslHostnameVerifier);
return this;
}
}



Loading