com.github.vincentrussell.nexus3.x509.dn.security.plugin.X509DnAuthenticatingRealm Maven / Gradle / Ivy
package com.github.vincentrussell.nexus3.x509.dn.security.plugin;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.x509.X509AuthenticationInfo;
import org.apache.shiro.authc.x509.X509AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.x509.AbstractX509Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.eclipse.sisu.Description;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.security.anonymous.AnonymousPrincipalCollection;
import org.yaml.snakeyaml.Yaml;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.security.auth.x500.X500Principal;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
/**
* The Class X509DnAuthenticatingRealm.
*/
@Singleton
@Named(X509DnAuthenticatingRealm.NAME)
@Description("X509-Dn Authenticating Realm")
public class X509DnAuthenticatingRealm extends AbstractX509Realm {
private static final Logger LOGGER = LoggerFactory.getLogger(X509DnAuthenticatingRealm.class);
public static final X509Certificate DEFAULT_ANONYMOUS_CERT = getDefaultAnonymousCert();
private static X509Certificate getDefaultAnonymousCert() {
try (InputStream inputStream = X509DnAuthenticatingRealm.class.getResourceAsStream("/certs/anonymous/anonymous.cer")) {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
final X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(inputStream);
return certificate;
} catch (Throwable e) {
LOGGER.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}
protected static final String NAME = "X509DnAuthenticatingRealm";
protected static final String CONFIG_FILE = X509DnAuthenticatingRealm.class.getSimpleName() + ".config.file";
public static final SimpleAuthorizationInfo ANONYMOUS_AUTHORIZATION_INFO = new SimpleAuthorizationInfo(Sets.newHashSet("nx-anonymous"));
private final Yaml yaml = new Yaml();
private final Multimap roleToDnMultimap = HashMultimap.create();
private final Multimap dnToRoleMultimap = HashMultimap.create();
public X509DnAuthenticatingRealm() {
try (FileInputStream fileInputStream = new FileInputStream(System.getProperty(CONFIG_FILE))) {
Map> compiledYaml = yaml.load(fileInputStream);
generateMultiMaps(compiledYaml);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
setAuthenticationTokenClass(X509AuthenticationToken.class);
setName(NAME);
setAuthenticationCachingEnabled(true);
}
private void generateMultiMaps(Map> compiledYaml) {
for (Map.Entry> entry : compiledYaml.entrySet()) {
String role = entry.getKey();
for (String dn : entry.getValue()) {
String normalizedDn = normalizeDn(dn);
dnToRoleMultimap.put(normalizedDn, role);
roleToDnMultimap.put(normalizedDn, dn);
}
}
}
private String normalizeDn(String dn) {
X500Principal x500Principal = new X500Principal(dn);
return x500Principal.getName();
}
@Override
protected X509AuthenticationInfo doGetX509AuthenticationInfo(X509AuthenticationToken x509AuthenticationToken) {
final String dn = x509AuthenticationToken.getSubjectDN().getName();
LOGGER.info("dn received: {}", dn);
X509AuthenticationInfo x509AuthenticationInfo = new X509AuthenticationInfo(dn, x509AuthenticationToken.getSubjectDN(), NAME);
x509AuthenticationInfo.setCredentials(dn);
return x509AuthenticationInfo;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (AnonymousPrincipalCollection.class.isInstance(principals)) {
return ANONYMOUS_AUTHORIZATION_INFO;
}
String normalizeDn = normalizeDn((String) principals.getPrimaryPrincipal());
Set roles = new HashSet<>();
Collection potentialRoles = dnToRoleMultimap.get(normalizeDn);
if (potentialRoles == null || potentialRoles.size() == 0) {
return ANONYMOUS_AUTHORIZATION_INFO;
}
roles.addAll(potentialRoles);
return new SimpleAuthorizationInfo(roles);
}
}