├── .asf.yaml ├── .git-blame-ignore-revs ├── .github ├── ISSUE_TEMPLATE │ ├── BUG.yml │ ├── FEATURE.yml │ └── config.yml ├── dependabot.yml ├── pull_request_template.md ├── release-drafter.yml └── workflows │ ├── maven-verify.yml │ ├── pr-automation.yml │ ├── release-drafter.yml │ └── stale.yml ├── .gitignore ├── Jenkinsfile ├── README.md ├── pom.xml └── src ├── it ├── archive-dir │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── resources │ │ │ └── jars │ │ │ ├── excluded.jar │ │ │ └── included.jar │ └── verify.bsh ├── attachment-selection │ ├── excluded.jar │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── resources │ │ │ └── test.properties │ └── verify.bsh ├── basic │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── Main.java │ └── verify.bsh ├── keystore ├── resign │ └── pom.xml ├── settings.xml ├── spacy path │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── Main.java │ └── verify.bsh ├── type-detection │ ├── jar-with-unusual.ext │ ├── not-a-jar.properties │ ├── pom.xml │ ├── some.zip │ ├── src │ │ └── main │ │ │ └── resources │ │ │ └── test.properties │ └── verify.bsh ├── unsign │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── Main.java │ │ │ └── resources │ │ │ └── META-INF │ │ │ ├── UNSIGNED.DSA │ │ │ ├── UNSIGNED.RSA │ │ │ └── UNSIGNED.SF │ └── verify.bsh ├── verify-fail-if-not-signed │ ├── invoker.properties │ └── pom.xml └── verify-fail │ ├── invoker.properties │ ├── pom.xml │ └── tampered.jar ├── main ├── java │ └── org │ │ └── apache │ │ └── maven │ │ └── plugins │ │ └── jarsigner │ │ ├── AbstractJarsignerMojo.java │ │ ├── JarsignerSignMojo.java │ │ ├── JarsignerVerifyMojo.java │ │ └── TsaSelector.java └── resources │ ├── META-INF │ └── plexus │ │ └── components.xml │ ├── jarsigner.properties │ ├── jarsigner_de.properties │ ├── jarsigner_en.properties │ └── jarsigner_fr.properties ├── site ├── apt │ ├── examples │ │ └── sign-and-verify-project.apt.vm │ ├── index.apt.vm │ └── usage.apt.vm ├── fml │ └── faq.fml ├── resources │ └── download.cgi ├── site.xml └── xdoc │ └── download.xml.vm └── test └── java └── org └── apache └── maven └── plugins └── jarsigner ├── JarsignerSignMojoParallelTest.java ├── JarsignerSignMojoRetryTest.java ├── JarsignerSignMojoTest.java ├── JarsignerSignMojoTsaTest.java ├── JarsignerVerifyMojoTest.java ├── MojoTestCreator.java ├── PluginXmlParser.java ├── RequestMatchers.java ├── TestArtifacts.java ├── TestJavaToolResults.java └── TsaSelectorTest.java /.asf.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # see https://s.apache.org/asfyaml 18 | github: 19 | description: "Apache Maven Jarsigner Plugin" 20 | homepage: https://maven.apache.org/plugins/maven-jarsigner-plugin/ 21 | labels: 22 | - java 23 | - build-management 24 | - maven-plugins 25 | - maven-jarsigner-plugin 26 | - maven 27 | enabled_merge_buttons: 28 | squash: true 29 | merge: false 30 | rebase: true 31 | autolink_jira: 32 | - MJARSIGNER 33 | del_branch_on_merge: true 34 | features: 35 | issues: true 36 | notifications: 37 | commits: commits@maven.apache.org 38 | issues: issues@maven.apache.org 39 | pullrequests: issues@maven.apache.org 40 | jira_options: link label comment 41 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # code reformat after parent 39 19 | 3a3c74cd3448452956f6e811384d26f9a32af43e -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema 19 | 20 | name: Bug Report 21 | description: File a bug report 22 | labels: ["bug"] 23 | 24 | body: 25 | - type: markdown 26 | attributes: 27 | value: | 28 | Thanks for taking the time to fill out this bug report. 29 | 30 | Simple fixes in single PRs do not require issues. 31 | 32 | **Do you use the latest project version?** 33 | 34 | - type: input 35 | id: version 36 | attributes: 37 | label: Affected version 38 | validations: 39 | required: true 40 | 41 | - type: textarea 42 | id: message 43 | attributes: 44 | label: Bug description 45 | validations: 46 | required: true 47 | 48 | 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema 19 | 20 | name: Feature request 21 | description: File a proposal for new feature, improvement 22 | labels: ["enhancement"] 23 | 24 | body: 25 | - type: markdown 26 | attributes: 27 | value: | 28 | Thanks for taking the time to fill out this new feature, improvement proposal. 29 | 30 | - type: textarea 31 | id: message 32 | attributes: 33 | label: New feature, improvement proposal 34 | validations: 35 | required: true 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser 19 | 20 | blank_issues_enabled: false 21 | 22 | contact_links: 23 | 24 | - name: Project Mailing Lists 25 | url: https://maven.apache.org/mailing-lists.html 26 | about: Please ask a question or discuss here 27 | 28 | - name: Old JIRA Issues 29 | url: https://issues.apache.org/jira/projects/MJARSIGNER 30 | about: Please search old JIRA issues 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | version: 2 18 | updates: 19 | - package-ecosystem: "maven" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" 23 | - package-ecosystem: "github-actions" 24 | directory: "/" 25 | schedule: 26 | interval: "daily" 27 | 28 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Following this checklist to help us incorporate your 2 | contribution quickly and easily: 3 | 4 | - [ ] Your pull request should address just one issue, without pulling in other changes. 5 | - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. 6 | - [ ] Each commit in the pull request should have a meaningful subject line and body. 7 | Note that commits might be squashed by a maintainer on merge. 8 | - [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. 9 | This may not always be possible but is a best-practice. 10 | - [ ] Run `mvn verify` to make sure basic checks pass. 11 | A more thorough check will be performed on your pull request automatically. 12 | - [ ] You have run the integration tests successfully (`mvn -Prun-its verify`). 13 | 14 | If your pull request is about ~20 lines of code you don't need to sign an 15 | [Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf) if you are unsure 16 | please ask on the developers list. 17 | 18 | To make clear that you license your contribution under 19 | the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0) 20 | you have to acknowledge this by using the following check-box. 21 | 22 | - [ ] I hereby declare this contribution to be licenced under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0) 23 | - [ ] In any other case, please file an [Apache Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf). 24 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | _extends: maven-gh-actions-shared 19 | -------------------------------------------------------------------------------- /.github/workflows/maven-verify.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Verify 19 | 20 | on: 21 | push: 22 | pull_request: 23 | 24 | jobs: 25 | build: 26 | name: Verify 27 | uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v4 28 | -------------------------------------------------------------------------------- /.github/workflows/pr-automation.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: PR Automation 19 | on: 20 | pull_request_target: 21 | types: 22 | - closed 23 | 24 | jobs: 25 | pr-automation: 26 | name: PR Automation 27 | uses: apache/maven-gh-actions-shared/.github/workflows/pr-automation.yml@v4 28 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Release Drafter 19 | on: 20 | push: 21 | branches: 22 | - master 23 | workflow_dispatch: 24 | 25 | jobs: 26 | update_release_draft: 27 | uses: apache/maven-gh-actions-shared/.github/workflows/release-drafter.yml@v4 28 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Stale 19 | 20 | on: 21 | schedule: 22 | - cron: '47 0 * * *' 23 | issue_comment: 24 | types: [ 'created' ] 25 | 26 | jobs: 27 | stale: 28 | uses: 'apache/maven-gh-actions-shared/.github/workflows/stale.yml@v4' 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .project 3 | .classpath 4 | .settings/ 5 | .svn/ 6 | bin/ 7 | # Intellij 8 | *.ipr 9 | *.iml 10 | .idea 11 | out/ 12 | .DS_Store 13 | /bootstrap 14 | /dependencies.xml 15 | .java-version 16 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | asfMavenTlpPlgnBuild() 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 17 | Contributing to [Apache Maven Jarsigner Plugin](https://maven.apache.org/plugins/maven-jarsigner-plugin/) 18 | ====================== 19 | 20 | [![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/apache/maven.svg?label=License)][license] 21 | [![Maven Central](https://img.shields.io/maven-central/v/org.apache.maven.plugins/maven-jarsigner-plugin.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.maven.plugins/maven-jarsigner-plugin) 22 | [![Reproducible Builds](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/org/apache/maven/plugins/maven-jarsigner-plugin//badge.json)](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/org/apache/maven/plugins/maven-jarsigner-plugin/README.md) 23 | [![Jenkins Status](https://img.shields.io/jenkins/s/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven-jarsigner-plugin/job/master.svg?)][build] 24 | [![Jenkins tests](https://img.shields.io/jenkins/t/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven-jarsigner-plugin/job/master.svg?)][test-results] 25 | 26 | 27 | You have found a bug, or you have an idea for a cool new feature? Contributing 28 | code is a great way to give something back to the open source community. Before 29 | you dig right into the code, there are a few guidelines that we need 30 | contributors to follow so that we can have a chance of keeping on top of 31 | things. 32 | 33 | Getting Started 34 | --------------- 35 | 36 | + Make sure you have a [GitHub account](https://github.com/signup/free). 37 | + If you're planning to implement a new feature, it makes sense to discuss your changes 38 | on the [dev list][ml-list] first. 39 | This way you can make sure you're not wasting your time on something that isn't 40 | considered to be in Apache Maven's scope. 41 | + Submit a ticket for your issue, assuming one does not already exist. 42 | + Clearly describe the issue, including steps to reproduce when it is a bug. 43 | + Make sure you fill in the earliest version that you know has the issue. 44 | + Fork the repository on GitHub. 45 | 46 | Making and Submitting Changes 47 | -------------- 48 | 49 | We accept Pull Requests via GitHub. The [developer mailing list][ml-list] is the 50 | main channel of communication for contributors. 51 | There are some guidelines which will make applying PRs easier for us: 52 | + Create a topic branch from where you want to base your work (this is usually the master branch). 53 | Push your changes to a topic branch in your fork of the repository. 54 | + Make commits of logical units. 55 | + Respect the original code style: by using the same [codestyle][code-style], 56 | patches should only highlight the actual difference, not being disturbed by any formatting issues: 57 | + Only use spaces for indentation. 58 | + Create minimal diffs - disable on save actions like reformat source code or organize imports. 59 | If you feel the source code should be reformatted, create a separate PR for this change. 60 | + Check for unnecessary whitespace with `git diff --check` before committing. 61 | + Make sure you have added the necessary tests (JUnit/IT) for your changes. 62 | + Run all the tests with `mvn -Prun-its verify` to assure nothing else was accidentally broken. 63 | + Submit a pull request to the repository in the Apache organization. 64 | 65 | If you plan to contribute on a regular basis, please consider filing a [contributor license agreement][cla]. 66 | 67 | Additional Resources 68 | -------------------- 69 | 70 | + [Contributing patches](https://maven.apache.org/guides/development/guide-maven-development.html#Creating_and_submitting_a_patch) 71 | + [Contributor License Agreement][cla] 72 | + [General GitHub documentation](https://help.github.com/) 73 | + [GitHub pull request documentation](https://help.github.com/send-pull-requests/) 74 | + [Apache Maven X Account](https://x.com/ASFMavenProject) 75 | + [Apache Maven Bluesky Account](https://bsky.app/profile/maven.apache.org) 76 | + [Apache Maven Mastodon Account](https://mastodon.social/deck/@ASFMavenProject@fosstodon.org) 77 | 78 | [license]: https://www.apache.org/licenses/LICENSE-2.0 79 | [ml-list]: https://maven.apache.org/mailing-lists.html 80 | [code-style]: https://maven.apache.org/developers/conventions/code.html 81 | [cla]: https://www.apache.org/licenses/#clas 82 | [maven-wiki]: https://cwiki.apache.org/confluence/display/MAVEN/Index 83 | [test-results]: https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven-jarsigner-plugin/job/master/lastCompletedBuild/testReport/ 84 | [build]: https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven-jarsigner-plugin/job/master/ 85 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 4.0.0 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-plugins 26 | 43 27 | 28 | 29 | 30 | maven-jarsigner-plugin 31 | 3.1.1-SNAPSHOT 32 | maven-plugin 33 | 34 | Apache Maven Jarsigner Plugin 35 | Signs or verifies a project artifact and attachments using jarsigner. 36 | 37 | 38 | 39 | Christian Schulte 40 | 41 | 42 | Jerome Lacube 43 | 44 | 45 | 46 | 47 | ${mavenVersion} 48 | 49 | 50 | 51 | scm:git:https://gitbox.apache.org/repos/asf/maven-jarsigner-plugin.git 52 | scm:git:https://gitbox.apache.org/repos/asf/maven-jarsigner-plugin.git 53 | HEAD 54 | https://github.com/apache/maven-jarsigner-plugin/tree/${project.scm.tag} 55 | 56 | 57 | GitHub Issues 58 | https://github.com/apache/maven-jarsigner-plugin/issues 59 | 60 | 61 | Jenkins 62 | https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven-jarsigner-plugin/ 63 | 64 | 65 | 66 | apache.website 67 | scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path} 68 | 69 | 70 | 71 | 72 | 3.6.3 73 | 0.8.12 74 | 2024-09-03T16:36:13Z 75 | 76 | 77 | 78 | 79 | org.apache.maven 80 | maven-plugin-api 81 | ${mavenVersion} 82 | provided 83 | 84 | 85 | org.apache.maven 86 | maven-core 87 | ${mavenVersion} 88 | provided 89 | 90 | 91 | org.apache.maven 92 | maven-artifact 93 | ${mavenVersion} 94 | provided 95 | 96 | 97 | org.apache.maven 98 | maven-settings 99 | ${mavenVersion} 100 | provided 101 | 102 | 103 | org.apache.maven.plugin-tools 104 | maven-plugin-annotations 105 | provided 106 | 107 | 108 | org.apache.maven.shared 109 | maven-shared-utils 110 | 3.4.2 111 | 112 | 113 | org.sonatype.plexus 114 | plexus-sec-dispatcher 115 | 1.4 116 | compile 117 | 118 | 119 | org.apache.maven.shared 120 | maven-jarsigner 121 | 3.1.0 122 | 123 | 124 | javax.inject 125 | javax.inject 126 | 1 127 | provided 128 | 129 | 130 | junit 131 | junit 132 | 4.13.2 133 | test 134 | 135 | 136 | org.slf4j 137 | slf4j-api 138 | 1.7.36 139 | test 140 | 141 | 142 | 143 | org.slf4j 144 | slf4j-simple 145 | 1.7.36 146 | test 147 | 148 | 149 | org.mockito 150 | mockito-core 151 | 4.11.0 152 | test 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.rat 162 | apache-rat-plugin 163 | 164 | 165 | 168 | src/it/unsign/src/main/resources/META-INF/UNSIGNED.* 169 | src/it/keystore 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | org.jacoco 178 | jacoco-maven-plugin 179 | ${jacocoVersion} 180 | 181 | 182 | 183 | prepare-agent 184 | 185 | 186 | 187 | report 188 | 189 | report 190 | 191 | prepare-package 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | run-its 201 | 202 | 203 | 204 | 205 | org.apache.maven.plugins 206 | maven-invoker-plugin 207 | 208 | 209 | clean 210 | verify 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /src/it/archive-dir/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the signing of multiple JARs within a directory selected by includes/excludes. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-surefire-plugin 58 | 2.3.1 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jarsigner-plugin 63 | @project.version@ 64 | 65 | test-01 66 | key-passwd 67 | TESTING 68 | false 69 | target/classes/jars 70 | 71 | excluded.jar 72 | 73 | 74 | 75 | 76 | sign-jars 77 | 78 | sign 79 | 80 | 81 | 82 | verify-jars 83 | 84 | verify 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/it/archive-dir/src/main/resources/jars/excluded.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/archive-dir/src/main/resources/jars/excluded.jar -------------------------------------------------------------------------------- /src/it/archive-dir/src/main/resources/jars/included.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/archive-dir/src/main/resources/jars/included.jar -------------------------------------------------------------------------------- /src/it/archive-dir/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.jar.*; 22 | 23 | File jarDir = new File( basedir, "target/classes/jars" ); 24 | 25 | File includedJarFile = new File( jarDir, "included.jar" ); 26 | System.out.println( "Checking for existence of " + includedJarFile ); 27 | if ( !includedJarFile.isFile() ) 28 | { 29 | throw new Exception( "missing " + includedJarFile ); 30 | } 31 | 32 | JarFile includedJar = new JarFile( includedJarFile ); 33 | System.out.println( "Checking for existence of " + includedJarFile.getName() + "!/META-INF/TESTING.SF" ); 34 | if ( includedJar.getEntry( "META-INF/TESTING.SF" ) == null ) 35 | { 36 | throw new Exception( "missing " + includedJarFile.getName() + "!/META-INF/TESTING.SF" ); 37 | } 38 | System.out.println( "Checking for existence of " + includedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 39 | if ( includedJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 40 | { 41 | throw new Exception( "missing " + includedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 42 | } 43 | includedJar.close(); 44 | 45 | File excludedJarFile = new File( jarDir, "excluded.jar" ); 46 | System.out.println( "Checking for existence of " + excludedJarFile ); 47 | if ( !excludedJarFile.isFile() ) 48 | { 49 | throw new Exception( "missing " + excludedJarFile ); 50 | } 51 | 52 | JarFile excludedJar = new JarFile( excludedJarFile ); 53 | System.out.println( "Checking for absence of " + excludedJarFile.getName() + "!/META-INF/TESTING.SF" ); 54 | if ( excludedJar.getEntry( "META-INF/TESTING.SF" ) != null ) 55 | { 56 | throw new Exception( "present " + excludedJarFile.getName() + "!/META-INF/TESTING.SF" ); 57 | } 58 | System.out.println( "Checking for absence of " + excludedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 59 | if ( excludedJar.getEntry( "META-INF/TESTING.DSA" ) != null ) 60 | { 61 | throw new Exception( "present " + excludedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 62 | } 63 | excludedJar.close(); 64 | 65 | return true; 66 | -------------------------------------------------------------------------------- /src/it/attachment-selection/excluded.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/attachment-selection/excluded.jar -------------------------------------------------------------------------------- /src/it/attachment-selection/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the selection of specific attachments. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.codehaus.mojo 57 | build-helper-maven-plugin 58 | 1.2 59 | 60 | 61 | attach-artifacts 62 | 63 | attach-artifact 64 | 65 | 66 | 67 | 68 | excluded.jar 69 | jar 70 | unsigned 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-surefire-plugin 80 | 2.3.1 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-jarsigner-plugin 85 | @project.version@ 86 | 87 | test-01 88 | key-passwd 89 | TESTING 90 | 91 | unsigned 92 | 93 | 94 | 95 | 96 | sign-jars 97 | 98 | sign 99 | 100 | 101 | 102 | verify-jars 103 | 104 | verify 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/it/attachment-selection/src/main/resources/test.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | key = value -------------------------------------------------------------------------------- /src/it/attachment-selection/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.zip.*; 22 | 23 | File attachedJarFile = new File( basedir, "excluded.jar" ); 24 | System.out.println( "Checking for existence of " + attachedJarFile ); 25 | if ( !attachedJarFile.isFile() ) 26 | { 27 | throw new Exception( "missing " + attachedJarFile ); 28 | } 29 | 30 | ZipFile attachedJar = new ZipFile( attachedJarFile ); 31 | System.out.println( "Checking for absence of " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 32 | if ( attachedJar.getEntry( "META-INF/TESTING.SF" ) != null ) 33 | { 34 | throw new Exception( "present " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 35 | } 36 | System.out.println( "Checking for absence of " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 37 | if ( attachedJar.getEntry( "META-INF/TESTING.DSA" ) != null ) 38 | { 39 | throw new Exception( "present " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 40 | } 41 | attachedJar.close(); 42 | 43 | return true; 44 | -------------------------------------------------------------------------------- /src/it/basic/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the signing of a simple JAR. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-source-plugin 58 | 2.0.4 59 | 60 | 61 | attach-sources 62 | 63 | jar 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-surefire-plugin 71 | 2.3.1 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-jarsigner-plugin 76 | @project.version@ 77 | 78 | test-01 79 | key-passwd 80 | TESTING 81 | 82 | 83 | 84 | sign-jars 85 | 86 | sign 87 | 88 | 89 | 90 | verify-jars 91 | 92 | verify 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/it/basic/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * Application entry point. 22 | */ 23 | public class Main 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/it/basic/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.jar.*; 22 | 23 | File targetDir = new File( basedir, "target" ); 24 | 25 | File mainJarFile = new File( targetDir, "test-1.0.jar" ); 26 | System.out.println( "Checking for existence of " + mainJarFile ); 27 | if ( !mainJarFile.isFile() ) 28 | { 29 | throw new Exception( "missing " + mainJarFile ); 30 | } 31 | 32 | JarFile mainJar = new JarFile( mainJarFile ); 33 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 34 | if ( mainJar.getEntry( "META-INF/TESTING.SF" ) == null ) 35 | { 36 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 37 | } 38 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 39 | if ( mainJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 40 | { 41 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 42 | } 43 | mainJar.close(); 44 | 45 | File attachedJarFile = new File( targetDir, "test-1.0-sources.jar" ); 46 | System.out.println( "Checking for existence of " + attachedJarFile ); 47 | if ( !attachedJarFile.isFile() ) 48 | { 49 | throw new Exception( "missing " + attachedJarFile ); 50 | } 51 | 52 | JarFile attachedJar = new JarFile( attachedJarFile ); 53 | System.out.println( "Checking for existence of " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 54 | if ( attachedJar.getEntry( "META-INF/TESTING.SF" ) == null ) 55 | { 56 | throw new Exception( "missing " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 57 | } 58 | System.out.println( "Checking for existence of " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 59 | if ( attachedJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 60 | { 61 | throw new Exception( "missing " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 62 | } 63 | attachedJar.close(); 64 | 65 | return true; 66 | -------------------------------------------------------------------------------- /src/it/keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/keystore -------------------------------------------------------------------------------- /src/it/resign/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | org.apache.maven.its.jarsigner 25 | test 26 | 1.0 27 | jar 28 | 29 | 30 | Tests the signing of an already signed JAR (see https://issues.apache.org/jira/browse/MJARSIGNER-33) that should be unsigned before re-signing. 31 | 32 | 33 | 34 | true 35 | 36 | 37 | 38 | 39 | org.swinglabs 40 | jxlayer 41 | 3.0.4 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-compiler-plugin 50 | 2.0.2 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-jar-plugin 55 | 2.1 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-resources-plugin 60 | 2.2 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-dependency-plugin 65 | 2.8 66 | 67 | 68 | 69 | copy-dependencies 70 | 71 | 72 | ${project.build.directory}/deps 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-surefire-plugin 82 | 2.3.1 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-jarsigner-plugin 87 | @project.version@ 88 | 89 | test-01 90 | key-passwd 91 | TESTING 92 | true 93 | ${project.build.directory}/deps/jxlayer-3.0.4.jar 94 | 95 | 96 | 97 | sign-jars 98 | 99 | sign 100 | 101 | 102 | 103 | verify-jars 104 | 105 | verify 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/it/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | it-repo 26 | 27 | true 28 | 29 | 30 | 34 | @project.basedir@/src/it/keystore 35 | store-passwd 36 | 37 | 38 | 39 | local.central 40 | @localRepositoryUrl@ 41 | 42 | true 43 | 44 | 45 | true 46 | 47 | 48 | 49 | 50 | 51 | local.central 52 | @localRepositoryUrl@ 53 | 54 | true 55 | 56 | 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/it/spacy path/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the invocation of the jarsigner tool when paths with spaces are involved. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-surefire-plugin 58 | 2.3.1 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jarsigner-plugin 63 | @project.version@ 64 | 65 | test-01 66 | key-passwd 67 | TESTING 68 | 69 | 70 | 71 | sign-jars 72 | 73 | sign 74 | 75 | 76 | 77 | verify-jars 78 | 79 | verify 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/it/spacy path/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * Application entry point. 22 | */ 23 | public class Main 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/it/spacy path/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.jar.*; 22 | 23 | File targetDir = new File( basedir, "target" ); 24 | 25 | File mainJarFile = new File( targetDir, "test-1.0.jar" ); 26 | System.out.println( "Checking for existence of " + mainJarFile ); 27 | if ( !mainJarFile.isFile() ) 28 | { 29 | throw new Exception( "missing " + mainJarFile ); 30 | } 31 | 32 | JarFile mainJar = new JarFile( mainJarFile ); 33 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 34 | if ( mainJar.getEntry( "META-INF/TESTING.SF" ) == null ) 35 | { 36 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 37 | } 38 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 39 | if ( mainJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 40 | { 41 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 42 | } 43 | mainJar.close(); 44 | 45 | return true; 46 | -------------------------------------------------------------------------------- /src/it/type-detection/jar-with-unusual.ext: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/type-detection/jar-with-unusual.ext -------------------------------------------------------------------------------- /src/it/type-detection/not-a-jar.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | -------------------------------------------------------------------------------- /src/it/type-detection/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the detection of JAR/ZIP files (we don't want to sign/verify other file formats). 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.codehaus.mojo 57 | build-helper-maven-plugin 58 | 1.2 59 | 60 | 61 | attach-artifacts 62 | 63 | attach-artifact 64 | 65 | 66 | 67 | 68 | 72 | jar-with-unusual.ext 73 | foo 74 | a 75 | 76 | 77 | not-a-jar.properties 78 | bar 79 | b 80 | 81 | 82 | 83 | some.zip 84 | zip 85 | c 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-surefire-plugin 95 | 2.3.1 96 | 97 | 98 | org.apache.maven.plugins 99 | maven-jarsigner-plugin 100 | @project.version@ 101 | 102 | test-01 103 | key-passwd 104 | TESTING 105 | 106 | 107 | 108 | sign-jars 109 | 110 | sign 111 | 112 | 113 | 114 | verify-jars 115 | 116 | verify 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/it/type-detection/some.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/type-detection/some.zip -------------------------------------------------------------------------------- /src/it/type-detection/src/main/resources/test.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | key = value -------------------------------------------------------------------------------- /src/it/type-detection/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.zip.*; 22 | 23 | File attachedJarFile = new File( basedir, "jar-with-unusual.ext" ); 24 | System.out.println( "Checking for existence of " + attachedJarFile ); 25 | if ( !attachedJarFile.isFile() ) 26 | { 27 | throw new Exception( "missing " + attachedJarFile ); 28 | } 29 | 30 | ZipFile attachedJar = new ZipFile( attachedJarFile ); 31 | System.out.println( "Checking for existence of " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 32 | if ( attachedJar.getEntry( "META-INF/TESTING.SF" ) == null ) 33 | { 34 | throw new Exception( "missing " + attachedJarFile.getName() + "!/META-INF/TESTING.SF" ); 35 | } 36 | System.out.println( "Checking for existence of " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 37 | if ( attachedJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 38 | { 39 | throw new Exception( "missing " + attachedJarFile.getName() + "!/META-INF/TESTING.DSA" ); 40 | } 41 | attachedJar.close(); 42 | 43 | File attachedZipFile = new File( basedir, "some.zip" ); 44 | System.out.println( "Checking for existence of " + attachedZipFile ); 45 | if ( !attachedZipFile.isFile() ) 46 | { 47 | throw new Exception( "missing " + attachedZipFile ); 48 | } 49 | 50 | ZipFile attachedZip = new ZipFile( attachedZipFile ); 51 | System.out.println( "Checking for existence of " + attachedZipFile.getName() + "!/META-INF/TESTING.SF" ); 52 | if ( attachedZip.getEntry( "META-INF/TESTING.SF" ) == null ) 53 | { 54 | throw new Exception( "missing " + attachedZipFile.getName() + "!/META-INF/TESTING.SF" ); 55 | } 56 | System.out.println( "Checking for existence of " + attachedZipFile.getName() + "!/META-INF/TESTING.DSA" ); 57 | if ( attachedZip.getEntry( "META-INF/TESTING.DSA" ) == null ) 58 | { 59 | throw new Exception( "missing " + attachedZipFile.getName() + "!/META-INF/TESTING.DSA" ); 60 | } 61 | attachedZip.close(); 62 | 63 | return true; 64 | -------------------------------------------------------------------------------- /src/it/unsign/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests the signing of an already signed JAR that should be unsigned before re-signing. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-surefire-plugin 58 | 2.3.1 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jarsigner-plugin 63 | @project.version@ 64 | 65 | test-01 66 | key-passwd 67 | TESTING 68 | true 69 | 70 | 71 | 72 | sign-jars 73 | 74 | sign 75 | 76 | 77 | 78 | verify-jars 79 | 80 | verify 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/it/unsign/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * Application entry point. 22 | */ 23 | public class Main 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/it/unsign/src/main/resources/META-INF/UNSIGNED.DSA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/unsign/src/main/resources/META-INF/UNSIGNED.DSA -------------------------------------------------------------------------------- /src/it/unsign/src/main/resources/META-INF/UNSIGNED.RSA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/unsign/src/main/resources/META-INF/UNSIGNED.RSA -------------------------------------------------------------------------------- /src/it/unsign/src/main/resources/META-INF/UNSIGNED.SF: -------------------------------------------------------------------------------- 1 | Signature-Version: 1.0 2 | Created-By: 1.4.2_16 (Sun Microsystems Inc.) 3 | SHA1-Digest-Manifest: gTrf1t9RIQNLDAEO4n3ikaxAoIg= 4 | 5 | Name: Main.java 6 | SHA1-Digest: b+ff3QfBH9heex9FQjrfgsATWVc= 7 | 8 | -------------------------------------------------------------------------------- /src/it/unsign/verify.bsh: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | import java.io.*; 21 | import java.util.jar.*; 22 | 23 | File targetDir = new File( basedir, "target" ); 24 | 25 | File mainJarFile = new File( targetDir, "test-1.0.jar" ); 26 | System.out.println( "Checking for existence of " + mainJarFile ); 27 | if ( !mainJarFile.isFile() ) 28 | { 29 | throw new Exception( "missing " + mainJarFile ); 30 | } 31 | 32 | JarFile mainJar = new JarFile( mainJarFile ); 33 | 34 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 35 | if ( mainJar.getEntry( "META-INF/TESTING.SF" ) == null ) 36 | { 37 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.SF" ); 38 | } 39 | 40 | System.out.println( "Checking for existence of " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 41 | if ( mainJar.getEntry( "META-INF/TESTING.DSA" ) == null ) 42 | { 43 | throw new Exception( "missing " + mainJarFile.getName() + "!/META-INF/TESTING.DSA" ); 44 | } 45 | 46 | System.out.println( "Checking for absence of " + mainJarFile.getName() + "!/META-INF/UNSIGNED.SF" ); 47 | if ( mainJar.getEntry( "META-INF/UNSIGNED.SF" ) != null ) 48 | { 49 | throw new Exception( "present " + mainJarFile.getName() + "!/META-INF/UNSIGNED.SF" ); 50 | } 51 | 52 | System.out.println( "Checking for absence of " + mainJarFile.getName() + "!/META-INF/UNSIGNED.DSA" ); 53 | if ( mainJar.getEntry( "META-INF/UNSIGNED.DSA" ) != null ) 54 | { 55 | throw new Exception( "present " + mainJarFile.getName() + "!/META-INF/UNSIGNED.DSA" ); 56 | } 57 | 58 | System.out.println( "Checking for absence of " + mainJarFile.getName() + "!/META-INF/UNSIGNED.RSA" ); 59 | if ( mainJar.getEntry( "META-INF/UNSIGNED.RSA" ) != null ) 60 | { 61 | throw new Exception( "present " + mainJarFile.getName() + "!/META-INF/UNSIGNED.RSA" ); 62 | } 63 | 64 | mainJar.close(); 65 | 66 | return true; 67 | -------------------------------------------------------------------------------- /src/it/verify-fail-if-not-signed/invoker.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | invoker.buildResult = failure 19 | -------------------------------------------------------------------------------- /src/it/verify-fail-if-not-signed/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | 29 | 30 | Tests that verification of a none signed JAR fails when having the errorWhenNotsigned flag to true (see MJARSIGNED-18). 31 | 32 | 33 | 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-surefire-plugin 58 | 2.3.1 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jarsigner-plugin 63 | @project.version@ 64 | 65 | true 66 | 67 | 68 | 69 | verify-archive 70 | 71 | verify 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/it/verify-fail/invoker.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | invoker.buildResult = failure 19 | -------------------------------------------------------------------------------- /src/it/verify-fail/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 4.0.0 24 | 25 | org.apache.maven.its.jarsigner 26 | test 27 | 1.0 28 | jar 29 | 30 | 31 | Tests that verification of a tampared JAR fails. 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 2.0.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 2.1 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-resources-plugin 53 | 2.2 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-surefire-plugin 58 | 2.3.1 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jarsigner-plugin 63 | @project.version@ 64 | 65 | tampered.jar 66 | 93 | 94 | 95 | 96 | verify-archive 97 | 98 | verify 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/it/verify-fail/tampered.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apache/maven-jarsigner-plugin/48c135e902b77a603ce38e8f899f841c2c568445/src/it/verify-fail/tampered.jar -------------------------------------------------------------------------------- /src/main/java/org/apache/maven/plugins/jarsigner/JarsignerSignMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import javax.inject.Inject; 22 | import javax.inject.Named; 23 | 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.time.Duration; 27 | import java.util.List; 28 | import java.util.concurrent.Callable; 29 | import java.util.concurrent.ExecutionException; 30 | import java.util.concurrent.ExecutorService; 31 | import java.util.concurrent.Executors; 32 | import java.util.concurrent.Future; 33 | import java.util.stream.Collectors; 34 | 35 | import org.apache.maven.plugin.MojoExecutionException; 36 | import org.apache.maven.plugins.annotations.LifecyclePhase; 37 | import org.apache.maven.plugins.annotations.Mojo; 38 | import org.apache.maven.plugins.annotations.Parameter; 39 | import org.apache.maven.plugins.jarsigner.TsaSelector.TsaServer; 40 | import org.apache.maven.shared.jarsigner.JarSigner; 41 | import org.apache.maven.shared.jarsigner.JarSignerRequest; 42 | import org.apache.maven.shared.jarsigner.JarSignerSignRequest; 43 | import org.apache.maven.shared.jarsigner.JarSignerUtil; 44 | import org.apache.maven.shared.utils.StringUtils; 45 | import org.apache.maven.shared.utils.cli.Commandline; 46 | import org.apache.maven.shared.utils.cli.javatool.JavaToolException; 47 | import org.apache.maven.shared.utils.cli.javatool.JavaToolResult; 48 | import org.apache.maven.toolchain.ToolchainManager; 49 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 50 | 51 | /** 52 | * Signs a project artifact and attachments using jarsigner. 53 | * 54 | * @author Christian Schulte 55 | * @since 1.0 56 | */ 57 | @Mojo(name = "sign", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true) 58 | public class JarsignerSignMojo extends AbstractJarsignerMojo { 59 | 60 | /** 61 | * See options. 62 | */ 63 | @Parameter(property = "jarsigner.keypass") 64 | private String keypass; 65 | 66 | /** 67 | * See options. 68 | */ 69 | @Parameter(property = "jarsigner.sigfile") 70 | private String sigfile; 71 | 72 | /** 73 | * Indicates whether existing signatures should be removed from the processed JAR files prior to signing them. If 74 | * enabled, the resulting JAR will appear as being signed only once. 75 | * 76 | * @since 1.1 77 | */ 78 | @Parameter(property = "jarsigner.removeExistingSignatures", defaultValue = "false") 79 | private boolean removeExistingSignatures; 80 | 81 | /** 82 | *

