├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── base
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── ro
│ └── esolutions
│ └── licensing
│ ├── encryption
│ ├── FilePrivateKeyDataProvider.java
│ ├── PrivateKeyDataProvider.java
│ ├── RSAKeyPairGenerator.java
│ └── RSAKeyPairGeneratorInterface.java
│ ├── exception
│ └── RSA2048NotSupportedException.java
│ └── licensor
│ ├── LicenseCreator.java
│ └── LicenseCreatorProperties.java
├── core
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── ro
│ └── esolutions
│ └── licensing
│ ├── DataSignatureManager.java
│ ├── DefaultLicenseValidator.java
│ ├── DeserializingLicenseProvider.java
│ ├── Feature.java
│ ├── FeatureRestriction.java
│ ├── FeatureRestrictionOperand.java
│ ├── FileLicenseProvider.java
│ ├── License.java
│ ├── LicenseManager.java
│ ├── LicenseManagerProperties.java
│ ├── LicenseProvider.java
│ ├── LicenseSecurityManager.java
│ ├── LicenseValidator.java
│ ├── ObjectSerializer.java
│ ├── SignedLicense.java
│ ├── encryption
│ ├── Encryptor.java
│ ├── FilePublicKeyDataProvider.java
│ ├── Hasher.java
│ ├── KeyFileUtilities.java
│ ├── PasswordProvider.java
│ └── PublicKeyDataProvider.java
│ ├── exception
│ ├── AlgorithmNotSupportedException.java
│ ├── CorruptSignatureException.java
│ ├── ExpiredLicenseException.java
│ ├── FailedToDecryptException.java
│ ├── InappropriateKeyException.java
│ ├── InappropriateKeySpecificationException.java
│ ├── InsecureEnvironmentError.java
│ ├── InvalidLicenseException.java
│ ├── InvalidSignatureException.java
│ ├── KeyNotFoundException.java
│ ├── ObjectDeserializationException.java
│ ├── ObjectSerializationException.java
│ └── ObjectTypeNotExpectedException.java
│ └── immutable
│ ├── Immutable.java
│ ├── ImmutableAbstractCollection.java
│ ├── ImmutableArrayList.java
│ ├── ImmutableIterator.java
│ ├── ImmutableLinkedHashSet.java
│ ├── ImmutableListIterator.java
│ ├── ImmutableModifiedThroughReflectionException.java
│ └── ValidObject.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | license-manager.iml
2 | .idea/
3 |
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk: openjdk17
3 | script: mvn -B -V clean install
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # license-manager
2 | Java library for generation and validation of software licenses (forked from OddSource/java-license-manager).
3 |
4 | [](https://travis-ci.org/eSolutionsGrup/license-manager)
5 |
--------------------------------------------------------------------------------
/base/.gitignore:
--------------------------------------------------------------------------------
1 | license-manager-base.iml
2 | target
3 |
--------------------------------------------------------------------------------
/base/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
21 | 4.0.0
22 |
23 |
24 | ro.esolutions
25 | license-manager
26 | 1.0.4-SNAPSHOT
27 |
28 |
29 | license-manager-base
30 | jar
31 |
32 | License Manager - Base
33 |
34 |
35 |
36 | ro.esolutions
37 | license-manager-core
38 | ${project.version}
39 |
40 |
41 |
42 | commons-io
43 | commons-io
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/encryption/FilePrivateKeyDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FilePrivateKeyDataProvider.java from LicenseManager modified Thursday, January 24, 2013 16:41:55 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package ro.esolutions.licensing.encryption;
19 |
20 | import org.apache.commons.io.FileUtils;
21 |
22 | import java.io.File;
23 | import java.io.FileNotFoundException;
24 | import java.io.IOException;
25 |
26 | import ro.esolutions.licensing.exception.KeyNotFoundException;
27 |
28 | /**
29 | * A default implementation of {@link PrivateKeyDataProvider} that reads the private key from a file.
30 | *
31 | * This provider is immutable. Once created, the file that the private key is located at cannot be changed.
32 | *
33 | * @author Nick Williams
34 | * @version 1.0.0
35 | * @since 1.0.0
36 | */
37 | public class FilePrivateKeyDataProvider implements PrivateKeyDataProvider {
38 | private final File privateKeyFile;
39 |
40 | /**
41 | * Create a new provider, specifying the file from which the private key can be read.
42 | *
43 | * @param privateKeyFile the private key file
44 | */
45 | public FilePrivateKeyDataProvider(final File privateKeyFile) {
46 | this.privateKeyFile = privateKeyFile.getAbsoluteFile();
47 | }
48 |
49 | /**
50 | * Create a new provider, specifying the name of the file from which the private key can be read.
51 | *
52 | * @param privateKeyFileName The private key file name
53 | */
54 | public FilePrivateKeyDataProvider(final String privateKeyFileName) {
55 | this.privateKeyFile = new File(privateKeyFileName).getAbsoluteFile();
56 | }
57 |
58 | /**
59 | * This method returns the data from the file containing the encrypted
60 | * private key from the public/private key pair. The contract for this
61 | * method can be fulfilled by storing the data in a byte array literal
62 | * in the source code itself.
63 | *
64 | * It is imperative that you obfuscate the bytecode for the
65 | * implementation of this class. It is also imperative that the byte
66 | * array exist only for the life of this method (i.e., DO NOT store it as
67 | * an instance or class field).
68 | *
69 | * @return the encrypted file contents from the private key file.
70 | * @throws ro.esolutions.licensing.exception.KeyNotFoundException if the key data could not be retrieved; an
71 | * acceptable message or chained cause must be
72 | * provided.
73 | */
74 | @Override
75 | public byte[] getEncryptedPrivateKeyData() throws KeyNotFoundException {
76 | try {
77 | return FileUtils.readFileToByteArray(this.privateKeyFile);
78 | } catch (final FileNotFoundException e) {
79 | throw new KeyNotFoundException("The private key file [" + this.privateKeyFile.getPath() +
80 | "] does not exist.");
81 | } catch (final IOException e) {
82 | throw new KeyNotFoundException("Could not read from the private key file [" +
83 | this.privateKeyFile.getPath() + "].", e);
84 | }
85 | }
86 |
87 | /**
88 | * Gets the file that the private key is located at.
89 | *
90 | * @return the file.
91 | */
92 | public File getPrivateKeyFile() {
93 | return this.privateKeyFile;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/encryption/PrivateKeyDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PrivateKeyDataProvider.java from LicenseManager modified Thursday, January 24, 2013 16:37:10 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import ro.esolutions.licensing.exception.KeyNotFoundException;
22 |
23 | /**
24 | * Specifies an interface for retrieving the private key file data. This
25 | * interface only needs to be implemented in the application generating the
26 | * licenses. It need not (and for security reasons should not) be implemented
27 | * in the application using the licenses.
28 | *
29 | * @author Nick Williams
30 | * @version 1.0.0
31 | * @since 1.0.0
32 | */
33 | public interface PrivateKeyDataProvider {
34 | /**
35 | * This method returns the data from the file containing the encrypted
36 | * private key from the public/private key pair. The contract for this
37 | * method can be fulfilled by storing the data in a byte array literal
38 | * in the source code itself.
39 | *
40 | * It is imperative that you obfuscate the bytecode for the
41 | * implementation of this class. It is also imperative that the byte
42 | * array exist only for the life of this method (i.e., DO NOT store it as
43 | * an instance or class field).
44 | *
45 | * @return the encrypted file contents from the private key file.
46 | * @throws KeyNotFoundException if the key data could not be retrieved; an acceptable message or chained cause must
47 | * be provided.
48 | */
49 | byte[] getEncryptedPrivateKeyData() throws KeyNotFoundException;
50 | }
51 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/encryption/RSAKeyPairGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * RSAKeyPairGenerator.java from LicenseManager modified Thursday, January 24, 2013 16:37:10 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.security.InvalidParameterException;
24 | import java.security.KeyPair;
25 | import java.security.KeyPairGenerator;
26 | import java.security.NoSuchAlgorithmException;
27 | import java.security.PrivateKey;
28 | import java.security.PublicKey;
29 |
30 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
31 | import ro.esolutions.licensing.exception.InappropriateKeyException;
32 | import ro.esolutions.licensing.exception.InappropriateKeySpecificationException;
33 | import ro.esolutions.licensing.exception.RSA2048NotSupportedException;
34 |
35 | /**
36 | * The generator one should use to create public/private key pairs for use with
37 | * the application.
38 | *
39 | * @author Nick Williams
40 | * @version 1.0.0
41 | * @since 1.0.0
42 | */
43 | public final class RSAKeyPairGenerator implements RSAKeyPairGeneratorInterface {
44 |
45 | /**
46 | * Generates a key pair with RSA 2048-bit security.
47 | *
48 | * @return a public/private key pair.
49 | * @throws RSA2048NotSupportedException if RSA or 2048-bit encryption are not supported.
50 | */
51 | @Override
52 | public KeyPair generateKeyPair() throws RSA2048NotSupportedException {
53 | KeyPairGenerator keyGenerator;
54 |
55 | try {
56 | keyGenerator = KeyPairGenerator.getInstance(KeyFileUtilities.KEY_ALGORITHM);
57 | } catch (final NoSuchAlgorithmException e) {
58 | throw new RSA2048NotSupportedException("RSA keys are not supported on your system. Contact your system administrator for assistance.", e);
59 | }
60 |
61 | try {
62 | keyGenerator.initialize(2048);
63 | } catch (final InvalidParameterException e) {
64 | throw new RSA2048NotSupportedException("RSA is supported on your system, but 2048-bit keys are not. Contact your system administrator for assistance.", e);
65 | }
66 |
67 | return keyGenerator.generateKeyPair();
68 | }
69 |
70 | /**
71 | * Saves the key pair specified to output files specified, encrypting both with the specified password.
72 | *
73 | * @param keyPair The key pair to save to the files specified
74 | * @param privateOutputFileName The name of the file to save the encrypted private key to
75 | * @param publicOutputFileName The name of the file to save the encrypted public key to
76 | * @param password The password to encrypt both keys with
77 | * @throws IOException if an error occurs while writing to the files.
78 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
79 | * @throws InappropriateKeyException If the public or private keys are invalid
80 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
81 | */
82 | @Override
83 | public void saveKeyPairToFiles(final KeyPair keyPair,final String privateOutputFileName,final String publicOutputFileName,
84 | final char[] password)
85 | throws IOException, AlgorithmNotSupportedException, InappropriateKeyException,
86 | InappropriateKeySpecificationException {
87 | this.saveKeyPairToFiles(keyPair, privateOutputFileName, publicOutputFileName, password, password);
88 | }
89 |
90 | /**
91 | * Saves the key pair specified to output files specified, encrypting each with their specified passwords.
92 | *
93 | * @param keyPair The key pair to save to the files specified
94 | * @param privateOutputFileName The name of the file to save the encrypted private key to
95 | * @param publicOutputFileName The name of the file to save the encrypted public key to
96 | * @param privatePassword The password to encrypt the private key with
97 | * @param publicPassword The password to encrypt the public key with
98 | * @throws IOException if an error occurs while writing to the files.
99 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
100 | * @throws InappropriateKeyException If the public or private keys are invalid
101 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
102 | */
103 | @Override
104 | public void saveKeyPairToFiles(final KeyPair keyPair,final String privateOutputFileName,final String publicOutputFileName,
105 | final char[] privatePassword,final char[] publicPassword)
106 | throws IOException, AlgorithmNotSupportedException, InappropriateKeyException,
107 | InappropriateKeySpecificationException {
108 | final PrivateKey privateKey = keyPair.getPrivate();
109 | final PublicKey publicKey = keyPair.getPublic();
110 |
111 | KeyFileUtilities.writeEncryptedPrivateKey(privateKey, new File(privateOutputFileName), privatePassword);
112 | KeyFileUtilities.writeEncryptedPublicKey(publicKey, new File(publicOutputFileName), publicPassword);
113 | }
114 |
115 | /**
116 | * Saves the public and private keys specified to the respective
117 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} fields in
118 | * the provided {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor}s, encrypting both with the specified
119 | * password.
120 | *
121 | * @param keyPair The key pair to save
122 | * @param privateKeyProvider An object describing the {@link PrivateKeyDataProvider} class to generate, and into
123 | * which the generated code will be saved
124 | * @param publicKeyProvider An object describing the {@link PublicKeyDataProvider} class to generate, and into
125 | * which the generated code will be saved
126 | * @param password The password to encrypt the keys with
127 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
128 | * @throws InappropriateKeyException If the public or private keys are invalid
129 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
130 | */
131 | @Override
132 | public void saveKeyPairToProviders(final KeyPair keyPair,final GeneratedClassDescriptor privateKeyProvider,
133 | final GeneratedClassDescriptor publicKeyProvider,final char[] password)
134 | throws AlgorithmNotSupportedException, InappropriateKeyException, InappropriateKeySpecificationException {
135 | this.saveKeyPairToProviders(keyPair, privateKeyProvider, publicKeyProvider, password, password);
136 | }
137 |
138 | /**
139 | * Saves the public and private keys specified to the respective
140 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} fields in
141 | * the provided {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor}s, encrypting each with their
142 | * respective passwords.
143 | *
144 | * @param keyPair The key pair to save
145 | * @param privateKeyProvider An object describing the {@link PrivateKeyDataProvider} class to generate, and into
146 | * which the generated code will be saved
147 | * @param publicKeyProvider An object describing the {@link PublicKeyDataProvider} class to generate, and into
148 | * which the generated code will be saved
149 | * @param privatePassword The password to encrypt the private key with
150 | * @param publicPassword The password to encrypt the public key with
151 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
152 | * @throws InappropriateKeyException If the public or private keys are invalid
153 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
154 | */
155 | @Override
156 | public void saveKeyPairToProviders(final KeyPair keyPair,final GeneratedClassDescriptor privateKeyProvider,
157 | final GeneratedClassDescriptor publicKeyProvider,final char[] privatePassword,
158 | final char[] publicPassword)
159 | throws AlgorithmNotSupportedException, InappropriateKeyException, InappropriateKeySpecificationException {
160 | if (keyPair == null)
161 | throw new IllegalArgumentException("Parameter keyPair cannot be null.");
162 |
163 | if (privateKeyProvider == null)
164 | throw new IllegalArgumentException("Parameter privateKeyProvider cannot be null.");
165 |
166 | if (publicKeyProvider == null)
167 | throw new IllegalArgumentException("Parameter publicKeyProvider cannot be null.");
168 |
169 | if (passwordInValid(privatePassword))
170 | throw new IllegalArgumentException("Parameter privatePassword cannot be null or zero-length.");
171 |
172 | if (passwordInValid(publicPassword))
173 | throw new IllegalArgumentException("Parameter publicPassword cannot be null or zero-length.");
174 |
175 | final byte[] privateKey = KeyFileUtilities.writeEncryptedPrivateKey(keyPair.getPrivate(), privatePassword);
176 | final byte[] publicKey = KeyFileUtilities.writeEncryptedPublicKey(keyPair.getPublic(), publicPassword);
177 |
178 | final String privateKeyCode = this.arrayToCodeString(this.byteArrayToIntArray(privateKey), "byte");
179 | final String publicKeyCode = this.arrayToCodeString(this.byteArrayToIntArray(publicKey), "byte");
180 |
181 | privateKeyProvider.setJavaFileContents(this.generateJavaCode(
182 | privateKeyProvider.getPackageName(),
183 | privateKeyProvider.getClassName(),
184 | "PrivateKeyDataProvider",
185 | new String[]{
186 | "ro.esolutions.licensing.encryption.PrivateKeyDataProvider",
187 | "ro.esolutions.licensing.exception.KeyNotFoundException"
188 | },
189 | "public byte[] getEncryptedPrivateKeyData() throws KeyNotFoundException",
190 | privateKeyCode
191 | ));
192 |
193 | publicKeyProvider.setJavaFileContents(this.generateJavaCode(
194 | publicKeyProvider.getPackageName(),
195 | publicKeyProvider.getClassName(),
196 | "PublicKeyDataProvider",
197 | new String[]{
198 | "ro.esolutions.licensing.encryption.PublicKeyDataProvider",
199 | "ro.esolutions.licensing.exception.KeyNotFoundException"
200 | },
201 | "public byte[] getEncryptedPublicKeyData() throws KeyNotFoundException",
202 | publicKeyCode
203 | ));
204 | }
205 |
206 | /**
207 | * Saves the password specified to the
208 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} field in
209 | * the provided {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor}.
210 | *
211 | * @param password The password to save to the specified Java class
212 | * @param passwordProvider An object describing the {@link PasswordProvider} class to generate, and into which the
213 | * generated code will be saved
214 | */
215 | @Override
216 | public void savePasswordToProvider(final char[] password,final GeneratedClassDescriptor passwordProvider) {
217 | if (passwordInValid(password))
218 | throw new IllegalArgumentException("Parameter password cannot be null or zero-length.");
219 |
220 | if (passwordProvider == null)
221 | throw new IllegalArgumentException("Parameter passwordProvider cannot be null.");
222 |
223 | final String passwordCode = this.arrayToCodeString(this.charArrayToIntArray(password), "char");
224 |
225 | passwordProvider.setJavaFileContents(this.generateJavaCode(
226 | passwordProvider.getPackageName(),
227 | passwordProvider.getClassName(),
228 | "PasswordProvider",
229 | new String[]{"ro.esolutions.licensing.encryption.PasswordProvider"},
230 | "public char[] getPassword()",
231 | passwordCode
232 | ));
233 | }
234 |
235 | private boolean passwordInValid(final char[] password) {
236 | return password == null || password.length == 0;
237 | }
238 |
239 | /**
240 | * Generates a final, compilable Java class implementing the specified interface with a single, one-statement
241 | * method that returns a simple value.
242 | *
243 | * @param packageName The package name the class should be contained in, or {@code null} if no package
244 | * @param className The name of the class to create
245 | * @param interfaceName The interface this class should implement, or null if no interface
246 | * @param imports An array of classes to import at the top of the Java code
247 | * @param methodSignature The signature of the sole method in the class
248 | * @param returnValue The statement that the method should return (will be prepended with "return ")
249 | * @return the Java code for the specified class.
250 | */
251 | protected String generateJavaCode(final String packageName,final String className,final String interfaceName,
252 | final String[] imports,final String methodSignature,final String returnValue) {
253 | final StringBuilder stringBuilder = new StringBuilder();
254 |
255 | if (packageName != null && packageName.trim().length() > 0)
256 | stringBuilder.append("package ").append(packageName.trim()).append(";\r\n\r\n");
257 |
258 | if (imports != null && imports.length > 0) {
259 | for (String importClass : imports)
260 | stringBuilder.append("import ").append(importClass.trim()).append(";\r\n");
261 | stringBuilder.append("\r\n");
262 | }
263 |
264 | final boolean hasInterface = interfaceName != null && interfaceName.trim().length() > 0;
265 |
266 | stringBuilder.append("public final class ").append(className.trim());
267 | if (hasInterface)
268 | stringBuilder.append(" implements ").append(interfaceName.trim());
269 | stringBuilder.append("\r\n");
270 | stringBuilder.append("{\r\n");
271 | if (hasInterface)
272 | stringBuilder.append("\t@Override\r\n");
273 | stringBuilder.append("\t").append(methodSignature.trim()).append("\r\n");
274 | stringBuilder.append("\t{\r\n");
275 |
276 | stringBuilder.append("\t\treturn ").append(returnValue).append(";\r\n");
277 |
278 | stringBuilder.append("\t}\r\n");
279 |
280 | stringBuilder.append("}");
281 |
282 | return stringBuilder.toString();
283 | }
284 |
285 | /**
286 | * Takes an array of integer-representable primitives ({@code byte}, {@code char}, {@code short}, {@code int})
287 | * and returns a Java code array-literal instantiation of the array, with values in hexadecimal literal format.
288 | * It is the user's responsibility to ensure that the values contained in the array can fit within the smaller
289 | * precision of the array type, if applicable.
290 | *
291 | * @param values The array of values to include in the array code
292 | * @param type The data type ({@code byte}, {@code char}, {@code short}, {@code int}) of the array to return
293 | * @return the Java code representation of this array.
294 | */
295 | protected String arrayToCodeString(final int[] values,final String type) {
296 | final StringBuilder stringBuilder = new StringBuilder("new ").append(type).append("[] {\r\n\t\t\t\t");
297 | int i = 0, j = 1;
298 | for (int value : values) {
299 | if (i++ > 0)
300 | stringBuilder.append(", ");
301 | if (j++ > 8) {
302 | j = 2;
303 | stringBuilder.append("\r\n\t\t\t\t");
304 | }
305 | stringBuilder.append("0x");
306 | stringBuilder.append(String.format("%08x", value).toUpperCase());
307 | }
308 | stringBuilder.append("\r\n\t\t}");
309 | return stringBuilder.toString();
310 | }
311 |
312 | /**
313 | * Converts a {@code byte} array to an {@code int} array.
314 | *
315 | * @param array The {@code byte} array to convert
316 | * @return the converted array as an {@code int} array.
317 | */
318 | protected int[] byteArrayToIntArray(final byte[] array) {
319 | final int[] a = new int[array.length];
320 | int i = 0;
321 | for (byte b : array)
322 | a[i++] = b;
323 | return a;
324 | }
325 |
326 | /**
327 | * Converts a {@code char} array to an {@code int} array.
328 | *
329 | * @param array The {@code char} array to convert
330 | * @return the converted array as an {@code int} array.
331 | */
332 | protected int[] charArrayToIntArray(final char[] array) {
333 | final int[] a = new int[array.length];
334 | int i = 0;
335 | for (char c : array)
336 | a[i++] = c;
337 | return a;
338 | }
339 | }
340 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/encryption/RSAKeyPairGeneratorInterface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * RSAKeyPairGeneratorInterface.java from LicenseManager modified Thursday, January 24, 2013 16:37:10 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import java.io.IOException;
22 | import java.security.KeyPair;
23 |
24 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
25 | import ro.esolutions.licensing.exception.InappropriateKeyException;
26 | import ro.esolutions.licensing.exception.InappropriateKeySpecificationException;
27 | import ro.esolutions.licensing.exception.RSA2048NotSupportedException;
28 |
29 | /**
30 | * An interface for the key pair generator to make unit testing possible. This interface is only implemented by
31 | * {@link RSAKeyPairGenerator}.
32 | *
33 | * @author Nick Williams
34 | * @version 1.0.0
35 | * @since 1.0.0
36 | */
37 | public interface RSAKeyPairGeneratorInterface {
38 | /**
39 | * Generates a key pair with RSA 2048-bit security.
40 | *
41 | * @return a public/private key pair.
42 | * @throws RSA2048NotSupportedException if RSA or 2048-bit encryption are not supported.
43 | */
44 | KeyPair generateKeyPair() throws RSA2048NotSupportedException;
45 |
46 | /**
47 | * Saves the key pair specified to output files specified, encrypting both with the specified password.
48 | *
49 | * @param keyPair The key pair to save to the files specified
50 | * @param privateOutputFileName The name of the file to save the encrypted private key to
51 | * @param publicOutputFileName The name of the file to save the encrypted public key to
52 | * @param password The password to encrypt both keys with
53 | * @throws IOException if an error occurs while writing to the files.
54 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
55 | * @throws InappropriateKeyException If the public or private keys are invalid
56 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
57 | */
58 | void saveKeyPairToFiles(final KeyPair keyPair,final String privateOutputFileName,final String publicOutputFileName,
59 | final char[] password)
60 | throws IOException, AlgorithmNotSupportedException, InappropriateKeyException,
61 | InappropriateKeySpecificationException;
62 |
63 | /**
64 | * Saves the key pair specified to output files specified, encrypting each with their specified passwords.
65 | *
66 | * @param keyPair The key pair to save to the files specified
67 | * @param privateOutputFileName The name of the file to save the encrypted private key to
68 | * @param publicOutputFileName The name of the file to save the encrypted public key to
69 | * @param privatePassword The password to encrypt the private key with
70 | * @param publicPassword The password to encrypt the public key with
71 | * @throws IOException if an error occurs while writing to the files.
72 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
73 | * @throws InappropriateKeyException If the public or private keys are invalid
74 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
75 | */
76 | void saveKeyPairToFiles(final KeyPair keyPair,final String privateOutputFileName,final String publicOutputFileName,
77 | final char[] privatePassword,final char[] publicPassword)
78 | throws IOException, AlgorithmNotSupportedException, InappropriateKeyException,
79 | InappropriateKeySpecificationException;
80 |
81 | /**
82 | * Saves the public and private keys specified to the respective
83 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} fields in
84 | * the provided {@link GeneratedClassDescriptor}s, encrypting both with the specified password.
85 | *
86 | * @param keyPair The key pair to save
87 | * @param privateKeyProvider An object describing the {@link PrivateKeyDataProvider} class to generate, and into
88 | * which the generated code will be saved
89 | * @param publicKeyProvider An object describing the {@link PublicKeyDataProvider} class to generate, and into
90 | * which the generated code will be saved
91 | * @param password The password to encrypt the keys with
92 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
93 | * @throws InappropriateKeyException If the public or private keys are invalid
94 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
95 | */
96 | void saveKeyPairToProviders(final KeyPair keyPair,final GeneratedClassDescriptor privateKeyProvider,
97 | final GeneratedClassDescriptor publicKeyProvider,final char[] password)
98 | throws AlgorithmNotSupportedException, InappropriateKeyException, InappropriateKeySpecificationException;
99 |
100 | /**
101 | * Saves the public and private keys specified to the respective
102 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} fields in
103 | * the provided {@link GeneratedClassDescriptor}s, encrypting each with their respective passwords.
104 | *
105 | * @param keyPair The key pair to save
106 | * @param privateKeyProvider An object describing the {@link PrivateKeyDataProvider} class to generate, and into
107 | * which the generated code will be saved
108 | * @param publicKeyProvider An object describing the {@link PublicKeyDataProvider} class to generate, and into
109 | * which the generated code will be saved
110 | * @param privatePassword The password to encrypt the private key with
111 | * @param publicPassword The password to encrypt the public key with
112 | * @throws AlgorithmNotSupportedException If the encryption algorithm is not supported
113 | * @throws InappropriateKeyException If the public or private keys are invalid
114 | * @throws InappropriateKeySpecificationException If the public or private keys are invalid
115 | */
116 | void saveKeyPairToProviders(final KeyPair keyPair,final GeneratedClassDescriptor privateKeyProvider,
117 | final GeneratedClassDescriptor publicKeyProvider,final char[] privatePassword,
118 | final char[] publicPassword)
119 | throws AlgorithmNotSupportedException, InappropriateKeyException, InappropriateKeySpecificationException;
120 |
121 | /**
122 | * Saves the password specified to the
123 | * {@link RSAKeyPairGeneratorInterface.GeneratedClassDescriptor#getJavaFileContents() javaFileContents} field in
124 | * the provided {@link GeneratedClassDescriptor}.
125 | *
126 | * @param password The password to save to the specified Java class
127 | * @param passwordProvider An object describing the {@link PasswordProvider} class to generate, and into which the
128 | * generated code will be saved
129 | */
130 | void savePasswordToProvider(final char[] password,final GeneratedClassDescriptor passwordProvider);
131 |
132 | class GeneratedClassDescriptor {
133 | private String packageName;
134 |
135 | private String className;
136 |
137 | private String javaFileContents;
138 |
139 | public String getPackageName() {
140 | return this.packageName;
141 | }
142 |
143 | public GeneratedClassDescriptor setPackageName(final String packageName) {
144 | this.packageName = packageName;
145 | return this;
146 | }
147 |
148 | public String getClassName() {
149 | return this.className;
150 | }
151 |
152 | public GeneratedClassDescriptor setClassName(final String className) {
153 | this.className = className;
154 | return this;
155 | }
156 |
157 | public String getJavaFileContents() {
158 | return javaFileContents;
159 | }
160 |
161 | public GeneratedClassDescriptor setJavaFileContents(final String javaFileContents) {
162 | this.javaFileContents = javaFileContents;
163 | return this;
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/exception/RSA2048NotSupportedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * RSA2048NotSupportedException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown when 2048-bit RSA security, which is required for
23 | * this library to run, is not supported with the current JVM.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class RSA2048NotSupportedException extends RuntimeException {
31 |
32 | private static final String MESSAGE = "2048-bit RSA Security is not supported on this system.";
33 |
34 | public RSA2048NotSupportedException() {
35 | super(MESSAGE);
36 | }
37 |
38 | public RSA2048NotSupportedException(final String message) {
39 | super(message);
40 | }
41 |
42 | public RSA2048NotSupportedException(final Throwable cause) {
43 | super(MESSAGE, cause);
44 | }
45 |
46 | public RSA2048NotSupportedException(final String message,final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/licensor/LicenseCreator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LicenseCreator.java from LicenseManager modified Thursday, January 24, 2013 16:39:57 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.licensor;
20 |
21 | import java.security.PrivateKey;
22 | import java.util.Arrays;
23 |
24 | import ro.esolutions.licensing.DataSignatureManager;
25 | import ro.esolutions.licensing.License;
26 | import ro.esolutions.licensing.ObjectSerializer;
27 | import ro.esolutions.licensing.SignedLicense;
28 | import ro.esolutions.licensing.encryption.Encryptor;
29 | import ro.esolutions.licensing.encryption.KeyFileUtilities;
30 | import ro.esolutions.licensing.encryption.PasswordProvider;
31 | import ro.esolutions.licensing.encryption.PrivateKeyDataProvider;
32 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
33 | import ro.esolutions.licensing.exception.InappropriateKeyException;
34 | import ro.esolutions.licensing.exception.InappropriateKeySpecificationException;
35 | import ro.esolutions.licensing.exception.KeyNotFoundException;
36 | import ro.esolutions.licensing.exception.ObjectSerializationException;
37 |
38 | /**
39 | * This class manages the creation of licenses in the master application. Use this class within your license generation
40 | * software to sign and serialize license for distribution to the client. This class is not needed for the client
41 | * application, and in fact you should not use this class in your client application. For this reason, it is
42 | * in the package of classes (ro.esolutions.licensing.licensor) that is packaged separately from the
43 | * distributable client binary.
44 | *
45 | * Before getting the creator instance for the first time, relevant properties should be set in
46 | * {@link LicenseCreatorProperties}. The values in this class will be used to instantiate the license creator.
47 | * After setting all the necessary properties there, one can retrieve an instance using {@link #getInstance()}. Be
48 | * sure to set all the properties first; once {@link #getInstance()} is called for the first time, any changes to
49 | * {@link LicenseCreatorProperties} will be ignored.
50 | *
51 | * @author Nick Williams
52 | * @version 1.0.6
53 | * @since 1.0.0
54 | */
55 | public final class LicenseCreator {
56 | private static LicenseCreator instance;
57 |
58 | private final PrivateKeyDataProvider privateKeyDataProvider;
59 |
60 | private final PasswordProvider privateKeyPasswordProvider;
61 |
62 | private LicenseCreator() {
63 | if (LicenseCreatorProperties.getPrivateKeyDataProvider() == null)
64 | throw new IllegalArgumentException("Parameter privateKeyDataProvider must not be null.");
65 |
66 | if (LicenseCreatorProperties.getPrivateKeyPasswordProvider() == null)
67 | throw new IllegalArgumentException("Parameter privateKeyPasswordProvider must not be null.");
68 |
69 | this.privateKeyPasswordProvider = LicenseCreatorProperties.getPrivateKeyPasswordProvider();
70 | this.privateKeyDataProvider = LicenseCreatorProperties.getPrivateKeyDataProvider();
71 | }
72 |
73 | /**
74 | * Returns the license creator instance. Before this method can be called the first time, all of the parameters must
75 | * bet set in {@link LicenseCreatorProperties}. See the documentation for that class for more details.
76 | *
77 | * @return the license creator instance.
78 | * @throws IllegalArgumentException if {@link LicenseCreatorProperties#setPrivateKeyDataProvider(PrivateKeyDataProvider)
79 | * privateKeyDataProvider} or {@link LicenseCreatorProperties#setPrivateKeyPasswordProvider(PasswordProvider)
80 | * privateKeyPasswordProvider} are null
81 | */
82 | public static synchronized LicenseCreator getInstance() {
83 | if (LicenseCreator.instance == null) {
84 | LicenseCreator.instance = new LicenseCreator();
85 | }
86 |
87 | return LicenseCreator.instance;
88 | }
89 |
90 | /**
91 | * Takes a license object and creates a secure version of it for serialization and delivery to the customer.
92 | *
93 | * @param license The license object to be signed
94 | * @param licensePassword The password to encrypt the license with
95 | * @return the signed license object.
96 | * @throws AlgorithmNotSupportedException if the encryption algorithm is not supported.
97 | * @throws KeyNotFoundException if the public key data could not be found.
98 | * @throws InappropriateKeySpecificationException if an inappropriate key specification is provided.
99 | * @throws InappropriateKeyException if the key type and cipher type do not match.
100 | */
101 | public final SignedLicense signLicense(License license, char[] licensePassword)
102 | throws AlgorithmNotSupportedException, KeyNotFoundException, InappropriateKeySpecificationException,
103 | InappropriateKeyException {
104 | PrivateKey key;
105 | {
106 | char[] password = this.privateKeyPasswordProvider.getPassword();
107 | byte[] keyData = this.privateKeyDataProvider.getEncryptedPrivateKeyData();
108 |
109 | key = KeyFileUtilities.readEncryptedPrivateKey(keyData, password);
110 |
111 | Arrays.fill(password, '\u0000');
112 | Arrays.fill(keyData, (byte) 0);
113 | }
114 |
115 | byte[] encrypted = Encryptor.encryptRaw(license.serialize(), licensePassword);
116 |
117 | byte[] signature = new DataSignatureManager().signData(key, encrypted);
118 |
119 | SignedLicense signed = new SignedLicense(encrypted, signature);
120 |
121 | Arrays.fill(encrypted, (byte) 0);
122 | Arrays.fill(signature, (byte) 0);
123 |
124 | return signed;
125 | }
126 |
127 | /**
128 | * Takes a license object and creates a secure version of it for serialization and delivery to the customer.
129 | *
130 | * @param license The license object to be signed
131 | * @return the signed license object.
132 | * @throws AlgorithmNotSupportedException if the encryption algorithm is not supported.
133 | * @throws KeyNotFoundException if the public key data could not be found.
134 | * @throws InappropriateKeySpecificationException if an inappropriate key specification is provided.
135 | * @throws InappropriateKeyException if the key type and cipher type do not match.
136 | */
137 | public final SignedLicense signLicense(License license)
138 | throws AlgorithmNotSupportedException, KeyNotFoundException, InappropriateKeySpecificationException,
139 | InappropriateKeyException {
140 | return this.signLicense(license, this.privateKeyPasswordProvider.getPassword());
141 | }
142 |
143 | /**
144 | * Takes a license object and creates a secure and serialized version of it for delivery to the customer.
145 | *
146 | * @param license The license object to be signed and serialized
147 | * @param licensePassword The password to encrypt the license with
148 | * @return the signed and serialized license object.
149 | * @throws AlgorithmNotSupportedException if the encryption algorithm is not supported.
150 | * @throws KeyNotFoundException if the public key data could not be found.
151 | * @throws InappropriateKeySpecificationException if an inappropriate key specification is provided.
152 | * @throws InappropriateKeyException if the key type and cipher type do not match.
153 | * @throws ObjectSerializationException if an error is encountered while serializing the key.
154 | */
155 | public final byte[] signAndSerializeLicense(License license, char[] licensePassword)
156 | throws AlgorithmNotSupportedException, KeyNotFoundException, InappropriateKeySpecificationException,
157 | InappropriateKeyException, ObjectSerializationException {
158 | return new ObjectSerializer().writeObject(this.signLicense(license, licensePassword));
159 | }
160 |
161 | /**
162 | * Takes a license object and creates a secure and serialized version of it for delivery to the customer.
163 | *
164 | * @param license The license object to be signed and serialized
165 | * @return the signed and serialized license object.
166 | * @throws AlgorithmNotSupportedException if the encryption algorithm is not supported.
167 | * @throws KeyNotFoundException if the public key data could not be found.
168 | * @throws InappropriateKeySpecificationException if an inappropriate key specification is provided.
169 | * @throws InappropriateKeyException if the key type and cipher type do not match.
170 | * @throws ObjectSerializationException if an error is encountered while serializing the key.
171 | */
172 | public final byte[] signAndSerializeLicense(License license)
173 | throws AlgorithmNotSupportedException, KeyNotFoundException, InappropriateKeySpecificationException,
174 | InappropriateKeyException, ObjectSerializationException {
175 | return new ObjectSerializer().writeObject(this.signLicense(license));
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/esolutions/licensing/licensor/LicenseCreatorProperties.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LicenseCreatorProperties.java from LicenseManager modified Thursday, January 24, 2013 16:37:10 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.licensor;
20 |
21 | import ro.esolutions.licensing.encryption.PasswordProvider;
22 | import ro.esolutions.licensing.encryption.PrivateKeyDataProvider;
23 |
24 | /**
25 | * This class is used to set properties that will be used to instantiate the {@link LicenseCreator}. Read the
26 | * documentation for each property below.
27 | *
28 | * @author Nick Williams
29 | * @version 1.0.0
30 | * @since 1.0.0
31 | */
32 | public final class LicenseCreatorProperties {
33 | private static PrivateKeyDataProvider privateKeyDataProvider;
34 |
35 | private static PasswordProvider privateKeyPasswordProvider;
36 |
37 | /**
38 | * Sets the provider of the data for the private key used to sign the license object.
39 | *
40 | * This field is required.
41 | *
42 | * @param privateKeyDataProvider The provider of the data for the private key used to sign the license object
43 | */
44 | public static void setPrivateKeyDataProvider(PrivateKeyDataProvider privateKeyDataProvider) {
45 | LicenseCreatorProperties.privateKeyDataProvider = privateKeyDataProvider;
46 | }
47 |
48 | static PrivateKeyDataProvider getPrivateKeyDataProvider() {
49 | return LicenseCreatorProperties.privateKeyDataProvider;
50 | }
51 |
52 | /**
53 | * Sets the provider of the password for decrypting the private key.
54 | *
55 | * This field is required.
56 | *
57 | * @param privateKeyPasswordProvider The provider of the password for decrypting the private key
58 | */
59 | public static void setPrivateKeyPasswordProvider(PasswordProvider privateKeyPasswordProvider) {
60 | LicenseCreatorProperties.privateKeyPasswordProvider = privateKeyPasswordProvider;
61 | }
62 |
63 | static PasswordProvider getPrivateKeyPasswordProvider() {
64 | return LicenseCreatorProperties.privateKeyPasswordProvider;
65 | }
66 |
67 | /**
68 | * This class cannot be instantiated.
69 | */
70 | private LicenseCreatorProperties() {
71 | throw new RuntimeException("This class cannot be instantiated.");
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | license-manager-core.iml
2 | target
3 |
--------------------------------------------------------------------------------
/core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
21 | 4.0.0
22 |
23 |
24 | ro.esolutions
25 | license-manager
26 | 1.0.4-SNAPSHOT
27 |
28 |
29 | license-manager-core
30 | jar
31 |
32 | License Manager - Core
33 |
34 |
35 |
36 | commons-codec
37 | commons-codec
38 |
39 |
40 |
41 | commons-io
42 | commons-io
43 |
44 |
45 | com.google.guava
46 | guava
47 | compile
48 |
49 |
50 | commons-lang
51 | commons-lang
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/DataSignatureManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DataSignatureManager.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import java.security.InvalidKeyException;
22 | import java.security.NoSuchAlgorithmException;
23 | import java.security.PrivateKey;
24 | import java.security.PublicKey;
25 | import java.security.Signature;
26 | import java.security.SignatureException;
27 |
28 | import ro.esolutions.licensing.encryption.KeyFileUtilities;
29 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
30 | import ro.esolutions.licensing.exception.CorruptSignatureException;
31 | import ro.esolutions.licensing.exception.InappropriateKeyException;
32 | import ro.esolutions.licensing.exception.InvalidSignatureException;
33 |
34 | public final class DataSignatureManager {
35 | public final byte[] signData(final PrivateKey key, final byte[] data) throws AlgorithmNotSupportedException,
36 | InappropriateKeyException {
37 |
38 | final Signature signature = this.getSignature();
39 |
40 | try {
41 | signature.initSign(key);
42 | } catch (final InvalidKeyException e) {
43 | throw new InappropriateKeyException("While initializing the signature object with the public key.", e);
44 | }
45 |
46 | try {
47 | signature.update(data);
48 | } catch (final SignatureException e) {
49 | throw new RuntimeException("This should never happen.", e);
50 | }
51 |
52 | try {
53 | return signature.sign();
54 | } catch (final SignatureException e) {
55 | throw new RuntimeException("This should never happen.", e);
56 | }
57 | }
58 |
59 | public final void verifySignature(final PublicKey key, final byte[] data, final byte[] signatureContent)
60 | throws AlgorithmNotSupportedException, InappropriateKeyException, CorruptSignatureException, InvalidSignatureException {
61 |
62 | final Signature signature = this.getSignature();
63 |
64 | try {
65 | signature.initVerify(key);
66 | } catch (final InvalidKeyException e) {
67 | throw new InappropriateKeyException("While initializing the signature object with the public key.", e);
68 | }
69 |
70 | try {
71 | signature.update(data);
72 | } catch (final SignatureException e) {
73 | throw new RuntimeException("This should never happen.", e);
74 | }
75 |
76 | try {
77 | if (!signature.verify(signatureContent))
78 | throw new InvalidSignatureException("The license signature is invalid.");
79 | } catch (final SignatureException e) {
80 | throw new CorruptSignatureException("While verifying the signature.", e);
81 | }
82 | }
83 |
84 | private Signature getSignature() {
85 | try {
86 | return Signature.getInstance("SHA1with" + KeyFileUtilities.KEY_ALGORITHM);
87 | } catch (final NoSuchAlgorithmException e) {
88 | throw new AlgorithmNotSupportedException("SHA-1 with " + KeyFileUtilities.KEY_ALGORITHM);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/DefaultLicenseValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DefaultLicenseValidator.java from LicenseManager modified Tuesday, February 21, 2012 10:59:34 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import java.time.Instant;
22 | import java.time.format.DateTimeFormatter;
23 |
24 | import ro.esolutions.licensing.exception.ExpiredLicenseException;
25 | import ro.esolutions.licensing.exception.InvalidLicenseException;
26 |
27 | public class DefaultLicenseValidator implements LicenseValidator {
28 |
29 | @Override
30 | public void validateLicense(final License license) throws InvalidLicenseException {
31 | final Instant time = Instant.now();
32 | if (license.getGoodAfterDate().isAfter(time))
33 | throw new InvalidLicenseException("The " + this.getLicenseDescription(license) +
34 | " does not take effect until " + this.getFormattedDate(license.getGoodAfterDate()) + ".");
35 | if (license.getGoodBeforeDate().isBefore(time))
36 | throw new ExpiredLicenseException("The " + this.getLicenseDescription(license) +
37 | " expired on " + this.getFormattedDate(license.getGoodAfterDate()) + ".");
38 | }
39 |
40 | public String getLicenseDescription(final License license) {
41 | return license.getSubject() + " license for " + license.getHolder();
42 | }
43 |
44 | public String getFormattedDate(final Instant time) {
45 | return DateTimeFormatter.ISO_INSTANT.format(time);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/DeserializingLicenseProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DeserializingLicenseProvider.java from LicenseManager modified Tuesday, May 29, 2012 19:41:03 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | /**
22 | * An abstract implementation of the {@link LicenseProvider} interface that assumes the license will be stored in
23 | * serialized form. Users need only implement the method returning the raw byte data of the serialized license in order
24 | * to complete this implementation.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since 1.0.0
29 | */
30 | public abstract class DeserializingLicenseProvider implements LicenseProvider {
31 | /**
32 | * Gets the stored, still-encrypted license content and signature from the persistence store.
33 | *
34 | * @param context The context for which to get the license
35 | * @return the signed license object.
36 | */
37 | @Override
38 | public final SignedLicense getLicense(final Object context) {
39 | final byte[] data = this.getLicenseData(context);
40 |
41 | return data == null ? null : this.deserializeLicense(data);
42 | }
43 |
44 | public final SignedLicense deserializeLicense(final byte[] data) {
45 | return new ObjectSerializer().readObject(SignedLicense.class, data);
46 | }
47 |
48 | /**
49 | * Gets the stored, still-encrypted, still-serialized license content and signature from the persistence store. If
50 | * no license is found, this method should return null (not an empty array).
51 | *
52 | * @param context The context for which to get the license
53 | * @return the signed license data.
54 | */
55 | protected abstract byte[] getLicenseData(final Object context);
56 | }
57 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/Feature.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Feature.java from LicenseManager modified Wednesday, November 30, 2016 14:14:50 EET (+0200).
3 | *
4 | * Copyright 2010-2016 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import com.google.common.base.MoreObjects;
22 |
23 | import org.apache.commons.lang.builder.EqualsBuilder;
24 | import org.apache.commons.lang.builder.HashCodeBuilder;
25 |
26 | import java.io.Serializable;
27 | import java.time.Instant;
28 |
29 | public class Feature implements Cloneable, Serializable {
30 | private static final long serialVersionUID = 1L;
31 |
32 | private final String name;
33 | private final int seats;
34 | private final Instant goodBeforeDate;
35 |
36 | private Feature(final Builder builder) {
37 | this.name = builder.name;
38 | this.seats = builder.seats;
39 | this.goodBeforeDate = builder.goodBeforeDate;
40 | }
41 |
42 | public static Feature.Builder of(final String name) {
43 | return new Feature.Builder(name);
44 | }
45 |
46 | public int getSeats() {
47 | return seats;
48 | }
49 |
50 | public final String getName() {
51 | return name;
52 | }
53 |
54 | public final Instant getGoodBeforeDate() {
55 | return goodBeforeDate;
56 | }
57 |
58 | /**
59 | * Deserializes a string representation of a feature into a feature.
60 | *
61 | * @param input The string representation of a feature, generated with {@link #toString()}.
62 | * @return the unserialized feature.
63 | */
64 | static Feature fromString(final String input) {
65 | if (input == null)
66 | throw new IllegalArgumentException("The input argument did not contain exactly two parts.");
67 |
68 | final String[] parts = input.split("" + (char) 0x1F);
69 | if (parts.length != 3)
70 | throw new IllegalArgumentException("The input argument did not contain exactly two parts.");
71 |
72 | return Feature.of(parts[0])
73 | .seats(Integer.parseInt(parts[1]))
74 | .goodBeforeDate(Instant.parse(parts[2]))
75 | .build();
76 | }
77 |
78 | /**
79 | * Indicates whether these features are the same feature. Important note: Two features can be the same
80 | * feature (equal) and have different expiration dates.
81 | *
82 | * @param object The feature to check for equality against
83 | * @return {@code true} if the features are the same, {@code false} otherwise.
84 | */
85 | @Override
86 | public final boolean equals(final Object object) {
87 | return EqualsBuilder.reflectionEquals(this, object);
88 | }
89 |
90 | @Override
91 | public final int hashCode() {
92 | return HashCodeBuilder.reflectionHashCode(this);
93 | }
94 |
95 | public final String toString() {
96 | return MoreObjects.toStringHelper(this)
97 | .add("name", name)
98 | .add("seats", seats)
99 | .add("goodBeforeDate", goodBeforeDate)
100 | .toString();
101 | }
102 |
103 | @Override
104 | @SuppressWarnings("CloneDoesntCallSuperClone")
105 | public Feature clone() {
106 | return Feature.of(this.name)
107 | .seats(this.seats)
108 | .goodBeforeDate(this.goodBeforeDate)
109 | .build();
110 | }
111 |
112 | public static class Builder {
113 | private String name;
114 | private int seats;
115 | private Instant goodBeforeDate;
116 |
117 | private Builder(final String name) {
118 | this.name = name;
119 | }
120 |
121 | public Builder seats(final int seats) {
122 | this.seats = seats;
123 | return this;
124 | }
125 |
126 | public Builder goodBeforeDate(final Instant goodBeforeDate) {
127 | this.goodBeforeDate = goodBeforeDate;
128 | return this;
129 | }
130 |
131 | public Feature build() {
132 | return new Feature(this);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/FeatureRestriction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FeatureRestriction.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import java.lang.annotation.Documented;
22 | import java.lang.annotation.ElementType;
23 | import java.lang.annotation.Retention;
24 | import java.lang.annotation.RetentionPolicy;
25 | import java.lang.annotation.Target;
26 |
27 | /**
28 | * An annotation for indicating license-restricted methods, packages and types. For example, one might set an AspectJ
29 | * pointcut that is intercepted and asserts that annotated accesses are done with permission. If not, it might throw an
30 | * exception, which would be caught by the user interface (such as a servlet filter in a Java EE environment) and
31 | * handled accordingly.
32 | *
33 | * @author Nick Williams
34 | * @version 1.0.0
35 | * @since 1.0.0
36 | */
37 | @Documented
38 | @Target({ElementType.METHOD, ElementType.PACKAGE, ElementType.TYPE})
39 | @Retention(RetentionPolicy.RUNTIME)
40 | public @interface FeatureRestriction {
41 | String[] value();
42 |
43 | FeatureRestrictionOperand operand() default FeatureRestrictionOperand.AND;
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/FeatureRestrictionOperand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FeatureRestrictionOperand.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | /**
22 | * Indicates whether feature restrictions are "all-or-nothing" ({@link #AND}) or "any" ({@link #OR}).
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | public enum FeatureRestrictionOperand {
29 | AND,
30 | OR
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/FileLicenseProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FileLicenseProvider.java from LicenseManager modified Tuesday, September 4, 2012 14:17:42 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import org.apache.commons.codec.binary.Base64;
22 | import org.apache.commons.io.FileUtils;
23 |
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.net.URISyntaxException;
27 | import java.net.URL;
28 |
29 | /**
30 | * A default implementation of the {@link LicenseProvider} that assumes the binary data from the signed and serialized
31 | * license is stored in a file. Various properties of this provider allow configuration of file prefixes (such as
32 | * a directory), file suffixes (such as an extension), whether or not the file can be found on the classpath, and
33 | * whether or not the contents of the file are Base64 encoded.
34 | *
35 | * This implementation also assumes that license contexts (lookup keys) are always either strings or have a meaningful
36 | * {@link Object#toString()} implementation that can be used within the file name.
37 | *
38 | * @author Nick Williams
39 | * @version 1.0.0
40 | * @since 1.0.0
41 | */
42 | public class FileLicenseProvider extends DeserializingLicenseProvider {
43 | protected ClassLoader classLoader;
44 |
45 | private String filePrefix = "";
46 |
47 | private String fileSuffix = "";
48 |
49 | private boolean fileOnClasspath = false;
50 |
51 | private boolean base64Encoded = false;
52 |
53 | /**
54 | * Constructs a file-based license provider with the same class loader as the loader of this class and
55 | * {@link #setFileOnClasspath(boolean) fileOnClasspath} set to {@code false}. The class loader is only used if
56 | * {@code fileOnClasspath} is subsequently changed to {@code true}.
57 | */
58 | public FileLicenseProvider() {
59 | this.classLoader = this.getClass().getClassLoader();
60 | this.fileOnClasspath = false;
61 | }
62 |
63 | /**
64 | * Constructs a file-based license provider with the provided class loader and
65 | * {@link #setFileOnClasspath(boolean) fileOnClasspath} set to {@code true}. The class loader will be used to
66 | * locate the file unless {@code fileOnClasspath} is subsequently changed to {@code false}.
67 | *
68 | * @param classLoader The class loader to use for finding the file
69 | */
70 | public FileLicenseProvider(final ClassLoader classLoader) {
71 | if (classLoader == null) {
72 | throw new IllegalArgumentException("Argument classLoader cannot be null.");
73 | }
74 | this.classLoader = classLoader;
75 | this.fileOnClasspath = true;
76 | }
77 |
78 | /**
79 | * Gets the stored, still-encrypted, still-serialized license content and signature from the persistence store.
80 | * Returns null (not an empty array) if no license is found.
81 | *
82 | * @param context The context for which to get the license
83 | * @return the signed license data.
84 | */
85 | @Override
86 | protected byte[] getLicenseData(final Object context) {
87 | if (context == null) {
88 | throw new IllegalArgumentException("Argument context cannot be null.");
89 | }
90 | final File file = this.getLicenseFile(context);
91 | if (file == null || !file.exists() || !file.canRead()) {
92 | return null;
93 | }
94 | try {
95 | byte[] data = FileUtils.readFileToByteArray(file);
96 |
97 | if (this.isBase64Encoded()) {
98 | data = Base64.decodeBase64(data);
99 | }
100 |
101 | return data;
102 | } catch (final IOException e) {
103 | return null;
104 | }
105 | }
106 |
107 | /**
108 | * Gets the license file handle. Returns null if if no license is found, but if a license is found, this may
109 | * return a file handle to a non-existent file. So, the file should be checked for existence and readability.
110 | *
111 | * @param context The context for which to get the license
112 | * @return the license file handle.
113 | */
114 | protected File getLicenseFile(final Object context) {
115 | String fileName = this.getFilePrefix() + context.toString() + this.getFileSuffix();
116 |
117 | if (this.isFileOnClasspath()) {
118 | if (fileName.startsWith("/")) {
119 | fileName = fileName.substring(1);
120 | }
121 | final URL url = this.classLoader.getResource(fileName);
122 | if (url == null) {
123 | fileName = null;
124 | } else {
125 | try {
126 | return new File(url.toURI());
127 | } catch (final URISyntaxException e) {
128 | return new File(url.getPath());
129 | }
130 | }
131 | }
132 |
133 | return fileName == null ? null : new File(fileName);
134 | }
135 |
136 | /**
137 | * Gets the prefix that will be prepended to the file name before looking for it. For example, if a license
138 | * context was "customer01" and the file name was "C:\product\licenses\file-customer01.lic", then the prefix
139 | * would be "C:\product\licenses\file-" and the suffix would be ".lic".
140 | *
141 | * @return the file prefix.
142 | */
143 | public String getFilePrefix() {
144 | return this.filePrefix;
145 | }
146 |
147 | /**
148 | * Sets the prefix that will be prepended to the file name before looking for it. For example, if a license
149 | * context was "customer01" and the file name was "C:\product\licenses\file-customer01.lic", then the prefix
150 | * would be "C:\product\licenses\file-" and the suffix would be ".lic".
151 | *
152 | * @param filePrefix The file prefix
153 | */
154 | public void setFilePrefix(final String filePrefix) {
155 | if (filePrefix == null) {
156 | throw new IllegalArgumentException("Argument filePrefix cannot be null.");
157 | }
158 | this.filePrefix = filePrefix;
159 | }
160 |
161 | /**
162 | * Gets the file suffix that will be appended to the file name before looking for it. For example, if a license
163 | * context was "customer01" and the file name was "C:\product\licenses\file-customer01.lic", then the prefix
164 | * would be "C:\product\licenses\file-" and the suffix would be ".lic".
165 | *
166 | * @return the file suffix.
167 | */
168 | public String getFileSuffix() {
169 | return this.fileSuffix;
170 | }
171 |
172 | /**
173 | * Sets the file suffix that will be appended to the file name before looking for it. For example, if a license
174 | * context was "customer01" and the file name was "C:\product\licenses\file-customer01.lic", then the prefix
175 | * would be "C:\product\licenses\file-" and the suffix would be ".lic".
176 | *
177 | * @param fileSuffix The file suffix
178 | */
179 | public void setFileSuffix(final String fileSuffix) {
180 | if (fileSuffix == null) {
181 | throw new IllegalArgumentException("Argument fileSuffix cannot be null.");
182 | }
183 | this.fileSuffix = fileSuffix;
184 | }
185 |
186 | /**
187 | * Indicates whether the file should be found on the file system or on the classpath via a class loader. If
188 | * {@code false} it will be looked for on the file system; if {@code true} it will be looked for on the classpath.
189 | * If {@code true}, the file prefix should be the package-path and prefix and the suffix the suffix.
190 | *
191 | * For example, if a license context was "customer02" and the file name was "file-customer02.lic" and was located
192 | * in the package ro.esolutions.licensing.licenses, then the prefix would be
193 | * "net/nicholaswilliams/java/licensing/licenses/file-" and the suffix should be ".lic".
194 | *
195 | * @return whether the file is on the classpath.
196 | */
197 | public boolean isFileOnClasspath() {
198 | return this.fileOnClasspath;
199 | }
200 |
201 | /**
202 | * Sets whether the file should be found on the file system or on the classpath via a class loader. If
203 | * {@code false} it will be looked for on the file system; if {@code true} it will be looked for on the classpath.
204 | * If {@code true}, the file prefix should be the package-path and prefix and the suffix the suffix.
205 | *
206 | * For example, if a license context was "customer02" and the file name was "file-customer02.lic" and was located
207 | * in the package ro.esolutions.licensing.licenses, then the prefix would be
208 | * "net/nicholaswilliams/java/licensing/licenses/file-" and the suffix should be ".lic".
209 | *
210 | * @param fileOnClasspath Whether the file is on the classpath
211 | */
212 | public void setFileOnClasspath(final boolean fileOnClasspath) {
213 | this.fileOnClasspath = fileOnClasspath;
214 | }
215 |
216 | /**
217 | * Indicates whether the file is Base64 encoded. If the file is Base64 encoded, its data will be decoded before
218 | * being returned by {@link #getLicenseData(Object)}.
219 | *
220 | * @return whether the file is Base64 encoded.
221 | */
222 | public boolean isBase64Encoded() {
223 | return this.base64Encoded;
224 | }
225 |
226 | /**
227 | * Sets whether the file is Base64 encoded. If the file is Base64 encoded, its data will be decoded before
228 | * being returned by {@link #getLicenseData(Object)}.
229 | *
230 | * @param base64Encoded Whether the file is Base64 encoded.
231 | */
232 | public void setBase64Encoded(final boolean base64Encoded) {
233 | this.base64Encoded = base64Encoded;
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/License.java:
--------------------------------------------------------------------------------
1 | /*
2 | * License.java from LicenseManager modified Monday, April 8, 2013 12:10:38 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package ro.esolutions.licensing;
19 |
20 | import com.google.common.base.MoreObjects;
21 | import com.google.common.base.Strings;
22 | import org.apache.commons.lang.SerializationUtils;
23 | import org.apache.commons.lang.builder.EqualsBuilder;
24 | import org.apache.commons.lang.builder.HashCodeBuilder;
25 | import ro.esolutions.licensing.immutable.ImmutableLinkedHashSet;
26 |
27 | import java.io.Serializable;
28 | import java.time.Instant;
29 | import java.util.Arrays;
30 | import java.util.LinkedHashSet;
31 | import java.util.Objects;
32 | import java.util.Set;
33 |
34 | public final class License implements Serializable, Cloneable {
35 | private static final long serialVersionUID = 1L;
36 |
37 | private final String productKey;
38 | private final String holder;
39 | private final String issuer;
40 | private final String subject;
41 | private final Instant issueDate;
42 | private final Instant goodAfterDate;
43 | private final Instant goodBeforeDate;
44 | private final int seats;
45 | private final ImmutableLinkedHashSet features;
46 |
47 | private License(final License.Builder builder) {
48 | this.productKey = Strings.nullToEmpty(builder.productKey);
49 | this.holder = Strings.nullToEmpty(builder.holder);
50 | this.issuer = Strings.nullToEmpty(builder.issuer);
51 | this.subject = Strings.nullToEmpty(builder.subject);
52 | this.issueDate = builder.issueDate;
53 | this.goodAfterDate = builder.goodAfterDate;
54 | this.goodBeforeDate = builder.goodBeforeDate;
55 | this.seats = builder.seats;
56 | this.features = new ImmutableLinkedHashSet<>(builder.features);
57 | }
58 |
59 | public final byte[] serialize() {
60 | return SerializationUtils.serialize(this);
61 | }
62 |
63 | static License deserialize(byte[] data) {
64 | return (License) SerializationUtils.deserialize(data);
65 | }
66 |
67 | public final String getProductKey() {
68 | return this.productKey;
69 | }
70 |
71 | public final String getIssuer() {
72 | return this.issuer;
73 | }
74 |
75 | public final String getHolder() {
76 | return this.holder;
77 | }
78 |
79 | public final String getSubject() {
80 | return this.subject;
81 | }
82 |
83 | public final Instant getIssueDate() {
84 | return this.issueDate;
85 | }
86 |
87 | public final Instant getGoodAfterDate() {
88 | return this.goodAfterDate;
89 | }
90 |
91 | public final Instant getGoodBeforeDate() {
92 | return this.goodBeforeDate;
93 | }
94 |
95 | public final int getSeats() {
96 | return this.seats;
97 | }
98 |
99 | public final ImmutableLinkedHashSet getFeatures() {
100 | return this.features.clone();
101 | }
102 |
103 | public final boolean hasLicenseForFeature(final Feature feature) {
104 | return hasLicenseForFeature(feature.getName());
105 | }
106 |
107 | public final boolean hasLicenseForFeature(final String featureName) {
108 | return this.features.stream().filter(f -> Objects.equals(f.getName(), featureName))
109 | .findAny()
110 | .map(feature -> feature.getGoodBeforeDate() == null || feature.getGoodBeforeDate().isAfter(Instant.now()))
111 | .orElse(false);
112 | }
113 |
114 | public final boolean hasLicenseForAnyFeature(final Feature... features) {
115 | return Arrays.stream(features)
116 | .map(Feature::getName)
117 | .anyMatch(this::hasLicenseForFeature);
118 | }
119 |
120 | public final boolean hasLicenseForAnyFeature(final String... featureNames) {
121 | return Arrays.stream(featureNames)
122 | .anyMatch(this::hasLicenseForFeature);
123 | }
124 |
125 | public final boolean hasLicenseForAllFeatures(final Feature... features) {
126 | return Arrays.stream(features)
127 | .map(Feature::getName)
128 | .allMatch(this::hasLicenseForFeature);
129 | }
130 |
131 | public final boolean hasLicenseForAllFeatures(final String... featureNames) {
132 | return Arrays.stream(featureNames)
133 | .allMatch(this::hasLicenseForFeature);
134 | }
135 |
136 | @Override
137 | public final boolean equals(final Object object) {
138 | return EqualsBuilder.reflectionEquals(this, object);
139 | }
140 |
141 | @Override
142 | public final int hashCode() {
143 | return HashCodeBuilder.reflectionHashCode(this);
144 | }
145 |
146 | @Override
147 | public final String toString() {
148 | return MoreObjects.toStringHelper(License.class)
149 | .add("productKey", productKey)
150 | .add("holder", holder)
151 | .add("issuer", issuer)
152 | .add("subject", subject)
153 | .add("issueDate", issueDate)
154 | .add("validFrom", goodAfterDate)
155 | .add("goodBeforeDate", goodBeforeDate)
156 | .add("seats", seats)
157 | .add("features", features)
158 | .toString();
159 | }
160 |
161 | @Override
162 | @SuppressWarnings("CloneDoesntCallSuperClone")
163 | public final License clone() {
164 | final License.Builder builder = new License.Builder()
165 | .withProductKey(this.productKey)
166 | .withHolder(this.holder)
167 | .withIssuer(this.issuer)
168 | .withSubject(this.subject)
169 | .withIssueDate(this.issueDate)
170 | .withGoodAfter(this.goodAfterDate)
171 | .withGoodBefore(this.goodBeforeDate)
172 | .withSeats(this.seats);
173 |
174 | features.forEach(builder::withFeature);
175 |
176 | return builder.build();
177 | }
178 |
179 | public static final class Builder {
180 | private String productKey;
181 | private String holder;
182 | private String issuer;
183 | private String subject;
184 | private Instant issueDate = Instant.now();
185 | private Instant goodAfterDate = Instant.MIN;
186 | private Instant goodBeforeDate = Instant.MAX;
187 | private int seats = Integer.MAX_VALUE;
188 | private Set features = new LinkedHashSet<>();
189 |
190 | public Builder withProductKey(final String productKey) {
191 | this.productKey = productKey;
192 | return this;
193 | }
194 |
195 | public Builder withIssuer(final String issuer) {
196 | this.issuer = issuer;
197 | return this;
198 | }
199 |
200 | public Builder withHolder(final String holder) {
201 | this.holder = holder;
202 | return this;
203 | }
204 |
205 | public Builder withSubject(final String subject) {
206 | this.subject = subject;
207 | return this;
208 | }
209 |
210 | public Builder withIssueDate(final Instant issueDate) {
211 | this.issueDate = issueDate;
212 | return this;
213 | }
214 |
215 | public Builder withGoodAfter(final Instant goodAfterDate) {
216 | this.goodAfterDate = goodAfterDate;
217 | return this;
218 | }
219 |
220 | public Builder withGoodBefore(final Instant goodBeforeDate) {
221 | this.goodBeforeDate = goodBeforeDate;
222 | return this;
223 | }
224 |
225 | public Builder withSeats(final int seats) {
226 | this.seats = seats;
227 | return this;
228 | }
229 |
230 | public Builder withFeature(final String featureName) {
231 | this.features.add(Feature.of(featureName).build());
232 | return this;
233 | }
234 |
235 | public Builder withFeature(final Feature feature) {
236 | this.features.add(feature);
237 | return this;
238 | }
239 |
240 | public License build() {
241 | return new License(this);
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/LicenseManagerProperties.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LicenseManagerProperties.java from LicenseManager modified Thursday, May 17, 2012 21:31:40 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import ro.esolutions.licensing.encryption.PasswordProvider;
22 | import ro.esolutions.licensing.encryption.PublicKeyDataProvider;
23 |
24 | /**
25 | * This class is used to set properties that will be used to instantiate the {@link LicenseManager}. Read the
26 | * documentation for each property below.
27 | *
28 | * @author Nick Williams
29 | * @version 1.0.0
30 | * @since 1.0.0
31 | */
32 | public final class LicenseManagerProperties {
33 | private static PublicKeyDataProvider publicKeyDataProvider;
34 |
35 | private static PasswordProvider publicKeyPasswordProvider;
36 |
37 | private static LicenseProvider licenseProvider;
38 |
39 | private static PasswordProvider licensePasswordProvider;
40 |
41 | private static LicenseValidator licenseValidator;
42 |
43 | private static int cacheTimeInMinutes;
44 |
45 | /**
46 | * Sets the provider of the data for the public key companion to the private key used to sign the license
47 | * object.
48 | *
49 | * This field is required.
50 | *
51 | * @param publicKeyDataProvider The provider of the data for the public key companion to the private key used to
52 | * sign the license object
53 | */
54 | public static void setPublicKeyDataProvider(final PublicKeyDataProvider publicKeyDataProvider) {
55 | LicenseManagerProperties.publicKeyDataProvider = publicKeyDataProvider;
56 | }
57 |
58 | static PublicKeyDataProvider getPublicKeyDataProvider() {
59 | return LicenseManagerProperties.publicKeyDataProvider;
60 | }
61 |
62 | /**
63 | * Sets the provider of the password for decrypting the public key.
64 | *
65 | * This field is required.
66 | *
67 | * @param publicKeyPasswordProvider The provider of the password for decrypting the public key
68 | */
69 | public static void setPublicKeyPasswordProvider(final PasswordProvider publicKeyPasswordProvider) {
70 | LicenseManagerProperties.publicKeyPasswordProvider = publicKeyPasswordProvider;
71 | }
72 |
73 | static PasswordProvider getPublicKeyPasswordProvider() {
74 | return LicenseManagerProperties.publicKeyPasswordProvider;
75 | }
76 |
77 | /**
78 | * Sets the provider of the persisted license data.
79 | *
80 | * This field is required.
81 | *
82 | * @param licenseProvider The provider of the persisted license data
83 | */
84 | public static void setLicenseProvider(final LicenseProvider licenseProvider) {
85 | LicenseManagerProperties.licenseProvider = licenseProvider;
86 | }
87 |
88 | static LicenseProvider getLicenseProvider() {
89 | return LicenseManagerProperties.licenseProvider;
90 | }
91 |
92 | /**
93 | * Sets the provider of the password for the persisted license data.
94 | *
95 | * This field is optional. If not provided, the
96 | * {@link #setPublicKeyPasswordProvider(PasswordProvider) publicKeyPasswordProvider} will be used to decrypt
97 | * licenses.
98 | *
99 | * @param licensePasswordProvider The provider of the password for decrypting license data
100 | */
101 | public static void setLicensePasswordProvider(final PasswordProvider licensePasswordProvider) {
102 | LicenseManagerProperties.licensePasswordProvider = licensePasswordProvider;
103 | }
104 |
105 | static PasswordProvider getLicensePasswordProvider() {
106 | return LicenseManagerProperties.licensePasswordProvider;
107 | }
108 |
109 | /**
110 | * Sets the validator implementation that validates all licenses; if null, licenses are assumed to always be valid.
111 | * If you do not want to validate licenses automatically, you do not need to provide a validator, or you may set
112 | * it to null.
113 | *
114 | * This field is optional and defaults to no validation.
115 | *
116 | * @param licenseValidator The validator implementation that validates all licenses; if null, licenses are assumed
117 | * to always be valid
118 | */
119 | public static void setLicenseValidator(final LicenseValidator licenseValidator) {
120 | LicenseManagerProperties.licenseValidator = licenseValidator;
121 | }
122 |
123 | static LicenseValidator getLicenseValidator() {
124 | return LicenseManagerProperties.licenseValidator;
125 | }
126 |
127 | /**
128 | * Sets the length of time in minutes to cache license information (for performance reasons, anything less than 1
129 | * minute results in a 10-second cache life; the cache cannot be disabled completely).
130 | *
131 | * This field is optional and defaults to 10 seconds.
132 | *
133 | * @param cacheTimeInMinutes The length of time in minutes to cache license information
134 | */
135 | public static void setCacheTimeInMinutes(final int cacheTimeInMinutes) {
136 | LicenseManagerProperties.cacheTimeInMinutes = cacheTimeInMinutes;
137 | }
138 |
139 | static int getCacheTimeInMinutes() {
140 | return cacheTimeInMinutes;
141 | }
142 |
143 | /**
144 | * This class cannot be instantiated.
145 | */
146 | private LicenseManagerProperties() {
147 | throw new RuntimeException("This class cannot be instantiated.");
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/LicenseProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LicenseProvider.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | /**
22 | * This specifies an interface for providing and persisting the stored, still-encrypted license content and signature
23 | * object.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | public interface LicenseProvider {
30 | /**
31 | * Gets the stored, still-encrypted license content and signature from the persistence store.
32 | *
33 | * @param context The context for which to get the license
34 | * @return the signed license object.
35 | */
36 | SignedLicense getLicense(final Object context);
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/LicenseValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * LicenseValidator.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import ro.esolutions.licensing.exception.InvalidLicenseException;
22 |
23 | /**
24 | * Specifies an interface for validating licenses. Users of License Manager do not have to implement this interface.
25 | * If it is not implemented, it is assumed that all licenses are valid. Users are encouraged, however, to implement
26 | * interface.
27 | *
28 | * There is a default implementation, {@link DefaultLicenseValidator}, that ensures the current date is between the
29 | * license's good-after and good-before dates (the license has taken effect and hasn't expired).
30 | *
31 | * @author Nick Williams
32 | * @version 1.0.1
33 | * @since 1.0.0
34 | */
35 | public interface LicenseValidator {
36 | /**
37 | * Validates the license provided and throws an exception if the license is invalid for any reason
38 | * (expired, not who it belongs to, etc.).
39 | *
40 | * @param license The license to validate
41 | * @throws InvalidLicenseException when the license is invalid for any reason; the
42 | * implementer is required to provide adequate
43 | * description in this exception to indicate why
44 | * the license is invalid; extending the exception
45 | * is encouraged.
46 | * @throws ro.esolutions.licensing.exception.ExpiredLicenseException when the license is expired.
47 | */
48 | void validateLicense(final License license) throws InvalidLicenseException;
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/ObjectSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ObjectSerializer.java from LicenseManager modified Thursday, May 17, 2012 21:31:40 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import org.apache.commons.io.output.ByteArrayOutputStream;
22 | import ro.esolutions.licensing.exception.ObjectDeserializationException;
23 | import ro.esolutions.licensing.exception.ObjectSerializationException;
24 | import ro.esolutions.licensing.exception.ObjectTypeNotExpectedException;
25 |
26 | import java.io.*;
27 |
28 | /**
29 | * This is a helper class for writing any object and reading simple objects (no
30 | * arrays, collections, or generic top-level objects) to and from byte arrays.
31 | *
32 | * @author Nick Williams
33 | * @version 1.0.0
34 | * @since 1.0.0
35 | */
36 | public final class ObjectSerializer {
37 |
38 | public final T readObject(final Class expectedType, final byte[] byteStream)
39 | throws ObjectDeserializationException {
40 | try (final ByteArrayInputStream bytes = new ByteArrayInputStream(byteStream);
41 | final ObjectInputStream stream = new ObjectInputStream(bytes)) {
42 |
43 | final Object allegedObject = stream.readObject();
44 | if (!expectedType.isInstance(allegedObject)) {
45 | throw new ObjectTypeNotExpectedException(expectedType.getName(), allegedObject.getClass().getName());
46 | }
47 |
48 | return expectedType.cast(allegedObject);
49 | } catch (final IOException e) {
50 | throw new ObjectDeserializationException("An I/O error occurred while reading the object from the byte array.", e);
51 | } catch (final ClassNotFoundException | NoClassDefFoundError e) {
52 | throw new ObjectTypeNotExpectedException(expectedType.getName(), e.getMessage(), e);
53 | }
54 | }
55 |
56 | /**
57 | * Serializes the {@link Serializable} object passed and returns it as a byte array.
58 | *
59 | * @param object The object to serialize
60 | * @return the byte stream with the object serialized in it.
61 | * @throws ObjectSerializationException if an I/O exception occurs while serializing the object.
62 | */
63 | public final byte[] writeObject(final Serializable object) throws ObjectSerializationException {
64 |
65 | try (final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
66 | final ObjectOutputStream stream = new ObjectOutputStream(bytes)) {
67 | stream.writeObject(object);
68 | return bytes.toByteArray();
69 | } catch (final IOException e) {
70 | throw new ObjectSerializationException(e);
71 | }
72 |
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/SignedLicense.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SignedLicense.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing;
20 |
21 | import java.io.Serializable;
22 | import java.util.Arrays;
23 |
24 | /**
25 | * This class contains the encrypted license content and the signature for the
26 | * encrypted license content.
27 | *
28 | * @author Nick Williams
29 | * @version 1.0.0
30 | * @since 1.0.0
31 | */
32 | public final class SignedLicense implements Serializable {
33 | private final static long serialVersionUID = -8465360339059185020L;
34 |
35 | private final byte[] licenseContent;
36 | private final byte[] signatureContent;
37 |
38 | public SignedLicense(final byte[] licenseContent,final byte[] signatureContent) {
39 | this.licenseContent = Arrays.copyOf(licenseContent, licenseContent.length);
40 | this.signatureContent = Arrays.copyOf(signatureContent, signatureContent.length);
41 | }
42 |
43 | /**
44 | * Get the content of the actual license object. This is encrypted and
45 | * corresponds to {@link License}. For security reasons, only a copy of
46 | * the content is returned.
47 | *
48 | * @return the encrypted license content.
49 | */
50 | public final byte[] getLicenseContent() {
51 | return Arrays.copyOf(this.licenseContent, this.licenseContent.length);
52 | }
53 |
54 | /**
55 | * Get the signature for the license content. For security reasons, only a
56 | * copy of the signature is returned.
57 | *
58 | * @return the license signature.
59 | */
60 | public final byte[] getSignatureContent() {
61 | return Arrays.copyOf(this.signatureContent, this.signatureContent.length);
62 | }
63 |
64 | /**
65 | * Erase the contents of this object. This is a security feature to write
66 | * zeroes to the license and signature data so that it doesn't hang around
67 | * in memory where it might be reverse engineered.
68 | */
69 | protected final void erase() {
70 | Arrays.fill(this.licenseContent, (byte) 0);
71 | Arrays.fill(this.signatureContent, (byte) 0);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/Encryptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Encryptor.java from LicenseManager modified Monday, April 8, 2013 12:11:51 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import org.apache.commons.codec.Charsets;
22 | import org.apache.commons.codec.binary.Base64;
23 |
24 | import java.security.InvalidKeyException;
25 | import java.security.NoSuchAlgorithmException;
26 | import java.security.SecureRandom;
27 | import java.security.spec.InvalidKeySpecException;
28 |
29 | import javax.crypto.BadPaddingException;
30 | import javax.crypto.Cipher;
31 | import javax.crypto.IllegalBlockSizeException;
32 | import javax.crypto.NoSuchPaddingException;
33 | import javax.crypto.SecretKey;
34 | import javax.crypto.SecretKeyFactory;
35 | import javax.crypto.spec.PBEKeySpec;
36 | import javax.crypto.spec.SecretKeySpec;
37 |
38 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
39 | import ro.esolutions.licensing.exception.FailedToDecryptException;
40 | import ro.esolutions.licensing.exception.InappropriateKeyException;
41 | import ro.esolutions.licensing.exception.InappropriateKeySpecificationException;
42 |
43 | /**
44 | * A class for easy, strong, two-way encryption/decryption of strings. Versions prior to 0.9.1-beta used 256-bit AES
45 | * encryption, which is not exportable, and will only work by default on Mac OS X and Linux. The Windows JVM will throw
46 | * an exception without the JCE Unlimited Strength policy file. Versions 0.9.1-beta and higher use 128-bit AES
47 | * encryption that is both exportable and platform-independent.
48 | *
49 | * This encryptor still uses a combination of MD5+DES and SHA-1+AES encryption.
50 | *
51 | * Data encrypted with this class prior to version 0.9.1-beta cannot be decrypted anymore.
52 | *
53 | * @author Nick Williams
54 | * @version 1.5.0
55 | * @since 1.0.0
56 | */
57 | public final class Encryptor {
58 | private static final int MINIMUM_PADDED_LENGTH = 20;
59 | private static final char[] DEFAULT_PASS_PHRASE = {
60 | 'j', '4', 'K', 'g', 'U', '3', '0', '5', 'P', 'Z', 'p', '\'', 't',
61 | '.', '"', '%', 'o', 'r', 'd', 'A', 'Y', '7', 'q', '*', '?', 'z',
62 | '9', '%', '8', ']', 'a', 'm', 'N', 'L', '(', '0', 'W', 'x', '5',
63 | 'e', 'G', '4', '9', 'b', '1', 's', 'R', 'j', '(', '^', ';', '8',
64 | 'K', 'g', '2', 'w', '0', 'E', 'o', 'M'
65 | };
66 |
67 | private static final byte[] SALT = {
68 | (byte) 0xA9, (byte) 0xA2, (byte) 0xB5, (byte) 0xDE,
69 | (byte) 0x2A, (byte) 0x8A, (byte) 0x9A, (byte) 0xE6
70 | };
71 |
72 | private static final int ITERATION_COUNT = 1024;
73 |
74 | // must be 128, 192, 256; 128 is maximum without "unlimited strength" JCE policy files
75 | private static final int AES_KEY_LENGTH = 128;
76 |
77 | private static final SecureRandom SECURE_RANDOM = new SecureRandom();
78 |
79 | private static Cipher defaultEncryptionCipher;
80 | private static Cipher defaultDecryptionCipher;
81 |
82 | /**
83 | * Encrypt the plain-text string using the default passphrase.
84 | * For encrypting, the data will first be padded to a safe number of
85 | * bytes with randomized data.
86 | *
87 | * @param unencrypted The plain-text string to encrypt
88 | * @return the encrypted string Base64-encoded.
89 | * @see Encryptor#pad(byte[], int)
90 | */
91 | public static String encrypt(final String unencrypted) {
92 | return Encryptor.encrypt(unencrypted.getBytes(Charsets.UTF_8));
93 | }
94 |
95 | /**
96 | * Encrypt the plain-text string. For encrypting, the
97 | * string will first be padded to a safe number of
98 | * characters with randomized data.
99 | *
100 | * @param unencrypted The plain-text string to encrypt
101 | * @param passPhrase The passPhrase to encrypt the data with
102 | * @return the encrypted string Base64-encoded.
103 | */
104 | public static String encrypt(final String unencrypted, final char[] passPhrase) {
105 | return Encryptor.encrypt(unencrypted.getBytes(Charsets.UTF_8), passPhrase);
106 | }
107 |
108 | /**
109 | * Encrypt the binary data using the default passphrase.
110 | * For encrypting, the data will first be padded to a safe number of
111 | * bytes with randomized data.
112 | *
113 | * @param unencrypted The binary data to encrypt
114 | * @return the encrypted string Base64-encoded.
115 | * @see Encryptor#pad(byte[], int)
116 | */
117 | public static String encrypt(final byte[] unencrypted) {
118 | return new String(Base64.encodeBase64URLSafe(Encryptor.encryptRaw(unencrypted)), Charsets.UTF_8);
119 | }
120 |
121 | /**
122 | * Encrypt the binary data. For encrypting, the
123 | * data will first be padded to a safe number of
124 | * bytes with randomized data.
125 | *
126 | * @param unencrypted The binary data to encrypt
127 | * @param passPhrase The passPhrase to encrypt the data with
128 | * @return the encrypted string Base64-encoded.
129 | * @see Encryptor#pad(byte[], int)
130 | */
131 | public static String encrypt(final byte[] unencrypted, final char[] passPhrase) {
132 | return new String(
133 | Base64.encodeBase64URLSafe(Encryptor.encryptRaw(unencrypted, passPhrase)), Charsets.UTF_8);
134 | }
135 |
136 | /**
137 | * Encrypt the binary data using the default passphrase.
138 | * For encrypting, the data will first be padded to a safe number of
139 | * bytes with randomized data.
140 | *
141 | * @param unencrypted The binary data to encrypt
142 | * @return the encrypted data.
143 | * @see Encryptor#pad(byte[], int)
144 | */
145 | public static byte[] encryptRaw(final byte[] unencrypted) {
146 | try {
147 | return Encryptor.getDefaultEncryptionCipher()
148 | .doFinal(Encryptor.pad(unencrypted, Encryptor.MINIMUM_PADDED_LENGTH));
149 | } catch (final IllegalBlockSizeException | BadPaddingException e) {
150 | throw new RuntimeException("While encrypting the data...", e);
151 | }
152 | }
153 |
154 | /**
155 | * Encrypt the binary data. For encrypting, the
156 | * data will first be padded to a safe number of
157 | * bytes with randomized data.
158 | *
159 | * @param unencrypted The binary data to encrypt
160 | * @param passPhrase The passPhrase to encrypt the data with
161 | * @return the encrypted data.
162 | * @see Encryptor#pad(byte[], int)
163 | */
164 | public static byte[] encryptRaw(final byte[] unencrypted, final char[] passPhrase) {
165 | try {
166 | return Encryptor.getEncryptionCipher(passPhrase)
167 | .doFinal(Encryptor.pad(unencrypted, Encryptor.MINIMUM_PADDED_LENGTH)
168 | );
169 | } catch (final IllegalBlockSizeException | BadPaddingException e) {
170 | throw new RuntimeException("While encrypting the data...", e);
171 | }
172 | }
173 |
174 | /**
175 | * Decrypt an encrypted string using the default passphrase.
176 | * Any padded data will be removed from the string prior to its return.
177 | *
178 | * @param encrypted The encrypted string to decrypt
179 | * @return the decrypted string.
180 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
181 | * password was incorrect. It is impossible to know which is the actual cause.
182 | * @see Encryptor#unPad(byte[])
183 | */
184 | public static String decrypt(final String encrypted) {
185 | return Encryptor.decrypt(Base64.decodeBase64(encrypted));
186 | }
187 |
188 | /**
189 | * Decrypt an encrypted string. Any padded data will
190 | * be removed from the string prior to its return.
191 | *
192 | * @param encrypted The encrypted string to decrypt
193 | * @param passPhrase The passPhrase to decrypt the string with
194 | * @return the decrypted string.
195 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
196 | * password was incorrect. It is impossible to know which is the actual cause.
197 | * @see Encryptor#unPad(byte[])
198 | */
199 | public static String decrypt(final String encrypted, final char[] passPhrase) {
200 | return Encryptor.decrypt(Base64.decodeBase64(encrypted), passPhrase);
201 | }
202 |
203 | /**
204 | * Decrypt encrypted data using the default passphrase.
205 | * Any padded data will be removed from the string prior to its return.
206 | *
207 | * @param encrypted The encrypted data to decrypt
208 | * @return the decrypted string.
209 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
210 | * password was incorrect. It is impossible to know which is the actual cause.
211 | * @see Encryptor#unPad(byte[])
212 | */
213 | public static String decrypt(final byte[] encrypted) {
214 | return new String(Encryptor.decryptRaw(encrypted), Charsets.UTF_8);
215 | }
216 |
217 | /**
218 | * Decrypt an encrypted data. Any padded data will
219 | * be removed from the string prior to its return.
220 | *
221 | * @param encrypted The encrypted data to decrypt
222 | * @param passPhrase The passPhrase to decrypt the data with
223 | * @return the decrypted string.
224 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
225 | * password was incorrect. It is impossible to know which is the actual cause.
226 | * @see Encryptor#unPad(byte[])
227 | */
228 | public static String decrypt(final byte[] encrypted, final char[] passPhrase) {
229 | return new String(Encryptor.decryptRaw(encrypted, passPhrase), Charsets.UTF_8);
230 | }
231 |
232 | /**
233 | * Decrypt encrypted data using the default passphrase.
234 | * Any padded data will be removed from the string prior to its return.
235 | *
236 | * @param encrypted The encrypted data to decrypt
237 | * @return the decrypted binary data.
238 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
239 | * password was incorrect. It is impossible to know which is the actual cause.
240 | * @see Encryptor#unPad(byte[])
241 | */
242 | public static byte[] decryptRaw(final byte[] encrypted) {
243 | try {
244 | return Encryptor.unPad(Encryptor.getDefaultDecryptionCipher().doFinal(encrypted));
245 | } catch (final IllegalBlockSizeException | BadPaddingException e) {
246 | throw new FailedToDecryptException(e);
247 | }
248 | }
249 |
250 | /**
251 | * Decrypt encrypted data. Any padded data will
252 | * be removed from the string prior to its return.
253 | *
254 | * @param encrypted The encrypted data to decrypt
255 | * @param passPhrase The passPhrase to decrypt the data with
256 | * @return the decrypted binary data.
257 | * @throws FailedToDecryptException when the data was corrupt and undecryptable or when the provided decryption
258 | * password was incorrect. It is impossible to know which is the actual cause.
259 | * @see Encryptor#unPad(byte[])
260 | */
261 | public static byte[] decryptRaw(final byte[] encrypted, final char[] passPhrase) {
262 | try {
263 | return Encryptor.unPad(Encryptor.getDecryptionCipher(passPhrase).doFinal(encrypted));
264 | } catch (final IllegalBlockSizeException | BadPaddingException e) {
265 | throw new FailedToDecryptException(e);
266 | }
267 | }
268 |
269 | /**
270 | * Pads a {@code byte} array to the specified length.
271 | * The output is pretty simple. The begin {@code byte}s
272 | * are the values from {@code bytes}. The last
273 | * {@code byte}, when cast to an integer, indicates the
274 | * number of end {@code byte}s (including itself) that
275 | * make up the padding. The returned array will always
276 | * be at least one element longer than the input.
277 | *
278 | * For example, if passed an array of 5 {@code byte}s and
279 | * the length 10, the first five {@code byte}s will be the
280 | * values from {@code bytes}. {@code byte}s 6-10 (indexes
281 | * 5-9) will be randomized data and {@code byte} 11
282 | * (index 10) will be the integer 6 cast as a byte. The
283 | * actual returned array will be 11 {@code byte}s long.
284 | *
285 | * If passed an array of 10 {@code byte}s and the length
286 | * of 10, the first 10 {@code byte}s will be the input
287 | * and {@code byte} 11 will be 1.
288 | *
289 | * @param bytes The array of {@code byte}s to pad
290 | * @param length The length to pad the array of {@code byte}s to
291 | * @return the padded {@code byte} array.
292 | * @see Encryptor#unPad(byte[])
293 | */
294 | private static byte[] pad(final byte[] bytes, final int length) {
295 | if (bytes.length >= length) {
296 | final byte[] out = new byte[bytes.length + 1];
297 | System.arraycopy(bytes, 0, out, 0, bytes.length);
298 | out[bytes.length] = (byte) 1;
299 | return out;
300 | }
301 |
302 | final byte[] out = new byte[length + 1];
303 |
304 | int i = 0;
305 | for (; i < bytes.length; i++)
306 | out[i] = bytes[i];
307 |
308 | final int padded = length - i;
309 |
310 | // fill the rest with SECURE_RANDOM bytes
311 | final byte[] fill = new byte[padded - 1];
312 | Encryptor.SECURE_RANDOM.nextBytes(fill);
313 | System.arraycopy(fill, 0, out, i, padded - 1);
314 |
315 | out[length] = (byte) (padded + 1);
316 |
317 | return out;
318 | }
319 |
320 | /**
321 | * Un-pads the specified array of {@code byte}s. Expects
322 | * an input that was padded with
323 | * {@link Encryptor#pad(byte[], int)}. Its behavior is
324 | * unspecified if passed an input that was not the
325 | * result of {@link Encryptor#pad(byte[], int)}.
326 | *
327 | * The returned array will be the {@code byte}s with all
328 | * the padding removed and the original {@code byte}s
329 | * left intact.
330 | *
331 | * @param bytes The array of {@code byte}s to un-pad
332 | * @return the un-padded {@code byte} array.
333 | * @see Encryptor#pad(byte[], int)
334 | */
335 | private static byte[] unPad(final byte[] bytes) {
336 | final int padded = (int) bytes[bytes.length - 1];
337 | final int targetLength = bytes.length - padded;
338 |
339 | final byte[] out = new byte[targetLength];
340 |
341 | System.arraycopy(bytes, 0, out, 0, targetLength);
342 |
343 | return out;
344 | }
345 |
346 | private static SecretKey getSecretKey(final char[] passPhrase) {
347 | try {
348 | final PBEKeySpec keySpec = new PBEKeySpec(
349 | passPhrase,
350 | Encryptor.SALT,
351 | Encryptor.ITERATION_COUNT,
352 | Encryptor.AES_KEY_LENGTH
353 | );
354 |
355 | final byte[] shortKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").
356 | generateSecret(keySpec).getEncoded();
357 |
358 | final byte[] intermediaryKey = new byte[Encryptor.AES_KEY_LENGTH / 8];
359 | for (int i = 0, j = 0; i < Encryptor.AES_KEY_LENGTH / 8; i++) {
360 | intermediaryKey[i] = shortKey[j];
361 | if (++j == shortKey.length)
362 | j = 0;
363 | }
364 |
365 | return new SecretKeySpec(intermediaryKey, "AES");
366 | } catch (final NoSuchAlgorithmException e) {
367 | throw new AlgorithmNotSupportedException("DES with an MD5 Digest", e);
368 | } catch (final InvalidKeySpecException e) {
369 | throw new InappropriateKeySpecificationException(e);
370 | }
371 | }
372 |
373 | private static Cipher getDefaultEncryptionCipher() {
374 | if (Encryptor.defaultEncryptionCipher == null)
375 | Encryptor.defaultEncryptionCipher = Encryptor.getEncryptionCipher(Encryptor.DEFAULT_PASS_PHRASE);
376 |
377 | return Encryptor.defaultEncryptionCipher;
378 | }
379 |
380 | private static Cipher getEncryptionCipher(final char[] passPhrase) {
381 | return Encryptor.getEncryptionCipher(Encryptor.getSecretKey(passPhrase));
382 | }
383 |
384 | private static Cipher getEncryptionCipher(final SecretKey secretKey) {
385 | try {
386 | final Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
387 | cipher.init(Cipher.ENCRYPT_MODE, secretKey, Encryptor.SECURE_RANDOM);
388 | return cipher;
389 | } catch (final NoSuchAlgorithmException e) {
390 | throw new AlgorithmNotSupportedException("AES With SHA-1 digest", e);
391 | } catch (final NoSuchPaddingException e) {
392 | throw new RuntimeException(e.getMessage(), e);
393 | } catch (final InvalidKeyException e) {
394 | throw new InappropriateKeyException(e.getMessage(), e);
395 | }
396 | }
397 |
398 | private static Cipher getDefaultDecryptionCipher() {
399 | if (Encryptor.defaultDecryptionCipher == null) {
400 | Encryptor.defaultDecryptionCipher = Encryptor.getDecryptionCipher(Encryptor.DEFAULT_PASS_PHRASE);
401 | }
402 | return Encryptor.defaultDecryptionCipher;
403 | }
404 |
405 | private static Cipher getDecryptionCipher(char[] passPhrase) {
406 | return Encryptor.getDecryptionCipher(Encryptor.getSecretKey(passPhrase));
407 | }
408 |
409 | private static Cipher getDecryptionCipher(final SecretKey secretKey) {
410 | try {
411 | final Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
412 | cipher.init(Cipher.DECRYPT_MODE, secretKey, Encryptor.SECURE_RANDOM);
413 | return cipher;
414 | } catch (final NoSuchAlgorithmException e) {
415 | throw new AlgorithmNotSupportedException("AES With SHA-1 digest", e);
416 | } catch (final NoSuchPaddingException e) {
417 | throw new RuntimeException(e.getMessage(), e);
418 | } catch (final InvalidKeyException e) {
419 | throw new InappropriateKeyException(e.getMessage(), e);
420 | }
421 | }
422 |
423 | /**
424 | * This class cannot be instantiated.
425 | */
426 | private Encryptor() {
427 | throw new RuntimeException("This class cannot be instantiated.");
428 | }
429 | }
430 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/FilePublicKeyDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FilePublicKeyDataProvider.java from LicenseManager modified Thursday, May 17, 2012 21:31:40 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import org.apache.commons.io.FileUtils;
22 | import ro.esolutions.licensing.exception.KeyNotFoundException;
23 |
24 | import java.io.File;
25 | import java.io.FileNotFoundException;
26 | import java.io.IOException;
27 |
28 | /**
29 | * A default implementation of {@link PublicKeyDataProvider} that reads the public key from a file.
30 | *
31 | * This provider is immutable. Once created, the file that the public key is located at cannot be changed.
32 | *
33 | * @author Nick Williams
34 | * @version 1.0.0
35 | * @since 1.0.0
36 | */
37 | public class FilePublicKeyDataProvider implements PublicKeyDataProvider {
38 | private final File publicKeyFile;
39 |
40 | /**
41 | * Create a new provider, specifying the file from which the public key can be read.
42 | *
43 | * @param publicKeyFile the public key file
44 | */
45 | public FilePublicKeyDataProvider(final File publicKeyFile) {
46 | this.publicKeyFile = publicKeyFile.getAbsoluteFile();
47 | }
48 |
49 | /**
50 | * Create a new provider, specifying the name of the file from which the public key can be read.
51 | *
52 | * @param publicKeyFileName The public key file name
53 | */
54 | public FilePublicKeyDataProvider(final String publicKeyFileName) {
55 | this.publicKeyFile = new File(publicKeyFileName).getAbsoluteFile();
56 | }
57 |
58 | /**
59 | * This method returns the data from the file containing the encrypted
60 | * public key from the public/private key pair. The contract for this
61 | * method can be fulfilled by storing the data in a byte array literal
62 | * in the source code itself.
63 | *
64 | * It is imperative that you obfuscate the bytecode for the
65 | * implementation of this class. It is also imperative that the byte
66 | * array exist only for the life of this method (i.e., DO NOT store it as
67 | * an instance or class field).
68 | *
69 | * @return the encrypted file contents from the public key file.
70 | * @throws KeyNotFoundException if the key data could not be retrieved; an acceptable message or chained cause must
71 | * be provided.
72 | */
73 | @Override
74 | public byte[] getEncryptedPublicKeyData() throws KeyNotFoundException {
75 | try {
76 | return FileUtils.readFileToByteArray(this.publicKeyFile);
77 | } catch (final FileNotFoundException e) {
78 | throw new KeyNotFoundException("The public key file [" + this.publicKeyFile.getPath() + "] does not exist.");
79 | } catch (final IOException e) {
80 | throw new KeyNotFoundException("Could not read from the public key file [" + this.publicKeyFile.getPath() + "].", e);
81 | }
82 | }
83 |
84 | /**
85 | * Gets the file that the public key is located at.
86 | *
87 | * @return the file.
88 | */
89 | public File getPublicKeyFile() {
90 | return this.publicKeyFile;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/Hasher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Hasher.java from LicenseManager modified Monday, April 8, 2013 12:11:51 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import org.apache.commons.codec.Charsets;
22 | import org.apache.commons.codec.binary.Base64;
23 |
24 | import java.security.MessageDigest;
25 | import java.security.NoSuchAlgorithmException;
26 |
27 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
28 |
29 | /**
30 | * Used for creating hash keys of things that won't need to be unencrypted.
31 | *
32 | * @author Nick Williams
33 | * @version 1.0.0
34 | * @since 1.0.0
35 | */
36 | public class Hasher {
37 | /**
38 | * The ALGORITHM we use to hash strings.
39 | */
40 | private static final String ALGORITHM = "SHA-512";
41 |
42 | /**
43 | * The salt that we use to hash strings.
44 | */
45 | private static final String SALT =
46 | "j4KgU305PZp't.\"%ordAY7q*?z9%8]amNL(0Wx5eG49b1sRj(^;8Kg2w0EoM";
47 |
48 | /**
49 | * Calculate the SHA-512 message digest hash of the
50 | * provided string and return it with its binary
51 | * data Base64 encoded.
52 | *
53 | * @param string The string to hash
54 | * @return the hashed string Base64 encoded.
55 | */
56 | public static String hash(final String string) {
57 | try {
58 | final byte[] digest = MessageDigest.getInstance(ALGORITHM).digest((string + SALT).getBytes(Charsets.UTF_8));
59 | return new String(Base64.encodeBase64(digest),Charsets.UTF_8);
60 | } catch (final NoSuchAlgorithmException e) {
61 | throw new AlgorithmNotSupportedException(ALGORITHM, e);
62 | }
63 | }
64 |
65 | /**
66 | * This class cannot be instantiated.
67 | */
68 | private Hasher() {
69 | throw new RuntimeException("This class cannot be instantiated.");
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/KeyFileUtilities.java:
--------------------------------------------------------------------------------
1 | /*
2 | * KeyFileUtilities.java from LicenseManager modified Tuesday, February 21, 2012 10:59:34 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import org.apache.commons.io.FileUtils;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.security.KeyFactory;
26 | import java.security.NoSuchAlgorithmException;
27 | import java.security.PrivateKey;
28 | import java.security.PublicKey;
29 | import java.security.spec.InvalidKeySpecException;
30 | import java.security.spec.PKCS8EncodedKeySpec;
31 | import java.security.spec.X509EncodedKeySpec;
32 |
33 | import ro.esolutions.licensing.exception.AlgorithmNotSupportedException;
34 | import ro.esolutions.licensing.exception.InappropriateKeySpecificationException;
35 |
36 | /**
37 | * A class of utility methods for reading and writing private and public keys
38 | * to files.
39 | *
40 | * @author Nicholas Williamo
41 | * @version 1.0.0
42 | * @since 1.0.0
43 | */
44 | public class KeyFileUtilities {
45 | public static final String KEY_ALGORITHM = "RSA";
46 |
47 | protected static void writeEncryptedPrivateKey(final PrivateKey privateKey,final File file, char[] passPhrase)
48 | throws IOException {
49 |
50 | FileUtils.writeByteArrayToFile(file, KeyFileUtilities.writeEncryptedPrivateKey(privateKey, passPhrase));
51 | }
52 |
53 | protected static void writeEncryptedPublicKey(final PublicKey publicKey,final File file,final char[] passPhrase)
54 | throws IOException {
55 | FileUtils.writeByteArrayToFile(file, KeyFileUtilities.writeEncryptedPublicKey(publicKey, passPhrase));
56 | }
57 |
58 | protected static PrivateKey readEncryptedPrivateKey(final File file,final char[] passPhrase) throws IOException {
59 | return KeyFileUtilities.readEncryptedPrivateKey(FileUtils.readFileToByteArray(file), passPhrase);
60 | }
61 |
62 | protected static PublicKey readEncryptedPublicKey(final File file,final char[] passPhrase) throws IOException {
63 | return KeyFileUtilities.readEncryptedPublicKey(FileUtils.readFileToByteArray(file), passPhrase);
64 | }
65 |
66 | protected static byte[] writeEncryptedPrivateKey(final PrivateKey privateKey,final char[] passPhrase) {
67 | final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
68 | return Encryptor.encryptRaw(pkcs8EncodedKeySpec.getEncoded(), passPhrase);
69 | }
70 |
71 | protected static byte[] writeEncryptedPublicKey(final PublicKey publicKey,final char[] passPhrase) {
72 | final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
73 | return Encryptor.encryptRaw(x509EncodedKeySpec.getEncoded(), passPhrase);
74 | }
75 |
76 | public static PrivateKey readEncryptedPrivateKey(final byte[] fileContents,final char[] passPhrase) {
77 | final PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Encryptor.decryptRaw(fileContents, passPhrase));
78 |
79 | try {
80 | return KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(privateKeySpec);
81 | } catch (final NoSuchAlgorithmException e) {
82 | throw new AlgorithmNotSupportedException(KEY_ALGORITHM, e);
83 | } catch (final InvalidKeySpecException e) {
84 | throw new InappropriateKeySpecificationException(e);
85 | }
86 | }
87 |
88 | public static PublicKey readEncryptedPublicKey(final byte[] fileContents,final char[] passPhrase) {
89 | final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Encryptor.decryptRaw(fileContents, passPhrase));
90 |
91 | try {
92 | return KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(publicKeySpec);
93 | } catch (final NoSuchAlgorithmException e) {
94 | throw new AlgorithmNotSupportedException(KEY_ALGORITHM, e);
95 | } catch (final InvalidKeySpecException e) {
96 | throw new InappropriateKeySpecificationException(e);
97 | }
98 | }
99 |
100 | private KeyFileUtilities() {
101 | throw new RuntimeException("This class cannot be instantiated.");
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/PasswordProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PasswordProvider.java from LicenseManager modified Tuesday, April 9, 2013 10:55:17 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | /**
22 | * This specifies an interface for providing a password for decrypting a key or license. Every user of this library
23 | * must implement this (one to three times). See the documentation for
24 | * {@code ro.esolutions.licensing.encryption.RSAKeyPairGenerator},
25 | * {@code ro.esolutions.licensing.licensor.LicenseCreator} and
26 | * {@link ro.esolutions.licensing.LicenseManager} for more information.
27 | *
28 | * @author Nick Williams
29 | * @version 1.5.0
30 | * @since 1.0.0
31 | */
32 | public interface PasswordProvider {
33 | /**
34 | * When integrating the license manager in your application, you must
35 | * implement this interface. It should return the password that you used
36 | * when encrypting the key or license.
37 | *
38 | * Also, do not implement this using any strings, i.e:
39 | *
40 | *
41 | * return "myInsecurePassword".toCharArray();
42 | *
43 | *
44 | * Strings persist in memory for a long time, and the string's contents
45 | * cannot be overwritten. Using only a character array allows the license
46 | * manager to overwrite the password when it is finished with it, thus
47 | * keeping it in the memory pool for as short a time as possible.
48 | *
49 | * Finally, the password must be between six and 32 characters
50 | * (inclusively). We recommend it be at least 10 characters.
51 | *
52 | * It is imperative that you obfuscate the bytecode for the
53 | * implementation of this class. It is also imperative that the character
54 | * array exist only for the life of this method (i.e., DO NOT store it as
55 | * an instance or class field).
56 | *
57 | * @return the password in character array form.
58 | */
59 | char[] getPassword();
60 | }
61 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/encryption/PublicKeyDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PublicKeyDataProvider.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.encryption;
20 |
21 | import ro.esolutions.licensing.exception.KeyNotFoundException;
22 |
23 | /**
24 | * Specifies an interface for retrieving the public key file data. This
25 | * interface only needs to be implemented in the application using the
26 | * licenses. It need not be implemented in the application generating the
27 | * licenses.
28 | *
29 | * @author Nick Williams
30 | * @version 1.0.0
31 | * @since 1.0.0
32 | */
33 | public interface PublicKeyDataProvider {
34 | /**
35 | * This method returns the data from the file containing the encrypted
36 | * public key from the public/private key pair. The contract for this
37 | * method can be fulfilled by storing the data in a byte array literal
38 | * in the source code itself.
39 | *
40 | * It is imperative that you obfuscate the bytecode for the
41 | * implementation of this class. It is also imperative that the byte
42 | * array exist only for the life of this method (i.e., DO NOT store it as
43 | * an instance or class field).
44 | *
45 | * @return the encrypted file contents from the public key file.
46 | * @throws KeyNotFoundException if the key data could not be retrieved; an acceptable message or chained cause must
47 | * be provided.
48 | */
49 | byte[] getEncryptedPublicKeyData() throws KeyNotFoundException;
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/AlgorithmNotSupportedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * AlgorithmNotSupportedException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown when the specified algorithm is not supported by
23 | * this JVM.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class AlgorithmNotSupportedException extends RuntimeException {
31 |
32 | public AlgorithmNotSupportedException() {
33 | super("The specified algorithm is not supported on this system.");
34 | }
35 |
36 | public AlgorithmNotSupportedException(final String algorithm) {
37 | super("The algorithm \"" + algorithm + "\" is not supported on this system.");
38 | }
39 |
40 | public AlgorithmNotSupportedException(final Throwable cause) {
41 | super(cause);
42 | }
43 |
44 | public AlgorithmNotSupportedException(final String algorithm,final Throwable cause) {
45 | super("The algorithm \"" + algorithm + "\" is not supported on this system.", cause);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/CorruptSignatureException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * CorruptSignatureException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This is thrown when a corrupt signature ar non-signature is provided.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | @SuppressWarnings("unused")
29 | public class CorruptSignatureException extends RuntimeException {
30 |
31 | public CorruptSignatureException() {
32 | super("The signature provided is corrupt or not a signature.");
33 | }
34 |
35 | public CorruptSignatureException(final String message) {
36 | super(message);
37 | }
38 |
39 | public CorruptSignatureException(final Throwable cause) {
40 | super("The signature provided is corrupt or not a signature.", cause);
41 | }
42 |
43 | public CorruptSignatureException(final String message,final Throwable cause) {
44 | super(message, cause);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/ExpiredLicenseException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ExpiredLicenseException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown whenever a license is validated that has expired.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @see ro.esolutions.licensing.LicenseValidator
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class ExpiredLicenseException extends InvalidLicenseException {
31 |
32 | private static final String THE_LICENSE_HAS_EXPIRED = "The license has expired.";
33 |
34 | public ExpiredLicenseException() {
35 | super(THE_LICENSE_HAS_EXPIRED);
36 | }
37 |
38 | public ExpiredLicenseException(final String message) {
39 | super(message);
40 | }
41 |
42 | public ExpiredLicenseException(final Throwable cause) {
43 | super(THE_LICENSE_HAS_EXPIRED, cause);
44 | }
45 |
46 | public ExpiredLicenseException(final String message,final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/FailedToDecryptException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FailedToDecryptException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown when the data was corrupt and undecryptable or when
23 | * the provided decryption password was incorrect. It is impossible to know
24 | * which is the actual cause.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since 1.0.0
29 | */
30 | @SuppressWarnings("unused")
31 | public class FailedToDecryptException extends RuntimeException {
32 |
33 | private static final String MESSAGE = "Failed to decrypt the data. Either the password was incorrect or the data was corrupt.";
34 |
35 | public FailedToDecryptException() {
36 | super(MESSAGE);
37 | }
38 |
39 | public FailedToDecryptException(final String message) {
40 | super(message);
41 | }
42 |
43 | public FailedToDecryptException(final Throwable cause) {
44 | super(MESSAGE, cause);
45 | }
46 |
47 | public FailedToDecryptException(final String message, final Throwable cause) {
48 | super(message, cause);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/InappropriateKeyException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * InappropriateKeyException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown when the specified key is inappropriate for the
23 | * given cipher.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class InappropriateKeyException extends RuntimeException {
31 |
32 | private static final String MESSAGE = "The specified key is inappropriate for the cipher.";
33 |
34 | public InappropriateKeyException() {
35 | super(MESSAGE);
36 | }
37 |
38 | public InappropriateKeyException(final String message) {
39 | super(message);
40 | }
41 |
42 | public InappropriateKeyException(final Throwable cause) {
43 | super(MESSAGE, cause);
44 | }
45 |
46 | public InappropriateKeyException(final String message, final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/InappropriateKeySpecificationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * InappropriateKeySpecificationException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown when an inappropriate key specification is provided
23 | * for the key factory.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class InappropriateKeySpecificationException extends RuntimeException {
31 | private static final String MESSAGE = "The specified key specification is inappropriate for the factory.";
32 |
33 | public InappropriateKeySpecificationException() {
34 | super(MESSAGE);
35 | }
36 |
37 | public InappropriateKeySpecificationException(final String message) {
38 | super(message);
39 | }
40 |
41 | public InappropriateKeySpecificationException(final Throwable cause) {
42 | super(MESSAGE, cause);
43 | }
44 |
45 | public InappropriateKeySpecificationException(final String message,final Throwable cause) {
46 | super(message, cause);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/InsecureEnvironmentError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * InsecureEnvironmentException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * Thrown when a security manager is already installed that allows reflection access but doesn't allow a more secure
23 | * security manager to be installed.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class InsecureEnvironmentError extends Error {
31 |
32 | public InsecureEnvironmentError(final String message, final Throwable cause) {
33 | super("The license manager was activated in an insecure environment. " + message, cause);
34 | }
35 |
36 | public InsecureEnvironmentError(final SecurityException cause) {
37 | super("The license manager was activated in an insecure environment. A security manager has already been " +
38 | "installed, but it allows reflection access to the license cache and doesn't allow a new security " +
39 | "manager to be installed.", cause);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/InvalidLicenseException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * InvalidLicenseException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This exception is thrown whenever a license is validated that isn't valid for some reason.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @see ro.esolutions.licensing.LicenseValidator
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class InvalidLicenseException extends RuntimeException {
31 |
32 | private static final String MESSAGE = "The license is not valid.";
33 |
34 | public InvalidLicenseException() {
35 | super(MESSAGE);
36 | }
37 |
38 | public InvalidLicenseException(final String message) {
39 | super(message);
40 | }
41 |
42 | public InvalidLicenseException(final Throwable cause) {
43 | super(MESSAGE, cause);
44 | }
45 |
46 | public InvalidLicenseException(final String message, final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/InvalidSignatureException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * InvalidSignatureException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This is thrown when a signature is invalid and cannot be verified.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | @SuppressWarnings("unused")
29 | public class InvalidSignatureException extends RuntimeException {
30 |
31 | private static final String MESSAGE = "The signature provided is invalid and cannot be verified.";
32 |
33 | public InvalidSignatureException() {
34 | super(MESSAGE);
35 | }
36 |
37 | public InvalidSignatureException(final String message) {
38 | super(message);
39 | }
40 |
41 | public InvalidSignatureException(final Throwable cause) {
42 | super(MESSAGE, cause);
43 | }
44 |
45 | public InvalidSignatureException(final String message, final Throwable cause) {
46 | super(message, cause);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/KeyNotFoundException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * KeyNotFoundException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This is thrown when the key (file) could not be found.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | @SuppressWarnings("unused")
29 | public class KeyNotFoundException extends RuntimeException {
30 |
31 | private static final String MESSAGE = "The key file could not be found.";
32 |
33 | public KeyNotFoundException() {
34 | super(MESSAGE);
35 | }
36 |
37 | public KeyNotFoundException(final String message) {
38 | super(message);
39 | }
40 |
41 | public KeyNotFoundException(final Throwable cause) {
42 | super(MESSAGE, cause);
43 | }
44 |
45 | public KeyNotFoundException(final String message, final Throwable cause) {
46 | super(message, cause);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/ObjectDeserializationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ObjectDeserializationException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This class is thrown when an error occurs while reading an object from a
23 | * byte array. The general form of this error indicates an I/O problem.
24 | * Sub-classes of this exception indicate more specific problems.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since 1.0.0
29 | */
30 | @SuppressWarnings("unused")
31 | public class ObjectDeserializationException extends RuntimeException {
32 |
33 | private static final String MESSAGE = "An error occurred while reading the object from the byte array.";
34 |
35 | public ObjectDeserializationException() {
36 | super(MESSAGE);
37 | }
38 |
39 | public ObjectDeserializationException(final String message) {
40 | super(message);
41 | }
42 |
43 | public ObjectDeserializationException(final Throwable cause) {
44 | super(MESSAGE, cause);
45 | }
46 |
47 | public ObjectDeserializationException(final String message, final Throwable cause) {
48 | super(message, cause);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/ObjectSerializationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ObjectSerializationException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This class is thrown when an I/O error occurs while writing an object to a
23 | * byte array.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class ObjectSerializationException extends RuntimeException {
31 |
32 | private static final String MESSAGE = "An I/O error occurred while writing the object to the byte array.";
33 |
34 | public ObjectSerializationException() {
35 | super(MESSAGE);
36 | }
37 |
38 | public ObjectSerializationException(final String message) {
39 | super(message);
40 | }
41 |
42 | public ObjectSerializationException(final Throwable cause) {
43 | super(MESSAGE, cause);
44 | }
45 |
46 | public ObjectSerializationException(final String message, final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/exception/ObjectTypeNotExpectedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ObjectTypeNotExpectedException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.exception;
20 |
21 | /**
22 | * This class class is thrown when an object is deserialized that does not match the type that was expected.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | @SuppressWarnings("unused")
29 | public class ObjectTypeNotExpectedException extends ObjectDeserializationException {
30 |
31 | private static final String MESSAGE = "The type of object read did not match the type expected.";
32 |
33 | public ObjectTypeNotExpectedException() {
34 | super(MESSAGE);
35 | }
36 |
37 | public ObjectTypeNotExpectedException(final String message) {
38 | super(message);
39 | }
40 |
41 | public ObjectTypeNotExpectedException(final String expectedType,final String encounteredType) {
42 | super("While deserializing an object of expected type \"" + expectedType + "\", got an object of type \"" +
43 | encounteredType + "\" instead.");
44 | }
45 |
46 | public ObjectTypeNotExpectedException(final Throwable cause) {
47 | super("The type of object read did not match the type expected.", cause);
48 | }
49 |
50 | public ObjectTypeNotExpectedException(final String message,final Throwable cause) {
51 | super(message, cause);
52 | }
53 |
54 | public ObjectTypeNotExpectedException(final String expectedType,final String encounteredType,final Throwable cause) {
55 | super("While deserializing an object of expected type \"" + expectedType + "\", got an object of type \"" +
56 | encounteredType + "\" instead.", cause);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/Immutable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Immutable.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | /**
22 | * This interface denotes a collection or other object as being unmodifiable.
23 | *
24 | * @author Nick Williams
25 | * @version 1.0.0
26 | * @since 1.0.0
27 | */
28 | public interface Immutable {
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableAbstractCollection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableAbstractCollection.java from LicenseManager modified Tuesday, February 21, 2012 10:59:34 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | import java.io.Serializable;
22 | import java.util.Collection;
23 |
24 | /**
25 | * Wraps a collection such that it cannot be modified. There is some overhead
26 | * associated with this due to verification of hash codes on every call to
27 | * prevent tampering with via reflection, but this is well worth it if your goal
28 | * is security and you truly need an unmodifiable collection.
29 | *
30 | * @author Nick Williams
31 | * @version 1.0.0
32 | * @since 1.0.0
33 | */
34 | public abstract class ImmutableAbstractCollection extends ValidObject
35 | implements Immutable, Collection, Serializable {
36 | private final static long serialVersionUID = -4187794066638697055L;
37 |
38 | final Collection internalCollection;
39 |
40 | private final int internalSize;
41 |
42 | private final int internalHashCode;
43 |
44 | /**
45 | * Constructor that wraps (not copies).
46 | *
47 | * @param collection The collection to decorate, must not be null
48 | * @throws IllegalArgumentException if collection is null
49 | */
50 | protected ImmutableAbstractCollection(final Collection collection) {
51 | if (collection == null) {
52 | throw new IllegalArgumentException("Parameter collection must not be null.");
53 | }
54 | this.internalCollection = collection;
55 | this.internalSize = this.internalCollection.size();
56 | this.internalHashCode = this.internalCollection.hashCode();
57 | }
58 |
59 | /**
60 | * Checks the validity of this object, and throws an
61 | * {@link ImmutableModifiedThroughReflectionException} if that check fails.
62 | *
63 | * @throws ImmutableModifiedThroughReflectionException if the validity check fails.
64 | */
65 | @Override
66 | protected final void checkValidity() {
67 | if (this.internalSize != this.internalCollection.size() ||
68 | this.internalHashCode != this.internalCollection.hashCode())
69 | throw new ImmutableModifiedThroughReflectionException();
70 | }
71 |
72 | @Override
73 | public final boolean equals(final Object o) {
74 | synchronized (this.internalCollection) {
75 | this.checkValidity();
76 | return o == this || (
77 | o instanceof ImmutableAbstractCollection &&
78 | this.internalCollection.equals(
79 | ((ImmutableAbstractCollection) o).internalCollection
80 | )
81 | );
82 | }
83 | }
84 |
85 | @Override
86 | public final int hashCode() {
87 | synchronized (this.internalCollection) {
88 | this.checkValidity();
89 | return this.internalHashCode;
90 | }
91 | }
92 |
93 | @Override
94 | @SuppressWarnings("unchecked")
95 | public final boolean contains(final Object object) {
96 | synchronized (this.internalCollection) {
97 | this.checkValidity();
98 | try {
99 | return this.internalCollection.contains(object);
100 | } catch (final ClassCastException e) {
101 | return false;
102 | }
103 | }
104 | }
105 |
106 | @Override
107 | public final boolean containsAll(final Collection> c) {
108 | synchronized (this.internalCollection) {
109 | this.checkValidity();
110 | return this.internalCollection.containsAll(c);
111 | }
112 | }
113 |
114 | @Override
115 | public final boolean isEmpty() {
116 | synchronized (this.internalCollection) {
117 | this.checkValidity();
118 | return this.internalCollection.isEmpty();
119 | }
120 | }
121 |
122 | @Override
123 | public final ImmutableIterator iterator() {
124 | synchronized (this.internalCollection) {
125 | this.checkValidity();
126 | return new ImmutableIterator<>(this.internalCollection.iterator(), this);
127 | }
128 | }
129 |
130 | @Override
131 | public final int size() {
132 | synchronized (this.internalCollection) {
133 | this.checkValidity();
134 | return this.internalCollection.size();
135 | }
136 | }
137 |
138 | @Override
139 | public final Object[] toArray() {
140 | synchronized (this.internalCollection) {
141 | this.checkValidity();
142 | return this.internalCollection.toArray();
143 | }
144 | }
145 |
146 | @Override
147 | @SuppressWarnings("SuspiciousToArrayCall")
148 | public final T[] toArray(final T[] prototype) {
149 | synchronized (this.internalCollection) {
150 | this.checkValidity();
151 | return this.internalCollection.toArray(prototype);
152 | }
153 | }
154 |
155 | @Override
156 | public final String toString() {
157 | return this.internalCollection.toString();
158 | }
159 |
160 | @Override
161 | public final boolean add(final E e) {
162 | throw new UnsupportedOperationException("This collection cannot be modified.");
163 | }
164 |
165 | @Override
166 | public final boolean addAll(final Collection extends E> c) {
167 | throw new UnsupportedOperationException("This collection cannot be modified.");
168 | }
169 |
170 | @Override
171 | public final void clear() {
172 | throw new UnsupportedOperationException("This collection cannot be modified.");
173 | }
174 |
175 | @Override
176 | public final boolean remove(final Object o) {
177 | throw new UnsupportedOperationException("This collection cannot be modified.");
178 | }
179 |
180 | @Override
181 | public final boolean removeAll(final Collection> c) {
182 | throw new UnsupportedOperationException("This collection cannot be modified.");
183 | }
184 |
185 | @Override
186 | public final boolean retainAll(final Collection> c) {
187 | throw new UnsupportedOperationException("This collection cannot be modified.");
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableArrayList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableArrayList.java from LicenseManager modified Thursday, January 24, 2013 23:33:43 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | import java.io.Serializable;
22 | import java.util.ArrayList;
23 | import java.util.Collection;
24 | import java.util.List;
25 |
26 | /**
27 | * Wraps a list such that it cannot be modified. There is some overhead
28 | * associated with this due to verification of hash codes on every call to
29 | * prevent tampering with via reflection, but this is well worth it if your goal
30 | * is security and you truly need an unmodifiable list.
31 | *
32 | * @author Nick Williams
33 | * @version 1.0.0
34 | * @since 1.0.0
35 | */
36 | public final class ImmutableArrayList extends ImmutableAbstractCollection implements List, Serializable, Cloneable {
37 | private final static long serialVersionUID = -6912407141647481417L;
38 |
39 | private final ArrayList internalList;
40 |
41 | /**
42 | * Constructor that copies.
43 | *
44 | * @param list the list to decorate, must not be null
45 | * @throws IllegalArgumentException if list is null
46 | */
47 | public ImmutableArrayList(final List list) {
48 | super(new ArrayList<>(list));
49 |
50 | this.internalList = (ArrayList) this.internalCollection;
51 | this.internalList.trimToSize();
52 | }
53 |
54 | @Override
55 | @SuppressWarnings({"unchecked", "CloneDoesntCallSuperClone"})
56 | public final ImmutableArrayList clone() {
57 | synchronized (this.internalList) {
58 | this.checkValidity();
59 | return new ImmutableArrayList((List) this.internalList.clone());
60 | }
61 | }
62 |
63 | @Override
64 | public final E get(final int index) {
65 | synchronized (this.internalList) {
66 | this.checkValidity();
67 | return this.internalList.get(index);
68 | }
69 | }
70 |
71 | @Override
72 | public final int indexOf(final Object o) {
73 | synchronized (this.internalList) {
74 | this.checkValidity();
75 | return this.internalList.indexOf(o);
76 | }
77 | }
78 |
79 | @Override
80 | public final int lastIndexOf(final Object o) {
81 | synchronized (this.internalList) {
82 | this.checkValidity();
83 | return this.internalList.lastIndexOf(o);
84 | }
85 | }
86 |
87 | @Override
88 | @SuppressWarnings("unchecked")
89 | public final ImmutableListIterator listIterator() {
90 | synchronized (this.internalList) {
91 | this.checkValidity();
92 | return new ImmutableListIterator<>(this.internalList.listIterator(), this);
93 | }
94 | }
95 |
96 | @Override
97 | @SuppressWarnings("unchecked")
98 | public final ImmutableListIterator listIterator(final int index) {
99 | synchronized (this.internalList) {
100 | this.checkValidity();
101 | return new ImmutableListIterator<>(this.internalList.listIterator(index), this);
102 | }
103 | }
104 |
105 | @Override
106 | public final ImmutableArrayList subList(final int fromIndex,final int toIndex) {
107 | synchronized (this.internalList) {
108 | this.checkValidity();
109 | final List subList = this.internalList.subList(fromIndex, toIndex);
110 | return new ImmutableArrayList<>(subList);
111 | }
112 | }
113 |
114 | @Override
115 | public final void add(final int index,final E e) {
116 | throw new UnsupportedOperationException("This list cannot be modified.");
117 | }
118 |
119 | @Override
120 | public final boolean addAll(final int index,final Collection extends E> c) {
121 | throw new UnsupportedOperationException("This list cannot be modified.");
122 | }
123 |
124 | @Override
125 | public final E remove(final int index) {
126 | throw new UnsupportedOperationException("This list cannot be modified.");
127 | }
128 |
129 | @Override
130 | public final E set(final int index,final E e) {
131 | throw new UnsupportedOperationException("This list cannot be modified.");
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableIterator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableIterator.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | import java.util.Iterator;
22 |
23 | /**
24 | * Wraps an iterator such that it cannot be modified.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since 1.0.0
29 | */
30 | public final class ImmutableIterator implements Immutable, Iterator {
31 | private final Iterator internal;
32 |
33 | private final ValidObject validObject;
34 |
35 | ImmutableIterator(final Iterator iterator,final ValidObject validObject) {
36 | this.internal = iterator;
37 | this.validObject = validObject;
38 | }
39 |
40 | @Override
41 | public boolean hasNext() {
42 | synchronized (this.validObject) {
43 | this.validObject.checkValidity();
44 | return this.internal.hasNext();
45 | }
46 | }
47 |
48 | @Override
49 | public E next() {
50 | synchronized (this.validObject) {
51 | this.validObject.checkValidity();
52 | return this.internal.next();
53 | }
54 | }
55 |
56 | @Override
57 | public void remove() {
58 | throw new UnsupportedOperationException("This iterator cannot be modified.");
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableLinkedHashSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableLinkedHashSet.java from LicenseManager modified Tuesday, February 21, 2012 10:59:34 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | import java.io.Serializable;
22 | import java.util.ArrayList;
23 | import java.util.LinkedHashSet;
24 | import java.util.Set;
25 |
26 | /**
27 | * Wraps a set such that it cannot be modified. There is some overhead
28 | * associated with this due to verification of hash codes on every call to
29 | * prevent tampering with via reflection, but this is well worth it if your goal
30 | * is security and you truly need an unmodifiable set.
31 | *
32 | * @author Nick Williams
33 | * @version 1.5.0
34 | * @since 1.0.0
35 | */
36 | public final class ImmutableLinkedHashSet extends ImmutableAbstractCollection
37 | implements Set, Serializable, Cloneable {
38 | private final static long serialVersionUID = 2284350955829958161L;
39 |
40 | private final LinkedHashSet internalSet;
41 |
42 | private final ArrayList internalList;
43 |
44 | /**
45 | * Constructor that copies.
46 | *
47 | * @param list the set to decorate, must not be null
48 | * @throws IllegalArgumentException if list is null
49 | */
50 | public ImmutableLinkedHashSet(final Set list) {
51 | super(new LinkedHashSet<>(list));
52 |
53 | this.internalSet = (LinkedHashSet) this.internalCollection;
54 | this.internalList = new ArrayList<>(list);
55 | }
56 |
57 | @Override
58 | @SuppressWarnings({"unchecked", "CloneDoesntCallSuperClone"})
59 | public final ImmutableLinkedHashSet clone() {
60 | synchronized (this.internalSet) {
61 | this.checkValidity();
62 | return new ImmutableLinkedHashSet<>((Set) this.internalSet.clone());
63 | }
64 | }
65 |
66 | /**
67 | * Retrieves the indexed element specified.
68 | *
69 | * @param index The element to retrieve.
70 | * @return The element requested.
71 | */
72 | public E get(final int index) {
73 | return index < 0 ? null : this.internalList.get(index);
74 | }
75 |
76 | /**
77 | * Retrieves the matching element specified.
78 | *
79 | * @param object The element to match.
80 | * @return The element requested.
81 | */
82 | public E get(final E object) {
83 | return this.get(this.internalList.indexOf(object));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableListIterator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableListIterator.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | import java.util.ListIterator;
22 |
23 | /**
24 | * Wraps a list iterator such that it cannot be modified.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since x.x.x
29 | */
30 | public final class ImmutableListIterator implements Immutable, ListIterator {
31 | private final ListIterator internal;
32 |
33 | private final ValidObject validObject;
34 |
35 | ImmutableListIterator(final ListIterator iterator,final ValidObject validObject) {
36 | this.internal = iterator;
37 | this.validObject = validObject;
38 | }
39 |
40 | @Override
41 | public boolean hasNext() {
42 | synchronized (this.validObject) {
43 | this.validObject.checkValidity();
44 | return this.internal.hasNext();
45 | }
46 | }
47 |
48 | @Override
49 | public boolean hasPrevious() {
50 | synchronized (this.validObject) {
51 | this.validObject.checkValidity();
52 | return this.internal.hasPrevious();
53 | }
54 | }
55 |
56 | @Override
57 | public E next() {
58 | synchronized (this.validObject) {
59 | this.validObject.checkValidity();
60 | return this.internal.next();
61 | }
62 | }
63 |
64 | @Override
65 | public int nextIndex() {
66 | synchronized (this.validObject) {
67 | this.validObject.checkValidity();
68 | return this.internal.nextIndex();
69 | }
70 | }
71 |
72 | @Override
73 | public E previous() {
74 | synchronized (this.validObject) {
75 | this.validObject.checkValidity();
76 | return this.internal.previous();
77 | }
78 | }
79 |
80 | @Override
81 | public int previousIndex() {
82 | synchronized (this.validObject) {
83 | this.validObject.checkValidity();
84 | return this.internal.previousIndex();
85 | }
86 | }
87 |
88 | @Override
89 | public void add(final E e) {
90 | throw new UnsupportedOperationException("This iterator cannot be modified.");
91 | }
92 |
93 | @Override
94 | public void remove() {
95 | throw new UnsupportedOperationException("This iterator cannot be modified.");
96 | }
97 |
98 | @Override
99 | public void set(final E e) {
100 | throw new UnsupportedOperationException("This iterator cannot be modified.");
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ImmutableModifiedThroughReflectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ImmutableModifiedThroughReflectionException.java from LicenseManager modified Friday, September 21, 2012 07:46:54 CDT (-0500).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | /**
22 | * This exception is thrown when an unmodifiable list is modified illegally
23 | * through exception.
24 | *
25 | * @author Nick Williams
26 | * @version 1.0.0
27 | * @since 1.0.0
28 | */
29 | @SuppressWarnings("unused")
30 | public class ImmutableModifiedThroughReflectionException extends Error {
31 | private static final long serialVersionUID = 1L;
32 | private static final String MESSAGE = "This immutable object appears to have been modified through reflection.";
33 |
34 | public ImmutableModifiedThroughReflectionException() {
35 | super(MESSAGE);
36 | }
37 |
38 | public ImmutableModifiedThroughReflectionException(final String message) {
39 | super(message);
40 | }
41 |
42 | public ImmutableModifiedThroughReflectionException(final Throwable cause) {
43 | super(MESSAGE, cause);
44 | }
45 |
46 | public ImmutableModifiedThroughReflectionException(final String message, final Throwable cause) {
47 | super(message, cause);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/ro/esolutions/licensing/immutable/ValidObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ValidObject.java from LicenseManager modified Tuesday, February 21, 2012 10:59:35 CST (-0600).
3 | *
4 | * Copyright 2010-2013 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package ro.esolutions.licensing.immutable;
20 |
21 | /**
22 | * This class specifies an interface for checking the validity of an object. It
23 | * is specified as an abstract class instead of an interface so that the
24 | * implementing classes can keep the target method protected.
25 | *
26 | * @author Nick Williams
27 | * @version 1.0.0
28 | * @since 1.0.0
29 | */
30 | abstract class ValidObject {
31 | /**
32 | * Checks the validity of this object, and throws an
33 | * {@link ImmutableModifiedThroughReflectionException} if that check fails.
34 | *
35 | * @throws ImmutableModifiedThroughReflectionException if the validity check fails.
36 | */
37 | protected abstract void checkValidity();
38 | }
39 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
21 | 4.0.0
22 |
23 | ro.esolutions
24 | license-manager
25 | pom
26 |
27 | License Manager
28 | 1.0.4-SNAPSHOT
29 |
30 | License Manager - A Java-based licensing tool for licensing commercial applications.
31 |
32 |
33 |
34 | Apache License, Version 2.0
35 | https://www.apache.org/licenses/LICENSE-2.0.txt
36 | repo
37 |
38 |
39 |
40 |
41 | mstaicu
42 | Marius Staicu
43 | marius.staicu@esolutions.rio
44 | eSolutions Grup
45 | https://www.esolutions.ro
46 |
47 | software engineer
48 |
49 | Romania/Bucharest
50 |
51 |
52 | vborcea
53 | Virgil Borcea
54 | virgil.borcea@esolutions.rio
55 | eSolutions Grup
56 | https://www.esolutions.ro
57 |
58 | software engineer
59 |
60 | Romania/Bucharest
61 |
62 |
63 |
64 | core
65 | base
66 |
67 |
68 | https://github.com/eSolutionsGrup/license-manager
69 |
70 | https://github.com/eSolutionsGrup/license-manager
71 | scm:git:https://github.com/eSolutionsGrup/license-manager.git
72 | scm:git:https://github.com/eSolutionsGrup/license-manager.git
73 |
74 |
75 |
76 | 17
77 | ${java.version}
78 | ${java.version}
79 | UTF-8
80 | UTF-8
81 |
82 |
83 |
84 |
85 |
86 | commons-codec
87 | commons-codec
88 | 1.15
89 |
90 |
91 |
92 | commons-io
93 | commons-io
94 | 2.11.0
95 |
96 |
97 |
98 | commons-lang
99 | commons-lang
100 | 2.6
101 |
102 |
103 |
104 | com.google.guava
105 | guava
106 | 31.1-jre
107 |
108 |
109 |
110 | org.ow2.asm
111 | asm
112 | 9.4
113 |
114 |
115 |
116 |
117 |
118 |
119 | ossrh
120 | https://oss.sonatype.org/content/repositories/snapshots
121 |
122 |
123 | ossrh
124 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
125 |
126 |
127 |
128 |
129 |
130 |
131 | org.apache.maven.plugins
132 | maven-release-plugin
133 | 3.0.1
134 |
135 | SemVerVersionPolicy
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | release
144 |
145 |
146 |
147 | org.apache.maven.plugins
148 | maven-gpg-plugin
149 | 3.1.0
150 |
151 |
152 | sign-artifacts
153 | verify
154 |
155 | sign
156 |
157 |
158 |
159 |
160 |
161 | org.apache.maven.plugins
162 | maven-source-plugin
163 | 3.2.1
164 |
165 |
166 | attach-sources
167 |
168 | jar-no-fork
169 |
170 |
171 |
172 |
173 |
174 | org.apache.maven.plugins
175 | maven-javadoc-plugin
176 | 3.5.0
177 |
178 |
179 | attach-javadocs
180 |
181 | jar
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------