8311877: [macos] Add CLI options to provide signing identity directly to codesign and productbuild

Reviewed-by: asemenyuk
This commit is contained in:
Alexander Matveev 2023-10-24 21:41:20 +00:00
parent 9c819fd3b7
commit f1dfdc1a79
24 changed files with 531 additions and 105 deletions

View File

@ -85,6 +85,13 @@ public class MacAppBundler extends AppImageBundler {
}, },
(s, p) -> s); (s, p) -> s);
public static final BundlerParamInfo<String> APP_IMAGE_SIGN_IDENTITY =
new StandardBundlerParam<>(
Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(),
String.class,
params -> "",
null);
public static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX = public static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX =
new StandardBundlerParam<>( new StandardBundlerParam<>(
Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(),
@ -127,14 +134,21 @@ public class MacAppBundler extends AppImageBundler {
// reject explicitly set sign to true and no valid signature key // reject explicitly set sign to true and no valid signature key
if (Optional.ofNullable( if (Optional.ofNullable(
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
String signingIdentity = // Validate DEVELOPER_ID_APP_SIGNING_KEY only if user provided
DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); // SIGNING_KEY_USER.
if (signingIdentity == null) { if (!SIGNING_KEY_USER.getIsDefaultValue(params)) { // --mac-signing-key-user-name
throw new ConfigException( String signingIdentity =
I18N.getString("error.explicit-sign-no-cert"), DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
I18N.getString("error.explicit-sign-no-cert.advice")); if (signingIdentity == null) {
throw new ConfigException(
I18N.getString("error.explicit-sign-no-cert"),
I18N.getString("error.explicit-sign-no-cert.advice"));
}
} }
// No need to validate --mac-app-image-sign-identity, since it is
// pass through option.
// Signing will not work without Xcode with command line developer tools // Signing will not work without Xcode with command line developer tools
try { try {
ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "--help"); ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "--help");

View File

@ -25,8 +25,10 @@
package jdk.jpackage.internal; package jdk.jpackage.internal;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintStream;
import java.io.Writer; import java.io.Writer;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -53,7 +55,10 @@ import jdk.internal.util.OperatingSystem;
import jdk.internal.util.OSVersion; import jdk.internal.util.OSVersion;
import static jdk.jpackage.internal.MacAppBundler.BUNDLE_ID_SIGNING_PREFIX; import static jdk.jpackage.internal.MacAppBundler.BUNDLE_ID_SIGNING_PREFIX;
import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY;
import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY;
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER;
import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY;
import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.OverridableResource.createResource;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT;
@ -395,12 +400,25 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.error(e.getMessage()); Log.error(e.getMessage());
} }
String signingIdentity = String signingIdentity = null;
DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); // Try --mac-app-image-sign-identity first if set
if (!APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) {
signingIdentity = APP_IMAGE_SIGN_IDENTITY.fetchFrom(params);
} else {
// Check if INSTALLER_SIGN_IDENTITY is set and if it is set
// then do not sign app image, otherwise use --mac-signing-key-user-name
if (INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) {
// --mac-sign and/or --mac-signing-key-user-name case
signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
}
}
if (signingIdentity != null) { if (signingIdentity != null) {
signAppBundle(params, root, signingIdentity, signAppBundle(params, root, signingIdentity,
BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params),
ENTITLEMENTS.fetchFrom(params)); ENTITLEMENTS.fetchFrom(params));
} else {
// Case when user requested to sign installer only
signAppBundle(params, root, "-", null, null);
} }
restoreKeychainList(params); restoreKeychainList(params);
} else if (OperatingSystem.isMacOS()) { } else if (OperatingSystem.isMacOS()) {
@ -715,6 +733,25 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
return args; return args;
} }
private static void runCodesign(ProcessBuilder pb, boolean quiet)
throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos)) {
try {
IOUtils.exec(pb, false, ps, false,
Executor.INFINITE_TIMEOUT, quiet);
} catch (IOException ioe) {
// Log output of "codesign" in case of
// error. It should help user to diagnose
// issue when using --mac-app-image-sign-identity
Log.info(MessageFormat.format(I18N.getString(
"error.tool.failed.with.output"), "codesign"));
Log.info(baos.toString().strip());
throw ioe;
}
}
}
static void signAppBundle( static void signAppBundle(
Map<String, ? super Object> params, Path appLocation, Map<String, ? super Object> params, Path appLocation,
String signingIdentity, String identifierPrefix, Path entitlements) String signingIdentity, String identifierPrefix, Path entitlements)
@ -781,8 +818,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
p.toFile().setWritable(true, true); p.toFile().setWritable(true, true);
ProcessBuilder pb = new ProcessBuilder(args); ProcessBuilder pb = new ProcessBuilder(args);
// run quietly // run quietly
IOUtils.exec(pb, false, null, false, runCodesign(pb, true);
Executor.INFINITE_TIMEOUT, true);
Files.setPosixFilePermissions(p, oldPermissions); Files.setPosixFilePermissions(p, oldPermissions);
} catch (IOException ioe) { } catch (IOException ioe) {
toThrow.set(ioe); toThrow.set(ioe);
@ -810,8 +846,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
List<String> args = getCodesignArgs(true, path, signingIdentity, List<String> args = getCodesignArgs(true, path, signingIdentity,
identifierPrefix, entitlements, keyChain); identifierPrefix, entitlements, keyChain);
ProcessBuilder pb = new ProcessBuilder(args); ProcessBuilder pb = new ProcessBuilder(args);
runCodesign(pb, false);
IOUtils.exec(pb);
} catch (IOException e) { } catch (IOException e) {
toThrow.set(e); toThrow.set(e);
} }
@ -842,8 +877,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
List<String> args = getCodesignArgs(true, appLocation, signingIdentity, List<String> args = getCodesignArgs(true, appLocation, signingIdentity,
identifierPrefix, entitlements, keyChain); identifierPrefix, entitlements, keyChain);
ProcessBuilder pb = new ProcessBuilder(args); ProcessBuilder pb = new ProcessBuilder(args);
runCodesign(pb, false);
IOUtils.exec(pb);
} }
private static String extractBundleIdentifier(Map<String, Object> params) { private static String extractBundleIdentifier(Map<String, Object> params) {

View File

@ -79,6 +79,13 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler {
params -> "", params -> "",
null); null);
public static final BundlerParamInfo<String> INSTALLER_SIGN_IDENTITY =
new StandardBundlerParam<>(
Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(),
String.class,
params -> "",
null);
public static final BundlerParamInfo<String> MAC_INSTALLER_NAME = public static final BundlerParamInfo<String> MAC_INSTALLER_NAME =
new StandardBundlerParam<> ( new StandardBundlerParam<> (
"mac.installerName", "mac.installerName",

View File

@ -28,7 +28,9 @@ package jdk.jpackage.internal;
import jdk.internal.util.Architecture; import jdk.internal.util.Architecture;
import jdk.internal.util.OSVersion; import jdk.internal.util.OSVersion;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -54,6 +56,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE;
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER;
import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY;
import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY;
import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE;
import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER;
import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.OverridableResource.createResource;
@ -605,8 +609,19 @@ public class MacPkgBundler extends MacBaseInstallerBundler {
Log.verbose(I18N.getString("message.signing.pkg")); Log.verbose(I18N.getString("message.signing.pkg"));
} }
String signingIdentity = String signingIdentity = null;
DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); // --mac-installer-sign-identity
if (!INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) {
signingIdentity = INSTALLER_SIGN_IDENTITY.fetchFrom(params);
} else {
// Use --mac-signing-key-user-name if user did not request
// to sign just app image using --mac-app-image-sign-identity
if (APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) {
// --mac-signing-key-user-name
signingIdentity = DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params);
}
}
if (signingIdentity != null) { if (signingIdentity != null) {
commandLine.add("--sign"); commandLine.add("--sign");
commandLine.add(signingIdentity); commandLine.add(signingIdentity);
@ -638,7 +653,21 @@ public class MacPkgBundler extends MacBaseInstallerBundler {
commandLine.add(finalPKG.toAbsolutePath().toString()); commandLine.add(finalPKG.toAbsolutePath().toString());
pb = new ProcessBuilder(commandLine); pb = new ProcessBuilder(commandLine);
IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos)) {
try {
IOUtils.exec(pb, false, ps, true, Executor.INFINITE_TIMEOUT);
} catch (IOException ioe) {
// Log output of "productbuild" in case of
// error. It should help user to diagnose
// issue when using --mac-installer-sign-identity
Log.info(MessageFormat.format(I18N.getString(
"error.tool.failed.with.output"), "productbuild"));
Log.info(baos.toString().strip());
throw ioe;
}
}
return finalPKG; return finalPKG;
} catch (Exception ignored) { } catch (Exception ignored) {
@ -702,14 +731,19 @@ public class MacPkgBundler extends MacBaseInstallerBundler {
// reject explicitly set sign to true and no valid signature key // reject explicitly set sign to true and no valid signature key
if (Optional.ofNullable( if (Optional.ofNullable(
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
String signingIdentity = if (!SIGNING_KEY_USER.getIsDefaultValue(params)) {
DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); String signingIdentity =
if (signingIdentity == null) { DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params);
throw new ConfigException( if (signingIdentity == null) {
I18N.getString("error.explicit-sign-no-cert"), throw new ConfigException(
I18N.getString( I18N.getString("error.explicit-sign-no-cert"),
"error.explicit-sign-no-cert.advice")); I18N.getString(
"error.explicit-sign-no-cert.advice"));
}
} }
// No need to validate --mac-installer-sign-identity, since it is
// pass through option.
} }
// hdiutil is always available so there's no need // hdiutil is always available so there's no need

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Install Xcode with command line developer tools.
error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.cert.not.found=No certificate found matching [{0}] using keychain [{1}]
error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one
error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image] error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image]
error.tool.failed.with.output=Error: "{0}" failed with following output:
resource.bundle-config-file=Bundle config file resource.bundle-config-file=Bundle config file
resource.app-info-plist=Application Info.plist resource.app-info-plist=Application Info.plist
resource.runtime-info-plist=Java Runtime Info.plist resource.runtime-info-plist=Java Runtime Info.plist

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Installieren Sie Xcode mit Befehlszeilen-Entwickle
error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht
error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet
error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich
error.tool.failed.with.output=Error: "{0}" failed with following output:
resource.bundle-config-file=Bundle-Konfigurationsdatei resource.bundle-config-file=Bundle-Konfigurationsdatei
resource.app-info-plist=Info.plist der Anwendung resource.app-info-plist=Info.plist der Anwendung
resource.runtime-info-plist=Info.plist von Java Runtime resource.runtime-info-plist=Info.plist von Java Runtime

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Xcodeとコマンドライン・デベロッパ・
error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません
error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します
error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です
error.tool.failed.with.output=Error: "{0}" failed with following output:
resource.bundle-config-file=バンドル構成ファイル resource.bundle-config-file=バンドル構成ファイル
resource.app-info-plist=アプリケーションのInfo.plist resource.app-info-plist=アプリケーションのInfo.plist
resource.runtime-info-plist=JavaランタイムのInfo.plist resource.runtime-info-plist=JavaランタイムのInfo.plist

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ error.no.xcode.signing.advice=安装带命令行开发人员工具的 Xcode。
error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书 error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书
error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书 error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书
error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项 error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项
error.tool.failed.with.output=Error: "{0}" failed with following output:
resource.bundle-config-file=包配置文件 resource.bundle-config-file=包配置文件
resource.app-info-plist=应用程序 Info.plist resource.app-info-plist=应用程序 Info.plist
resource.runtime-info-plist=Java 运行时 Info.plist resource.runtime-info-plist=Java 运行时 Info.plist

