/*
 * Copyright (c) 2009-2013, United States Government, as represented by the Secretary of Health and Human Services. 
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 *     * Redistributions of source code must retain the above 
 *       copyright notice, this list of conditions and the following disclaimer. 
 *     * Redistributions in binary form must reproduce the above copyright 
 *       notice, this list of conditions and the following disclaimer in the documentation 
 *       and/or other materials provided with the distribution. 
 *     * Neither the name of the United States Government nor the 
 *       names of its contributors may be used to endorse or promote products 
 *       derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE UNITED STATES GOVERNMENT BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package gov.hhs.fha.nhinc.callback.cxf;

import java.util.LinkedList;
import java.util.List;

import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.ldap.LdapName;

import gov.hhs.fha.nhinc.nhinclib.NhincConstants;

import org.apache.commons.lang.StringUtils;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.Subject;
import org.opensaml.saml2.core.validator.AssertionSpecValidator;
import org.opensaml.xml.security.x509.PKIXX509CredentialTrustEngine;
import org.opensaml.xml.validation.ValidationException;
import org.opensaml.xml.validation.ValidatorSuite;

import org.apache.commons.validator.routines.EmailValidator;
import org.apache.log4j.Logger;

/**
 * The Class Saml2ExchangeAuthFrameworkValidator.
 * 
 * @author msw
 */
public class Saml2ExchangeAuthFrameworkValidator extends AssertionSpecValidator {

    /** The Constant LOG. */
    private static final Logger LOG = Logger.getLogger(Saml2ExchangeAuthFrameworkValidator.class);
    
    /** The Constant invalidDomainNameChars. */
    private static final char[] invalidDomainNameChars = { '\\', '/', ':', '*', '?', '\"', '<', '>', '|'};
    
    /** The Constant invalidUserNameChars. */
    private static final char[] invalidUserNameChars = { ';', ':', '\"', '<', '>', '*', '+', '=', '\\', '|', '?', ','};

    /**
     * (non-Javadoc).
     * 
     * @param assertion the assertion
     * @throws ValidationException the validation exception
     * @see org.opensaml.saml2.core.validator.AssertionSpecValidator#validate(org.opensaml.saml2.core.Assertion)
     */
    @Override
    public void validate(Assertion assertion) throws ValidationException {
        super.validate(assertion);

        validateSubject(assertion.getSubject());
        validateIssuer(assertion.getIssuer());
    }

    /**
     * Validate issuer.
     *
     * @param issuer the issuer
     * @throws ValidationException the validation exception
     */
    protected void validateIssuer(Issuer issuer) throws ValidationException {
        if (StringUtils.isBlank(issuer.getFormat())) {
            throw new ValidationException("Issuer format cannot be blank.");
        }

        validateNameIdFormatValue(issuer.getFormat(), issuer.getValue());
    }

    /**
     * Checks that the subject is valid (checks for the presence of a name id).
     * 
     * @param subject the subject
     * @return true if Subject is valid, false otherwise.
     * @throws ValidationException the validation exception
     */
    protected void validateSubject(Subject subject) throws ValidationException {
        NameID name = subject.getNameID();
        if (subject == null || name == null) {
            throw new ValidationException("Subject is empty or invalid.");
        }

        String format = name.getFormat();
        if (!NhincConstants.AUTH_FRWK_NAME_ID_FORMAT_EMAIL_ADDRESS.equals(format)
                && !NhincConstants.AUTH_FRWK_NAME_ID_FORMAT_X509.equals(format)) {
            throw new ValidationException("Subject Name Id format must be x509 or Email.");
        }
        
        validateNameIdFormatValue(format, name.getValue());
    }

    /**
     * Validate name id format value.
     *
     * @param format the format
     * @param value the value
     * @throws ValidationException the validation exception
     */
    protected void validateNameIdFormatValue(String format, String value) throws ValidationException {
        if (NhincConstants.AUTH_FRWK_NAME_ID_FORMAT_EMAIL_ADDRESS.equals(format)) {
            EmailValidator validator = EmailValidator.getInstance();
            if (!validator.isValid(value)) {
                throw new ValidationException("Not a valid email address.");
            }
        } else if (NhincConstants.AUTH_FRWK_NAME_ID_FORMAT_X509.equals(format)) {
            try {
                Name name = new LdapName(value);
            } catch (Exception e) {
                LOG.info("Validation of X509 Subject Name failed:", e);
                throw new ValidationException("Not a valid X509 Subject Name.");
            }
        } else if (NhincConstants.AUTH_FRWK_NAME_ID_FORMAT_WINDOWS_NAME.equals(format)) {
            String[] parts = StringUtils.split(value, "\\");

            if (parts.length > 2) {
                throw new ValidationException("Invalid Windows Domain Name format: multiple backslashes.");
            }

            String domainName = null;
            String userName = null;
            if (parts.length == 1) {
                userName = parts[0];
            } else {
                domainName = parts[0];
                userName = parts[1];
            }

            if (StringUtils.containsAny(domainName, invalidDomainNameChars)) {
                throw new ValidationException(
                        "Invalid Windows Domain Name format: domain name contains invalid characters.");
            }
            
            if (StringUtils.containsAny(userName, invalidUserNameChars)) {
                throw new ValidationException(
                        "Invalid Windows Domain Name format: user name contains invalid characters.");
            }
        }
    }
}

@@ -4367,51 +4367,8 @@
 n %7B%0A
-        NameID name = subject.getNameID();%0A
     
@@ -4394,20 +4394,35 @@
 null %7C%7C 
-name
+subject.getNameID()
  == null
@@ -4503,32 +4503,75 @@
 .%22);%0A        %7D%0A%0A
+        NameID name = subject.getNameID();%0A
         String f

fix for code review comment.