blob: 688b225cfac4b01c55c911ecc98a4ccb9da3f73a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.security.templates;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.logging.log4j.Logger;
import org.apache.geode.LogWriter;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.security.AuthenticationFailedException;
import org.apache.geode.security.Authenticator;
/**
* An implementation of {@link Authenticator} that uses PKCS.
*/
public class PKCSAuthenticator implements Authenticator {
private static final Logger logger = LogService.getLogger();
public static final String PUBLIC_KEY_FILE = "security-publickey-filepath";
public static final String PUBLIC_KEYSTORE_PASSWORD = "security-publickey-pass";
private String pubKeyFilePath;
private String pubKeyPass;
private Map aliasCertificateMap;
private LogWriter systemLogWriter;
private LogWriter securityLogWriter;
public static Authenticator create() {
return new PKCSAuthenticator();
}
@Override
public void init(final Properties securityProperties, final LogWriter systemLogWriter,
final LogWriter securityLogWriter) throws AuthenticationFailedException {
this.systemLogWriter = systemLogWriter;
this.securityLogWriter = securityLogWriter;
this.pubKeyFilePath = securityProperties.getProperty(PUBLIC_KEY_FILE);
if (this.pubKeyFilePath == null) {
throw new AuthenticationFailedException("PKCSAuthenticator: property " + PUBLIC_KEY_FILE
+ " not specified as the public key file.");
}
this.pubKeyPass = securityProperties.getProperty(PUBLIC_KEYSTORE_PASSWORD);
this.aliasCertificateMap = new HashMap();
populateMap();
}
@Override
public Principal authenticate(final Properties credentials, final DistributedMember member)
throws AuthenticationFailedException {
final String alias = (String) credentials.get(PKCSAuthInit.KEYSTORE_ALIAS);
if (alias == null || alias.length() <= 0) {
throw new AuthenticationFailedException("No alias received");
}
try {
final X509Certificate cert = getCertificate(alias);
if (cert == null) {
throw newException("No certificate found for alias:" + alias);
}
final byte[] signatureBytes = (byte[]) credentials.get(PKCSAuthInit.SIGNATURE_DATA);
if (signatureBytes == null) {
throw newException(
"signature data property [" + PKCSAuthInit.SIGNATURE_DATA + "] not provided");
}
final Signature sig = Signature.getInstance(cert.getSigAlgName());
sig.initVerify(cert);
sig.update(alias.getBytes("UTF-8"));
if (!sig.verify(signatureBytes)) {
throw newException("verification of client signature failed");
}
return new PKCSPrincipal(alias);
} catch (Exception ex) {
throw newException(ex.toString(), ex);
}
}
@Override
public void close() {}
private void populateMap() {
try {
final KeyStore keyStore = KeyStore.getInstance("JKS");
final char[] passPhrase = this.pubKeyPass != null ? this.pubKeyPass.toCharArray() : null;
final FileInputStream keyStoreFile = new FileInputStream(this.pubKeyFilePath);
try {
keyStore.load(keyStoreFile, passPhrase);
} finally {
keyStoreFile.close();
}
for (Enumeration e = keyStore.aliases(); e.hasMoreElements();) {
final Object alias = e.nextElement();
final Certificate cert = keyStore.getCertificate((String) alias);
if (cert instanceof X509Certificate) {
this.aliasCertificateMap.put(alias, cert);
}
}
} catch (Exception e) {
throw new AuthenticationFailedException(
"Exception while getting public keys: " + e.getMessage(), e);
}
}
private AuthenticationFailedException newException(final String message, final Exception cause) {
final String fullMessage =
"PKCSAuthenticator: Authentication of client failed due to: " + message;
if (cause != null) {
return new AuthenticationFailedException(fullMessage, cause);
} else {
return new AuthenticationFailedException(fullMessage);
}
}
private AuthenticationFailedException newException(final String message) {
return newException(message, null);
}
private X509Certificate getCertificate(final String alias)
throws NoSuchAlgorithmException, InvalidKeySpecException {
if (this.aliasCertificateMap.containsKey(alias)) {
return (X509Certificate) this.aliasCertificateMap.get(alias);
}
return null;
}
}