View File

@ -338,6 +338,12 @@ public class Arguments {
MAC_SIGNING_KEY_NAME ("mac-signing-key-user-name", MAC_SIGNING_KEY_NAME ("mac-signing-key-user-name",
OptionCategories.PLATFORM_MAC), OptionCategories.PLATFORM_MAC),
MAC_APP_IMAGE_SIGN_IDENTITY ("mac-app-image-sign-identity",
OptionCategories.PLATFORM_MAC),
MAC_INSTALLER_SIGN_IDENTITY ("mac-installer-sign-identity",
OptionCategories.PLATFORM_MAC),
MAC_SIGNING_KEYCHAIN ("mac-signing-keychain", MAC_SIGNING_KEYCHAIN ("mac-signing-keychain",
OptionCategories.PLATFORM_MAC), OptionCategories.PLATFORM_MAC),
@ -631,6 +637,24 @@ public class Arguments {
CLIOptions.JLINK_OPTIONS.getIdWithPrefix()); CLIOptions.JLINK_OPTIONS.getIdWithPrefix());
} }
} }
if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) &&
allOptions.contains(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY)) {
throw new PackagerException("ERR_MutuallyExclusiveOptions",
CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(),
CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getIdWithPrefix());
}
if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) &&
allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) {
throw new PackagerException("ERR_MutuallyExclusiveOptions",
CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(),
CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix());
}
if (isMac && (imageOnly || "dmg".equals(type)) &&
allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) {
throw new PackagerException("ERR_InvalidTypeOption",
CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix(),
type);
}
if (allOptions.contains(CLIOptions.DMG_CONTENT) if (allOptions.contains(CLIOptions.DMG_CONTENT)
&& !("dmg".equals(type))) { && !("dmg".equals(type))) {
throw new PackagerException("ERR_InvalidTypeOption", throw new PackagerException("ERR_InvalidTypeOption",

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -46,11 +46,6 @@ class BundlerParamInfo<T> {
*/ */
Class<T> valueType; Class<T> valueType;
/**
* Indicates if value was set using default value function
*/
boolean isDefaultValue;
/** /**
* If the value is not set, and no fallback value is found, * If the value is not set, and no fallback value is found,
* the parameter uses the value returned by the producer. * the parameter uses the value returned by the producer.
@ -70,8 +65,24 @@ class BundlerParamInfo<T> {
return valueType; return valueType;
} }
boolean getIsDefaultValue() { /**
return isDefaultValue; * Returns true if value was not provided on command line for this
* parameter.
*
* @param params - params from which value will be fetch
* @return true if value was not provided on command line, false otherwise
*/
boolean getIsDefaultValue(Map<String, ? super Object> params) {
Object o = params.get(getID());
if (o != null) {
return false; // We have user provided value
}
if (params.containsKey(getID())) {
return false; // explicit nulls are allowed for provided value
}
return true;
} }
Function<Map<String, ? super Object>, T> getDefaultValueFunction() { Function<Map<String, ? super Object>, T> getDefaultValueFunction() {
@ -114,7 +125,6 @@ class BundlerParamInfo<T> {
T result = getDefaultValueFunction().apply(params); T result = getDefaultValueFunction().apply(params);
if (result != null) { if (result != null) {
params.put(getID(), result); params.put(getID(), result);
isDefaultValue = true;
} }
return result; return result;
} }

View File

@ -27,6 +27,7 @@ package jdk.jpackage.internal;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import jdk.internal.util.OperatingSystem; import jdk.internal.util.OperatingSystem;
import jdk.jpackage.internal.Arguments.CLIOptions; import jdk.jpackage.internal.Arguments.CLIOptions;
@ -62,7 +63,6 @@ class ValidOptions {
private static final HashMap<String, EnumSet<USE>> options = new HashMap<>(); private static final HashMap<String, EnumSet<USE>> options = new HashMap<>();
// initializing list of mandatory arguments // initializing list of mandatory arguments
static { static {
put(CLIOptions.NAME.getId(), USE.ALL); put(CLIOptions.NAME.getId(), USE.ALL);
@ -130,6 +130,10 @@ class ValidOptions {
EnumSet.of(USE.ALL, USE.SIGN)); EnumSet.of(USE.ALL, USE.SIGN));
put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(), put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(),
EnumSet.of(USE.ALL, USE.SIGN)); EnumSet.of(USE.ALL, USE.SIGN));
put(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(),
EnumSet.of(USE.ALL, USE.SIGN));
put(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(),
EnumSet.of(USE.INSTALL, USE.SIGN));
put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(),
EnumSet.of(USE.ALL, USE.SIGN)); EnumSet.of(USE.ALL, USE.SIGN));
put(CLIOptions.MAC_APP_STORE.getId(), USE.ALL); put(CLIOptions.MAC_APP_STORE.getId(), USE.ALL);

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -265,7 +265,19 @@ MSG_Help_mac_launcher=\
\ Name of the keychain to search for the signing identity\n\ \ Name of the keychain to search for the signing identity\n\
\ If not specified, the standard keychains are used.\n\ \ If not specified, the standard keychains are used.\n\
\ --mac-signing-key-user-name <team name>\n\ \ --mac-signing-key-user-name <team name>\n\
\ Team or user name portion of Apple signing identities.\n\ \ Team or user name portion of Apple signing identities. For direct\n\
\ control of the signing identity used to sign application images or\n\
\ installers use --mac-app-image-sign-identity and/or\n\
\ --mac-installer-sign-identity. This option cannot be combined with\n\
\ --mac-app-image-sign-identity or --mac-installer-sign-identity.\n\
\ --mac-app-image-sign-identity <identity>\n\
\ Identity used to sign application image. This value will be passed\n\
\ directly to --sign option of "codesign" tool. This option cannot\n\
\ be combined with --mac-signing-key-user-name.\n\
\ --mac-installer-sign-identity <identity>\n\
\ Identity used to sign "pkg" installer. This value will be passed\n\
\ directly to --sign option of "productbuild" tool. This option\n\
\ cannot be combined with --mac-signing-key-user-name.\n\
\ --mac-app-store\n\ \ --mac-app-store\n\
\ Indicates that the jpackage output is intended for the\n\ \ Indicates that the jpackage output is intended for the\n\
\ Mac App Store.\n\ \ Mac App Store.\n\

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -92,10 +92,11 @@ ERR_NoMainClass=Error: Main application class is missing
ERR_UnsupportedOption=Error: Option [{0}] is not valid on this platform ERR_UnsupportedOption=Error: Option [{0}] is not valid on this platform
ERR_InvalidTypeOption=Error: Option [{0}] is not valid with type [{1}] ERR_InvalidTypeOption=Error: Option [{0}] is not valid with type [{1}]
ERR_NoInstallerEntryPoint=Error: Option [{0}] is not valid without --module or --main-jar entry point option ERR_NoInstallerEntryPoint=Error: Option [{0}] is not valid without --module or --main-jar entry point option
ERR_MutuallyExclusiveOptions="Error: Mutually exclusive options [{0}] and [{1}] ERR_MutuallyExclusiveOptions=Error: Mutually exclusive options [{0}] and [{1}]
ERR_InvalidOptionWithAppImageSigning=Error: Option [{0}] is not valid when signing application image ERR_InvalidOptionWithAppImageSigning=Error: Option [{0}] is not valid when signing application image
ERR_MissingArgument=Error: Missing argument: {0} ERR_MissingArgument=Error: Missing argument: {0}
ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s)
ERR_MissingAppResources=Error: No application jars found ERR_MissingAppResources=Error: No application jars found
ERR_AppImageNotExist=Error: App image directory "{0}" does not exist ERR_AppImageNotExist=Error: App image directory "{0}" does not exist
ERR_NoAddLauncherName=Error: --add-launcher option requires a name and a file path (--add-launcher <name>=<file path>) ERR_NoAddLauncherName=Error: --add-launcher option requires a name and a file path (--add-launcher <name>=<file path>)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="Fehler: Optionen [{0}] und [{1}] schließen sich g
ERR_InvalidOptionWithAppImageSigning=Fehler: Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages ERR_InvalidOptionWithAppImageSigning=Fehler: Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages
ERR_MissingArgument=Fehler: Fehlendes Argument: {0} ERR_MissingArgument=Fehler: Fehlendes Argument: {0}
ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s)
ERR_MissingAppResources=Fehler: Keine Anwendungs-JAR-Dateien gefunden ERR_MissingAppResources=Fehler: Keine Anwendungs-JAR-Dateien gefunden
ERR_AppImageNotExist=Fehler: Anwendungsimageverzeichnis "{0}" ist nicht vorhanden ERR_AppImageNotExist=Fehler: Anwendungsimageverzeichnis "{0}" ist nicht vorhanden
ERR_NoAddLauncherName=Fehler: Für Option --add-launcher müssen ein Name und ein Dateipfad angegeben werden (--add-launcher <Name>=<Dateipfad>) ERR_NoAddLauncherName=Fehler: Für Option --add-launcher müssen ein Name und ein Dateipfad angegeben werden (--add-launcher <Name>=<Dateipfad>)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="エラー: 相互排他的なオプション[{0}]
ERR_InvalidOptionWithAppImageSigning=エラー: アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません ERR_InvalidOptionWithAppImageSigning=エラー: アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません
ERR_MissingArgument=エラー: 引数がありません: {0} ERR_MissingArgument=エラー: 引数がありません: {0}
ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s)
ERR_MissingAppResources=エラー: アプリケーションjarが見つかりませんでした ERR_MissingAppResources=エラー: アプリケーションjarが見つかりませんでした
ERR_AppImageNotExist=エラー: アプリケーション・イメージ・ディレクトリ"{0}"は存在しません ERR_AppImageNotExist=エラー: アプリケーション・イメージ・ディレクトリ"{0}"は存在しません
ERR_NoAddLauncherName=エラー: --add-launcherオプションには名前およびファイル・パスが必要です(--add-launcher <name>=<file path>) ERR_NoAddLauncherName=エラー: --add-launcherオプションには名前およびファイル・パスが必要です(--add-launcher <name>=<file path>)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="错误:选项 [{0}] 和 [{1}] 相互排斥
ERR_InvalidOptionWithAppImageSigning=错误:对应用程序映像签名时,选项 [{0}] 无效 ERR_InvalidOptionWithAppImageSigning=错误:对应用程序映像签名时,选项 [{0}] 无效
ERR_MissingArgument=错误: 缺少参数: {0} ERR_MissingArgument=错误: 缺少参数: {0}
ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s)
ERR_MissingAppResources=错误: 找不到应用程序 jar ERR_MissingAppResources=错误: 找不到应用程序 jar
ERR_AppImageNotExist=错误:应用程序映像目录 "{0}" 不存在 ERR_AppImageNotExist=错误:应用程序映像目录 "{0}" 不存在
ERR_NoAddLauncherName=错误:--add-launcher 选项需要一个名称和一个文件路径 (--add-launcher <name>=<file path>) ERR_NoAddLauncherName=错误:--add-launcher 选项需要一个名称和一个文件路径 (--add-launcher <name>=<file path>)