URL(s) to Time Stamping Authority (TSA) server(s) to use to timestamp the signing. 83 | * See options. 84 | * Separate multiple TSA URLs with comma (without space) or a nested XML tag.

85 | * 86 | *
{@code
 87 |      * 
 88 |      *   http://timestamp.digicert.com,http://timestamp.globalsign.com/tsa/r6advanced1
 89 |      * 
 90 |      * }
91 | * 92 | *
{@code
 93 |      * 
 94 |      *   
 95 |      *     http://timestamp.digicert.com
 96 |      *     http://timestamp.globalsign.com/tsa/r6advanced1
 97 |      *   
 98 |      * 
 99 |      * }
100 | * 101 | *

Usage of multiple TSA servers only makes sense when {@link #maxTries} is more than 1. A different TSA server 102 | * will only be used at retries.

103 | * 104 | *

Changed to a list since 3.1.0. Single XML element (without comma) is still supported.

105 | * 106 | * @since 1.3 107 | */ 108 | @Parameter(property = "jarsigner.tsa") 109 | private String[] tsa; 110 | 111 | /** 112 | *

Alias(es) for certificate(s) in the active keystore used to find a TSA URL. From the certificate the X509v3 113 | * extension "Subject Information Access" field is examined to find the TSA server URL. See 114 | * options. 115 | * Separate multiple aliases with comma (without space) or a nested XML tag.

116 | * 117 | *
{@code
118 |      * 
119 |      *   alias1,alias2
120 |      * 
121 |      * }
122 | * 123 | *
{@code
124 |      * 
125 |      *   
126 |      *     alias1
127 |      *     alias2
128 |      *   
129 |      * 
130 |      * }
131 | * 132 | *

Should not be used at the same time as the {@link #tsa} parameter (because jarsigner will typically ignore 133 | * tsacert, if tsa is set).

134 | * 135 | *

Usage of multiple aliases only makes sense when {@link #maxTries} is more than 1. A different TSA server 136 | * will only be used at retries.

137 | * 138 | *

Changed to a list since 3.1.0. Single XML element (without comma) is still supported.

139 | * 140 | * @since 1.3 141 | */ 142 | @Parameter(property = "jarsigner.tsacert") 143 | private String[] tsacert; 144 | 145 | /** 146 | *

OID(s) to send to the TSA server to identify the policy ID the server should use. If not specified TSA server 147 | * will choose a default policy ID. Each TSA server vendor will typically define their own policy OIDs. See 148 | * options. 149 | * Separate multiple OIDs with comma (without space) or a nested XML tag.

150 | * 151 | *
{@code
152 |      * 
153 |      *   1.3.6.1.4.1.4146.2.3.1.2,2.16.840.1.114412.7.1
154 |      * 
155 |      * }
156 | * 157 | *
{@code
158 |      * 
159 |      *   
160 |      *     1.3.6.1.4.1.4146.2.3.1.2
161 |      *     2.16.840.1.114412.7.1
162 |      *   
163 |      * 
164 |      * }
165 | * 166 | *

If used, the number of OIDs should be the same as the number of elements in {@link #tsa} or {@link #tsacert}. 167 | * The first OID will be used for the first TSA server, the second OID for the second TSA server and so on.

168 | * 169 | * @since 3.1.0 170 | */ 171 | @Parameter(property = "jarsigner.tsapolicyid") 172 | private String[] tsapolicyid; 173 | 174 | /** 175 | * The message digest algorithm to use in the messageImprint that the TSA server will timestamp. A default value 176 | * (for example {@code SHA-384}) will be selected by jarsigner if this parameter is not set. Only available in 177 | * Java 11 and later. See options. 178 | * 179 | * @since 3.1.0 180 | */ 181 | @Parameter(property = "jarsigner.tsadigestalg") 182 | private String tsadigestalg; 183 | 184 | /** 185 | * Location of the extra certificate chain file. See 186 | * options. 187 | * 188 | * @since 1.5 189 | */ 190 | @Parameter(property = "jarsigner.certchain", required = false) 191 | private File certchain; 192 | 193 | /** 194 | * How many times to try to sign a jar (assuming each previous attempt is a failure). This option may be desirable 195 | * if any network operations are used during signing, for example using a Time Stamp Authority or network based 196 | * PKCS11 HSM solution for storing code signing keys. 197 | * 198 | * The default value of 1 indicates that no retries should be made. 199 | * 200 | * @since 3.1.0 201 | */ 202 | @Parameter(property = "jarsigner.maxTries", defaultValue = "1") 203 | private int maxTries; 204 | 205 | /** 206 | * Maximum delay, in seconds, to wait after a failed attempt before re-trying. The delay after a failed attempt 207 | * follows an exponential backoff strategy, with increasing delay times. 208 | * 209 | * @since 3.1.0 210 | */ 211 | @Parameter(property = "jarsigner.maxRetryDelaySeconds", defaultValue = "0") 212 | private int maxRetryDelaySeconds; 213 | 214 | /** 215 | * Maximum number of parallel threads to use when signing jar files. Increases performance when signing multiple jar 216 | * files, especially when network operations are used during signing, for example when using a Time Stamp Authority 217 | * or network based PKCS11 HSM solution for storing code signing keys. Note: the logging from the signing process 218 | * will be interleaved, and harder to read, when using many threads. 219 | * 220 | * @since 3.1.0 221 | */ 222 | @Parameter(property = "jarsigner.threadCount", defaultValue = "1") 223 | private int threadCount; 224 | 225 | /** Current WaitStrategy, to allow for sleeping after a signing failure. */ 226 | private WaitStrategy waitStrategy = this::defaultWaitStrategy; 227 | 228 | private TsaSelector tsaSelector; 229 | 230 | /** Exponent limit for exponential wait after failure function. 2^20 = 1048576 sec ~= 12 days. */ 231 | private static final int MAX_WAIT_EXPONENT_ATTEMPT = 20; 232 | 233 | @Inject 234 | public JarsignerSignMojo( 235 | JarSigner jarSigner, 236 | ToolchainManager toolchainManager, 237 | @Named("mng-4384") SecDispatcher securityDispatcher) { 238 | super(jarSigner, toolchainManager, securityDispatcher); 239 | } 240 | 241 | // for testing; invoked via reflection 242 | JarsignerSignMojo() { 243 | super(null, null, null); 244 | } 245 | 246 | @Override 247 | protected String getCommandlineInfo(final Commandline commandLine) { 248 | String commandLineInfo = commandLine != null ? commandLine.toString() : null; 249 | 250 | if (commandLineInfo != null) { 251 | commandLineInfo = StringUtils.replace(commandLineInfo, this.keypass, "'*****'"); 252 | } 253 | 254 | return commandLineInfo; 255 | } 256 | 257 | @Override 258 | protected void preProcessArchive(final File archive) throws MojoExecutionException { 259 | if (removeExistingSignatures) { 260 | try { 261 | JarSignerUtil.unsignArchive(archive); 262 | } catch (IOException e) { 263 | throw new MojoExecutionException("Failed to unsign archive " + archive + ": " + e.getMessage(), e); 264 | } 265 | } 266 | } 267 | 268 | @Override 269 | protected void validateParameters() throws MojoExecutionException { 270 | super.validateParameters(); 271 | 272 | if (maxTries < 1) { 273 | getLog().warn(getMessage("invalidMaxTries", maxTries)); 274 | maxTries = 1; 275 | } 276 | 277 | if (maxRetryDelaySeconds < 0) { 278 | getLog().warn(getMessage("invalidMaxRetryDelaySeconds", maxRetryDelaySeconds)); 279 | maxRetryDelaySeconds = 0; 280 | } 281 | 282 | if (threadCount < 1) { 283 | getLog().warn(getMessage("invalidThreadCount", threadCount)); 284 | threadCount = 1; 285 | } 286 | 287 | if (tsa.length > 0 && tsacert.length > 0) { 288 | getLog().warn(getMessage("warnUsageTsaAndTsacertSimultaneous")); 289 | } 290 | if (tsapolicyid.length > tsa.length || tsapolicyid.length > tsacert.length) { 291 | getLog().warn(getMessage("warnUsageTsapolicyidTooMany", tsapolicyid.length, tsa.length, tsacert.length)); 292 | } 293 | if (tsa.length > 1 && maxTries == 1) { 294 | getLog().warn(getMessage("warnUsageMultiTsaWithoutRetry", tsa.length)); 295 | } 296 | if (tsacert.length > 1 && maxTries == 1) { 297 | getLog().warn(getMessage("warnUsageMultiTsacertWithoutRetry", tsacert.length)); 298 | } 299 | tsaSelector = new TsaSelector(tsa, tsacert, tsapolicyid, tsadigestalg); 300 | } 301 | 302 | /** 303 | * {@inheritDoc} 304 | */ 305 | @Override 306 | protected JarSignerRequest createRequest(File archive) throws MojoExecutionException { 307 | JarSignerSignRequest request = new JarSignerSignRequest(); 308 | request.setSigfile(sigfile); 309 | updateJarSignerRequestWithTsa(request, tsaSelector.getServer()); 310 | request.setCertchain(certchain); 311 | 312 | // Special handling for passwords through the Maven Security Dispatcher 313 | request.setKeypass(decrypt(keypass)); 314 | return request; 315 | } 316 | 317 | /** Modifies JarSignerRequest with TSA parameters */ 318 | private void updateJarSignerRequestWithTsa(JarSignerSignRequest request, TsaServer tsaServer) { 319 | request.setTsaLocation(tsaServer.getTsaUrl()); 320 | request.setTsaAlias(tsaServer.getTsaAlias()); 321 | request.setTsapolicyid(tsaServer.getTsaPolicyId()); 322 | request.setTsadigestalg(tsaServer.getTsaDigestAlg()); 323 | } 324 | 325 | /** 326 | * {@inheritDoc} Processing of files may be parallelized for increased performance. 327 | */ 328 | @Override 329 | protected void processArchives(List archives) throws MojoExecutionException { 330 | ExecutorService executor = Executors.newFixedThreadPool(threadCount); 331 | List> futures = archives.stream() 332 | .map(file -> executor.submit((Callable) () -> { 333 | processArchive(file); 334 | return null; // Return dummy value to conform with Void type 335 | })) 336 | .collect(Collectors.toList()); 337 | try { 338 | for (Future future : futures) { 339 | future.get(); // Wait for completion. Result ignored, but may raise any Exception 340 | } 341 | } catch (InterruptedException e) { 342 | Thread.currentThread().interrupt(); 343 | throw new MojoExecutionException("Thread interrupted while waiting for jarsigner to complete", e); 344 | } catch (ExecutionException e) { 345 | if (e.getCause() instanceof MojoExecutionException) { 346 | throw (MojoExecutionException) e.getCause(); 347 | } 348 | throw new MojoExecutionException("Error processing archives", e); 349 | } finally { 350 | // Shutdown of thread pool. If an Exception occurred, remaining threads will be aborted "best effort" 351 | executor.shutdownNow(); 352 | } 353 | } 354 | 355 | /** 356 | * {@inheritDoc} 357 | * 358 | * Will retry signing up to maxTries times if it fails. 359 | * 360 | * @throws MojoExecutionException if all signing attempts fail 361 | */ 362 | @Override 363 | protected void executeJarSigner(JarSigner jarSigner, JarSignerRequest request) 364 | throws JavaToolException, MojoExecutionException { 365 | for (int attempt = 0; attempt < maxTries; attempt++) { 366 | JavaToolResult result = jarSigner.execute(request); 367 | int resultCode = result.getExitCode(); 368 | if (resultCode == 0) { 369 | return; 370 | } 371 | tsaSelector.registerFailure(); // Could be TSA server problem or something unrelated to TSA 372 | 373 | if (attempt < maxTries - 1) { // If not last attempt 374 | waitStrategy.waitAfterFailure(attempt, Duration.ofSeconds(maxRetryDelaySeconds)); 375 | updateJarSignerRequestWithTsa((JarSignerSignRequest) request, tsaSelector.getServer()); 376 | } else { 377 | // Last attempt failed, use this failure as resulting failure 378 | throw new MojoExecutionException( 379 | getMessage("failure", getCommandlineInfo(result.getCommandline()), resultCode)); 380 | } 381 | } 382 | } 383 | 384 | /** Set current WaitStrategy. Package private for testing. */ 385 | void setWaitStrategy(WaitStrategy waitStrategy) { 386 | this.waitStrategy = waitStrategy; 387 | } 388 | 389 | /** Wait/sleep after a signing failure before the next re-try should happen. */ 390 | @FunctionalInterface 391 | interface WaitStrategy { 392 | /** 393 | * Will be called after a signing failure, if a re-try is about to happen. May as a side effect sleep current 394 | * thread for some time. 395 | * 396 | * @param attempt the attempt number (0 is the first) 397 | * @param maxRetryDelay the maximum duration to sleep (may be zero) 398 | * @throws MojoExecutionException if the sleep was interrupted 399 | */ 400 | void waitAfterFailure(int attempt, Duration maxRetryDelay) throws MojoExecutionException; 401 | } 402 | 403 | private void defaultWaitStrategy(int attempt, Duration maxRetryDelay) throws MojoExecutionException { 404 | waitAfterFailure(attempt, maxRetryDelay, Thread::sleep); 405 | } 406 | 407 | /** Thread.sleep(long millis) interface to make testing easier */ 408 | @FunctionalInterface 409 | interface Sleeper { 410 | void sleep(long millis) throws InterruptedException; 411 | } 412 | 413 | /** Package private for testing */ 414 | void waitAfterFailure(int attempt, Duration maxRetryDelay, Sleeper sleeper) throws MojoExecutionException { 415 | // Use attempt as exponent in the exponential function, but limit it to avoid too big values. 416 | int exponentAttempt = Math.min(attempt, MAX_WAIT_EXPONENT_ATTEMPT); 417 | long delayMillis = (long) (Duration.ofSeconds(1).toMillis() * Math.pow(2, exponentAttempt)); 418 | delayMillis = Math.min(delayMillis, maxRetryDelay.toMillis()); 419 | if (delayMillis > 0) { 420 | getLog().info("Sleeping after failed attempt for " + (delayMillis / 1000) + " seconds..."); 421 | try { 422 | sleeper.sleep(delayMillis); 423 | } catch (InterruptedException e) { 424 | Thread.currentThread().interrupt(); 425 | throw new MojoExecutionException("Thread interrupted while waiting after failure", e); 426 | } 427 | } 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /src/main/java/org/apache/maven/plugins/jarsigner/JarsignerVerifyMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import javax.inject.Inject; 22 | import javax.inject.Named; 23 | 24 | import java.io.File; 25 | import java.io.IOException; 26 | 27 | import org.apache.maven.plugin.MojoExecutionException; 28 | import org.apache.maven.plugins.annotations.LifecyclePhase; 29 | import org.apache.maven.plugins.annotations.Mojo; 30 | import org.apache.maven.plugins.annotations.Parameter; 31 | import org.apache.maven.shared.jarsigner.JarSigner; 32 | import org.apache.maven.shared.jarsigner.JarSignerRequest; 33 | import org.apache.maven.shared.jarsigner.JarSignerUtil; 34 | import org.apache.maven.shared.jarsigner.JarSignerVerifyRequest; 35 | import org.apache.maven.shared.utils.cli.javatool.JavaToolException; 36 | import org.apache.maven.shared.utils.cli.javatool.JavaToolResult; 37 | import org.apache.maven.toolchain.ToolchainManager; 38 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 39 | 40 | /** 41 | * Checks the signatures of a project artifact and attachments using jarsigner. 42 | * 43 | * @author Christian Schulte 44 | * @since 1.0 45 | */ 46 | @Mojo(name = "verify", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) 47 | public class JarsignerVerifyMojo extends AbstractJarsignerMojo { 48 | 49 | /** 50 | * See options. 51 | */ 52 | @Parameter(property = "jarsigner.certs", defaultValue = "false") 53 | private boolean certs; 54 | 55 | /** 56 | * When true this will make the execute() operation fail, 57 | * throwing an exception, when verifying an unsigned jar. 58 | * Primarily to keep backwards compatibility with existing code, and allow reusing the 59 | * mojo in unattended operations when set to false. 60 | * 61 | * @since 1.3 62 | **/ 63 | @Parameter(property = "jarsigner.errorWhenNotSigned", defaultValue = "false") 64 | private boolean errorWhenNotSigned; 65 | 66 | @Inject 67 | public JarsignerVerifyMojo( 68 | JarSigner jarSigner, 69 | ToolchainManager toolchainManager, 70 | @Named("mng-4384") SecDispatcher securityDispatcher) { 71 | super(jarSigner, toolchainManager, securityDispatcher); 72 | } 73 | 74 | // for testing; invoked via reflection 75 | JarsignerVerifyMojo() { 76 | super(null, null, null); 77 | } 78 | 79 | /** 80 | * {@inheritDoc} 81 | */ 82 | @Override 83 | protected JarSignerRequest createRequest(File archive) { 84 | JarSignerVerifyRequest request = new JarSignerVerifyRequest(); 85 | request.setCerts(certs); 86 | return request; 87 | } 88 | 89 | @Override 90 | protected void preProcessArchive(File archive) throws MojoExecutionException { 91 | super.preProcessArchive(archive); 92 | 93 | if (errorWhenNotSigned) { 94 | 95 | // check archive if signed 96 | boolean archiveSigned; 97 | try { 98 | archiveSigned = JarSignerUtil.isArchiveSigned(archive); 99 | } catch (IOException e) { 100 | throw new MojoExecutionException( 101 | "Failed to check if archive " + archive + " is signed: " + e.getMessage(), e); 102 | } 103 | 104 | if (!archiveSigned) { 105 | 106 | // fails, archive must be signed 107 | throw new MojoExecutionException(getMessage("archiveNotSigned", archive)); 108 | } 109 | } 110 | } 111 | 112 | @Override 113 | protected void executeJarSigner(JarSigner jarSigner, JarSignerRequest request) 114 | throws JavaToolException, MojoExecutionException { 115 | JavaToolResult result = jarSigner.execute(request); 116 | int resultCode = result.getExitCode(); 117 | if (resultCode != 0) { 118 | throw new MojoExecutionException( 119 | getMessage("failure", getCommandlineInfo(result.getCommandline()), resultCode)); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/apache/maven/plugins/jarsigner/TsaSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Collections; 23 | import java.util.List; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | /** 27 | * Helper class to select a Time Stamping Authority (TSA) server along with parameters to send. The protocol is defined 28 | * in RFC 3161: Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP). 29 | * 30 | * From a jarsigner perspective there are two things that are important: 31 | * 1. Finding a TSA server URL 32 | * 2. What parameters to use for TSA server communication. 33 | * 34 | * Finding a URL can be done in two ways: 35 | * a) The end-user has specified an explicit URL (the most common way) 36 | * b) The end-user has specified a keystore alias that points to a certificate in the active keystore. From the 37 | * certificate the X509v3 extension "Subject Information Access" field is examined to find the TSA server URL. 38 | * Example: 39 | *
 40 |  *    [vagrant@podmanhost ~]$ openssl x509 -noout -ext subjectInfoAccess -in tsa-server.crt
 41 |  *    Subject Information Access:
 42 |  *        AD Time Stamping - URI:http://timestamp.globalsign.com/tsa/r6advanced1
 43 |  *    
44 | * 45 | * Each TSA server vendor typically has defined its own OID for what "policy" to use in the timestamping process. For 46 | * example GlobalSign might use 1.3.6.1.4.1.4146.2.3.1.2. A DigiCert TSA server would not accept this OID. In most cases 47 | * there is no need for the end-user to specify this because the TSA server will choose a default. 48 | * 49 | * jarsigner will send a message digest to the TSA server along with the message digest algorithm. For example 50 | * {@code SHA-384}. A TSA server might reject the chosen algorithm, but typically most TSA servers supports the "common" 51 | * ones (like SHA-256, SHA-384 and SHA-512). In most cases there is no need for the end-user to specify this because the 52 | * jarsigner tool choose a good default. 53 | */ 54 | class TsaSelector { 55 | 56 | /** The current TsaServer in use (if any). One per thread */ 57 | private final ThreadLocal currentTsaServer = new ThreadLocal<>(); 58 | 59 | /** List of TSA servers. Will at minimum contain a dummy/empty value */ 60 | private final List tsaServers; 61 | 62 | TsaSelector(String[] tsa, String[] tsacert, String[] tsapolicyid, String tsadigestalg) { 63 | List tsaServersTmp = new ArrayList<>(); 64 | 65 | for (int i = 0; i < Math.max(tsa.length, tsacert.length); i++) { 66 | String tsaUrl = i < tsa.length ? tsa[i] : null; 67 | String tsaAlias = i < tsacert.length ? tsacert[i] : null; 68 | String tsaPolicyId = i < tsapolicyid.length ? tsapolicyid[i] : null; 69 | tsaServersTmp.add(new TsaServer(tsaUrl, tsaAlias, tsaPolicyId, tsadigestalg)); 70 | } 71 | 72 | if (tsaServersTmp.isEmpty()) { 73 | tsaServersTmp.add(TsaServer.EMPTY); 74 | } 75 | this.tsaServers = Collections.unmodifiableList(tsaServersTmp); 76 | } 77 | 78 | /** 79 | * Gets the next "best" TSA server to use. 80 | * 81 | * Uses a "best effort" approach without any synchronization. It may not select the "snapshot-consistent" best TSA 82 | * server, but good enough. 83 | */ 84 | TsaServer getServer() { 85 | TsaServer best = tsaServers.get(0); 86 | for (int i = 1; i < tsaServers.size(); i++) { 87 | if (best.failureCount.get() > tsaServers.get(i).failureCount.get()) { 88 | best = tsaServers.get(i); 89 | } 90 | } 91 | currentTsaServer.set(best); 92 | return best; 93 | } 94 | 95 | /** 96 | * Register that the current used TsaServer was involved in a jarsigner execution that failed. This could be a 97 | * problem with the TsaServer, but it could also be other factors unrelated to the TsaServer. Regardless of the 98 | * cause of the failure it is registered as a failure for the current used TsaServer to be used when determining the 99 | * next TsaServer to try. 100 | */ 101 | void registerFailure() { 102 | if (currentTsaServer.get() != null) { 103 | currentTsaServer.get().failureCount.incrementAndGet(); 104 | } 105 | } 106 | 107 | /** Representation of a single TSA server and the parameters to use for it */ 108 | static class TsaServer { 109 | private static final TsaServer EMPTY = new TsaServer(null, null, null, null); 110 | 111 | private final AtomicInteger failureCount = new AtomicInteger(0); 112 | private final String tsaUrl; 113 | private final String tsaAlias; 114 | private final String tsaPolicyId; 115 | private final String tsaDigestAlg; 116 | 117 | private TsaServer(String tsaUrl, String tsaAlias, String tsaPolicyId, String tsaDigestAlg) { 118 | this.tsaUrl = tsaUrl; 119 | this.tsaAlias = tsaAlias; 120 | this.tsaPolicyId = tsaPolicyId; 121 | this.tsaDigestAlg = tsaDigestAlg; 122 | } 123 | 124 | String getTsaUrl() { 125 | return tsaUrl; 126 | } 127 | 128 | String getTsaAlias() { 129 | return tsaAlias; 130 | } 131 | 132 | String getTsaPolicyId() { 133 | return tsaPolicyId; 134 | } 135 | 136 | String getTsaDigestAlg() { 137 | return tsaDigestAlg; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plexus/components.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | org.sonatype.plexus.components.sec.dispatcher.SecDispatcher 23 | mng-4384 24 | org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher 25 | 26 | 27 | org.sonatype.plexus.components.cipher.PlexusCipher 28 | mng-4384 29 | _cipher 30 | 31 | 32 | 33 | <_configuration-file>~/.m2/settings-security.xml 34 | 35 | 36 | 37 | org.sonatype.plexus.components.cipher.PlexusCipher 38 | mng-4384 39 | org.sonatype.plexus.components.cipher.DefaultPlexusCipher 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/resources/jarsigner.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | disabled = Disabled 19 | ignoringAttachments = Forcibly ignoring attached artifacts 20 | unsupported = Unsupported artifact {0} ignored 21 | processing = Processing {0} 22 | processed = {0} archive(s) processed 23 | command = ''{0}'' 24 | commandLineException = Failed executing ''{0}'' 25 | failure = Failed executing ''{0}'' - exitcode {1,number} 26 | archiveNotSigned = Archive ''{0}'' is not signed 27 | invalidMaxTries = Invalid maxTries value. Was ''{0}'' but should be >= 1 28 | invalidMaxRetryDelaySeconds = Invalid maxRetryDelaySeconds value. Was ''{0}'' but should be >= 0 29 | invalidThreadCount = Invalid threadCount value. Was ''{0}'' but should be >= 1 30 | warnUsageTsaAndTsacertSimultaneous = Usage of both -tsa and -tsacert is undefined 31 | warnUsageTsapolicyidTooMany = Too many ({0}) number of OIDs given, but only {1} and {2} TSA URL and TSA certificate alias, respectively 32 | warnUsageMultiTsaWithoutRetry = {0} TSA URLs specified. Only first will be used because maxTries is set to 1 33 | warnUsageMultiTsacertWithoutRetry = {0} TSA certificate aliases specified. Only first will be used because maxTries is set to 1 34 | -------------------------------------------------------------------------------- /src/main/resources/jarsigner_de.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | disabled = Deaktiviert 19 | ignoringAttachments = Verarbeitung von angeh\u00E4ngten Artefakten unterdr\u00FCckt 20 | unsupported = Nicht unterst\u00FCtztes Artefakt {0} ignoriert 21 | processing = Verarbeite {0} 22 | processed = {0} Archiv(e) verarbeitet 23 | command = ''{0}'' 24 | commandLineException = Ausf\u00FChrung von ''{0}'' gescheitert 25 | failure = Ausf\u00FChrung von ''{0}'' fehlgeschlagen - Ergebniscode ({1,number}) 26 | archiveNotSigned = Archive ''{0}'' nicht unterdr\u00FCckt -------------------------------------------------------------------------------- /src/main/resources/jarsigner_en.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # NOTE: 19 | # This bundle is intentionally empty because English strings are provided by the base bundle via the parent chain. It 20 | # must be provided nevertheless such that a request for locale "en" will not erroneously pick up the bundle for the 21 | # JVM's default locale (which need not be "en"). See the method javadoc about 22 | # ResourceBundle.getBundle(String, Locale, ClassLoader) 23 | # for a full description of the lookup strategy. 24 | -------------------------------------------------------------------------------- /src/main/resources/jarsigner_fr.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | ignoringAttachments=Ignorer les fichiers attach\u00E9s 19 | disabled=D\u00E9sactiv\u00E9 20 | unsupported=Artifact non support\u00E9 {0} ignor\u00E9 21 | processing=En cours de traitement {0} 22 | processed={0} archive(s) trait\u00E9es 23 | command=''{0}'' 24 | commandLineException=Erreur lors de l'ex\u00E9cution ''{0}'' 25 | failure=Erreur lors de l'ex\u00E9cution ''{0}'' - code de sortie {1,number} 26 | archiveNotSigned = L'archive ''{0}'' n'est pas signée -------------------------------------------------------------------------------- /src/site/apt/examples/sign-and-verify-project.apt.vm: -------------------------------------------------------------------------------- 1 | ------ 2 | Sign and verify a project 3 | ------ 4 | Christian Schulte 5 | ------ 6 | 08 April 2009 7 | ------ 8 | 9 | ~~ Licensed to the Apache Software Foundation (ASF) under one 10 | ~~ or more contributor license agreements. See the NOTICE file 11 | ~~ distributed with this work for additional information 12 | ~~ regarding copyright ownership. The ASF licenses this file 13 | ~~ to you under the Apache License, Version 2.0 (the 14 | ~~ "License"); you may not use this file except in compliance 15 | ~~ with the License. You may obtain a copy of the License at 16 | ~~ 17 | ~~ http://www.apache.org/licenses/LICENSE-2.0 18 | ~~ 19 | ~~ Unless required by applicable law or agreed to in writing, 20 | ~~ software distributed under the License is distributed on an 21 | ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22 | ~~ KIND, either express or implied. See the License for the 23 | ~~ specific language governing permissions and limitations 24 | ~~ under the License. 25 | 26 | 27 | Sign and verify a project 28 | 29 | If you need to sign a project artifact and all attached artifacts and want 30 | to verify the signatures afterwards, just configure the sign and verify goal 31 | appropriately in your <<>> for the signing to occur automatically 32 | during the package phase and for the verification to occur during the verify 33 | phase. 34 | 35 | +-----------------+ 36 | 37 | ... 38 | 39 | 40 | ... 41 | 42 | org.apache.maven.plugins 43 | maven-jarsigner-plugin 44 | ${project.version} 45 | 46 | 47 | sign 48 | 49 | sign 50 | 51 | 52 | 53 | verify 54 | 55 | verify 56 | 57 | 58 | 59 | 60 | ... 61 | 62 | 63 | ... 64 | 65 | +-----------------+ 66 | 67 | Note: The sign goal requires at least the alias to use for signing. This alias 68 | can be passed using the command line like <<<-Djarsigner.alias="Alias Name">>> 69 | or set as a property in the <<>> file when not configured in the POM. 70 | -------------------------------------------------------------------------------- /src/site/apt/index.apt.vm: -------------------------------------------------------------------------------- 1 | ------ 2 | Introduction 3 | ------ 4 | Christian Schulte 5 | ------ 6 | 2013-07-22 7 | ------ 8 | 9 | ~~ Licensed to the Apache Software Foundation (ASF) under one 10 | ~~ or more contributor license agreements. See the NOTICE file 11 | ~~ distributed with this work for additional information 12 | ~~ regarding copyright ownership. The ASF licenses this file 13 | ~~ to you under the Apache License, Version 2.0 (the 14 | ~~ "License"); you may not use this file except in compliance 15 | ~~ with the License. You may obtain a copy of the License at 16 | ~~ 17 | ~~ http://www.apache.org/licenses/LICENSE-2.0 18 | ~~ 19 | ~~ Unless required by applicable law or agreed to in writing, 20 | ~~ software distributed under the License is distributed on an 21 | ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22 | ~~ KIND, either express or implied. See the License for the 23 | ~~ specific language governing permissions and limitations 24 | ~~ under the License. 25 | 26 | ~~ NOTE: For help with the syntax of this file, see: 27 | ~~ http://maven.apache.org/doxia/references/apt-format.html 28 | 29 | ${project.name} 30 | 31 | This plugin provides the capability to sign or verify a project artifact 32 | and attachments using jarsigner. 33 | 34 | * Goals Overview 35 | 36 | * {{{./sign-mojo.html}jarsigner:sign}} sign a project artifact and attached artifacts. 37 | 38 | * {{{./verify-mojo.html}jarsigner:verify}} verify a project artifact and attached artifacts. 39 | 40 | [] 41 | 42 | * Usage 43 | 44 | General instructions on how to use the Jarsigner Plugin can be found on the {{{./usage.html}usage page}}. Some more 45 | specific use cases are described in the examples given below. Additionally, users can contribute to the 46 | {{{https://github.com/apache/maven-jarsigner-plugin}GitHub project}}. 47 | 48 | In case you still have questions regarding the plugin's usage, please have a look at the {{{./faq.html}FAQ}} and feel 49 | free to contact the {{{./mailing-lists.html}user mailing list}}. The posts to the mailing list are archived and could 50 | already contain the answer to your question as part of an older thread. Hence, it is also worth browsing/searching 51 | the {{{./mailing-lists.html}mail archive}}. 52 | 53 | If you feel like the plugin is missing a feature or has a defect, you can file a feature request or bug report in our 54 | {{{./issue-management.html}issue tracker}}. When creating a new issue, please provide a comprehensive description of your 55 | concern. Especially for fixing bugs it is crucial that the developers can reproduce your problem. For this reason, 56 | entire debug logs, POMs or most preferably little demo projects attached to the issue are very much appreciated. 57 | Of course, patches are welcome, too. Contributors can check out the project from our 58 | {{{./scm.html}source repository}} and will find supplementary information in the 59 | {{{https://maven.apache.org/guides/development/guide-helping.html}guide to helping with Maven}}. 60 | 61 | * Examples 62 | 63 | To provide you with better understanding of some usages of the Jarsigner 64 | Plugin, you can take a look at the following example: 65 | 66 | * {{{./examples/sign-and-verify-project.html}Sign and verify a project}} 67 | 68 | [] 69 | -------------------------------------------------------------------------------- /src/site/apt/usage.apt.vm: -------------------------------------------------------------------------------- 1 | ------ 2 | Usage 3 | ------ 4 | Christian Schulte 5 | ------ 6 | 08 April 2009 7 | ------ 8 | 9 | ~~ Licensed to the Apache Software Foundation (ASF) under one 10 | ~~ or more contributor license agreements. See the NOTICE file 11 | ~~ distributed with this work for additional information 12 | ~~ regarding copyright ownership. The ASF licenses this file 13 | ~~ to you under the Apache License, Version 2.0 (the 14 | ~~ "License"); you may not use this file except in compliance 15 | ~~ with the License. You may obtain a copy of the License at 16 | ~~ 17 | ~~ http://www.apache.org/licenses/LICENSE-2.0 18 | ~~ 19 | ~~ Unless required by applicable law or agreed to in writing, 20 | ~~ software distributed under the License is distributed on an 21 | ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22 | ~~ KIND, either express or implied. See the License for the 23 | ~~ specific language governing permissions and limitations 24 | ~~ under the License. 25 | 26 | ~~ NOTE: For help with the syntax of this file, see: 27 | ~~ http://maven.apache.org/doxia/references/apt-format.html 28 | 29 | Usage 30 | 31 | Some brief examples on how to use this plugin. 32 | 33 | * Signing a project artifact and attachments 34 | 35 | If you need to sign a project artifact and all attached artifacts, just 36 | configure the sign goal appropriately in your <<>> for the 37 | signing to occur automatically during the package phase. 38 | 39 | +-----------------+ 40 | 41 | ... 42 | 43 | 44 | ... 45 | 46 | org.apache.maven.plugins 47 | maven-jarsigner-plugin 48 | ${project.version} 49 | 50 | 51 | sign 52 | 53 | sign 54 | 55 | 56 | 57 | 58 | /path/to/the/keystore 59 | Alias name 60 | Store password 61 | Key password 62 | 63 | 64 | ... 65 | 66 | 67 | ... 68 | 69 | +-----------------+ 70 | 71 | <> you can encrypt <<>> and <<>> using the 72 | maven encryption mechanism. 73 | 74 | See {{{https://maven.apache.org/guides/mini/guide-encryption.html}Maven encryption guide}}. 75 | 76 | * Verifying the signature of a project artifact and attachments 77 | 78 | If you need to verify the signatures of a project artifact and all attached 79 | artifacts, just configure the verify goal appropriately in your <<>> 80 | for the verification to occur automatically during the verify phase. 81 | 82 | +-----------------+ 83 | 84 | ... 85 | 86 | 87 | ... 88 | 89 | org.apache.maven.plugins 90 | maven-jarsigner-plugin 91 | ${project.version} 92 | 93 | 94 | verify 95 | 96 | verify 97 | 98 | 99 | 100 | 101 | true 102 | true 103 | 104 | 105 | ... 106 | 107 | 108 | ... 109 | 110 | +-----------------+ 111 | 112 | * How to disable attachment processing 113 | 114 | +-----------------+ 115 | mvn ... -Djarsigner.attachments=false 116 | +-----------------+ 117 | 118 | 119 | * How to disable the Jarsigner Plugin 120 | 121 | +-----------------+ 122 | mvn ... -Djarsigner.skip=true 123 | +-----------------+ 124 | 125 | For full documentation, please see the respective {{{./plugin-info.html}goal documentation}}. 126 | 127 | * How to use encrypted password 128 | 129 | Since version 1.3, you can pass to the plugin some password encrypted by the maven encryption mechanism. 130 | -------------------------------------------------------------------------------- /src/site/fml/faq.fml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 27 | 28 | 29 | What is Jarsigner? 30 | 31 |

32 | You can read more about this tool in the offical guide: 33 | jarsigner - JAR Signing and Verification Tool. 34 |

35 |
36 |
37 | 38 | Is it possible to sign a single archive file? 39 | 40 |

41 | Signing or verifying a Java archive which is neither a project artifact 42 | nor an attached artifact can be done by using the archive parameter 43 | of the sign and verify goals. If 44 | this parameter is set, the goals will process the specified archive and will not process any project 45 | artifacts. 46 |

47 |
48 |
49 | 50 | How can I unsign JARs before re-signing them with my key? 51 | 52 |

53 | To remove any existing signatures from the JARs before signing with your own key, simply set the parameter 54 | removeExistingSignatures of the 55 | sign mojo to true. The resulting JAR will then appear 56 | to be signed exactly once. 57 |

58 |
59 |
60 | 61 | Why if I want to sign an artifact and then assembly there is some problem under windows? 62 | 63 |

64 | To fix the problem, just move the assembly execution so it comes after the jarsigner execution in the pom. 65 |

66 |

67 | The whole story of the problem can be found in MJARSIGNER-13 issue. 68 |

69 |
70 |
71 |
72 |
73 | -------------------------------------------------------------------------------- /src/site/resources/download.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # 20 | # Just call the standard mirrors.cgi script. It will use download.html 21 | # as the input template. 22 | exec /www/www.apache.org/dyn/mirrors/mirrors.cgi $* -------------------------------------------------------------------------------- /src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/site/xdoc/download.xml.vm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | Download ${project.name} Source 25 | 26 | 27 | 28 |
29 | 30 |

${project.name} ${project.version} is distributed in source format.

31 | 32 |

Use a source archive if you intend to build ${project.name} yourself.

33 | 34 |

Otherwise, simply use the ready-made binary artifacts from central repository.

35 | 36 |

${project.name} is distributed under the Apache License, version 2.0.

37 | 38 | 39 | 40 |

This is the current stable version of ${project.name}.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
LinkChecksumSignature
${project.name} ${project.version} (Source zip)${project.artifactId}-${project.version}-source-release.zip${project.artifactId}-${project.version}-source-release.zip.sha512${project.artifactId}-${project.version}-source-release.zip.asc
60 | 61 |

It is essential that you verify the integrity of the downloaded file 62 | using the checksum (.sha512 file) 63 | or using the signature (.asc file) against the public KEYS used by the Apache Maven developers. 64 |

65 | 66 |
67 | 68 | 69 |

It is strongly recommended to use the latest release version of ${project.name} to take advantage of the newest features and bug fixes.

70 |

Older non-recommended releases can be found on our archive site.

71 |
72 |
73 | 74 |
75 | 76 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/JarsignerSignMojoParallelTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.time.Duration; 24 | import java.util.LinkedHashMap; 25 | import java.util.Map; 26 | import java.util.concurrent.ExecutorService; 27 | import java.util.concurrent.Executors; 28 | import java.util.concurrent.Future; 29 | import java.util.concurrent.Semaphore; 30 | import java.util.concurrent.ThreadFactory; 31 | import java.util.concurrent.TimeUnit; 32 | 33 | import org.apache.maven.artifact.Artifact; 34 | import org.apache.maven.plugin.MojoExecutionException; 35 | import org.apache.maven.plugin.logging.Log; 36 | import org.apache.maven.project.MavenProject; 37 | import org.apache.maven.shared.jarsigner.JarSigner; 38 | import org.apache.maven.shared.jarsigner.JarSignerSignRequest; 39 | import org.junit.After; 40 | import org.junit.Before; 41 | import org.junit.Rule; 42 | import org.junit.Test; 43 | import org.junit.rules.TemporaryFolder; 44 | 45 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_ERROR; 46 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_OK; 47 | import static org.hamcrest.CoreMatchers.containsString; 48 | import static org.hamcrest.MatcherAssert.assertThat; 49 | import static org.junit.Assert.*; 50 | import static org.mockito.ArgumentMatchers.any; 51 | import static org.mockito.ArgumentMatchers.contains; 52 | import static org.mockito.ArgumentMatchers.isA; 53 | import static org.mockito.Mockito.*; 54 | 55 | public class JarsignerSignMojoParallelTest { 56 | @Rule 57 | public TemporaryFolder folder = new TemporaryFolder(); 58 | 59 | private MavenProject project = mock(MavenProject.class); 60 | private JarSigner jarSigner = mock(JarSigner.class); 61 | private File projectDir; 62 | private Map configuration = new LinkedHashMap<>(); 63 | private MojoTestCreator mojoTestCreator; 64 | private ExecutorService executor; 65 | private Log log; 66 | 67 | @Before 68 | public void setUp() throws Exception { 69 | projectDir = folder.newFolder("dummy-project"); 70 | configuration.put("processMainArtifact", "false"); 71 | mojoTestCreator = 72 | new MojoTestCreator(JarsignerSignMojo.class, project, projectDir, jarSigner); 73 | log = mock(Log.class); 74 | mojoTestCreator.setLog(log); 75 | executor = 76 | Executors.newSingleThreadExecutor(namedThreadFactory(getClass().getSimpleName())); 77 | } 78 | 79 | @After 80 | public void tearDown() { 81 | executor.shutdown(); 82 | } 83 | 84 | @Test(timeout = 30000) 85 | public void test10Files2Parallel() throws Exception { 86 | configuration.put("archiveDirectory", createArchives(10).getPath()); 87 | configuration.put("threadCount", "2"); 88 | 89 | // Make one jar file wait until some external event happens and let nine pass 90 | Semaphore semaphore = new Semaphore(9); 91 | when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> { 92 | semaphore.acquire(); 93 | return RESULT_OK; 94 | }); 95 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 96 | 97 | Future future = executor.submit(() -> { 98 | mojo.execute(); 99 | return null; 100 | }); 101 | 102 | // Wait until 10 invocation of execute() has happened (nine files are done and one are hanging) 103 | verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any()); 104 | // Even though 10 invocations of execute() have happened, mojo is not yet done executing (it is waiting for one) 105 | assertFalse(future.isDone()); 106 | 107 | semaphore.release(); // Release the one waiting jar file 108 | future.get(10, TimeUnit.SECONDS); // Wait for entire Mojo to finish 109 | assertTrue(future.isDone()); 110 | } 111 | 112 | @Test(timeout = 30000) 113 | public void test10Files2Parallel3Hanging() throws Exception { 114 | configuration.put("archiveDirectory", createArchives(10).getPath()); 115 | configuration.put("threadCount", "2"); 116 | 117 | // Make three jar files wait until some external event happens and let seven pass 118 | Semaphore semaphore = new Semaphore(7); 119 | when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> { 120 | semaphore.acquire(); 121 | return RESULT_OK; 122 | }); 123 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 124 | 125 | Future future = executor.submit(() -> { 126 | mojo.execute(); 127 | return null; 128 | }); 129 | 130 | // Wait until 9 invocations to execute has happened (2 is ongoing and 1 has not yet happened) 131 | verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(9)).execute(any()); 132 | assertFalse(future.isDone()); 133 | 134 | semaphore.release(); // Release one waiting jar file 135 | 136 | // Wait until 10 invocation to execute has happened (8 are done and 2 are hanging) 137 | verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any()); 138 | 139 | semaphore.release(2); // Release last two jar files 140 | future.get(10, TimeUnit.SECONDS); // Wait for entire Mojo to finish 141 | assertTrue(future.isDone()); 142 | } 143 | 144 | @Test(timeout = 30000) 145 | public void test10Files1Parallel() throws Exception { 146 | configuration.put("archiveDirectory", createArchives(10).getPath()); 147 | configuration.put("threadCount", "1"); 148 | 149 | // Make one jar file wait until some external event happens and let nine pass 150 | Semaphore semaphore = new Semaphore(9); 151 | when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> { 152 | semaphore.acquire(); 153 | return RESULT_OK; 154 | }); 155 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 156 | 157 | Future future = executor.submit(() -> { 158 | mojo.execute(); 159 | return null; 160 | }); 161 | 162 | // Wait until 10 invocation to execute has happened (nine has finished and one is hanging). 163 | verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any()); 164 | assertFalse(future.isDone()); 165 | 166 | semaphore.release(); // Release the one waiting jar file 167 | future.get(10, TimeUnit.SECONDS); // Wait for entire Mojo to finish 168 | assertTrue(future.isDone()); 169 | } 170 | 171 | @Test(timeout = 30000) 172 | public void test10Files2ParallelOneFail() throws Exception { 173 | configuration.put("archiveDirectory", createArchives(10).getPath()); 174 | configuration.put("threadCount", "2"); 175 | 176 | when(jarSigner.execute(isA(JarSignerSignRequest.class))) 177 | .thenReturn(RESULT_OK) 178 | .thenReturn(RESULT_OK) 179 | .thenReturn(RESULT_ERROR) 180 | .thenReturn(RESULT_OK); 181 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 182 | 183 | MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> { 184 | mojo.execute(); 185 | }); 186 | 187 | assertThat(mojoException.getMessage(), containsString(String.valueOf("Failed executing 'jarsigner "))); 188 | } 189 | 190 | @Test 191 | public void testInvalidThreadCount() throws Exception { 192 | Artifact mainArtifact = TestArtifacts.createJarArtifact(projectDir, "my-project.jar"); 193 | when(project.getArtifact()).thenReturn(mainArtifact); 194 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 195 | configuration.put("processMainArtifact", "true"); 196 | configuration.put("threadCount", "0"); // Setting an "invalid" value 197 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 198 | 199 | mojo.execute(); 200 | 201 | verify(jarSigner, times(1)).execute(any()); 202 | verify(log).warn(contains("Invalid threadCount value")); 203 | verify(log).warn(contains("Was '0'")); 204 | } 205 | 206 | private File createArchives(int numberOfArchives) throws IOException { 207 | File archiveDirectory = new File(projectDir, "my_archive_dir"); 208 | archiveDirectory.mkdir(); 209 | for (int i = 0; i < numberOfArchives; i++) { 210 | TestArtifacts.createDummyZipFile(new File(archiveDirectory, "archive" + i + ".jar")); 211 | } 212 | return archiveDirectory; 213 | } 214 | 215 | private static ThreadFactory namedThreadFactory(String threadNamePrefix) { 216 | return r -> new Thread(r, threadNamePrefix + "-Thread"); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/JarsignerSignMojoRetryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.time.Duration; 23 | import java.util.LinkedHashMap; 24 | import java.util.Locale; 25 | import java.util.Map; 26 | import java.util.concurrent.atomic.AtomicLong; 27 | 28 | import org.apache.maven.artifact.Artifact; 29 | import org.apache.maven.plugin.MojoExecutionException; 30 | import org.apache.maven.plugin.logging.Log; 31 | import org.apache.maven.plugins.jarsigner.JarsignerSignMojo.Sleeper; 32 | import org.apache.maven.plugins.jarsigner.JarsignerSignMojo.WaitStrategy; 33 | import org.apache.maven.project.MavenProject; 34 | import org.apache.maven.shared.jarsigner.JarSigner; 35 | import org.apache.maven.shared.jarsigner.JarSignerSignRequest; 36 | import org.apache.maven.shared.utils.cli.javatool.JavaToolResult; 37 | import org.junit.After; 38 | import org.junit.Before; 39 | import org.junit.Rule; 40 | import org.junit.Test; 41 | import org.junit.rules.TemporaryFolder; 42 | 43 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_ERROR; 44 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_OK; 45 | import static org.hamcrest.CoreMatchers.containsString; 46 | import static org.hamcrest.CoreMatchers.not; 47 | import static org.hamcrest.MatcherAssert.assertThat; 48 | import static org.junit.Assert.*; 49 | import static org.mockito.ArgumentMatchers.any; 50 | import static org.mockito.ArgumentMatchers.contains; 51 | import static org.mockito.Mockito.argThat; 52 | import static org.mockito.Mockito.mock; 53 | import static org.mockito.Mockito.times; 54 | import static org.mockito.Mockito.verify; 55 | import static org.mockito.Mockito.when; 56 | 57 | public class JarsignerSignMojoRetryTest { 58 | @Rule 59 | public TemporaryFolder folder = new TemporaryFolder(); 60 | 61 | private Locale originalLocale; 62 | private MavenProject project = mock(MavenProject.class); 63 | private JarSigner jarSigner = mock(JarSigner.class); 64 | private WaitStrategy waitStrategy = mock(WaitStrategy.class); 65 | private File projectDir; 66 | private Map configuration = new LinkedHashMap<>(); 67 | private Log log; 68 | private MojoTestCreator mojoTestCreator; 69 | 70 | @Before 71 | public void setUp() throws Exception { 72 | originalLocale = Locale.getDefault(); 73 | Locale.setDefault(Locale.ENGLISH); // For English ResourceBundle to test log messages 74 | projectDir = folder.newFolder("dummy-project"); 75 | mojoTestCreator = 76 | new MojoTestCreator(JarsignerSignMojo.class, project, projectDir, jarSigner); 77 | log = mock(Log.class); 78 | mojoTestCreator.setLog(log); 79 | Artifact mainArtifact = TestArtifacts.createJarArtifact(projectDir, "my-project.jar"); 80 | when(project.getArtifact()).thenReturn(mainArtifact); 81 | } 82 | 83 | @After 84 | public void tearDown() { 85 | Locale.setDefault(originalLocale); 86 | } 87 | 88 | @Test 89 | public void testSignSuccessOnFirst() throws Exception { 90 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 91 | configuration.put("maxTries", "1"); 92 | mojoTestCreator.setWaitStrategy(waitStrategy); 93 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 94 | 95 | mojo.execute(); 96 | 97 | verify(jarSigner) 98 | .execute(argThat(request -> request.getArchive().getPath().endsWith("my-project.jar"))); 99 | verify(waitStrategy, times(0)).waitAfterFailure(0, Duration.ofSeconds(0)); 100 | } 101 | 102 | @Test 103 | public void testSignFailureOnFirst() throws Exception { 104 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_ERROR); 105 | configuration.put("maxTries", "1"); 106 | mojoTestCreator.setWaitStrategy(waitStrategy); 107 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 108 | assertThrows(MojoExecutionException.class, () -> { 109 | mojo.execute(); 110 | }); 111 | verify(jarSigner, times(1)).execute(any()); 112 | verify(waitStrategy, times(0)).waitAfterFailure(0, Duration.ofSeconds(0)); 113 | } 114 | 115 | @Test 116 | public void testSignFailureOnFirstSuccessOnSecond() throws Exception { 117 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 118 | .thenReturn(RESULT_ERROR) 119 | .thenReturn(RESULT_OK); 120 | configuration.put("maxTries", "2"); 121 | mojoTestCreator.setWaitStrategy(waitStrategy); 122 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 123 | 124 | mojo.execute(); 125 | 126 | verify(jarSigner, times(2)).execute(any()); 127 | verify(waitStrategy, times(1)).waitAfterFailure(0, Duration.ofSeconds(0)); 128 | } 129 | 130 | @Test 131 | public void testSignFailureOnFirstFailureOnSecond() throws Exception { 132 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 133 | .thenReturn(RESULT_ERROR) 134 | .thenReturn(RESULT_ERROR); 135 | configuration.put("maxTries", "2"); 136 | mojoTestCreator.setWaitStrategy(waitStrategy); 137 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 138 | assertThrows(MojoExecutionException.class, () -> { 139 | mojo.execute(); 140 | }); 141 | verify(jarSigner, times(2)).execute(any()); 142 | verify(waitStrategy, times(1)).waitAfterFailure(0, Duration.ofSeconds(0)); 143 | } 144 | 145 | @Test 146 | public void testInvalidMaxTries_zero() throws Exception { 147 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_ERROR); 148 | 149 | configuration.put("maxTries", "0"); // Setting an "invalid" value 150 | mojoTestCreator.setWaitStrategy(waitStrategy); 151 | 152 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 153 | 154 | assertThrows(MojoExecutionException.class, () -> { 155 | mojo.execute(); 156 | }); 157 | 158 | verify(jarSigner, times(1)).execute(any()); // Should have tried exactly one time, regardless of invalid value 159 | verify(log).warn(contains("Invalid maxTries")); 160 | verify(log).warn(contains("0")); 161 | } 162 | 163 | @Test 164 | public void testInvalidMaxTries_negative() throws Exception { 165 | // Make result ok, to make this test check more things (compared to testInvalidMaxTries_zero()) 166 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 167 | 168 | configuration.put("maxTries", "-2"); // Setting an "invalid" value 169 | mojoTestCreator.setWaitStrategy(waitStrategy); 170 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 171 | 172 | mojo.execute(); 173 | 174 | verify(jarSigner, times(1)).execute(any()); // Should have tried exactly one time, regardless of invalid value 175 | verify(log).warn(contains("Invalid maxTries")); 176 | verify(log).warn(contains("-2")); 177 | } 178 | 179 | @Test 180 | public void testMaxRetryDelaySeconds() throws Exception { 181 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 182 | .thenReturn(RESULT_ERROR) 183 | .thenReturn(RESULT_ERROR) 184 | .thenReturn(RESULT_OK); 185 | 186 | configuration.put("maxTries", "3"); 187 | configuration.put("maxRetryDelaySeconds", "30"); 188 | mojoTestCreator.setWaitStrategy(waitStrategy); 189 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 190 | 191 | mojo.execute(); 192 | 193 | verify(waitStrategy, times(1)).waitAfterFailure(0, Duration.ofSeconds(30)); 194 | verify(waitStrategy, times(1)).waitAfterFailure(1, Duration.ofSeconds(30)); 195 | } 196 | 197 | @Test 198 | public void testInvalidMaxRetryDelaySeconds_negative() throws Exception { 199 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 200 | .thenReturn(RESULT_ERROR) 201 | .thenReturn(RESULT_OK); 202 | 203 | configuration.put("maxTries", "10"); 204 | configuration.put("maxRetryDelaySeconds", "-5"); // Setting an "invalid" value 205 | mojoTestCreator.setWaitStrategy(waitStrategy); 206 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 207 | 208 | mojo.execute(); 209 | 210 | verify(waitStrategy).waitAfterFailure(0, Duration.ofSeconds(0)); 211 | verify(jarSigner, times(2)).execute(any()); 212 | verify(log).warn(contains("Invalid maxRetryDelaySeconds")); 213 | verify(log).warn(contains("-5")); 214 | } 215 | 216 | @Test 217 | public void testDefaultWaitStrategy() throws Exception { 218 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 219 | 220 | long NO_SLEEP_VALUE = 42_001; 221 | // Storage of the most recent sleep value 222 | AtomicLong sleepValue = new AtomicLong(NO_SLEEP_VALUE); 223 | Sleeper sleeper = value -> sleepValue.set(value); 224 | 225 | mojo.waitAfterFailure(0, Duration.ofSeconds(0), sleeper); 226 | assertEquals(NO_SLEEP_VALUE, sleepValue.get()); 227 | 228 | mojo.waitAfterFailure(1, Duration.ofSeconds(0), sleeper); 229 | assertEquals(NO_SLEEP_VALUE, sleepValue.get()); 230 | 231 | mojo.waitAfterFailure(0, Duration.ofSeconds(1), sleeper); 232 | assertEquals(1000, sleepValue.get()); 233 | verify(log).info(contains("for 1 seconds")); 234 | 235 | mojo.waitAfterFailure(1, Duration.ofSeconds(1), sleeper); 236 | assertEquals(1000, sleepValue.get()); 237 | mojo.waitAfterFailure(2, Duration.ofSeconds(1), sleeper); 238 | assertEquals(1000, sleepValue.get()); 239 | 240 | mojo.waitAfterFailure(3, Duration.ofSeconds(100), sleeper); 241 | assertEquals(8000, sleepValue.get()); 242 | 243 | mojo.waitAfterFailure(Integer.MAX_VALUE, Duration.ofSeconds(100), sleeper); 244 | assertEquals(100_000, sleepValue.get()); 245 | 246 | sleepValue.set(NO_SLEEP_VALUE); // "reset" sleep value 247 | mojo.waitAfterFailure(Integer.MIN_VALUE, Duration.ofSeconds(100), sleeper); 248 | // Make sure sleep has not been invoked, should be the "reset" value 249 | assertEquals(NO_SLEEP_VALUE, sleepValue.get()); 250 | 251 | // Testing the attempt limit used in exponential function. Will return a odd value (2^20). 252 | mojo.waitAfterFailure(10000, Duration.ofDays(356), sleeper); 253 | assertEquals(Duration.ofSeconds(1048576).toMillis(), sleepValue.get()); 254 | // Testing of attempt limit, when using a smaller maxRetryDelay 255 | mojo.waitAfterFailure(10000, Duration.ofDays(1), sleeper); 256 | assertEquals(Duration.ofDays(1).toMillis(), sleepValue.get()); 257 | 258 | Sleeper iterruptedSleeper = value -> { 259 | throw new InterruptedException("Thread was interrupted while sleeping."); 260 | }; 261 | MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> { 262 | mojo.waitAfterFailure(0, Duration.ofSeconds(10), iterruptedSleeper); 263 | }); 264 | assertThat(mojoException.getMessage(), containsString("interrupted while waiting after failure")); 265 | } 266 | 267 | /** Check that the error returned from a re-try scenario where all execution fails is the "correct" error */ 268 | @Test 269 | public void testLastErrorReturned() throws Exception { 270 | JavaToolResult lastError = new JavaToolResult(); 271 | lastError.setExitCode(42); // The exit code of the last jarsigner execution 272 | lastError.setExecutionException(null); 273 | lastError.setCommandline(RESULT_ERROR.getCommandline()); 274 | 275 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 276 | .thenReturn(RESULT_ERROR) 277 | .thenReturn(lastError); 278 | 279 | configuration.put("maxTries", "5"); 280 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 281 | 282 | MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> { 283 | mojo.execute(); 284 | }); 285 | 286 | // Make sure that the last error exit code is present 287 | assertThat(mojoException.getMessage(), containsString(String.valueOf(42))); 288 | // Make sure that the first error exit code is not present 289 | assertThat(mojoException.getMessage(), not(containsString(String.valueOf(1)))); 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/JarsignerSignMojoTsaTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.util.ArrayList; 24 | import java.util.LinkedHashMap; 25 | import java.util.List; 26 | import java.util.Locale; 27 | import java.util.Map; 28 | 29 | import org.apache.maven.artifact.Artifact; 30 | import org.apache.maven.plugin.logging.Log; 31 | import org.apache.maven.project.MavenProject; 32 | import org.apache.maven.shared.jarsigner.JarSigner; 33 | import org.apache.maven.shared.jarsigner.JarSignerSignRequest; 34 | import org.junit.After; 35 | import org.junit.Before; 36 | import org.junit.Rule; 37 | import org.junit.Test; 38 | import org.junit.rules.TemporaryFolder; 39 | import org.mockito.ArgumentCaptor; 40 | 41 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_ERROR; 42 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_OK; 43 | import static org.hamcrest.CoreMatchers.everyItem; 44 | import static org.hamcrest.MatcherAssert.assertThat; 45 | import static org.junit.Assert.*; 46 | import static org.mockito.ArgumentMatchers.any; 47 | import static org.mockito.ArgumentMatchers.contains; 48 | import static org.mockito.Mockito.mock; 49 | import static org.mockito.Mockito.times; 50 | import static org.mockito.Mockito.verify; 51 | import static org.mockito.Mockito.when; 52 | 53 | public class JarsignerSignMojoTsaTest { 54 | @Rule 55 | public TemporaryFolder folder = new TemporaryFolder(); 56 | 57 | private Locale originalLocale; 58 | private MavenProject project = mock(MavenProject.class); 59 | private JarSigner jarSigner = mock(JarSigner.class); 60 | 61 | private File projectDir; 62 | private Map configuration = new LinkedHashMap<>(); 63 | private Log log; 64 | private MojoTestCreator mojoTestCreator; 65 | 66 | @Before 67 | public void setUp() throws Exception { 68 | originalLocale = Locale.getDefault(); 69 | Locale.setDefault(Locale.ENGLISH); // For English ResourceBundle to test log messages 70 | projectDir = folder.newFolder("dummy-project"); 71 | mojoTestCreator = 72 | new MojoTestCreator(JarsignerSignMojo.class, project, projectDir, jarSigner); 73 | log = mock(Log.class); 74 | mojoTestCreator.setLog(log); 75 | Artifact mainArtifact = TestArtifacts.createJarArtifact(projectDir, "my-project.jar"); 76 | when(project.getArtifact()).thenReturn(mainArtifact); 77 | } 78 | 79 | @After 80 | public void tearDown() { 81 | Locale.setDefault(originalLocale); 82 | } 83 | 84 | @Test 85 | public void testAllTsaParameters() throws Exception { 86 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 87 | configuration.put("archiveDirectory", createArchives(2).getPath()); 88 | configuration.put("tsa", "http://my-timestamp.server.com"); 89 | configuration.put("tsacert", "mytsacertalias"); // Normally you would not set both "tsacert alias" and "tsa url" 90 | configuration.put("tsapolicyid", "0.1.2.3.4"); 91 | configuration.put("tsadigestalg", "SHA-384"); 92 | 93 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 94 | 95 | mojo.execute(); 96 | 97 | ArgumentCaptor requestArgument = ArgumentCaptor.forClass(JarSignerSignRequest.class); 98 | verify(jarSigner, times(3)).execute(requestArgument.capture()); 99 | List requests = requestArgument.getAllValues(); 100 | assertThat(requests, everyItem(RequestMatchers.hasTsa("http://my-timestamp.server.com"))); 101 | assertThat(requests, everyItem(RequestMatchers.hasTsacert("mytsacertalias"))); 102 | assertThat(requests, everyItem(RequestMatchers.hasTsaPolicyid("0.1.2.3.4"))); 103 | assertThat(requests, everyItem(RequestMatchers.hasTsaDigestalg("SHA-384"))); 104 | } 105 | 106 | @Test 107 | public void testMutipleTsa() throws Exception { 108 | // Special setup (non-normal) Mockito, because the same JarSignerSignRequest instance is used with modified URL 109 | List tsaUrls = new ArrayList<>(); 110 | when(jarSigner.execute(any(JarSignerSignRequest.class))) 111 | .thenAnswer(invocation -> { 112 | JarSignerSignRequest request = 113 | (JarSignerSignRequest) invocation.getArguments()[0]; 114 | tsaUrls.add(request.getTsaLocation()); 115 | return RESULT_ERROR; 116 | }) 117 | .thenAnswer(invocation -> { 118 | JarSignerSignRequest request = 119 | (JarSignerSignRequest) invocation.getArguments()[0]; 120 | tsaUrls.add(request.getTsaLocation()); 121 | return RESULT_OK; 122 | }); 123 | 124 | configuration.put("maxTries", "10"); 125 | configuration.put("tsa", "http://my-timestamp.server.com,http://other-timestamp.example.com"); 126 | 127 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 128 | 129 | mojo.execute(); 130 | 131 | verify(jarSigner, times(2)).execute(any()); 132 | assertEquals("http://my-timestamp.server.com", tsaUrls.get(0)); 133 | assertEquals("http://other-timestamp.example.com", tsaUrls.get(1)); 134 | } 135 | 136 | @Test 137 | public void testVerifyUsageOfBothTsaAndTsacert() throws Exception { 138 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 139 | configuration.put("maxTries", "2"); 140 | configuration.put("tsa", "http://my-timestamp.server.com"); 141 | configuration.put("tsacert", "mytsacertalias"); 142 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 143 | 144 | mojo.execute(); 145 | 146 | verify(log).warn(contains("Usage of both -tsa and -tsacert is undefined")); 147 | } 148 | 149 | @Test 150 | public void testVerifyUsageOfDifferentNumberOfTsapolicyidAndTsa() throws Exception { 151 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 152 | configuration.put("maxTries", "2"); 153 | configuration.put("tsa", "http://my-timestamp1.server.com,http://my-timestamp2.server.com"); 154 | configuration.put("tsapolicyid", "1.1,1.2,1.3"); // Too many OIDs specified 155 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 156 | 157 | mojo.execute(); 158 | 159 | verify(log).warn(contains("Too many (3) number of OIDs given")); 160 | } 161 | 162 | @Test 163 | public void testVerifyUsageOfDifferentNumberOfTsapolicyidAndTsacert() throws Exception { 164 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 165 | configuration.put("maxTries", "2"); 166 | configuration.put("tsacert", "alias1,alias2"); 167 | configuration.put("tsapolicyid", "1.1,1.2,1.3"); // Too many OIDs specified 168 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 169 | 170 | mojo.execute(); 171 | 172 | // Alomst the same warning log as previous test case 173 | verify(log).warn(contains("Too many (3) number of OIDs given")); 174 | } 175 | 176 | @Test 177 | public void testVerifyMultipleTsaButNoRetry() throws Exception { 178 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 179 | configuration.put("tsa", "http://my-timestamp1.server.com,http://my-timestamp2.server.com"); 180 | configuration.put("maxTries", "1"); 181 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 182 | 183 | mojo.execute(); 184 | 185 | verify(log).warn(contains("2 TSA URLs specified. Only first will be used because maxTries is set to 1")); 186 | } 187 | 188 | @Test 189 | public void testVerifyMultipleTsacertButNoRetry() throws Exception { 190 | when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK); 191 | configuration.put("tsacert", "alias1,alias2"); 192 | configuration.put("maxTries", "1"); 193 | JarsignerSignMojo mojo = mojoTestCreator.configure(configuration); 194 | 195 | mojo.execute(); 196 | 197 | verify(log).warn(contains("2 TSA certificate aliases specified. Only first")); 198 | } 199 | 200 | private File createArchives(int numberOfArchives) throws IOException { 201 | File archiveDirectory = new File(projectDir, "my_archive_dir"); 202 | archiveDirectory.mkdir(); 203 | for (int i = 0; i < numberOfArchives; i++) { 204 | TestArtifacts.createDummyZipFile(new File(archiveDirectory, "archive" + i + ".jar")); 205 | } 206 | return archiveDirectory; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/JarsignerVerifyMojoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.util.LinkedHashMap; 23 | import java.util.Map; 24 | 25 | import org.apache.maven.artifact.Artifact; 26 | import org.apache.maven.plugin.MojoExecutionException; 27 | import org.apache.maven.plugin.logging.Log; 28 | import org.apache.maven.project.MavenProject; 29 | import org.apache.maven.shared.jarsigner.JarSigner; 30 | import org.apache.maven.shared.jarsigner.JarSignerVerifyRequest; 31 | import org.junit.Before; 32 | import org.junit.Rule; 33 | import org.junit.Test; 34 | import org.junit.rules.TemporaryFolder; 35 | import org.mockito.ArgumentCaptor; 36 | import org.mockito.hamcrest.MockitoHamcrest; 37 | 38 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_ERROR; 39 | import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_OK; 40 | import static org.hamcrest.CoreMatchers.containsString; 41 | import static org.hamcrest.CoreMatchers.startsWith; 42 | import static org.hamcrest.MatcherAssert.assertThat; 43 | import static org.junit.Assert.*; 44 | import static org.mockito.ArgumentMatchers.any; 45 | import static org.mockito.ArgumentMatchers.argThat; 46 | import static org.mockito.Mockito.mock; 47 | import static org.mockito.Mockito.verify; 48 | import static org.mockito.Mockito.when; 49 | 50 | public class JarsignerVerifyMojoTest { 51 | 52 | @Rule 53 | public TemporaryFolder folder = new TemporaryFolder(); 54 | 55 | private MavenProject project = mock(MavenProject.class); 56 | private JarSigner jarSigner = mock(JarSigner.class); 57 | private File dummyMavenProjectDir; 58 | private Map configuration = new LinkedHashMap<>(); 59 | private Log log; 60 | private MojoTestCreator mojoTestCreator; 61 | 62 | @Before 63 | public void setUp() throws Exception { 64 | dummyMavenProjectDir = folder.newFolder("dummy-project"); 65 | mojoTestCreator = new MojoTestCreator( 66 | JarsignerVerifyMojo.class, project, dummyMavenProjectDir, jarSigner); 67 | log = mock(Log.class); 68 | mojoTestCreator.setLog(log); 69 | } 70 | 71 | /** Standard Java project with nothing special configured */ 72 | @Test 73 | public void testStandardJavaProject() throws Exception { 74 | Artifact mainArtifact = TestArtifacts.createJarArtifact(dummyMavenProjectDir, "my-project.jar"); 75 | when(project.getArtifact()).thenReturn(mainArtifact); 76 | when(jarSigner.execute(any(JarSignerVerifyRequest.class))).thenReturn(RESULT_OK); 77 | JarsignerVerifyMojo mojo = mojoTestCreator.configure(configuration); 78 | 79 | mojo.execute(); 80 | 81 | ArgumentCaptor requestArgument = ArgumentCaptor.forClass(JarSignerVerifyRequest.class); 82 | verify(jarSigner).execute(requestArgument.capture()); 83 | JarSignerVerifyRequest request = requestArgument.getValue(); 84 | 85 | assertFalse(request.isVerbose()); 86 | assertNull(request.getKeystore()); 87 | assertNull(request.getStoretype()); 88 | assertNull(request.getStorepass()); 89 | assertNull(request.getAlias()); 90 | assertNull(request.getProviderName()); 91 | assertNull(request.getProviderClass()); 92 | assertNull(request.getProviderArg()); 93 | assertNull(request.getMaxMemory()); 94 | assertThat(request.getArguments()[0], startsWith("-J-Dfile.encoding=")); 95 | assertEquals(dummyMavenProjectDir, request.getWorkingDirectory()); 96 | assertEquals(mainArtifact.getFile(), request.getArchive()); 97 | assertFalse(request.isProtectedAuthenticationPath()); 98 | 99 | assertFalse(request.isCerts()); // Only verify specific parameter 100 | } 101 | 102 | /** Invocing jarsigner with the -certs parameter */ 103 | @Test 104 | public void testCertsTrue() throws Exception { 105 | Artifact mainArtifact = TestArtifacts.createJarArtifact(dummyMavenProjectDir, "my-project.jar"); 106 | when(project.getArtifact()).thenReturn(mainArtifact); 107 | when(jarSigner.execute(any(JarSignerVerifyRequest.class))).thenReturn(RESULT_OK); 108 | configuration.put("certs", "true"); 109 | JarsignerVerifyMojo mojo = mojoTestCreator.configure(configuration); 110 | 111 | mojo.execute(); 112 | 113 | verify(jarSigner).execute(argThat(request -> ((JarSignerVerifyRequest) request).isCerts())); 114 | } 115 | 116 | /** When the jarsigner signing verification check tells there is a problem with the signing of the file */ 117 | @Test 118 | public void testVerifyFailure() throws Exception { 119 | Artifact mainArtifact = TestArtifacts.createJarArtifact(dummyMavenProjectDir, "my-project.jar"); 120 | when(project.getArtifact()).thenReturn(mainArtifact); 121 | when(jarSigner.execute(any(JarSignerVerifyRequest.class))).thenReturn(RESULT_ERROR); 122 | JarsignerVerifyMojo mojo = mojoTestCreator.configure(configuration); 123 | 124 | MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> { 125 | mojo.execute(); 126 | }); 127 | assertThat(mojoException.getMessage(), containsString(String.valueOf(RESULT_ERROR.getExitCode()))); 128 | assertThat( 129 | mojoException.getMessage(), 130 | containsString(RESULT_ERROR.getCommandline().toString())); 131 | } 132 | 133 | /** When setting errorWhenNotSigned, for file that has existing signing (should not fail) */ 134 | @Test 135 | public void testErrorWhenNotSignedOnExistingSigning() throws Exception { 136 | File signedJar = TestArtifacts.createDummySignedJarFile(new File(dummyMavenProjectDir, "my-project.jar")); 137 | Artifact mainArtifact = TestArtifacts.createArtifact(signedJar); 138 | when(project.getArtifact()).thenReturn(mainArtifact); 139 | when(jarSigner.execute(any(JarSignerVerifyRequest.class))).thenReturn(RESULT_OK); 140 | configuration.put("errorWhenNotSigned", "true"); 141 | 142 | JarsignerVerifyMojo mojo = mojoTestCreator.configure(configuration); 143 | 144 | mojo.execute(); 145 | 146 | verify(jarSigner).execute(MockitoHamcrest.argThat(RequestMatchers.hasFileName("my-project.jar"))); 147 | } 148 | 149 | /** When setting errorWhenNotSigned, for file that does not have existing signing (should fail) */ 150 | @Test 151 | public void testErrorWhenNotSignedOnNonExistingSigning() throws Exception { 152 | Artifact mainArtifact = TestArtifacts.createJarArtifact(dummyMavenProjectDir, "my-project.jar"); 153 | when(project.getArtifact()).thenReturn(mainArtifact); 154 | when(jarSigner.execute(any(JarSignerVerifyRequest.class))).thenReturn(RESULT_OK); 155 | configuration.put("errorWhenNotSigned", "true"); 156 | 157 | JarsignerVerifyMojo mojo = mojoTestCreator.configure(configuration); 158 | 159 | MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> { 160 | mojo.execute(); 161 | }); 162 | assertThat( 163 | mojoException.getMessage(), 164 | containsString(mainArtifact.getFile().getPath())); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/MojoTestCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.lang.reflect.Field; 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.regex.Matcher; 28 | import java.util.regex.Pattern; 29 | 30 | import org.apache.maven.plugin.Mojo; 31 | import org.apache.maven.plugin.logging.Log; 32 | import org.apache.maven.plugins.jarsigner.JarsignerSignMojo.WaitStrategy; 33 | import org.apache.maven.project.MavenProject; 34 | import org.apache.maven.shared.jarsigner.JarSigner; 35 | import org.apache.maven.toolchain.ToolchainManager; 36 | import org.slf4j.Logger; 37 | import org.slf4j.LoggerFactory; 38 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 39 | 40 | /** 41 | * Creates and configures a Mojo instance to be used in testing. 42 | * 43 | * @param The type of Mojo 44 | */ 45 | public class MojoTestCreator { 46 | 47 | private final Logger logger = LoggerFactory.getLogger(MojoTestCreator.class); 48 | 49 | private final Class clazz; 50 | private final MavenProject project; 51 | private final File projectDir; 52 | private final JarSigner jarSigner; 53 | private ToolchainManager toolchainManager; 54 | private SecDispatcher securityDispatcher; 55 | private WaitStrategy waitStrategy; 56 | private Log log; 57 | private List fields; 58 | 59 | public MojoTestCreator(Class clazz, MavenProject project, File projectDir, JarSigner jarSigner) 60 | throws Exception { 61 | this.clazz = clazz; 62 | this.project = project; 63 | this.projectDir = projectDir; 64 | this.jarSigner = jarSigner; 65 | 66 | securityDispatcher = str -> str; // Simple SecDispatcher that only returns parameter 67 | fields = getAllFields(clazz); 68 | } 69 | 70 | public void setToolchainManager(ToolchainManager toolchainManager) { 71 | this.toolchainManager = toolchainManager; 72 | } 73 | 74 | public void setSecDispatcher(SecDispatcher securityDispatcher) { 75 | this.securityDispatcher = securityDispatcher; 76 | } 77 | 78 | public void setWaitStrategy(WaitStrategy waitStrategy) { 79 | this.waitStrategy = waitStrategy; 80 | } 81 | 82 | public void setLog(Log log) { 83 | this.log = log; 84 | } 85 | 86 | /** 87 | * Creates and configures the Mojo instance. 88 | * 89 | * @param configuration user supplied configuration 90 | */ 91 | public T configure(Map configuration, Class... parameterTypes) throws Exception { 92 | T mojo = clazz.getDeclaredConstructor(parameterTypes).newInstance(); 93 | setDefaultValues(mojo); 94 | 95 | setAttribute(mojo, "project", project); 96 | setAttribute(mojo, "jarSigner", jarSigner); 97 | setAttribute(mojo, "securityDispatcher", securityDispatcher); 98 | if (toolchainManager != null) { 99 | setAttribute(mojo, "toolchainManager", toolchainManager); 100 | } 101 | if (waitStrategy != null) { 102 | ((JarsignerSignMojo) mojo).setWaitStrategy(waitStrategy); 103 | } 104 | if (log != null) { 105 | mojo.setLog(log); 106 | } 107 | 108 | for (Map.Entry entry : configuration.entrySet()) { 109 | Field field = getField(mojo, entry.getKey()); 110 | setFieldByStringValue(mojo, field, entry.getValue()); 111 | } 112 | 113 | return mojo; 114 | } 115 | 116 | private void setFieldByStringValue(Object instance, Field field, String stringValue) throws Exception { 117 | field.setAccessible(true); 118 | Class fieldType = field.getType(); 119 | if (fieldType.equals(String.class)) { 120 | field.set(instance, stringValue); 121 | } else if (fieldType.equals(int.class)) { 122 | field.setInt(instance, Integer.parseInt(stringValue)); 123 | } else if (fieldType.equals(boolean.class)) { 124 | field.setBoolean(instance, Boolean.parseBoolean(stringValue)); 125 | } else if (fieldType.equals(File.class)) { 126 | field.set(instance, new File(stringValue)); 127 | } else if (fieldType.equals(String[].class)) { 128 | if (stringValue.isEmpty()) { 129 | // Maven defaults to empty list if no default value exists 130 | field.set(instance, new String[0]); 131 | } else { 132 | String[] values = stringValue.split(","); 133 | field.set(instance, values); 134 | } 135 | } else { 136 | if (!stringValue.startsWith("${")) { 137 | logger.warn( 138 | "Not implemented support to set of field of type {} to value {}", 139 | fieldType.getSimpleName(), 140 | stringValue); 141 | } 142 | } 143 | } 144 | 145 | private Field getField(Object instance, String fieldName) { 146 | return fields.stream() 147 | .filter(f -> f.getName().equals(fieldName)) 148 | .findFirst() 149 | .orElseThrow(() -> new RuntimeException("Could not find field " + fieldName + " in class " 150 | + instance.getClass().getName())); 151 | } 152 | 153 | private void setAttribute(Object instance, String fieldName, Object value) throws Exception { 154 | Field field = getField(instance, fieldName); 155 | field.setAccessible(true); 156 | field.set(instance, value); 157 | } 158 | 159 | private void setDefaultValues(Mojo mojo) throws Exception { 160 | Map defaultConfiguration = PluginXmlParser.getMojoDefaultConfiguration(mojo.getClass()); 161 | for (String parameterName : defaultConfiguration.keySet()) { 162 | String defaultValue = defaultConfiguration.get(parameterName); 163 | defaultValue = substituteParameterValueVariables(defaultValue); 164 | Field field = getField(mojo, parameterName); 165 | setFieldByStringValue(mojo, field, defaultValue.toString()); 166 | } 167 | } 168 | 169 | private String substituteParameterValueVariables(String parameterValue) { 170 | parameterValue = parameterValue.replaceAll( 171 | Pattern.quote("${project.basedir}"), Matcher.quoteReplacement(projectDir.getPath())); 172 | return parameterValue; 173 | } 174 | 175 | static List getAllFields(Class clazz) { 176 | List fields = new ArrayList<>(); 177 | Class currentClazz = clazz; 178 | while (currentClazz != null) { 179 | fields.addAll(Arrays.asList(currentClazz.getDeclaredFields())); 180 | currentClazz = currentClazz.getSuperclass(); 181 | } 182 | return fields; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/PluginXmlParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import javax.xml.parsers.DocumentBuilder; 22 | import javax.xml.parsers.DocumentBuilderFactory; 23 | 24 | import java.io.InputStream; 25 | import java.util.LinkedHashMap; 26 | import java.util.Map; 27 | 28 | import org.apache.maven.plugin.Mojo; 29 | import org.w3c.dom.Document; 30 | import org.w3c.dom.Element; 31 | import org.w3c.dom.Node; 32 | import org.w3c.dom.NodeList; 33 | 34 | /** 35 | * Parser of the generated META-INF/maven/plugin.xml for this project. The plugin.xml contains all mojos their 36 | * configuration parameters along with default values. 37 | */ 38 | public class PluginXmlParser { 39 | private static final String MOJO_IMPLEMENTATION_TAG = "implementation"; 40 | private static final String MOJO_TAG = "mojo"; 41 | private static final String CONF_DEFAULT_VALUE = "default-value"; 42 | private static final String PLUGIN_XML_PATH = "META-INF/maven/plugin.xml"; 43 | 44 | public static Map getMojoDefaultConfiguration(Class mojoClass) throws Exception { 45 | Map defaultConfiguration = new LinkedHashMap<>(); 46 | InputStream inputStream = PluginXmlParser.class.getClassLoader().getResourceAsStream(PLUGIN_XML_PATH); 47 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 48 | DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 49 | Document doc = dBuilder.parse(inputStream); 50 | doc.getDocumentElement().normalize(); 51 | 52 | Element mojoElement = findMojoByClass(doc, mojoClass.getName()); 53 | if (mojoElement == null) { 54 | throw new RuntimeException("Mojo not found for class: " + mojoClass.getName()); 55 | } 56 | 57 | Element configurationElement = 58 | (Element) mojoElement.getElementsByTagName("configuration").item(0); 59 | NodeList configurationList = configurationElement.getChildNodes(); 60 | for (int i = 0; i < configurationList.getLength(); i++) { 61 | Node child = configurationList.item(i); 62 | if (child.getNodeType() != Node.ELEMENT_NODE) { 63 | continue; 64 | } 65 | configurationElement = (Element) child; 66 | String configurationParameterName = configurationElement.getTagName(); 67 | 68 | if (configurationElement.hasAttribute(CONF_DEFAULT_VALUE)) { 69 | String defaultValue = configurationElement.getAttribute(CONF_DEFAULT_VALUE); 70 | defaultConfiguration.put(configurationParameterName, defaultValue); 71 | } else { 72 | if (configurationElement.hasAttribute("implementation")) { 73 | String implementation = configurationElement.getAttribute("implementation"); 74 | // String arrays are per default set to empty array if user does not configure them 75 | if ("java.lang.String[]".equals(implementation)) { 76 | defaultConfiguration.put(configurationParameterName, ""); 77 | } 78 | } 79 | } 80 | } 81 | return defaultConfiguration; 82 | } 83 | 84 | /** Searches in every mojo tag for an implementation tag matching the class name */ 85 | private static Element findMojoByClass(Document doc, String className) { 86 | NodeList mojoList = doc.getElementsByTagName(MOJO_TAG); 87 | for (int i = 0; i < mojoList.getLength(); i++) { 88 | Element mojoElement = (Element) mojoList.item(i); 89 | String mojoClass = getTextContent(mojoElement, MOJO_IMPLEMENTATION_TAG); 90 | if (mojoClass.equals(className)) { 91 | return mojoElement; 92 | } 93 | } 94 | return null; 95 | } 96 | 97 | private static String getTextContent(Element parentElement, String tagName) { 98 | NodeList nodeList = parentElement.getElementsByTagName(tagName); 99 | if (nodeList.getLength() > 0) { 100 | return nodeList.item(0).getTextContent(); 101 | } 102 | return null; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/RequestMatchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.util.Arrays; 22 | import java.util.List; 23 | import java.util.function.Predicate; 24 | 25 | import org.apache.maven.shared.jarsigner.AbstractJarSignerRequest; 26 | import org.apache.maven.shared.jarsigner.JarSignerSignRequest; 27 | import org.hamcrest.Description; 28 | import org.hamcrest.TypeSafeMatcher; 29 | 30 | /** 31 | * Hamcrest matcher(s) to match properties on a JarSignerRequest request instances 32 | */ 33 | class RequestMatchers { 34 | 35 | /** Matcher for parameters common for JarSignerRequest instances */ 36 | private static class AbstractJarSignerRequestMatcher 37 | extends TypeSafeMatcher { 38 | private final String predicateDescription; 39 | private final Object value; 40 | private final Predicate predicate; 41 | 42 | private AbstractJarSignerRequestMatcher( 43 | String predicateDescription, Object value, Predicate predicate) { 44 | this.predicateDescription = predicateDescription; 45 | this.value = value; 46 | this.predicate = predicate; 47 | } 48 | 49 | @Override 50 | protected boolean matchesSafely(AbstractJarSignerRequest request) { 51 | return predicate.test(request); 52 | } 53 | 54 | @Override 55 | public void describeTo(Description description) { 56 | description 57 | .appendText("request that ") 58 | .appendText(predicateDescription) 59 | .appendValue(value); 60 | } 61 | } 62 | 63 | /** Matcher for parameters specific to JarSignerSignRequest instances */ 64 | private static class JarSignerSignRequestMatcher extends TypeSafeMatcher { 65 | private final String predicateDescription; 66 | private final Object value; 67 | private final Predicate predicate; 68 | 69 | private JarSignerSignRequestMatcher( 70 | String predicateDescription, Object value, Predicate predicate) { 71 | this.predicateDescription = predicateDescription; 72 | this.value = value; 73 | this.predicate = predicate; 74 | } 75 | 76 | @Override 77 | protected boolean matchesSafely(JarSignerSignRequest request) { 78 | return predicate.test(request); 79 | } 80 | 81 | @Override 82 | public void describeTo(Description description) { 83 | description 84 | .appendText("request that ") 85 | .appendText(predicateDescription) 86 | .appendValue(value); 87 | } 88 | } 89 | 90 | /** Create a matcher that matches when the request is using a specific file name for the archive */ 91 | static TypeSafeMatcher hasFileName(String expectedFileName) { 92 | return new AbstractJarSignerRequestMatcher( 93 | "has archive file name ", 94 | expectedFileName, 95 | request -> request.getArchive().getPath().endsWith(expectedFileName)); 96 | } 97 | 98 | static TypeSafeMatcher hasAlias(String alias) { 99 | return new AbstractJarSignerRequestMatcher( 100 | "has alias ", alias, request -> request.getAlias().equals(alias)); 101 | } 102 | 103 | static TypeSafeMatcher hasArguments(String[] arguments) { 104 | return new AbstractJarSignerRequestMatcher("has arguments ", arguments, request -> { 105 | List haystack = Arrays.asList(request.getArguments()); 106 | for (String argumentNeedle : arguments) { 107 | if (!haystack.contains(argumentNeedle)) { 108 | return false; 109 | } 110 | } 111 | return true; 112 | }); 113 | } 114 | 115 | static TypeSafeMatcher hasKeystore(String keystore) { 116 | return new AbstractJarSignerRequestMatcher( 117 | "has keystore ", keystore, request -> request.getKeystore().equals(keystore)); 118 | } 119 | 120 | static TypeSafeMatcher hasMaxMemory(String maxMemory) { 121 | return new AbstractJarSignerRequestMatcher( 122 | "has maxMemory ", maxMemory, request -> request.getMaxMemory().equals(maxMemory)); 123 | } 124 | 125 | static TypeSafeMatcher hasProtectedAuthenticationPath( 126 | boolean protectedAuthenticationPath) { 127 | return new AbstractJarSignerRequestMatcher( 128 | "has protectedAuthenticationPath ", 129 | protectedAuthenticationPath, 130 | request -> request.isProtectedAuthenticationPath() == protectedAuthenticationPath); 131 | } 132 | 133 | static TypeSafeMatcher hasProviderArg(String providerArg) { 134 | return new AbstractJarSignerRequestMatcher( 135 | "has providerArg ", providerArg, request -> request.getProviderArg() 136 | .equals(providerArg)); 137 | } 138 | 139 | static TypeSafeMatcher hasProviderClass(String providerClass) { 140 | return new AbstractJarSignerRequestMatcher( 141 | "has providerClass ", providerClass, request -> request.getProviderClass() 142 | .equals(providerClass)); 143 | } 144 | 145 | static TypeSafeMatcher hasProviderName(String providerName) { 146 | return new AbstractJarSignerRequestMatcher( 147 | "has providerName ", providerName, request -> request.getProviderName() 148 | .equals(providerName)); 149 | } 150 | 151 | static TypeSafeMatcher hasStorepass(String storepass) { 152 | return new AbstractJarSignerRequestMatcher( 153 | "has storepass ", storepass, request -> request.getStorepass().equals(storepass)); 154 | } 155 | 156 | static TypeSafeMatcher hasStoretype(String storetype) { 157 | return new AbstractJarSignerRequestMatcher( 158 | "has storetype ", storetype, request -> request.getStoretype().equals(storetype)); 159 | } 160 | 161 | static TypeSafeMatcher hasVerbose(boolean verbose) { 162 | return new AbstractJarSignerRequestMatcher( 163 | "has verbose ", verbose, request -> request.isVerbose() == verbose); 164 | } 165 | 166 | /* ************************************ JarSignerSignRequest specific matchers ************************************/ 167 | 168 | static TypeSafeMatcher hasKeypass(String keypass) { 169 | return new JarSignerSignRequestMatcher( 170 | "has keypass ", keypass, request -> request.getKeypass().equals(keypass)); 171 | } 172 | 173 | static TypeSafeMatcher hasSigfile(String sigfile) { 174 | return new JarSignerSignRequestMatcher( 175 | "has sigfile ", sigfile, request -> request.getSigfile().equals(sigfile)); 176 | } 177 | 178 | static TypeSafeMatcher hasTsa(String tsa) { 179 | return new JarSignerSignRequestMatcher( 180 | "has tsa ", tsa, request -> request.getTsaLocation().equals(tsa)); 181 | } 182 | 183 | static TypeSafeMatcher hasTsacert(String tsacert) { 184 | return new JarSignerSignRequestMatcher( 185 | "has tsacert ", tsacert, request -> request.getTsaAlias().equals(tsacert)); 186 | } 187 | 188 | static TypeSafeMatcher hasTsaPolicyid(String tsapolicyid) { 189 | return new JarSignerSignRequestMatcher("has tsapolicyid ", tsapolicyid, request -> request.getTsapolicyid() 190 | .equals(tsapolicyid)); 191 | } 192 | 193 | static TypeSafeMatcher hasTsaDigestalg(String tsadigestalg) { 194 | return new JarSignerSignRequestMatcher("has tsadigestalg ", tsadigestalg, request -> request.getTsadigestalg() 195 | .equals(tsadigestalg)); 196 | } 197 | 198 | static TypeSafeMatcher hasCertchain(String certchain) { 199 | return new JarSignerSignRequestMatcher("has certchain ", certchain, request -> request.getCertchain() 200 | .getPath() 201 | .equals(certchain)); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/TestArtifacts.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.io.File; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | import java.util.zip.ZipEntry; 26 | import java.util.zip.ZipOutputStream; 27 | 28 | import org.apache.maven.artifact.Artifact; 29 | import org.apache.maven.artifact.DefaultArtifact; 30 | 31 | /** 32 | * Test utility class to create Artifact objects, jar file or other files that Maven attaches to a project 33 | */ 34 | class TestArtifacts { 35 | static final String TEST_GROUPID = "org.test-group"; 36 | static final String TEST_ARTIFACTID = "test-artifact"; 37 | static final String TEST_VERSION = "9.10.2"; 38 | static final String TEST_TYPE = "jar"; 39 | static final String TEST_CLASSIFIER = ""; 40 | 41 | static Artifact createArtifact(File file) throws IOException { 42 | return createArtifact(file, TEST_TYPE, TEST_CLASSIFIER); 43 | } 44 | 45 | static Artifact createArtifact(File file, String type, String classifier) throws IOException { 46 | Artifact artifact = new DefaultArtifact( 47 | TEST_GROUPID, TEST_ARTIFACTID, TEST_VERSION, Artifact.SCOPE_COMPILE, type, classifier, null); 48 | artifact.setFile(file); 49 | return artifact; 50 | } 51 | 52 | static Artifact createJarArtifact(File directory, String filename) throws IOException { 53 | return createJarArtifact(directory, filename, TEST_CLASSIFIER); 54 | } 55 | 56 | public static Artifact createJarArtifact(File directory, String filename, String classifier) throws IOException { 57 | return createJarArtifact(directory, filename, classifier, TEST_TYPE); 58 | } 59 | 60 | public static Artifact createJarArtifact(File directory, String filename, String classifier, String type) 61 | throws IOException { 62 | File file = new File(directory, filename); 63 | createDummyZipFile(file); 64 | return createArtifact(file, type, classifier); 65 | } 66 | 67 | static Artifact createPomArtifact(File directory, String filename) throws IOException { 68 | File file = new File(directory, filename); 69 | createDummyXMLFile(file); 70 | return createArtifact(file, TEST_TYPE, ""); 71 | } 72 | 73 | /** Create a dummy JAR/ZIP file, enough to pass ZipInputStream.getNextEntry() */ 74 | static File createDummyZipFile(File zipFile) throws IOException { 75 | try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile))) { 76 | ZipEntry entry = new ZipEntry("dummy-entry.txt"); 77 | zipOutputStream.putNextEntry(entry); 78 | } 79 | return zipFile; 80 | } 81 | 82 | /** Create a dummy signed JAR, enough to pass JarSignerUtil.isArchiveSigned() */ 83 | static File createDummySignedJarFile(File jarFile) throws IOException { 84 | try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(jarFile))) { 85 | ZipEntry entry = new ZipEntry("dummy-entry.txt"); 86 | zipOutputStream.putNextEntry(entry); 87 | zipOutputStream.putNextEntry(new ZipEntry("META-INF/dummy.RSA")); 88 | } 89 | 90 | return jarFile; 91 | } 92 | 93 | /** Create a dummy XML file, for example to simulate a pom.xml file */ 94 | static File createDummyXMLFile(File xmlFile) throws IOException { 95 | Files.write(xmlFile.toPath(), "".getBytes()); 96 | return xmlFile; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/TestJavaToolResults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import org.apache.maven.shared.utils.cli.Commandline; 22 | import org.apache.maven.shared.utils.cli.javatool.JavaToolResult; 23 | import org.apache.maven.shared.utils.cli.shell.Shell; 24 | 25 | /** 26 | * Results from an invocation to {@link org.apache.maven.shared.utils.cli.javatool.JavaTool} to be used in tests. 27 | */ 28 | class TestJavaToolResults { 29 | static final JavaToolResult RESULT_OK = createOk(); 30 | static final JavaToolResult RESULT_ERROR = createError(); 31 | 32 | private static JavaToolResult createOk() { 33 | JavaToolResult result = new JavaToolResult(); 34 | result.setExitCode(0); 35 | result.setExecutionException(null); 36 | result.setCommandline(getSimpleCommandline()); 37 | return result; 38 | } 39 | 40 | private static JavaToolResult createError() { 41 | JavaToolResult result = new JavaToolResult(); 42 | result.setExitCode(1); 43 | result.setExecutionException(null); 44 | result.setCommandline(getSimpleCommandline()); 45 | return result; 46 | } 47 | 48 | private static Commandline getSimpleCommandline() { 49 | Shell shell = new Shell(); 50 | Commandline commandline = new Commandline(shell); 51 | commandline.setExecutable("jarsigner"); 52 | commandline.addArguments("my-project.jar", "myalias"); 53 | return commandline; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/plugins/jarsigner/TsaSelectorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.plugins.jarsigner; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | import java.util.concurrent.ExecutorService; 23 | import java.util.concurrent.Executors; 24 | import java.util.concurrent.Semaphore; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.concurrent.atomic.AtomicReference; 27 | 28 | import org.apache.maven.plugins.jarsigner.TsaSelector.TsaServer; 29 | import org.junit.Test; 30 | 31 | import static org.junit.Assert.*; 32 | 33 | public class TsaSelectorTest { 34 | private static final String[] EMPTY = new String[0]; 35 | private TsaSelector tsaSelector; 36 | private TsaServer tsaServer; 37 | private ExecutorService executor; 38 | 39 | @Test 40 | public void testNullInit() { 41 | tsaSelector = new TsaSelector(EMPTY, EMPTY, EMPTY, null); 42 | tsaServer = tsaSelector.getServer(); 43 | assertNull(tsaServer.getTsaUrl()); 44 | assertNull(tsaServer.getTsaAlias()); 45 | assertNull(tsaServer.getTsaPolicyId()); 46 | assertNull(tsaServer.getTsaDigestAlg()); 47 | 48 | // Make sure "next" server also contains null values 49 | tsaServer = tsaSelector.getServer(); 50 | assertNull(tsaServer.getTsaUrl()); 51 | assertNull(tsaServer.getTsaAlias()); 52 | assertNull(tsaServer.getTsaPolicyId()); 53 | assertNull(tsaServer.getTsaDigestAlg()); 54 | } 55 | 56 | @Test 57 | public void testFailureCount() { 58 | tsaSelector = new TsaSelector( 59 | new String[] {"http://url1.com", "http://url2.com", "http://url3.com"}, EMPTY, EMPTY, null); 60 | 61 | tsaServer = tsaSelector.getServer(); 62 | assertEquals("http://url1.com", tsaServer.getTsaUrl()); 63 | assertNull(tsaServer.getTsaAlias()); 64 | assertNull(tsaServer.getTsaPolicyId()); 65 | assertNull(tsaServer.getTsaDigestAlg()); 66 | 67 | tsaSelector.registerFailure(); 68 | 69 | tsaServer = tsaSelector.getServer(); 70 | assertEquals("http://url2.com", tsaServer.getTsaUrl()); 71 | assertNull(tsaServer.getTsaAlias()); 72 | assertNull(tsaServer.getTsaPolicyId()); 73 | assertNull(tsaServer.getTsaDigestAlg()); 74 | 75 | // Should get same server again 76 | tsaServer = tsaSelector.getServer(); 77 | assertEquals("http://url2.com", tsaServer.getTsaUrl()); 78 | assertNull(tsaServer.getTsaAlias()); 79 | assertNull(tsaServer.getTsaPolicyId()); 80 | assertNull(tsaServer.getTsaDigestAlg()); 81 | } 82 | 83 | @Test(timeout = 30000) 84 | public void testMultiThreadedScenario() throws InterruptedException { 85 | executor = Executors.newFixedThreadPool(2); 86 | 87 | tsaSelector = new TsaSelector( 88 | new String[] {"http://url1.com", "http://url2.com", "http://url3.com"}, EMPTY, EMPTY, null); 89 | 90 | // Register a single failure on the first URL so that the threads will use URL 2 91 | TsaServer serverThreadMain = tsaSelector.getServer(); 92 | tsaSelector.registerFailure(); 93 | 94 | CountDownLatch doneSignal = new CountDownLatch(2); // Indication that both threads has gotten a server 95 | Semaphore semaphore = new Semaphore(0); // When the threads may continue executing after gotten a server 96 | 97 | AtomicReference serverThread1 = new AtomicReference<>(); 98 | AtomicReference serverThread2 = new AtomicReference<>(); 99 | executor.submit(() -> { 100 | serverThread1.set(tsaSelector.getServer()); 101 | doneSignal.countDown(); 102 | semaphore.acquireUninterruptibly(); 103 | tsaSelector.registerFailure(); 104 | }); 105 | executor.submit(() -> { 106 | serverThread2.set(tsaSelector.getServer()); 107 | doneSignal.countDown(); 108 | semaphore.acquireUninterruptibly(); 109 | tsaSelector.registerFailure(); 110 | }); 111 | 112 | doneSignal.await(); // Wait until both threads has gotten an TsaServer 113 | semaphore.release(2); // Release both threads waiting for the semaphore 114 | 115 | executor.shutdown(); 116 | executor.awaitTermination(10, TimeUnit.SECONDS); 117 | 118 | assertEquals("http://url1.com", serverThreadMain.getTsaUrl()); 119 | assertEquals("http://url2.com", serverThread1.get().getTsaUrl()); 120 | assertEquals("http://url2.com", serverThread2.get().getTsaUrl()); 121 | 122 | // The best URL is now number 3 123 | assertEquals("http://url3.com", tsaSelector.getServer().getTsaUrl()); 124 | 125 | // Trigger a new failure, now URL 1 is best again. 126 | tsaSelector.registerFailure(); 127 | assertEquals("http://url1.com", tsaSelector.getServer().getTsaUrl()); 128 | } 129 | 130 | @Test 131 | public void testDigestAlgoritm() { 132 | tsaSelector = new TsaSelector( 133 | new String[] {"http://url1.com", "http://url2.com", "http://url3.com"}, EMPTY, EMPTY, "SHA-512"); 134 | tsaServer = tsaSelector.getServer(); 135 | assertEquals("http://url1.com", tsaServer.getTsaUrl()); 136 | assertNull(tsaServer.getTsaAlias()); 137 | assertNull(tsaServer.getTsaPolicyId()); 138 | assertEquals("SHA-512", tsaServer.getTsaDigestAlg()); 139 | 140 | // Make sure that the next URL has the same digest algorithm 141 | tsaSelector.registerFailure(); 142 | tsaServer = tsaSelector.getServer(); 143 | assertEquals("http://url2.com", tsaServer.getTsaUrl()); 144 | assertNull(tsaServer.getTsaAlias()); 145 | assertNull(tsaServer.getTsaPolicyId()); 146 | assertEquals("SHA-512", tsaServer.getTsaDigestAlg()); 147 | } 148 | 149 | @Test 150 | public void testKeyStoreAliasAndOid() { 151 | tsaSelector = new TsaSelector(EMPTY, new String[] {"alias1", "alias2"}, new String[] {"1.1", "1.2"}, null); 152 | tsaServer = tsaSelector.getServer(); 153 | assertNull(tsaServer.getTsaUrl()); 154 | assertEquals("alias1", tsaServer.getTsaAlias()); 155 | assertEquals("1.1", tsaServer.getTsaPolicyId()); 156 | 157 | tsaSelector.registerFailure(); 158 | tsaServer = tsaSelector.getServer(); 159 | assertNull(tsaServer.getTsaUrl()); 160 | assertEquals("alias2", tsaServer.getTsaAlias()); 161 | assertEquals("1.2", tsaServer.getTsaPolicyId()); 162 | } 163 | 164 | @Test 165 | public void testFailureRegistrationWithoutCurrent() { 166 | tsaSelector = new TsaSelector( 167 | new String[] {"http://url1.com"}, new String[] {"alias1"}, new String[] {"1.1"}, "SHA-384"); 168 | tsaSelector.registerFailure(); // Should not throw any exception 169 | 170 | // Make sure further execution works 171 | tsaServer = tsaSelector.getServer(); 172 | assertEquals("http://url1.com", tsaServer.getTsaUrl()); 173 | assertEquals("alias1", tsaServer.getTsaAlias()); 174 | assertEquals("1.1", tsaServer.getTsaPolicyId()); 175 | assertEquals("SHA-384", tsaServer.getTsaDigestAlg()); 176 | } 177 | } 178 | --------------------------------------------------------------------------------