ddf.security.sts.SubjectDNConstraintsInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for ddf.security.sts.SubjectDNConstraintsInterceptor.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package ddf.security.sts;

import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.security.AccessDeniedException;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.ws.security.wss4j.AbstractWSS4JInterceptor;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.eclipse.jetty.server.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SubjectDNConstraintsInterceptor extends AbstractPhaseInterceptor<Message> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SubjectDNConstraintsInterceptor.class);

    public SubjectDNConstraintsInterceptor() {
        super(Phase.PRE_INVOKE);
        addAfter(AbstractWSS4JInterceptor.class.getName());
    }

    /**
     * Checks if the provided certificate matches the regular expression defined in the Subject DN
     * Certificate Constraints.
     *
     * @param message
     */
    @Override
    public void handleMessage(Message message) throws Fault {
        if (message != null) {
            String subjectDNConstraints = (String) message.get(WSHandlerConstants.SIG_SUBJECT_CERT_CONSTRAINTS);
            if (subjectDNConstraints == null) {
                LOGGER.warn("No Subject DN Certificate Constraints were defined. This could be a security issue");
            } else {
                Collection<Pattern> subjectDNPatterns = setSubjectDNPatterns(subjectDNConstraints);
                X509Certificate[] cert;
                cert = ((X509Certificate[]) (((Request) message.get("HTTP.REQUEST"))
                        .getAttribute("javax.servlet.request.X509Certificate")));
                if (cert == null) {
                    throw new AccessDeniedException("No certificate provided.");
                }
                if (!(matches(cert[0], subjectDNPatterns))) {
                    LOGGER.debug("Certificate does not match Subject DN Certificate Constraints");
                    throw new AccessDeniedException("Certificate DN does not match allowed pattern(s).");
                }
            }
        }
    }

    Collection<Pattern> setSubjectDNPatterns(String subjectDNConstraints) {
        ArrayList<Pattern> subjectDNPatterns = new ArrayList<>();
        if (StringUtils.isNotEmpty(subjectDNConstraints)) {
            String[] patterns = subjectDNConstraints.split("\\|");
            for (String pattern : patterns) {
                Pattern p = Pattern.compile(pattern);
                subjectDNPatterns.add(p);
            }
        }
        return subjectDNPatterns;
    }

    /**
     * Checks the certificate against the list of regular expressions given. Only matching one of the
     * regular expressions is necessary.
     *
     * @param cert
     * @param subjectDNPatterns
     * @return true if the certificate matches the constraints
     */
    protected boolean matches(final X509Certificate cert, final Collection<Pattern> subjectDNPatterns) {
        if (subjectDNPatterns == null || subjectDNPatterns.isEmpty()) {
            LOGGER.warn("No Subject DN Certificate Constraints were defined. This could be a security issue");
        } else {
            if (cert == null) {
                LOGGER.debug("The certificate is null so no constraints matching was possible");
                return false;
            }
            String subjectName = cert.getSubjectX500Principal().getName();

            for (Pattern subjectDNPattern : subjectDNPatterns) {
                final Matcher matcher = subjectDNPattern.matcher(subjectName);
                if (matcher.matches()) {
                    LOGGER.debug("Subject DN {} matches with pattern {}", subjectName, subjectDNPattern);
                    return true;
                }
            }
            return false;
        }

        return true;
    }
}