View File

@ -55,28 +55,40 @@ import jdk.jpackage.test.AdditionalLauncher;
* @build SigningAppImageTest * @build SigningAppImageTest
* @modules jdk.jpackage/jdk.jpackage.internal * @modules jdk.jpackage/jdk.jpackage.internal
* @requires (os.family == "mac") * @requires (os.family == "mac")
* @run main/othervm -Xmx512m jdk.jpackage.test.Main * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=SigningAppImageTest * --jpt-run=SigningAppImageTest
*/ */
public class SigningAppImageTest { public class SigningAppImageTest {
@Test @Test
@Parameter({"true", "0"}) // ({"sign or not", "certificate index"}) // ({"sign or not", "signing-key or sign-identity", "certificate index"})
@Parameter({"true", "1"}) // Sign, signing-key and ASCII certificate
@Parameter({"false", "-1"}) @Parameter({"true", "true", SigningBase.ASCII_INDEX})
// Sign, signing-key and UNICODE certificate
@Parameter({"true", "true", SigningBase.UNICODE_INDEX})
// Sign, signing-indentity and UNICODE certificate
@Parameter({"true", "false", SigningBase.UNICODE_INDEX})
// Unsigned
@Parameter({"false", "true", "-1"})
public void test(String... testArgs) throws Exception { public void test(String... testArgs) throws Exception {
boolean doSign = Boolean.parseBoolean(testArgs[0]); boolean doSign = Boolean.parseBoolean(testArgs[0]);
int certIndex = Integer.parseInt(testArgs[1]); boolean signingKey = Boolean.parseBoolean(testArgs[1]);
int certIndex = Integer.parseInt(testArgs[2]);
SigningCheck.checkCertificates(certIndex); SigningCheck.checkCertificates(certIndex);
JPackageCommand cmd = JPackageCommand.helloAppImage(); JPackageCommand cmd = JPackageCommand.helloAppImage();
if (doSign) { if (doSign) {
cmd.addArguments("--mac-sign", cmd.addArguments("--mac-sign",
"--mac-signing-key-user-name",
SigningBase.getDevName(certIndex),
"--mac-signing-keychain", "--mac-signing-keychain",
SigningBase.getKeyChain()); SigningBase.getKeyChain());
if (signingKey) {
cmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(certIndex));
} else {
cmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(certIndex));
}
} }
AdditionalLauncher testAL = new AdditionalLauncher("testAL"); AdditionalLauncher testAL = new AdditionalLauncher("testAL");
testAL.applyTo(cmd); testAL.applyTo(cmd);

View File

@ -56,15 +56,23 @@ import jdk.jpackage.test.AdditionalLauncher;
* @build SigningAppImageTwoStepsTest * @build SigningAppImageTwoStepsTest
* @modules jdk.jpackage/jdk.jpackage.internal * @modules jdk.jpackage/jdk.jpackage.internal
* @requires (os.family == "mac") * @requires (os.family == "mac")
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=SigningAppImageTwoStepsTest * --jpt-run=SigningAppImageTwoStepsTest
*/ */
public class SigningAppImageTwoStepsTest { public class SigningAppImageTwoStepsTest {
@Test @Test
@Parameter("true") // ({"sign or not", "signing-key or sign-identity"})
@Parameter("false") // Sign and signing-key
public void test(boolean signAppImage) throws Exception { @Parameter({"true", "true"})
// Sign and sign-identity
@Parameter({"true", "false"})
// Unsigned
@Parameter({"false", "true"})
public void test(String... testArgs) throws Exception {
boolean signAppImage = Boolean.parseBoolean(testArgs[0]);
boolean signingKey = Boolean.parseBoolean(testArgs[1]);
SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX);
Path appimageOutput = TKit.createTempDirectory("appimage"); Path appimageOutput = TKit.createTempDirectory("appimage");
@ -76,10 +84,15 @@ public class SigningAppImageTwoStepsTest {
.setArgumentValue("--dest", appimageOutput); .setArgumentValue("--dest", appimageOutput);
if (signAppImage) { if (signAppImage) {
appImageCmd.addArguments("--mac-sign", appImageCmd.addArguments("--mac-sign",
"--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX),
"--mac-signing-keychain", "--mac-signing-keychain",
SigningBase.getKeyChain()); SigningBase.getKeyChain());
if (signingKey) {
appImageCmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
appImageCmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
} }
// Add addtional launcher // Add addtional launcher
@ -97,9 +110,14 @@ public class SigningAppImageTwoStepsTest {
cmd.setPackageType(PackageType.IMAGE) cmd.setPackageType(PackageType.IMAGE)
.addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath())
.addArguments("--mac-sign") .addArguments("--mac-sign")
.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX))
.addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); .addArguments("--mac-signing-keychain", SigningBase.getKeyChain());
if (signingKey) {
cmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
cmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
cmd.executeAndAssertImageCreated(); cmd.executeAndAssertImageCreated();
// Should be signed app image // Should be signed app image

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Collection;
import java.util.List;
import jdk.jpackage.test.Annotations.Parameters;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.TKit;
/*
* @test
* @summary Test jpackage signing options errors
* @library ../helpers
* @build SigningOptionsTest
* @modules jdk.jpackage/jdk.jpackage.internal
* @requires (os.family == "mac")
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=SigningOptionsTest
* --jpt-before-run=jdk.jpackage.test.JPackageCommand.useExecutableByDefault
*/
/*
* @test
* @summary Test jpackage signing options errors
* @library ../helpers
* @build SigningOptionsTest
* @modules jdk.jpackage/jdk.jpackage.internal
* @requires (os.family == "mac")
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=SigningOptionsTest
* --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault
*/
public final class SigningOptionsTest {
private final String expectedError;
private final JPackageCommand cmd;
@Parameters
public static Collection input() {
return List.of(new Object[][]{
// --mac-signing-key-user-name and --mac-app-image-sign-identity
{"Hello",
new String[]{"--mac-sign",
"--mac-signing-key-user-name", "test-key",
"--mac-app-image-sign-identity", "test-identity"},
null,
"Mutually exclusive options"},
// --mac-signing-key-user-name and --mac-installer-sign-identity
{"Hello",
new String[]{"--mac-sign",
"--mac-signing-key-user-name", "test-key",
"--mac-installer-sign-identity", "test-identity"},
null,
"Mutually exclusive options"},
// --mac-installer-sign-identity and --type app-image
{"Hello",
new String[]{"--mac-sign",
"--mac-installer-sign-identity", "test-identity"},
null,
"Option [--mac-installer-sign-identity] is not valid with type"},
// --mac-installer-sign-identity and --type dmg
{"Hello",
new String[]{"--type", "dmg",
"--mac-sign",
"--mac-installer-sign-identity", "test-identity"},
new String[]{"--type"},
"Option [--mac-installer-sign-identity] is not valid with type"},
});
}
public SigningOptionsTest(String javaAppDesc, String[] jpackageArgs,
String[] removeArgs, String expectedError) {
this.expectedError = expectedError;
cmd = JPackageCommand.helloAppImage(javaAppDesc)
.saveConsoleOutput(true).dumpOutput(true);
if (jpackageArgs != null) {
cmd.addArguments(jpackageArgs);
} if (removeArgs != null) {
for (String arg : removeArgs) {
cmd.removeArgumentWithValue(arg);
}
}
}
@Test
public void test() {
List<String> output = cmd.execute(1).getOutput();
TKit.assertNotNull(output, "output is null");
TKit.assertTextStream(expectedError).apply(output.stream());
}
}

View File

@ -72,7 +72,7 @@ public class SigningPackageFromTwoStepAppImageTest {
} }
Path outputBundle = cmd.outputBundle(); Path outputBundle = cmd.outputBundle();
SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX);
SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX);
} }
@ -97,9 +97,17 @@ public class SigningPackageFromTwoStepAppImageTest {
} }
@Test @Test
@Parameter("true") // ({"sign or not", "signing-key or sign-identity"})
@Parameter("false") // Sign and signing-key
public static void test(boolean signAppImage) throws Exception { @Parameter({"true", "true"})
// Sign and sign-identity
@Parameter({"true", "false"})
// Unsigned
@Parameter({"false", "true"})
public void test(String... testArgs) throws Exception {
boolean signAppImage = Boolean.parseBoolean(testArgs[0]);
boolean signingKey = Boolean.parseBoolean(testArgs[1]);
SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX);
Path appimageOutput = TKit.createTempDirectory("appimage"); Path appimageOutput = TKit.createTempDirectory("appimage");
@ -110,9 +118,15 @@ public class SigningPackageFromTwoStepAppImageTest {
JPackageCommand appImageCmd = JPackageCommand.helloAppImage() JPackageCommand appImageCmd = JPackageCommand.helloAppImage()
.setArgumentValue("--dest", appimageOutput); .setArgumentValue("--dest", appimageOutput);
if (signAppImage) { if (signAppImage) {
appImageCmd.addArguments("--mac-sign", "--mac-signing-key-user-name", appImageCmd.addArguments("--mac-sign",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX),
"--mac-signing-keychain", SigningBase.getKeyChain()); "--mac-signing-keychain", SigningBase.getKeyChain());
if (signingKey) {
appImageCmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
appImageCmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
} }
// Generate app image // Generate app image
@ -126,9 +140,14 @@ public class SigningPackageFromTwoStepAppImageTest {
appImageSignedCmd.setPackageType(PackageType.IMAGE) appImageSignedCmd.setPackageType(PackageType.IMAGE)
.addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath())
.addArguments("--mac-sign") .addArguments("--mac-sign")
.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX))
.addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); .addArguments("--mac-signing-keychain", SigningBase.getKeyChain());
if (signingKey) {
appImageSignedCmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
appImageSignedCmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
appImageSignedCmd.executeAndAssertImageCreated(); appImageSignedCmd.executeAndAssertImageCreated();
// Should be signed app image // Should be signed app image
@ -141,16 +160,30 @@ public class SigningPackageFromTwoStepAppImageTest {
cmd.removeArgumentWithValue("--input"); cmd.removeArgumentWithValue("--input");
if (signAppImage) { if (signAppImage) {
cmd.addArguments("--mac-sign", cmd.addArguments("--mac-sign",
"--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX),
"--mac-signing-keychain", "--mac-signing-keychain",
SigningBase.getKeyChain()); SigningBase.getKeyChain());
if (signingKey) {
cmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
cmd.addArguments("--mac-installer-sign-identity",
SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX));
}
} }
}) })
.forTypes(PackageType.MAC_PKG) .forTypes(PackageType.MAC_PKG)
.addBundleVerifier( .addBundleVerifier(
SigningPackageFromTwoStepAppImageTest::verifyPKG) SigningPackageFromTwoStepAppImageTest::verifyPKG)
.forTypes(PackageType.MAC_DMG) .forTypes(PackageType.MAC_DMG)
.addInitializer(cmd -> {
if (signAppImage && !signingKey) {
// jpackage throws expected error with
// --mac-installer-sign-identity and DMG type
cmd.removeArgument("--mac-sign");
cmd.removeArgumentWithValue("--mac-signing-keychain");
cmd.removeArgumentWithValue("--mac-installer-sign-identity");
}
})
.addBundleVerifier( .addBundleVerifier(
SigningPackageFromTwoStepAppImageTest::verifyDMG) SigningPackageFromTwoStepAppImageTest::verifyDMG)
.addBundleVerifier( .addBundleVerifier(

View File

@ -59,15 +59,27 @@ import jdk.jpackage.test.Annotations.Parameter;
* @build SigningPackageTest * @build SigningPackageTest
* @modules jdk.jpackage/jdk.jpackage.internal * @modules jdk.jpackage/jdk.jpackage.internal
* @requires (os.family == "mac") * @requires (os.family == "mac")
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=SigningPackageTest * --jpt-run=SigningPackageTest
*/ */
public class SigningPackageTest { public class SigningPackageTest {
private static boolean isAppImageSigned(JPackageCommand cmd) {
return cmd.hasArgument("--mac-signing-key-user-name") ||
cmd.hasArgument("--mac-app-image-sign-identity");
}
private static boolean isPKGSigned(JPackageCommand cmd) {
return cmd.hasArgument("--mac-signing-key-user-name") ||
cmd.hasArgument("--mac-installer-sign-identity");
}
private static void verifyPKG(JPackageCommand cmd) { private static void verifyPKG(JPackageCommand cmd) {
Path outputBundle = cmd.outputBundle(); Path outputBundle = cmd.outputBundle();
SigningBase.verifyPkgutil(outputBundle, getCertIndex(cmd)); SigningBase.verifyPkgutil(outputBundle, isPKGSigned(cmd), getCertIndex(cmd));
SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); if (isPKGSigned(cmd)) {
SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd));
}
} }
private static void verifyDMG(JPackageCommand cmd) { private static void verifyDMG(JPackageCommand cmd) {
@ -82,22 +94,45 @@ public class SigningPackageTest {
// We will be called with all folders in DMG since JDK-8263155, but // We will be called with all folders in DMG since JDK-8263155, but
// we only need to verify app. // we only need to verify app.
if (dmgImage.endsWith(cmd.name() + ".app")) { if (dmgImage.endsWith(cmd.name() + ".app")) {
SigningBase.verifyCodesign(launcherPath, true, getCertIndex(cmd)); SigningBase.verifyCodesign(launcherPath, isAppImageSigned(cmd),
SigningBase.verifyCodesign(dmgImage, true, getCertIndex(cmd)); getCertIndex(cmd));
SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); SigningBase.verifyCodesign(dmgImage, isAppImageSigned(cmd),
getCertIndex(cmd));
if (isAppImageSigned(cmd)) {
SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd));
}
} }
}); });
} }
private static int getCertIndex(JPackageCommand cmd) { private static int getCertIndex(JPackageCommand cmd) {
String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); if (cmd.hasArgument("--mac-signing-key-user-name")) {
return SigningBase.getDevNameIndex(devName); String devName = cmd.getArgumentValue("--mac-signing-key-user-name");
return SigningBase.getDevNameIndex(devName);
} else {
// Signing-indentity
return Integer.valueOf(SigningBase.UNICODE_INDEX);
}
} }
@Test @Test
@Parameter("0") // ("signing-key or sign-identity", "sign app-image", "sign pkg", "certificate index"})
@Parameter("1") // Signing-key and ASCII certificate
public static void test(int certIndex) throws Exception { @Parameter({"true", "true", "true", SigningBase.ASCII_INDEX})
// Signing-key and UNICODE certificate
@Parameter({"true", "true", "true", SigningBase.UNICODE_INDEX})
// Signing-indentity and UNICODE certificate
@Parameter({"false", "true", "true", SigningBase.UNICODE_INDEX})
// Signing-indentity, but sign app-image only and UNICODE certificate
@Parameter({"false", "true", "false", SigningBase.UNICODE_INDEX})
// Signing-indentity, but sign pkg only and UNICODE certificate
@Parameter({"false", "false", "true", SigningBase.UNICODE_INDEX})
public static void test(String... testArgs) throws Exception {
boolean signingKey = Boolean.parseBoolean(testArgs[0]);
boolean signAppImage = Boolean.parseBoolean(testArgs[1]);
boolean signPKG = Boolean.parseBoolean(testArgs[2]);
int certIndex = Integer.parseInt(testArgs[3]);
SigningCheck.checkCertificates(certIndex); SigningCheck.checkCertificates(certIndex);
new PackageTest() new PackageTest()
@ -105,12 +140,39 @@ public class SigningPackageTest {
.forTypes(PackageType.MAC) .forTypes(PackageType.MAC)
.addInitializer(cmd -> { .addInitializer(cmd -> {
cmd.addArguments("--mac-sign", cmd.addArguments("--mac-sign",
"--mac-signing-key-user-name", SigningBase.getDevName(certIndex),
"--mac-signing-keychain", SigningBase.getKeyChain()); "--mac-signing-keychain", SigningBase.getKeyChain());
if (signingKey) {
cmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(certIndex));
} else {
if (signAppImage) {
cmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(certIndex));
}
if (signPKG) {
cmd.addArguments("--mac-installer-sign-identity",
SigningBase.getInstallerCert(certIndex));
}
}
}) })
.forTypes(PackageType.MAC_PKG) .forTypes(PackageType.MAC_PKG)
.addBundleVerifier(SigningPackageTest::verifyPKG) .addBundleVerifier(SigningPackageTest::verifyPKG)
.forTypes(PackageType.MAC_DMG) .forTypes(PackageType.MAC_DMG)
.addInitializer(cmd -> {
if (!signingKey) {
// jpackage throws expected error with
// --mac-installer-sign-identity and DMG type
cmd.removeArgumentWithValue("--mac-installer-sign-identity");
// In case of not signing app image and DMG we need to
// remove signing completely, otherwise we will default
// to --mac-signing-key-user-name once
// --mac-installer-sign-identity is removed.
if (!signAppImage) {
cmd.removeArgumentWithValue("--mac-signing-keychain");
cmd.removeArgument("--mac-sign");
}
}
})
.addBundleVerifier(SigningPackageTest::verifyDMG) .addBundleVerifier(SigningPackageTest::verifyDMG)
.addBundleVerifier(SigningPackageTest::verifyAppImageInDMG) .addBundleVerifier(SigningPackageTest::verifyAppImageInDMG)
.run(); .run();

View File

@ -73,7 +73,7 @@ public class SigningPackageTwoStepTest {
} }
Path outputBundle = cmd.outputBundle(); Path outputBundle = cmd.outputBundle();
SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX);
SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX);
} }
@ -101,10 +101,18 @@ public class SigningPackageTwoStepTest {
} }
@Test @Test
@Parameter("true") // (Signed, "signing-key or sign-identity"})
@Parameter("false") // Signed and signing-key
public static void test(boolean signAppImage) throws Exception { @Parameter({"true", "true"})
SigningCheck.checkCertificates(0); // Signed and signing-identity
@Parameter({"true", "false"})
// Unsigned
@Parameter({"false", "true"})
public static void test(String... testArgs) throws Exception {
boolean signAppImage = Boolean.parseBoolean(testArgs[0]);
boolean signingKey = Boolean.parseBoolean(testArgs[1]);
SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX);
Path appimageOutput = TKit.createTempDirectory("appimage"); Path appimageOutput = TKit.createTempDirectory("appimage");
@ -112,10 +120,15 @@ public class SigningPackageTwoStepTest {
.setArgumentValue("--dest", appimageOutput); .setArgumentValue("--dest", appimageOutput);
if (signAppImage) { if (signAppImage) {
appImageCmd.addArguments("--mac-sign") appImageCmd.addArguments("--mac-sign")
.addArguments("--mac-signing-key-user-name", .addArguments("--mac-signing-keychain",
SigningBase.getDevName(0)) SigningBase.getKeyChain());
.addArguments("--mac-signing-keychain", if (signingKey) {
SigningBase.getKeyChain()); appImageCmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
appImageCmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
} }
new PackageTest() new PackageTest()
@ -126,15 +139,31 @@ public class SigningPackageTwoStepTest {
cmd.removeArgumentWithValue("--input"); cmd.removeArgumentWithValue("--input");
if (signAppImage) { if (signAppImage) {
cmd.addArguments("--mac-sign", cmd.addArguments("--mac-sign",
"--mac-signing-key-user-name",
SigningBase.getDevName(0),
"--mac-signing-keychain", "--mac-signing-keychain",
SigningBase.getKeyChain()); SigningBase.getKeyChain());
if (signingKey) {
cmd.addArguments("--mac-signing-key-user-name",
SigningBase.getDevName(SigningBase.DEFAULT_INDEX));
} else {
cmd.addArguments("--mac-installer-sign-identity",
SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX));
}
} }
}) })
.forTypes(PackageType.MAC_PKG) .forTypes(PackageType.MAC_PKG)
.addBundleVerifier(SigningPackageTwoStepTest::verifyPKG) .addBundleVerifier(SigningPackageTwoStepTest::verifyPKG)
.forTypes(PackageType.MAC_DMG) .forTypes(PackageType.MAC_DMG)
.addInitializer(cmd -> {
if (signAppImage && !signingKey) {
// jpackage throws expected error with
// --mac-installer-sign-identity and DMG type
cmd.removeArgumentWithValue("--mac-installer-sign-identity");
// It will do nothing, but it signals test that app
// image itself is signed for verification.
cmd.addArguments("--mac-app-image-sign-identity",
SigningBase.getAppCert(SigningBase.DEFAULT_INDEX));
}
})
.addBundleVerifier(SigningPackageTwoStepTest::verifyDMG) .addBundleVerifier(SigningPackageTwoStepTest::verifyDMG)
.addBundleVerifier(SigningPackageTwoStepTest::verifyAppImageInDMG) .addBundleVerifier(SigningPackageTwoStepTest::verifyAppImageInDMG)
.run(); .run();

