/src/org/jgroups/auth/X509Token.java
Java | 245 lines | 189 code | 31 blank | 25 comment | 40 complexity | 51a331f96a31688d3ff1909a53266be3 MD5 | raw file
Possible License(s): LGPL-2.1
1package org.jgroups.auth;
2
3import org.jgroups.util.Util;
4import org.jgroups.Message;
5
6import javax.crypto.Cipher;
7import java.io.*;
8import java.util.Properties;
9import java.security.cert.X509Certificate;
10import java.security.PrivateKey;
11import java.security.KeyStore;
12/**
13 * <p>
14 * This is an example of using a preshared token that is encrypted using an X509 certificate for authentication purposes. All members of the group have to have the same string value in the JGroups config.
15 * </p>
16 * <p>
17 * This example uses certificates contained within a specified keystore. Configuration parameters for this example are shown below:
18 * </p>
19 * <ul>
20 * <li>keystore_type = JKS(default)/PKCS12 - see http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA</li>
21 * <li>keystore_path (required) = the location of the keystore</li>
22 * <li>keystore_password (required) = the password of the keystore</li>
23 * <li>cert_alias (required) = the alias of the certification within the keystore</li>
24 * <li>cert_password = the password of the certification within the keystore</li>
25 * <li>auth_value (required) = the string to encrypt</li>
26 * <li>cipher_type = RSA(default)/AES/Blowfish/DES/DESede/PBEWithMD5AndDES/PBEWithHmacSHA1AndDESede/RC2/RC4/RC5 - see http://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA</li>
27 * </ul>
28 * @see org.jgroups.auth.AuthToken
29 * @author Chris Mills
30 */
31public class X509Token extends AuthToken {
32
33 public static final String KEYSTORE_TYPE = "keystore_type";
34 public static final String KEYSTORE_PATH = "keystore_path";
35 public static final String KEYSTORE_PASSWORD = "keystore_password";
36 public static final String CERT_ALIAS = "cert_alias";
37 public static final String CERT_PASSWORD = "cert_password";
38 public static final String TOKEN_ATTR = "auth_value";
39 public static final String CIPHER_TYPE = "cipher_type";
40
41 private boolean valueSet = false;
42
43 private String keystore_type = null;
44 private String cert_alias = null;
45 private String keystore_path = null;
46 private String token_attr = null;
47 private String cipher_type = null;
48
49 private byte[] encryptedToken = null;
50
51 private char[] cert_password = null;
52 private char[] keystore_password = null;
53
54 private Cipher cipher = null;
55 private PrivateKey certPrivateKey = null;
56 private X509Certificate certificate = null;
57
58 public X509Token() {
59 //need an empty constructor
60 }
61
62 public void setValue(Properties properties) {
63 if(log.isDebugEnabled()){
64 log.debug("setting values on X509Token object");
65 }
66
67 if(properties.containsKey(TOKEN_ATTR)){
68 this.token_attr = (String) properties.get(TOKEN_ATTR);
69 properties.remove(TOKEN_ATTR);
70 if(log.isDebugEnabled()){
71 log.debug("token_attr = " + this.token_attr);
72 }
73 }
74
75 if(properties.containsKey(KEYSTORE_TYPE)){
76 this.keystore_type = (String) properties.get(KEYSTORE_TYPE);
77 properties.remove(KEYSTORE_TYPE);
78 if(log.isDebugEnabled()){
79 log.debug("keystore_type = " + this.keystore_type);
80 }
81 }else{
82 this.keystore_type = "JKS";
83 if(log.isDebugEnabled()){
84 log.debug("keystore_type = " + this.keystore_type);
85 }
86 }
87
88 if(properties.containsKey(KEYSTORE_PATH)){
89 this.keystore_path = (String) properties.get(KEYSTORE_PATH);
90 properties.remove(KEYSTORE_PATH);
91 if(log.isDebugEnabled()){
92 log.debug("keystore_path = " + this.keystore_path);
93 }
94 }
95
96 if(properties.containsKey(KEYSTORE_PASSWORD)){
97 this.keystore_password = ((String) properties.get(KEYSTORE_PASSWORD)).toCharArray();
98 properties.remove(KEYSTORE_PASSWORD);
99 if(log.isDebugEnabled()){
100 log.debug("keystore_password = " + this.keystore_password);
101 }
102 }
103
104 if(properties.containsKey(CERT_ALIAS)){
105 this.cert_alias = (String) properties.get(CERT_ALIAS);
106 properties.remove(CERT_ALIAS);
107 if(log.isDebugEnabled()){
108 log.debug("cert_alias = " + this.cert_alias);
109 }
110 }
111
112 if(properties.containsKey(CERT_PASSWORD)){
113 this.cert_password = ((String) properties.get(CERT_PASSWORD)).toCharArray();
114 properties.remove(CERT_PASSWORD);
115 if(log.isDebugEnabled()){
116 log.debug("cert_password = " + this.cert_password);
117 }
118 }else{
119 this.cert_password = this.keystore_password;
120 if(log.isDebugEnabled()){
121 log.debug("cert_password = " + this.cert_password);
122 }
123 }
124
125 if(properties.containsKey(CIPHER_TYPE)){
126 this.cipher_type = (String) properties.get(CIPHER_TYPE);
127 properties.remove(CIPHER_TYPE);
128 if(log.isDebugEnabled()){
129 log.debug("cipher_type = " + this.cipher_type);
130 }
131 }else{
132 this.cipher_type = "RSA";
133 if(log.isDebugEnabled()){
134 log.debug("cipher_type = " + this.cipher_type);
135 }
136 }
137
138 if(getCertificate()){
139 this.valueSet = true;
140 if(log.isDebugEnabled()){
141 log.debug("X509Token created correctly");
142 }
143 }
144 }
145
146 public String getName() {
147 return "org.jgroups.auth.X509Token";
148 }
149
150 public boolean authenticate(AuthToken token, Message msg) {
151 if (!this.valueSet) {
152 if(log.isFatalEnabled()){
153 log.fatal("X509Token not setup correctly - check token attrs");
154 }
155 return false;
156 }
157
158 if((token != null) && (token instanceof X509Token)){
159 //got a valid X509 token object
160 X509Token serverToken = (X509Token)token;
161 if(!serverToken.valueSet){
162 if(log.isFatalEnabled()){
163 log.fatal("X509Token - recieved token not valid");
164 }
165 return false;
166 }
167
168 try{
169 if(log.isDebugEnabled()){
170 log.debug("setting cipher to decrypt mode");
171 }
172 this.cipher.init(Cipher.DECRYPT_MODE, this.certPrivateKey);
173 String serverBytes = new String(this.cipher.doFinal(serverToken.encryptedToken));
174 if((serverBytes != null) && (serverBytes.equalsIgnoreCase(this.token_attr))){
175 if(log.isDebugEnabled()){
176 log.debug("X509 authentication passed");
177 }
178 return true;
179 }
180 }catch(Exception e){
181 if(log.isFatalEnabled()){
182 log.fatal(e);
183 }
184 }
185 }
186 if(log.isWarnEnabled()){
187 log.warn("X509 authentication failed");
188 }
189 return false;
190 }
191
192 public void writeTo(DataOutputStream out) throws IOException {
193 if(log.isDebugEnabled()){
194 log.debug("X509Token writeTo()");
195 }
196 Util.writeByteBuffer(this.encryptedToken, out);
197 }
198
199 public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
200 if(log.isDebugEnabled()){
201 log.debug("X509Token readFrom()");
202 }
203 this.encryptedToken = Util.readByteBuffer(in);
204 this.valueSet = true;
205 }
206 /**
207 * Used during setup to get the certification from the keystore and encrypt the auth_value with the private key
208 * @return true if the certificate was found and the string encypted correctly otherwise returns false
209 */
210 private boolean getCertificate() {
211 try{
212 KeyStore store = KeyStore.getInstance(this.keystore_type);
213 java.io.FileInputStream fis = new java.io.FileInputStream(this.keystore_path);
214 store.load(fis, this.keystore_password);
215
216 this.cipher = Cipher.getInstance(this.cipher_type);
217 this.certificate = (X509Certificate) store.getCertificate(this.cert_alias);
218
219 if(log.isDebugEnabled()){
220 log.debug("certificate = " + this.certificate.toString());
221 }
222
223 this.cipher.init(Cipher.ENCRYPT_MODE, this.certificate);
224 this.encryptedToken = this.cipher.doFinal(this.token_attr.getBytes());
225
226 if(log.isDebugEnabled()){
227 log.debug("encryptedToken = " + this.encryptedToken);
228 }
229
230 KeyStore.PrivateKeyEntry privateKey = (KeyStore.PrivateKeyEntry)store.getEntry(this.cert_alias, new KeyStore.PasswordProtection(this.cert_password));
231 this.certPrivateKey = privateKey.getPrivateKey();
232
233 if(log.isDebugEnabled()){
234 log.debug("certPrivateKey = " + this.certPrivateKey.toString());
235 }
236
237 return true;
238 }catch(Exception e){
239 if(log.isFatalEnabled()){
240 log.fatal(e);
241 }
242 return false;
243 }
244 }
245}