Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 1bff224

Browse files
authored
Merge pull request #506 from BillFarber/feature/deployCredentials
Now have deploy/undeploy credentials commands
2 parents ff754ce + 5696cf2 commit 1bff224

File tree

11 files changed

+208
-9
lines changed

11 files changed

+208
-9
lines changed

src/main/java/com/marklogic/appdeployer/ConfigDir.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,8 @@ public File getProjectDir() {
262262
public File getSecureCredentialsDir() {
263263
return new File(getSecurityDir(), "secure-credentials");
264264
}
265+
266+
public File getCredentialsDir() {
267+
return new File(getSecurityDir(), "credentials");
268+
}
265269
}

src/main/java/com/marklogic/appdeployer/command/CommandMapBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ private void addCommandsThatDoNotWriteToDatabases(Map<String, List<Command>> map
161161
securityCommands.add(new InsertCertificateHostsTemplateCommand());
162162
securityCommands.add(new DeployExternalSecurityCommand());
163163
securityCommands.add(new DeploySecureCredentialsCommand());
164+
securityCommands.add(new DeployCredentialsCommand());
164165
securityCommands.add(new DeployPrivilegesCommand());
165166
securityCommands.add(new DeployPrivilegeRolesCommand());
166167
securityCommands.add(new DeployProtectedCollectionsCommand());

src/main/java/com/marklogic/appdeployer/command/SortOrderConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public abstract class SortOrderConstants {
3333

3434
public static Integer DEPLOY_EXTERNAL_SECURITY = 35;
3535
public static Integer DEPLOY_SECURE_CREDENTIALS = 36;
36+
public static Integer DEPLOY_CREDENTIALS = 37;
3637
public static Integer DEPLOY_PROTECTED_COLLECTIONS = 40;
3738
public static Integer DEPLOY_MIMETYPES = 45;
3839

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2023 MarkLogic Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.marklogic.appdeployer.command.security;
17+
18+
import com.marklogic.appdeployer.command.AbstractResourceCommand;
19+
import com.marklogic.appdeployer.command.CommandContext;
20+
import com.marklogic.appdeployer.command.SortOrderConstants;
21+
import com.marklogic.appdeployer.command.UndoableCommand;
22+
import com.marklogic.mgmt.resource.ResourceManager;
23+
import com.marklogic.mgmt.resource.security.CredentialsManager;
24+
25+
import java.io.File;
26+
27+
public class DeployCredentialsCommand extends AbstractResourceCommand implements UndoableCommand {
28+
29+
public DeployCredentialsCommand() {
30+
setExecuteSortOrder(SortOrderConstants.DEPLOY_CREDENTIALS);
31+
setUndoSortOrder(SortOrderConstants.DEPLOY_CREDENTIALS);
32+
}
33+
34+
@Override
35+
protected File[] getResourceDirs(CommandContext context) {
36+
return findResourceDirs(context, configDir -> configDir.getCredentialsDir());
37+
}
38+
39+
@Override
40+
protected ResourceManager getResourceManager(CommandContext context) {
41+
return new CredentialsManager(context.getManageClient());
42+
}
43+
}

src/main/java/com/marklogic/mgmt/ManageClient.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.marklogic.rest.util.RestConfig;
2323
import com.marklogic.rest.util.RestTemplateUtil;
2424
import org.jdom2.Namespace;
25+
import org.springframework.core.io.Resource;
2526
import org.springframework.http.*;
2627
import org.springframework.util.LinkedMultiValueMap;
2728
import org.springframework.util.MultiValueMap;
@@ -204,16 +205,28 @@ public String getJsonAsSecurityUser(String path) {
204205
.getBody();
205206
}
206207

207-
public void delete(String path) {
208+
public void delete(String path, String... headerNamesAndValues) {
208209
logRequest(path, "", "DELETE");
209-
getRestTemplate().delete(buildUri(path));
210+
delete(getRestTemplate(), path, headerNamesAndValues);
210211
}
211212

212-
public void deleteAsSecurityUser(String path) {
213+
public void deleteAsSecurityUser(String path, String... headerNamesAndValues) {
213214
logSecurityUserRequest(path, "", "DELETE");
214-
getSecurityUserRestTemplate().delete(buildUri(path));
215+
delete(getSecurityUserRestTemplate(), path, headerNamesAndValues);
215216
}
216217

218+
private void delete(RestTemplate restTemplate, String path, String... headerNamesAndValues) {
219+
URI uri = buildUri(path);
220+
HttpHeaders headers = new HttpHeaders();
221+
if (headerNamesAndValues != null) {
222+
for (int i = 0; i < headerNamesAndValues.length; i += 2) {
223+
headers.add(headerNamesAndValues[i], headerNamesAndValues[i + 1]);
224+
}
225+
}
226+
HttpEntity<Resource> entity = new HttpEntity<>(null, headers);
227+
restTemplate.exchange(uri, HttpMethod.DELETE, entity, String.class);
228+
}
229+
217230
/**
218231
* Per #187 and version 3.1.0, when an HttpEntity is constructed with a JSON payload, this method will check to see
219232
* if it should "clean" the JSON via the Jackson library, which is primarily intended for removing comments from

src/main/java/com/marklogic/mgmt/resource/AbstractResourceManager.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ public abstract class AbstractResourceManager extends AbstractManager implements
3232

3333
private ManageClient manageClient;
3434
private boolean updateAllowed = true;
35+
protected final boolean usePutForCreate;
3536

3637
public AbstractResourceManager(ManageClient client) {
37-
this.manageClient = client;
38+
this(client, false);
3839
}
3940

41+
public AbstractResourceManager(ManageClient client, boolean usePutForCreate) {
42+
this.manageClient = client;
43+
this.usePutForCreate = usePutForCreate;
44+
}
45+
4046
public String getResourcesPath() {
4147
return format("/manage/v2/%ss", getResourceName());
4248
}
@@ -119,7 +125,9 @@ protected SaveReceipt createNewResource(String payload, String resourceId) {
119125
logger.info(format("Creating %s: %s", label, resourceId));
120126
}
121127
String path = getCreateResourcePath(payload);
122-
ResponseEntity<String> response = postPayload(manageClient, path, payload);
128+
ResponseEntity<String> response = this.usePutForCreate ?
129+
putPayload(manageClient, path, payload) :
130+
postPayload(manageClient, path, payload);
123131
if (logger.isInfoEnabled()) {
124132
logger.info(format("Created %s: %s", label, resourceId));
125133
}
@@ -194,14 +202,15 @@ protected void beforeDelete(String resourceId, String path, String... resourceUr
194202
* Convenience method for performing a delete once the correct path for the resource has been constructed.
195203
*
196204
* @param path
205+
* @param headerNamesAndValues optional sequence of header names and values to be included in the DELETE request.
197206
*/
198-
public void deleteAtPath(String path) {
207+
public void deleteAtPath(String path, String... headerNamesAndValues) {
199208
String label = getResourceName();
200209
logger.info(format("Deleting %s at path %s", label, path));
201210
if (useSecurityUser()) {
202-
manageClient.deleteAsSecurityUser(path);
211+
manageClient.deleteAsSecurityUser(path, headerNamesAndValues);
203212
} else {
204-
manageClient.delete(path);
213+
manageClient.delete(path, headerNamesAndValues);
205214
}
206215
logger.info(format("Deleted %s at path %s", label, path));
207216
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2023 MarkLogic Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.marklogic.mgmt.resource.security;
17+
18+
import com.marklogic.mgmt.DeleteReceipt;
19+
import com.marklogic.mgmt.ManageClient;
20+
import com.marklogic.mgmt.resource.AbstractResourceManager;
21+
22+
public class CredentialsManager extends AbstractResourceManager {
23+
24+
public CredentialsManager(ManageClient client) {
25+
super(client, true);
26+
}
27+
28+
@Override
29+
public String getResourcesPath() {
30+
return "/manage/v2/credentials/properties";
31+
}
32+
33+
34+
@Override
35+
protected String getIdFieldName() {
36+
return "type";
37+
}
38+
39+
@Override
40+
protected String getResourceId(String payload) {
41+
return getCredentialsType(payload);
42+
}
43+
44+
@Override
45+
public DeleteReceipt delete(String payload, String... resourceUrlParams) {
46+
final String type = getCredentialsType(payload);
47+
final String path = "/manage/v2/credentials/properties?type=" + type;
48+
// The DELETE endpoint - https://docs.marklogic.com/REST/DELETE/manage/v2/credentials/properties - seems to
49+
// erroneously require a Content-type header, even though there's no request body.
50+
super.deleteAtPath(path, "Content-type", "application/json");
51+
return new DeleteReceipt(type, path, true);
52+
}
53+
54+
private String getCredentialsType(String payload) {
55+
if (payloadParser.isJsonPayload(payload)) {
56+
return payloadParser.getPayloadFieldValue(payload, getIdFieldName());
57+
}
58+
return payloadParser.getPayloadFieldValue(payload, "azure", false) != null ? "azure" : "aws";
59+
}
60+
}

src/main/java/com/marklogic/rest/util/Fragment.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public Fragment(String xml, Namespace... namespaces) {
6363
list.add(Namespace.getNamespace("sec", "http://marklogic.com/xdmp/security"));
6464
list.add(Namespace.getNamespace("ts", "http://marklogic.com/manage/task-server"));
6565
list.add(Namespace.getNamespace("t", "http://marklogic.com/manage/tasks"));
66+
list.add(Namespace.getNamespace("creds", "http://marklogic.com/manage/credentials/properties"));
6667
list.addAll(Arrays.asList(namespaces));
6768
this.namespaces = list.toArray(new Namespace[] {});
6869
} catch (Exception e) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2023 MarkLogic Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.marklogic.appdeployer.command.security;
17+
18+
import com.marklogic.appdeployer.command.AbstractManageResourceTest;
19+
import com.marklogic.appdeployer.command.Command;
20+
import com.marklogic.mgmt.resource.ResourceManager;
21+
import com.marklogic.mgmt.resource.security.CredentialsManager;
22+
import com.marklogic.rest.util.Fragment;
23+
24+
import static org.junit.jupiter.api.Assertions.*;
25+
26+
public class DeployCredentialsTest extends AbstractManageResourceTest {
27+
28+
@Override
29+
protected ResourceManager newResourceManager() {
30+
return new CredentialsManager(manageClient);
31+
}
32+
33+
@Override
34+
protected Command newCommand() {
35+
return new DeployCredentialsCommand();
36+
}
37+
38+
@Override
39+
protected String[] getResourceNames() {
40+
return new String[]{};
41+
}
42+
43+
@Override
44+
protected void afterResourcesCreated() {
45+
Fragment f = manageClient.getXml(new CredentialsManager(manageClient).getResourcesPath()+"?format=xml");
46+
assertEquals("AWS-ACCESS-KEY", f.getElementValue("/creds:credentials-properties/creds:aws/creds:access-key"));
47+
assertEquals("AZURE-STORAGE-ACCOUNT", f.getElementValue("/creds:credentials-properties/creds:azure/creds:storage-account"));
48+
}
49+
50+
@Override
51+
protected void verifyResourcesWereDeleted(ResourceManager mgr) {
52+
Fragment f = manageClient.getXml(new CredentialsManager(manageClient).getResourcesPath()+"?format=xml");
53+
assertNull(f.getElementValue("/creds:credentials-properties/creds:aws/creds:access-key"));
54+
assertNull(f.getElementValue("/creds:credentials-properties/creds:azure/creds:storage-account"));
55+
}
56+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "aws",
3+
"access-key": "AWS-ACCESS-KEY",
4+
"secret-key": "SECRET-KEY"
5+
}

0 commit comments

Comments
 (0)