View File

@ -33,6 +33,8 @@ import jdk.jpackage.test.Executor.Result;
public class SigningBase { public class SigningBase {
public static int DEFAULT_INDEX = 0; public static int DEFAULT_INDEX = 0;
public static final String ASCII_INDEX = "0";
public static final String UNICODE_INDEX = "0";
private static String [] DEV_NAMES = { private static String [] DEV_NAMES = {
"jpackage.openjdk.java.net", "jpackage.openjdk.java.net",
"jpackage.openjdk.java.net (ö)", "jpackage.openjdk.java.net (ö)",
@ -182,22 +184,30 @@ public class SigningBase {
checkString(output, lookupString); checkString(output, lookupString);
} }
private static List<String> pkgutilResult(Path target) { private static List<String> pkgutilResult(Path target, boolean signed) {
List<String> result = new Executor() List<String> result = new Executor()
.setExecutable("/usr/sbin/pkgutil") .setExecutable("/usr/sbin/pkgutil")
.addArguments("--check-signature", .addArguments("--check-signature",
target.toString()) target.toString())
.executeAndGetOutput(); .saveOutput()
.execute(signed ? 0 : 1)
.getOutput();
return result; return result;
} }
private static void verifyPkgutilResult(List<String> result, int certIndex) { private static void verifyPkgutilResult(List<String> result, boolean signed,
int certIndex) {
result.stream().forEachOrdered(TKit::trace); result.stream().forEachOrdered(TKit::trace);
String lookupString = "Status: signed by"; if (signed) {
checkString(result, lookupString); String lookupString = "Status: signed by";
lookupString = "1. " + getInstallerCert(certIndex); checkString(result, lookupString);
checkString(result, lookupString); lookupString = "1. " + getInstallerCert(certIndex);
checkString(result, lookupString);
} else {
String lookupString = "Status: no signature";
checkString(result, lookupString);
}
} }
public static void verifyCodesign(Path target, boolean signed, int certIndex) { public static void verifyCodesign(Path target, boolean signed, int certIndex) {
@ -228,9 +238,9 @@ public class SigningBase {
verifySpctlResult(output, target, type, result.getExitCode(), certIndex); verifySpctlResult(output, target, type, result.getExitCode(), certIndex);
} }
public static void verifyPkgutil(Path target, int certIndex) { public static void verifyPkgutil(Path target, boolean signed, int certIndex) {
List<String> result = pkgutilResult(target); List<String> result = pkgutilResult(target, signed);
verifyPkgutilResult(result, certIndex); verifyPkgutilResult(result, signed, certIndex);
} }
public static void verifyAppImageSignature(JPackageCommand appImageCmd, public static void verifyAppImageSignature(JPackageCommand appImageCmd,
@ -247,7 +257,7 @@ public class SigningBase {
Path appImage = appImageCmd.outputBundle(); Path appImage = appImageCmd.outputBundle();
SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX); SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX);
if (isSigned) { if (isSigned) {
SigningBase.verifySpctl(appImage, "exec", 0); SigningBase.verifySpctl(appImage, "exec", SigningBase.DEFAULT_INDEX);
} }
} }

View File

@ -69,7 +69,7 @@ public final class PredefinedAppImageErrorTest {
}, },
// --mac-app-store is required // --mac-app-store is required
{"Hello", {"Hello",
new String[]{"--mac-sign", "--mac-app-store"}, new String[]{"--mac-sign", "--mac-app-store", "--mac-app-image-sign-identity", "test"},
new String[]{"--input", "--dest", "--name", "--main-jar", "--main-class"}, new String[]{"--input", "--dest", "--name", "--main-jar", "--main-class"},
TKit.isOSX() ? TKit.isOSX() ?
"Option [--mac-app-store] is not valid" : "Option [--mac-app-store] is not valid" :