/* * Copyright (c) 2011 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. */ package eu.emi.security.authn.x509.helpers.ns; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.security.auth.x500.X500Principal; import eu.emi.security.authn.x509.NamespaceCheckingMode; import eu.emi.security.authn.x509.ValidationError; import eu.emi.security.authn.x509.ValidationErrorCode; import eu.emi.security.authn.x509.impl.X500NameUtils; import eu.emi.security.authn.x509.proxy.ProxyUtils; /** * Implements namespace policy checking. The class is populated with a namespace policy store * which provides the policies. The implementation gets * * * @author K. Benedyczak */ public class NamespaceChecker { private boolean namespaceRequired; private boolean checkAll; private NamespacesStore[] nsStores; public NamespaceChecker(NamespaceCheckingMode mode, NamespacesStore pmaStore, NamespacesStore globusStore) { namespaceRequired = mode.isRequired(); checkAll = (mode == NamespaceCheckingMode.EUGRIDPMA_AND_GLOBUS || mode == NamespaceCheckingMode.EUGRIDPMA_AND_GLOBUS_REQUIRE); int used = 0; if (mode.globusEnabled()) used++; if (mode.euGridPmaEnabled()) used++; nsStores = new NamespacesStore[used]; if (mode.isGlobusFirst()) { nsStores[0] = globusStore; if (mode.euGridPmaEnabled()) nsStores[1] = pmaStore; } else { if (mode.euGridPmaEnabled()) nsStores[0] = pmaStore; if (mode.globusEnabled()) nsStores[1] = globusStore; } } /** * Checks all certificates in the chain whether they are correct w.r.t. namespace policies * which are configured. If the parameter contains any proxy certificates those are ignored. * Self signed certificates in the chain are ignored, so the root CA certificate may be safely * present in the chain. * @param chain to be checked * @return list of validation errors */ public List<ValidationError> check(X509Certificate[] chain) { if (nsStores.length == 0) return Collections.emptyList(); List<ValidationError> ret = new ArrayList<ValidationError>(); for (int i=0; i<chain.length; i++) { boolean found = false; X500Principal certIssuer = chain[i].getIssuerX500Principal(); X500Principal certSubject = chain[i].getSubjectX500Principal(); if (certIssuer.equals(certSubject)) continue; if (ProxyUtils.isProxy(chain[i])) continue; for (NamespacesStore nsStore: nsStores) { List<NamespacePolicy> policies = nsStore.getPolicies(chain, i); if (policies == null || policies.size() == 0) continue; found = true; doCheck(certSubject, policies, ret, i, chain); if (!checkAll) break; } if (!found && namespaceRequired) { ret.add(new ValidationError(chain, i, ValidationErrorCode.nsUndefinedAndRequired, X500NameUtils.getReadableForm(certIssuer))); } } return ret; } private void doCheck(X500Principal subject, List<NamespacePolicy> policies, List<ValidationError> ret, int pos, X509Certificate[] chain) { boolean permitFound = false; StringBuilder policyNames = new StringBuilder(); for (NamespacePolicy policy: policies) { policyNames.append(policy.getIdentification()).append(" "); if (policy.isSubjectMatching(subject)) { if (!policy.isPermit()) ret.add(new ValidationError(chain, pos, ValidationErrorCode.nsDeny, X500NameUtils.getReadableForm(subject), policy.getIdentification())); else permitFound = true; } } if (!permitFound) { ret.add(new ValidationError(chain, pos, ValidationErrorCode.nsNotAccepted, X500NameUtils.getReadableForm(subject), policyNames.toString())); } } }