org.jgroups.auth.X509Token Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
package org.jgroups.auth;
import org.jgroups.Message;
import org.jgroups.annotations.Property;
import org.jgroups.util.Util;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
*
* 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.
*
*
* This example uses certificates contained within a specified keystore. Configuration parameters
* for this example are shown below:
*
*
* - keystore_type = JKS(default)/PKCS12 - see
* http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA
* - keystore_path (required) = the location of the keystore
* - keystore_password (required) = the password of the keystore
* - cert_alias (required) = the alias of the certification within the keystore
* - cert_password = the password of the certification within the keystore
* - auth_value (required) = the string to encrypt
* - 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
*
*
* @author Chris Mills
* @author Bela Ban
* @see org.jgroups.auth.AuthToken
*/
public class X509Token extends AuthToken {
private boolean valueSet;
@Property
protected String keystore_type = "JKS";
@Property
protected String cert_alias;
@Property
protected String keystore_path;
@Property(exposeAsManagedAttribute=false)
protected String auth_value;
@Property
protected String cipher_type = "RSA";
private byte[] encryptedToken;
private char[] cert_password;
private char[] keystore_password;
private Cipher cipher;
private PrivateKey certPrivateKey;
private X509Certificate certificate;
public X509Token() {
// need an empty constructor
}
@Property(name = "cert_password",exposeAsManagedAttribute=false)
public void setCertPassword(String pwd) {
this.cert_password = pwd.toCharArray();
}
@Property(name = "keystore_password",exposeAsManagedAttribute=false)
public void setKeyStorePassword(String pwd) {
this.keystore_password = pwd.toCharArray();
if (cert_password == null)
cert_password = keystore_password;
}
/** To be used for testing only */
public X509Token encryptedToken(byte[] buf) {
encryptedToken=buf;
return this;
}
public String getName() {
return X509Token.class.getName();
}
public boolean authenticate(AuthToken token, Message msg) {
if (!this.valueSet) {
log.error(Util.getMessage("X509TokenNotSetupCorrectlyCheckTokenAttrs"));
return false;
}
if (token instanceof X509Token) {
// got a valid X509 token object
X509Token serverToken = (X509Token) token;
if (!serverToken.valueSet) {
log.error(Util.getMessage("X509TokenReceivedTokenNotValid"));
return false;
}
try {
this.cipher.init(Cipher.DECRYPT_MODE, this.certPrivateKey);
String serverBytes = new String(this.cipher.doFinal(serverToken.encryptedToken));
if ((serverBytes.equalsIgnoreCase(this.auth_value))) {
log.debug("X509 authentication passed");
return true;
}
} catch (Exception e) {
log.error(e.toString());
}
}
return false;
}
@Override
public void writeTo(DataOutput out) throws IOException {
Util.writeByteBuffer(this.encryptedToken, out);
}
@Override
public void readFrom(DataInput in) throws IOException {
this.encryptedToken = Util.readByteBuffer(in);
this.valueSet = true;
}
public int size() {
return Util.size(encryptedToken);
}
/**
* Used during setup to get the certification from the keystore and encrypt the auth_value with
* the private key
*/
public void setCertificate() throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, UnrecoverableEntryException {
KeyStore store = KeyStore.getInstance(this.keystore_type);
InputStream inputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream(this.keystore_path);
if(inputStream == null)
inputStream=new FileInputStream(this.keystore_path);
store.load(inputStream, this.keystore_password);
this.cipher = Cipher.getInstance(this.cipher_type);
this.certificate = (X509Certificate) store.getCertificate(this.cert_alias);
log.debug("certificate = " + this.certificate.toString());
this.cipher.init(Cipher.ENCRYPT_MODE, this.certificate);
this.encryptedToken = this.cipher.doFinal(this.auth_value.getBytes());
KeyStore.PrivateKeyEntry privateKey = (KeyStore.PrivateKeyEntry) store.getEntry(
this.cert_alias, new KeyStore.PasswordProtection(this.cert_password));
this.certPrivateKey = privateKey.getPrivateKey();
this.valueSet=true;
}
}