>From c4e428c6f8cc90f446278ebcc47fce4bb2a21462 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Wed, 23 Jul 2014 02:40:07 -0400 Subject: [PATCH 9/9] Update pki-profile CLI commands to work with "raw" format Update CLI commands for working with the (now LDAP-based) profiles in the same format as was used by the files, by way of the --raw option. Also add the "edit" command to interactively edit a profile. --- .../dogtagpki/server/ca/rest/ProfileService.java | 179 ++++++++++++++++++--- .../netscape/certsrv/profile/ProfileClient.java | 42 +++++ .../netscape/certsrv/profile/ProfileResource.java | 20 ++- .../netscape/cmstools/profile/ProfileAddCLI.java | 25 ++- .../com/netscape/cmstools/profile/ProfileCLI.java | 15 ++ .../netscape/cmstools/profile/ProfileEditCLI.java | 113 +++++++++++++ .../cmstools/profile/ProfileModifyCLI.java | 26 ++- .../netscape/cmstools/profile/ProfileShowCLI.java | 34 ++-- 8 files changed, 410 insertions(+), 44 deletions(-) create mode 100644 base/java-tools/src/com/netscape/cmstools/profile/ProfileEditCLI.java diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java index d3f08b270fd66154da880d47be30ea48716b75bd..692009eff4eab8e5e6e447e6f2304fbd229a395c 100644 --- a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java +++ b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java @@ -18,6 +18,8 @@ package org.dogtagpki.server.ca.rest; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URI; import java.security.Principal; @@ -27,6 +29,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Properties; import java.util.Vector; import javax.servlet.http.HttpServletRequest; @@ -163,9 +166,7 @@ public class ProfileService extends PKIService implements ProfileResource { return createOKResponse(infos); } - @Override - public Response retrieveProfile(String profileId) throws ProfileNotFoundException { - ProfileData data = null; + private IProfile getProfile(String profileId) throws ProfileNotFoundException { boolean visibleOnly = true; if (profileId == null) { @@ -185,24 +186,12 @@ public class ProfileService extends PKIService implements ProfileResource { visibleOnly = false; } - Enumeration profileIds = ps.getProfileIds(); - - IProfile profile = null; - if (profileIds != null) { - while (profileIds.hasMoreElements()) { - String id = profileIds.nextElement(); - - if (id.equals(profileId)) { - - try { - profile = ps.getProfile(profileId); - } catch (EProfileException e) { - e.printStackTrace(); - throw new ProfileNotFoundException(profileId); - } - break; - } - } + IProfile profile; + try { + profile = ps.getProfile(profileId); + } catch (EProfileException e) { + e.printStackTrace(); + throw new ProfileNotFoundException(profileId); } if (profile == null) { @@ -213,6 +202,14 @@ public class ProfileService extends PKIService implements ProfileResource { throw new ProfileNotFoundException(profileId); } + return profile; + } + + @Override + public Response retrieveProfile(String profileId) throws ProfileNotFoundException { + IProfile profile = getProfile(profileId); + + ProfileData data = null; try { data = createProfileData(profileId); } catch (EBaseException e) { @@ -228,6 +225,19 @@ public class ProfileService extends PKIService implements ProfileResource { return createOKResponse(data); } + @Override + public Response retrieveProfileRaw(String profileId) + throws ProfileNotFoundException { + IProfile profile = getProfile(profileId); + ByteArrayOutputStream data = new ByteArrayOutputStream(); + // add profileId and classId "virtual" properties + profile.getConfigStore().put("profileId", profileId); + profile.getConfigStore().put("classId", ps.getProfileClassId(profileId)); + profile.getConfigStore().save(data, null); + return createOKResponse(data.toByteArray()); + } + + public ProfileData createProfileData(String profileId) throws EBaseException { IProfile profile; @@ -499,6 +509,81 @@ public class ProfileService extends PKIService implements ProfileResource { return createCreatedResponse(profileData, profileData.getLink().getHref()); } catch (EBaseException e) { + CMS.debug("createProfile: error creating profile"); + CMS.debug(e); + + auditProfileChange( + ScopeDef.SC_PROFILE_RULES, + OpDef.OP_ADD, + profileId, + ILogger.FAILURE, + auditParams); + + throw new PKIException("Error in creating profile"); + } + } + + @Override + public Response createProfileRaw(byte[] data) { + if (data == null) { + CMS.debug("createProfileRaw: profile data is null"); + throw new BadRequestException("Unable to create profile: Invalid profile data."); + } + + if (ps == null) { + CMS.debug("createProfile: ps is null"); + throw new PKIException("Error creating profile. Profile Service not available"); + } + + Map auditParams = new LinkedHashMap(); + String profileId = null; + String classId = null; + Properties properties = new Properties(); + try { + // load data and read profileId and classId + properties.load(new ByteArrayInputStream(data)); + profileId = properties.getProperty("profileId"); + classId = properties.getProperty("classId"); + } catch (IOException e) { + throw new BadRequestException("Could not parse raw profile data."); + } + if (profileId == null) { + throw new BadRequestException("Profile data did not contain profileId attribute."); + } + if (classId == null) { + throw new BadRequestException("Profile data did not contain classId attribute."); + } + properties.remove("profileId"); + properties.remove("classId"); + + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + properties.store(out, null); + data = out.toByteArray(); // original data sans profileId, classId + + IProfile profile = ps.getProfile(profileId); + if (profile != null) { + throw new BadRequestException("Profile already exists"); + } + + auditParams.put("class_id", classId); + + IPluginInfo info = registry.getPluginInfo("profile", classId); + + profile = ps.createProfile(profileId, classId, info.getClassName()); + profile.getConfigStore().commit(false); + profile.getConfigStore().load(new ByteArrayInputStream(data)); + ps.disableProfile(profileId); + + auditProfileChange( + ScopeDef.SC_PROFILE_RULES, + OpDef.OP_ADD, + profileId, + ILogger.SUCCESS, + auditParams); + + return createCreatedResponse(data, uriInfo.getAbsolutePath()); + } catch (EBaseException | IOException e) { CMS.debug("createProfile: error in creating profile: " + e); e.printStackTrace(); @@ -550,6 +635,58 @@ public class ProfileService extends PKIService implements ProfileResource { } } + @Override + public Response modifyProfileRaw(String profileId, byte[] data) { + if (profileId == null) { + CMS.debug("modifyProfile: invalid request. profileId is null"); + throw new BadRequestException("Unable to modify profile: Invalid Profile Id"); + } + + if (data == null) { + CMS.debug("modifyProfile: invalid request. data is null"); + throw new BadRequestException("Unable to modify profile: Invalid profile data"); + } + + if (ps == null) { + CMS.debug("modifyProfile: ps is null"); + throw new PKIException("Error modifying profile. Profile Service not available"); + } + + if (ps.isProfileEnable(profileId)) { + throw new BadRequestException("Cannot change profile data. Profile must be disabled"); + } + + Properties properties = new Properties(); + try { + properties.load(new ByteArrayInputStream(data)); + } catch (IOException e) { + throw new BadRequestException("Could not parse raw profile data."); + } + properties.remove("profileId"); + properties.remove("classId"); + + try { + IProfile profile = ps.getProfile(profileId); + if (profile == null) { + throw new ProfileNotFoundException(profileId); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + properties.store(out, null); + data = out.toByteArray(); // original data sans profileId, classId + + profile.getConfigStore().load(new ByteArrayInputStream(data)); + ps.disableProfile(profileId); + profile.getConfigStore().commit(false); + + return createOKResponse(data); + } catch (EBaseException | IOException e) { + CMS.debug("modifyProfile: error modifying profile " + profileId); + CMS.debug(e); + throw new PKIException("Error modifying profile."); + } + } + private void changeProfileData(ProfileData data, IProfile profile) { String profileId = data.getId(); if (profile == null) { diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileClient.java b/base/common/src/com/netscape/certsrv/profile/ProfileClient.java index 51d159aca687719a2dace939da5b09c4809872ec..7f0b08f0e40d9a5314bcf741c2dc2fc514802ad5 100644 --- a/base/common/src/com/netscape/certsrv/profile/ProfileClient.java +++ b/base/common/src/com/netscape/certsrv/profile/ProfileClient.java @@ -17,10 +17,15 @@ //--- END COPYRIGHT BLOCK --- package com.netscape.certsrv.profile; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.URISyntaxException; +import java.util.Properties; import javax.ws.rs.core.Response; +import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.client.Client; import com.netscape.certsrv.client.PKIClient; @@ -45,6 +50,11 @@ public class ProfileClient extends Client { return client.getEntity(response, ProfileData.class); } + public Properties retrieveProfileRaw(String id) { + Response response = profileClient.retrieveProfileRaw(id); + return byteArrayToProperties(client.getEntity(response, byte[].class)); + } + public ProfileDataInfos listProfiles(Integer start, Integer size) { Response response = profileClient.listProfiles(start, size); return client.getEntity(response, ProfileDataInfos.class); @@ -65,13 +75,45 @@ public class ProfileClient extends Client { return client.getEntity(response, ProfileData.class); } + public Properties createProfileRaw(Properties properties) { + Response response = + profileClient.createProfileRaw(propertiesToByteArray(properties)); + return byteArrayToProperties(client.getEntity(response, byte[].class)); + } + public ProfileData modifyProfile(ProfileData data) { Response response = profileClient.modifyProfile(data.getId(), data); return client.getEntity(response, ProfileData.class); } + public Properties modifyProfileRaw(String profileId, Properties properties) { + Response response = + profileClient.modifyProfileRaw(profileId, propertiesToByteArray(properties)); + return byteArrayToProperties(client.getEntity(response, byte[].class)); + } + public void deleteProfile(String id) { Response response = profileClient.deleteProfile(id); client.getEntity(response, Void.class); } + + private Properties byteArrayToProperties(byte[] data) throws PKIException { + Properties properties = new Properties(); + try { + properties.load(new ByteArrayInputStream(data)); + } catch (IOException e) { + throw new PKIException("Failed to decode profile Properties: " + e.toString()); + } + return properties; + } + + private byte[] propertiesToByteArray(Properties properties) throws PKIException { + ByteArrayOutputStream data = new ByteArrayOutputStream(); + try { + properties.store(data, null); + } catch (IOException e) { + throw new PKIException("Failed to encode profile Properties: " + e.toString()); + } + return data.toByteArray(); + } } diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileResource.java b/base/common/src/com/netscape/certsrv/profile/ProfileResource.java index 87449b27e749c6088f65b53192eb5ac101263f1e..410f98a468dbfca0bf587623935f2a63e97923e9 100644 --- a/base/common/src/com/netscape/certsrv/profile/ProfileResource.java +++ b/base/common/src/com/netscape/certsrv/profile/ProfileResource.java @@ -31,12 +31,24 @@ public interface ProfileResource { @ACLMapping("profiles.read") public Response retrieveProfile(@PathParam("id") String id); + @GET + @Path("{id}/raw") + @ClientResponseType(entityType=byte[].class) + @ACLMapping("profiles.read") + public Response retrieveProfileRaw(@PathParam("id") String id); + @POST @ClientResponseType(entityType=ProfileData.class) @ACLMapping("profiles.create") public Response createProfile(ProfileData data); @POST + @Path("raw") + @ClientResponseType(entityType=byte[].class) + @ACLMapping("profiles.create") + public Response createProfileRaw(byte[] data); + + @POST @Path("{id}") @ClientResponseType(entityType=Void.class) @ACLMapping("profiles.approve") @@ -48,9 +60,15 @@ public interface ProfileResource { @ACLMapping("profiles.modify") public Response modifyProfile(@PathParam("id") String id, ProfileData data); + @PUT + @Path("{id}/raw") + @ClientResponseType(entityType=byte[].class) + @ACLMapping("profiles.modify") + public Response modifyProfileRaw(@PathParam("id") String id, byte[] data); + @DELETE @Path("{id}") @ClientResponseType(entityType=Void.class) @ACLMapping("profiles.delete") public Response deleteProfile(@PathParam("id") String id); -} \ No newline at end of file +} diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java index 62bd145261a798fd89b3b8aaed389d0b2fb886fa..7aaf09d8830fa02d52a5e5956e22fea4e45bf74e 100644 --- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java +++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java @@ -1,11 +1,13 @@ package com.netscape.cmstools.profile; -import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; +import java.util.Properties; import javax.xml.bind.JAXBException; import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import com.netscape.certsrv.profile.ProfileData; @@ -19,6 +21,10 @@ public class ProfileAddCLI extends CLI { public ProfileAddCLI(ProfileCLI profileCLI) { super("add", "Add profiles", profileCLI); this.profileCLI = profileCLI; + + Option optRaw = new Option(null, "raw", false, "Use raw format"); + optRaw.setArgName("raw"); + options.addOption(optRaw); } public void printHelp() { @@ -59,13 +65,20 @@ public class ProfileAddCLI extends CLI { } try { - ProfileData data = ProfileCLI.readProfileFromFile(filename); - data = profileCLI.profileClient.createProfile(data); + if (cmd.hasOption("raw")) { + Properties properties = ProfileCLI.readRawProfileFromFile(filename); + String profileId = properties.getProperty("profileId"); + profileCLI.profileClient.createProfileRaw(properties).store(System.out, null); + MainCLI.printMessage("Added profile " + profileId); + } else { + ProfileData data = ProfileCLI.readProfileFromFile(filename); + data = profileCLI.profileClient.createProfile(data); - MainCLI.printMessage("Added profile " + data.getId()); + MainCLI.printMessage("Added profile " + data.getId()); - ProfileCLI.printProfile(data, profileCLI.getClient().getConfig().getServerURI()); - } catch (FileNotFoundException | JAXBException e) { + ProfileCLI.printProfile(data, profileCLI.getClient().getConfig().getServerURI()); + } + } catch (IOException | JAXBException e) { System.err.println("Error: " + e.getMessage()); System.exit(-1); } diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java index 6d8c6b655ced3807ac01364fe304b422986de567..e9e21596a0593d63b417d6d8560f3ff9b54caaf0 100644 --- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java +++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java @@ -3,8 +3,12 @@ package com.netscape.cmstools.profile; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Locale; +import java.util.Properties; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -32,6 +36,7 @@ public class ProfileCLI extends CLI { addModule(new ProfileShowCLI(this)); addModule(new ProfileAddCLI(this)); addModule(new ProfileModifyCLI(this)); + addModule(new ProfileEditCLI(this)); addModule(new ProfileRemoveCLI(this)); addModule(new ProfileEnableCLI(this)); addModule(new ProfileDisableCLI(this)); @@ -128,6 +133,16 @@ public class ProfileCLI extends CLI { return data; } + public static Properties readRawProfileFromFile(String filename) + throws IOException, RuntimeException { + Properties properties = new Properties(); + properties.load(Files.newInputStream(Paths.get(filename))); + String profileId = properties.getProperty("profileId"); + if (profileId == null) + throw new RuntimeException("Error: Missing profileId property in profile data."); + return properties; + } + public static void saveEnrollmentTemplateToFile(String filename, CertEnrollmentRequest request) throws JAXBException, FileNotFoundException { JAXBContext context = JAXBContext.newInstance(CertEnrollmentRequest.class); diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileEditCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileEditCLI.java new file mode 100644 index 0000000000000000000000000000000000000000..50600ba155b9b84edfdeb54e1177b4d0d46cc397 --- /dev/null +++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileEditCLI.java @@ -0,0 +1,113 @@ +//--- BEGIN COPYRIGHT BLOCK --- +//This program is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; version 2 of the License. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License along +//with this program; if not, write to the Free Software Foundation, Inc., +//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +//(C) 2014 Red Hat, Inc. +//All rights reserved. +//--- END COPYRIGHT BLOCK --- + +package com.netscape.cmstools.profile; + +import java.lang.ProcessBuilder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Properties; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.ParseException; + +import com.netscape.cmstools.cli.CLI; + +public class ProfileEditCLI extends CLI { + + public ProfileCLI profileCLI; + + public ProfileEditCLI(ProfileCLI profileCLI) { + super("edit", "Edit profiles (config-store format)", profileCLI); + this.profileCLI = profileCLI; + } + + public void printHelp() { + formatter.printHelp(getFullName() + " [OPTIONS...]", options); + } + + public void execute(String[] args) throws Exception { + // Always check for "--help" prior to parsing + if (Arrays.asList(args).contains("--help")) { + // Display usage + printHelp(); + System.exit(0); + } + + CommandLine cmd = null; + + try { + cmd = parser.parse(options, args); + } catch (ParseException e) { + System.err.println("Error: " + e.getMessage()); + printHelp(); + System.exit(-1); + } + + String[] cmdArgs = cmd.getArgs(); + + if (cmdArgs.length < 1) { + System.err.println("Error: No Profile ID specified."); + printHelp(); + System.exit(-1); + } + + String profileId = cmdArgs[0]; + + // read profile into temporary file + Properties orig = profileCLI.profileClient.retrieveProfileRaw(profileId); + String enabled = orig.getProperty("enable"); + if (Boolean.valueOf(enabled)) { + System.err.println("Error: Cannot edit profile. Profile must be disabled."); + System.exit(-1); + } + Path tempFile = Files.createTempFile("pki", ".cfg"); + + try { + orig.store(Files.newOutputStream(tempFile), null); + + // invoke editor on temporary file + String editor = System.getenv("EDITOR"); + String[] command; + if (editor == null || editor.trim().isEmpty()) { + command = new String[] {"/usr/bin/env", "vi", tempFile.toString()}; + } else { + command = new String[] {editor.trim(), tempFile.toString()}; + } + ProcessBuilder pb = new ProcessBuilder(command); + pb.inheritIO(); + int exitCode = pb.start().waitFor(); + if (exitCode != 0) { + System.err.println("Error: editor exited abnormally."); + System.exit(-1); + } + + // read data from temporary file and modify if changed + Properties cur = new Properties(); + cur.load(Files.newInputStream(tempFile)); + + if (!cur.equals(orig)) { + profileCLI.profileClient.modifyProfileRaw(profileId, cur); + } + cur.store(System.out, null); + } finally { + Files.delete(tempFile); + } + } +} diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java index bbeb91981e79b6690efa55c8f293b017ea4ace31..cc0f415b78facbaa4cacb7ab4e914717586cfd0e 100644 --- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java +++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java @@ -1,11 +1,13 @@ package com.netscape.cmstools.profile; -import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; +import java.util.Properties; import javax.xml.bind.JAXBException; import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import com.netscape.certsrv.profile.ProfileData; @@ -19,6 +21,10 @@ public class ProfileModifyCLI extends CLI { public ProfileModifyCLI(ProfileCLI profileCLI) { super("mod", "Modify profiles", profileCLI); this.profileCLI = profileCLI; + + Option optRaw = new Option(null, "raw", false, "Use raw format"); + optRaw.setArgName("raw"); + options.addOption(optRaw); } public void printHelp() { @@ -59,14 +65,20 @@ public class ProfileModifyCLI extends CLI { } try { - ProfileData data = ProfileCLI.readProfileFromFile(filename); - data = profileCLI.profileClient.modifyProfile(data); + if (cmd.hasOption("raw")) { + Properties properties = ProfileCLI.readRawProfileFromFile(filename); + String profileId = properties.getProperty("profileId"); + profileCLI.profileClient.modifyProfileRaw(profileId, properties).store(System.out, null); + MainCLI.printMessage("Modified profile " + profileId); + } else { + ProfileData data = ProfileCLI.readProfileFromFile(filename); + data = profileCLI.profileClient.modifyProfile(data); - MainCLI.printMessage("Modified profile " + data.getId()); + MainCLI.printMessage("Modified profile " + data.getId()); - ProfileCLI.printProfile(data, profileCLI.getClient().getConfig().getServerURI()); - - } catch (FileNotFoundException | JAXBException e) { + ProfileCLI.printProfile(data, profileCLI.getClient().getConfig().getServerURI()); + } + } catch (IOException | JAXBException e) { System.err.println("Error: " + e.getMessage()); System.exit(-1); } diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java index f5b636c1a8f9dbfe60d29fc07bae373be3ea966e..1dd85f43bf349c4dbca9b4b764f2d40fe7f421aa 100644 --- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java +++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java @@ -1,6 +1,8 @@ package com.netscape.cmstools.profile; +import java.io.FileOutputStream; import java.util.Arrays; +import java.util.Properties; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; @@ -26,9 +28,13 @@ public class ProfileShowCLI extends CLI { } public void createOptions() { - Option option = new Option(null, "output", true, "Output filename"); - option.setArgName("filename"); - options.addOption(option); + Option optFilename = new Option(null, "output", true, "Output filename"); + optFilename.setArgName("filename"); + options.addOption(optFilename); + + Option optRaw = new Option(null, "raw", false, "Use raw format"); + optRaw.setArgName("raw"); + options.addOption(optRaw); } public void execute(String[] args) throws Exception { @@ -70,14 +76,24 @@ public class ProfileShowCLI extends CLI { } } - ProfileData profileData = profileCLI.profileClient.retrieveProfile(profileId); + if (cmd.hasOption("raw")) { + Properties profileConfig = profileCLI.profileClient.retrieveProfileRaw(profileId); - MainCLI.printMessage("Profile \"" + profileId + "\""); - - if (filename != null) { - ProfileCLI.saveProfileToFile(filename, profileData); + if (filename != null) { + profileConfig.store(new FileOutputStream(filename), null); + MainCLI.printMessage("Saved profile " + profileId + " to " + filename); + } else { + profileConfig.store(System.out, null); + } } else { - ProfileCLI.printProfile(profileData, profileCLI.getClient().getConfig().getServerURI()); + MainCLI.printMessage("Profile \"" + profileId + "\""); + ProfileData profileData = profileCLI.profileClient.retrieveProfile(profileId); + + if (filename != null) { + ProfileCLI.saveProfileToFile(filename, profileData); + } else { + ProfileCLI.printProfile(profileData, profileCLI.getClient().getConfig().getServerURI()); + } } } -- 2.1.0