/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.ws.security.wss4j.policyvalidators; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import org.w3c.dom.Element; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.ws.policy.AssertionInfo; import org.apache.cxf.ws.policy.AssertionInfoMap; import org.apache.cxf.ws.security.policy.PolicyUtils; import org.apache.wss4j.common.saml.SAMLKeyInfo; import org.apache.wss4j.common.saml.SamlAssertionWrapper; import org.apache.wss4j.common.token.BinarySecurity; import org.apache.wss4j.common.token.PKIPathSecurity; import org.apache.wss4j.common.token.X509Security; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.WSDataRef; import org.apache.wss4j.dom.engine.WSSecurityEngineResult; import org.apache.wss4j.policy.SP11Constants; import org.apache.wss4j.policy.SP12Constants; import org.apache.wss4j.policy.model.Layout; import org.apache.wss4j.policy.model.Layout.LayoutType; /** * Validate a Layout policy. */ public class LayoutPolicyValidator extends AbstractSecurityPolicyValidator { /** * Return true if this SecurityPolicyValidator implementation is capable of validating a * policy defined by the AssertionInfo parameter */ public boolean canValidatePolicy(AssertionInfo assertionInfo) { return assertionInfo.getAssertion() != null && (SP12Constants.LAYOUT.equals(assertionInfo.getAssertion().getName()) || SP11Constants.LAYOUT.equals(assertionInfo.getAssertion().getName())); } /** * Validate policies. */ public void validatePolicies(PolicyValidatorParameters parameters, Collection<AssertionInfo> ais) { for (AssertionInfo ai : ais) { Layout layout = (Layout)ai.getAssertion(); ai.setAsserted(true); assertToken(layout, parameters.getAssertionInfoMap()); if (!validatePolicy(layout, parameters.getResults().getResults(), parameters.getSignedResults())) { String error = "Layout does not match the requirements"; ai.setNotAsserted(error); } } } private void assertToken(Layout token, AssertionInfoMap aim) { String namespace = token.getName().getNamespaceURI(); LayoutType layoutType = token.getLayoutType(); if (layoutType != null) { PolicyUtils.assertPolicy(aim, new QName(namespace, layoutType.name())); } } private boolean validatePolicy( Layout layout, List<WSSecurityEngineResult> results, List<WSSecurityEngineResult> signedResults ) { boolean timestampFirst = layout.getLayoutType() == LayoutType.LaxTsFirst; boolean timestampLast = layout.getLayoutType() == LayoutType.LaxTsLast; boolean strict = layout.getLayoutType() == LayoutType.Strict; if (timestampFirst) { if (results.isEmpty()) { return false; } Integer firstAction = (Integer)results.get(results.size() - 1).get(WSSecurityEngineResult.TAG_ACTION); if (firstAction.intValue() != WSConstants.TS) { return false; } } else if (timestampLast) { if (results.isEmpty()) { return false; } Integer lastAction = (Integer)results.get(0).get(WSSecurityEngineResult.TAG_ACTION); if (lastAction.intValue() != WSConstants.TS) { return false; } } else if (strict && (!validateStrictSignaturePlacement(results, signedResults) || !validateStrictSignatureTokenPlacement(results) || !checkSignatureIsSignedPlacement(results, signedResults))) { return false; } return true; } private boolean validateStrictSignaturePlacement( List<WSSecurityEngineResult> results, List<WSSecurityEngineResult> signedResults ) { // Go through each Signature and check any security header token is before the Signature for (WSSecurityEngineResult signedResult : signedResults) { List<WSDataRef> sl = CastUtils.cast((List<?>)signedResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS)); Integer actInt = (Integer)signedResult.get(WSSecurityEngineResult.TAG_ACTION); if (sl == null || WSConstants.ST_SIGNED == actInt) { continue; } for (WSDataRef r : sl) { String xpath = r.getXpath(); if (xpath != null) { String[] nodes = StringUtils.split(xpath, "/"); // envelope/Header/wsse:Security/header if (nodes.length == 5) { Element protectedElement = r.getProtectedElement(); boolean tokenFound = false; // Results are stored in reverse order for (WSSecurityEngineResult result : results) { Element resultElement = (Element)result.get(WSSecurityEngineResult.TAG_TOKEN_ELEMENT); if (resultElement == protectedElement) { tokenFound = true; } if (tokenFound && result == signedResult) { return false; } else if (resultElement != null && result == signedResult) { break; } } } } } } return true; } private boolean validateStrictSignatureTokenPlacement(List<WSSecurityEngineResult> results) { // Go through each Signature and check that the Signing Token appears before the Signature for (int i = 0; i < results.size(); i++) { WSSecurityEngineResult result = results.get(i); Integer actInt = (Integer)result.get(WSSecurityEngineResult.TAG_ACTION); if (actInt == WSConstants.SIGN) { int correspondingIndex = findCorrespondingTokenIndex(result, results); if (correspondingIndex > 0 && correspondingIndex < i) { return false; } } } return true; } private boolean checkSignatureIsSignedPlacement( List<WSSecurityEngineResult> results, List<WSSecurityEngineResult> signedResults ) { for (WSSecurityEngineResult signedResult : signedResults) { List<WSDataRef> sl = CastUtils.cast((List<?>)signedResult.get( WSSecurityEngineResult.TAG_DATA_REF_URIS )); if (sl != null && sl.size() >= 1) { for (WSDataRef dataRef : sl) { QName signedQName = dataRef.getName(); if (WSConstants.SIGNATURE.equals(signedQName)) { Element protectedElement = dataRef.getProtectedElement(); if (!isEndorsingSignatureInCorrectPlace(results, signedResult, protectedElement)) { return false; } } } } } return true; } private boolean isEndorsingSignatureInCorrectPlace(List<WSSecurityEngineResult> results, WSSecurityEngineResult signedResult, Element protectedElement) { boolean endorsingSigFound = false; // Results are stored in reverse order for (WSSecurityEngineResult result : results) { Integer action = (Integer)result.get(WSSecurityEngineResult.TAG_ACTION); if (WSConstants.SIGN == action || WSConstants.ST_SIGNED == action || WSConstants.UT_SIGN == action) { if (result == signedResult) { endorsingSigFound = true; } Element resultElement = (Element)result.get(WSSecurityEngineResult.TAG_TOKEN_ELEMENT); if (endorsingSigFound && resultElement == protectedElement) { return true; } else if (resultElement == protectedElement) { return false; } } } return true; } /** * Find the index of the token corresponding to either the X509Certificate or PublicKey used * to sign the "signatureResult" argument. */ private int findCorrespondingTokenIndex( WSSecurityEngineResult signatureResult, List<WSSecurityEngineResult> results ) { // See what was used to sign this result X509Certificate cert = (X509Certificate)signatureResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE); PublicKey publicKey = (PublicKey)signatureResult.get(WSSecurityEngineResult.TAG_PUBLIC_KEY); for (int i = 0; i < results.size(); i++) { WSSecurityEngineResult token = results.get(i); Integer actInt = (Integer)token.get(WSSecurityEngineResult.TAG_ACTION); if (actInt == WSConstants.SIGN) { continue; } BinarySecurity binarySecurity = (BinarySecurity)token.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN); PublicKey foundPublicKey = (PublicKey)token.get(WSSecurityEngineResult.TAG_PUBLIC_KEY); if (binarySecurity instanceof X509Security || binarySecurity instanceof PKIPathSecurity) { X509Certificate foundCert = (X509Certificate)token.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE); if (foundCert.equals(cert)) { return i; } } else if (actInt.intValue() == WSConstants.ST_SIGNED || actInt.intValue() == WSConstants.ST_UNSIGNED) { SamlAssertionWrapper assertionWrapper = (SamlAssertionWrapper)token.get(WSSecurityEngineResult.TAG_SAML_ASSERTION); SAMLKeyInfo samlKeyInfo = assertionWrapper.getSubjectKeyInfo(); if (samlKeyInfo != null) { X509Certificate[] subjectCerts = samlKeyInfo.getCerts(); PublicKey subjectPublicKey = samlKeyInfo.getPublicKey(); if ((cert != null && subjectCerts != null && cert.equals(subjectCerts[0])) || (subjectPublicKey != null && subjectPublicKey.equals(publicKey))) { return i; } } } else if (publicKey != null && publicKey.equals(foundPublicKey)) { return i; } } return -1; } }