package io.lumify.web;
import io.lumify.core.exception.LumifyException;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.user.User;
import io.lumify.core.util.LumifyLogger;
import io.lumify.core.util.LumifyLoggerFactory;
import io.lumify.miniweb.HandlerChain;
import org.securegraph.Graph;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.List;
public abstract class X509AuthenticationHandler extends AuthenticationHandler {
public static final String CERTIFICATE_REQUEST_ATTRIBUTE = "javax.servlet.request.X509Certificate";
private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(X509AuthenticationHandler.class);
private final UserRepository userRepository;
private final Graph graph;
protected X509AuthenticationHandler(UserRepository userRepository, final Graph graph) {
this.userRepository = userRepository;
this.graph = graph;
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, HandlerChain chain) throws Exception {
String userId = CurrentUser.get(request);
if (userId == null) {
X509Certificate cert = extractCertificate(request);
if (isInvalid(cert)) {
respondWithAuthenticationFailure(response);
return;
}
User user = getUser(request, cert);
if (user == null) {
respondWithAuthenticationFailure(response);
return;
}
userRepository.recordLogin(user, request.getRemoteAddr());
CurrentUser.set(request, user.getUserId(), user.getUsername());
}
chain.next(request, response);
}
protected User getUser(HttpServletRequest request, X509Certificate cert) {
String username = getUsername(cert);
if (username == null || username.trim().equals("")) {
return null;
}
String displayName = getDisplayName(cert);
if (displayName == null || displayName.trim().equals("")) {
return null;
}
String randomPassword = UserRepository.createRandomPassword();
return userRepository.findOrAddUser(username, displayName, null, randomPassword, new String[0]);
}
protected boolean isInvalid(X509Certificate cert) {
if (cert == null) {
return true;
}
try {
cert.checkValidity();
return false;
} catch (CertificateExpiredException e) {
LOGGER.warn("Authentication attempt with expired certificate: %s", cert.getSubjectDN());
} catch (CertificateNotYetValidException e) {
LOGGER.warn("Authentication attempt with certificate that's not yet valid: %s", cert.getSubjectDN());
}
return true;
}
protected X509Certificate extractCertificate(HttpServletRequest request) {
X509Certificate[] certs = (X509Certificate[]) request.getAttribute(CERTIFICATE_REQUEST_ATTRIBUTE);
if (null != certs && certs.length > 0) {
return certs[0];
}
return null;
}
protected String getUsername(X509Certificate cert) {
String dn = getDn(cert);
if (dn != null) {
return dn;
} else {
throw new LumifyException("failed to get DN from cert for username");
}
}
protected String getDisplayName(X509Certificate cert) {
String cn = getCn(cert);
if (cn != null) {
return cn;
} else {
throw new LumifyException("failed to get CN from cert for displayName");
}
}
private String getDn(X509Certificate cert) {
String dn = cert.getSubjectX500Principal().getName();
LOGGER.debug("certificate DN is [%s]", dn);
return dn;
}
private String getCn(X509Certificate cert) {
String dn = getDn(cert);
try {
List<Rdn> rdns = new LdapName(dn).getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
Rdn rdn = rdns.get(i);
if (rdn.getType().equalsIgnoreCase("CN")) {
String cn = rdn.getValue().toString();
LOGGER.debug("certificate CN is [%s]", cn);
return cn;
}
}
} catch (InvalidNameException ine) {
return null;
}
return null;
}
protected void respondWithAuthenticationFailure(HttpServletResponse response) throws IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
protected UserRepository getUserRepository() {
return userRepository;
}
protected Graph getGraph() {
return graph;
}
}