| /** |
| * 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.wss4j.dom.str; |
| |
| import java.util.List; |
| |
| import javax.security.auth.callback.Callback; |
| import javax.security.auth.callback.CallbackHandler; |
| |
| import org.apache.wss4j.common.bsp.BSPEnforcer; |
| import org.apache.wss4j.common.bsp.BSPRule; |
| import org.apache.wss4j.common.ext.WSPasswordCallback; |
| import org.apache.wss4j.common.ext.WSSecurityException; |
| 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.SecurityTokenReference; |
| import org.apache.wss4j.common.token.X509Security; |
| import org.apache.wss4j.common.util.XMLUtils; |
| import org.apache.wss4j.dom.WSConstants; |
| import org.apache.wss4j.dom.WSDocInfo; |
| import org.apache.wss4j.dom.callback.CallbackLookup; |
| import org.apache.wss4j.dom.callback.DOMCallbackLookup; |
| import org.apache.wss4j.dom.engine.WSSecurityEngineResult; |
| import org.apache.wss4j.dom.handler.RequestData; |
| import org.apache.wss4j.dom.message.token.KerberosSecurity; |
| import org.apache.wss4j.dom.processor.Processor; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| /** |
| * Some utilities for the STRParsers. |
| */ |
| public final class STRParserUtil { |
| |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(STRParserUtil.class); |
| |
| private STRParserUtil() { |
| // complete |
| } |
| |
| /** |
| * Get an SamlAssertionWrapper object from parsing a SecurityTokenReference that uses |
| * a KeyIdentifier that points to a SAML Assertion. |
| * |
| * @param secRef the SecurityTokenReference to the SAML Assertion |
| * @param strElement The SecurityTokenReference DOM element |
| * @param request The RequestData instance used to obtain configuration |
| * @return an SamlAssertionWrapper object |
| * @throws WSSecurityException |
| */ |
| public static SamlAssertionWrapper getAssertionFromKeyIdentifier( |
| SecurityTokenReference secRef, |
| Element strElement, |
| RequestData request |
| ) throws WSSecurityException { |
| String keyIdentifierValue = secRef.getKeyIdentifierValue(); |
| String type = secRef.getKeyIdentifierValueType(); |
| WSSecurityEngineResult result = request.getWsDocInfo().getResult(keyIdentifierValue); |
| |
| SamlAssertionWrapper samlAssertion = null; |
| Element token = null; |
| if (result != null) { |
| samlAssertion = |
| (SamlAssertionWrapper)result.get(WSSecurityEngineResult.TAG_SAML_ASSERTION); |
| return samlAssertion; |
| } else { |
| token = |
| findProcessedTokenElement( |
| strElement.getOwnerDocument(), request.getWsDocInfo(), request.getCallbackHandler(), |
| keyIdentifierValue, type |
| ); |
| if (token != null) { |
| if (!"Assertion".equals(token.getLocalName())) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity" |
| ); |
| } |
| return new SamlAssertionWrapper(token); |
| } |
| token = |
| findUnprocessedTokenElement( |
| strElement.getOwnerDocument(), request.getWsDocInfo(), request.getCallbackHandler(), |
| keyIdentifierValue, type |
| ); |
| |
| if (token == null || !"Assertion".equals(token.getLocalName())) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity" |
| ); |
| } |
| Processor proc = request.getWssConfig().getProcessor(WSConstants.SAML_TOKEN); |
| List<WSSecurityEngineResult> samlResult = proc.handleToken(token, request); |
| return |
| (SamlAssertionWrapper)samlResult.get(0).get( |
| WSSecurityEngineResult.TAG_SAML_ASSERTION |
| ); |
| } |
| } |
| |
| |
| /** |
| * Check that the BinarySecurityToken referenced by the SecurityTokenReference argument |
| * is BSP compliant. |
| * @param secRef The SecurityTokenReference to the BinarySecurityToken |
| * @param token The BinarySecurityToken |
| * @param bspEnforcer a BSPEnforcer instance to enforce BSP rules |
| * @throws WSSecurityException |
| */ |
| public static void checkBinarySecurityBSPCompliance( |
| SecurityTokenReference secRef, |
| BinarySecurity token, |
| BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| if (secRef.containsReference()) { |
| // Check the ValueType attributes |
| String valueType = secRef.getReference().getValueType(); |
| if (token instanceof X509Security && !X509Security.X509_V3_TYPE.equals(valueType) |
| || token instanceof PKIPathSecurity && !PKIPathSecurity.PKI_TYPE.equals(valueType) |
| || token instanceof KerberosSecurity |
| && !(valueType == null || "".equals(valueType)) |
| && !WSConstants.WSS_GSS_KRB_V5_AP_REQ.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R3058); |
| } |
| } else if (secRef.containsKeyIdentifier()) { |
| String valueType = secRef.getKeyIdentifierValueType(); |
| if (!SecurityTokenReference.SKI_URI.equals(valueType) |
| && !SecurityTokenReference.THUMB_URI.equals(valueType) |
| && !WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(valueType) |
| && !X509Security.X509_V3_TYPE.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R3063); |
| } |
| } |
| |
| // Check TokenType attributes |
| if (token instanceof PKIPathSecurity) { |
| String tokenType = secRef.getTokenType(); |
| if (!PKIPathSecurity.PKI_TYPE.equals(tokenType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5215); |
| } |
| } |
| } |
| |
| /** |
| * Check that the EncryptedKey referenced by the SecurityTokenReference argument |
| * is BSP compliant. |
| * @param secRef The SecurityTokenReference to the BinarySecurityToken |
| * @param bspEnforcer a BSPEnforcer instance to enforce BSP rules |
| * @throws WSSecurityException |
| */ |
| public static void checkEncryptedKeyBSPCompliance( |
| SecurityTokenReference secRef, BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| if (secRef.containsKeyIdentifier()) { |
| String valueType = secRef.getKeyIdentifierValueType(); |
| if (!SecurityTokenReference.ENC_KEY_SHA1_URI.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R3063); |
| } |
| } |
| |
| String tokenType = secRef.getTokenType(); |
| if (!WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(tokenType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5215); |
| } |
| } |
| |
| /** |
| * Check that the SAML token referenced by the SecurityTokenReference argument |
| * is BSP compliant. |
| * @param secRef The SecurityTokenReference to the SAML token |
| * @param samlAssertion The SAML Token SamlAssertionWrapper object |
| * @param bspEnforcer a BSPEnforcer instance to enforce BSP rules |
| * @throws WSSecurityException |
| */ |
| public static void checkSamlTokenBSPCompliance( |
| SecurityTokenReference secRef, |
| SamlAssertionWrapper samlAssertion, |
| BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| // Check the KeyIdentifier ValueType attributes |
| if (secRef.containsKeyIdentifier()) { |
| String valueType = secRef.getKeyIdentifierValueType(); |
| if (samlAssertion.getSaml1() != null |
| && !WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6603); |
| } |
| if (samlAssertion.getSaml2() != null |
| && !WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6616); |
| } |
| String encoding = secRef.getKeyIdentifierEncodingType(); |
| if (encoding != null && !"".equals(encoding)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6604); |
| } |
| } |
| |
| // Check the TokenType attribute |
| String tokenType = secRef.getTokenType(); |
| if (samlAssertion.getSaml1() != null && !WSConstants.WSS_SAML_TOKEN_TYPE.equals(tokenType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6611); |
| } |
| if (samlAssertion.getSaml2() != null && !WSConstants.WSS_SAML2_TOKEN_TYPE.equals(tokenType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6617); |
| } |
| |
| // Check the ValueType attribute of the Reference for SAML2 |
| if (samlAssertion.getSaml2() != null && secRef.containsReference()) { |
| String valueType = secRef.getReference().getValueType(); |
| if (valueType != null && !"".equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R6614); |
| } |
| } |
| } |
| |
| /** |
| * Check that the Username token referenced by the SecurityTokenReference argument |
| * is BSP compliant. |
| * @param secRef The SecurityTokenReference to the Username token |
| * @param bspEnforcer a BSPEnforcer instance to enforce BSP rules |
| * @throws WSSecurityException |
| */ |
| public static void checkUsernameTokenBSPCompliance( |
| SecurityTokenReference secRef, BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| if (!secRef.containsReference()) { |
| // BSP does not permit using a KeyIdentifier to refer to a U/T |
| bspEnforcer.handleBSPRule(BSPRule.R4215); |
| } |
| |
| if (secRef.getReference() != null) { |
| String valueType = secRef.getReference().getValueType(); |
| if (!WSConstants.WSS_USERNAME_TOKEN_VALUE_TYPE.equals(valueType)) { |
| bspEnforcer.handleBSPRule(BSPRule.R4214); |
| } |
| } |
| } |
| |
| /** |
| * Get the Secret Key from a CallbackHandler |
| * @param id The id of the element |
| * @param type The type of the element (may be null) |
| * @param identifier The WSPasswordCallback usage identifier |
| * @poaram data The RequestData Object |
| * @return A Secret Key |
| * @throws WSSecurityException |
| */ |
| public static byte[] getSecretKeyFromToken( |
| String id, |
| String type, |
| int identifier, |
| RequestData data |
| ) throws WSSecurityException { |
| String uri = XMLUtils.getIDFromReference(id); |
| WSPasswordCallback pwcb = |
| new WSPasswordCallback(uri, null, type, identifier); |
| try { |
| Callback[] callbacks = new Callback[]{pwcb}; |
| if (data.getCallbackHandler() != null) { |
| data.getCallbackHandler().handle(callbacks); |
| return pwcb.getKey(); |
| } |
| } catch (Exception e) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILURE, e, |
| "noPassword", new Object[] {uri}); |
| } |
| |
| return null; |
| } |
| |
| public static Element getTokenElement( |
| Document doc, WSDocInfo docInfo, CallbackHandler cb, |
| String uri, String valueType |
| ) throws WSSecurityException { |
| LOG.debug("Token reference uri: {}", uri); |
| LOG.debug("Token reference ValueType: {}", valueType); |
| |
| if (uri == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.INVALID_SECURITY, "badReferenceURI" |
| ); |
| } |
| |
| Element tokElement = |
| findProcessedTokenElement(doc, docInfo, cb, uri, valueType); |
| if (tokElement == null) { |
| tokElement = findUnprocessedTokenElement(doc, docInfo, cb, uri, valueType); |
| } |
| |
| if (tokElement == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, |
| "noToken", new Object[] {uri}); |
| } |
| return tokElement; |
| } |
| |
| /** |
| * Find a token that has not been processed already - in other words, it searches for |
| * the element, rather than trying to access previous results to find the element |
| * @param doc Parent Document |
| * @param docInfo WSDocInfo instance |
| * @param cb CallbackHandler instance |
| * @param uri URI of the element |
| * @param type Type of the element |
| * @return A DOM element |
| * @throws WSSecurityException |
| */ |
| public static Element findUnprocessedTokenElement( |
| Document doc, |
| WSDocInfo docInfo, |
| CallbackHandler cb, |
| String uri, |
| String type |
| ) throws WSSecurityException { |
| String id = XMLUtils.getIDFromReference(uri); |
| // |
| // Delegate finding the element to the CallbackLookup instance |
| // |
| CallbackLookup callbackLookup = null; |
| if (docInfo != null) { |
| callbackLookup = docInfo.getCallbackLookup(); |
| } |
| if (callbackLookup == null) { |
| callbackLookup = new DOMCallbackLookup(doc); |
| } |
| return callbackLookup.getElement(id, type, true); |
| } |
| |
| /** |
| * Find a token that has been processed already - in other words, it access previous |
| * results to find the element, rather than conducting a general search |
| * @param doc Parent Document |
| * @param docInfo WSDocInfo instance |
| * @param cb CallbackHandler instance |
| * @param uri URI of the element |
| * @param type Type of the element |
| * @return A DOM element |
| * @throws WSSecurityException |
| */ |
| public static Element findProcessedTokenElement( |
| Document doc, |
| WSDocInfo docInfo, |
| CallbackHandler cb, |
| String uri, |
| String type |
| ) throws WSSecurityException { |
| String id = XMLUtils.getIDFromReference(uri); |
| // |
| // Try to find it from the WSDocInfo instance first |
| // |
| if (docInfo != null) { |
| Element token = docInfo.getTokenElement(id); |
| if (token != null) { |
| return token; |
| } |
| } |
| |
| // |
| // Try to find a custom token |
| // |
| if (cb != null && (WSConstants.WSC_SCT.equals(type) |
| || WSConstants.WSC_SCT_05_12.equals(type) |
| || WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(type) |
| || WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(type) |
| || KerberosSecurity.isKerberosToken(type))) { |
| //try to find a custom token |
| WSPasswordCallback pwcb = |
| new WSPasswordCallback(id, WSPasswordCallback.CUSTOM_TOKEN); |
| try { |
| cb.handle(new Callback[]{pwcb}); |
| Element assertionElem = pwcb.getCustomToken(); |
| if (assertionElem != null) { |
| return (Element)doc.importNode(assertionElem, true); |
| } |
| } catch (Exception e) { |
| LOG.debug(e.getMessage(), e); |
| // Consume this failure |
| } |
| } |
| return null; |
| } |
| |
| } |