MessageSecuritySender_wss4j.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.security.message.wss4j;
- import java.io.FileNotFoundException;
- import java.net.URISyntaxException;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Properties;
- import javax.security.auth.callback.CallbackHandler;
- import javax.xml.soap.SOAPMessage;
- import org.apache.cxf.binding.soap.SoapMessage;
- import org.apache.cxf.message.Attachment;
- import org.apache.cxf.message.Exchange;
- import org.apache.cxf.message.ExchangeImpl;
- import org.apache.cxf.message.MessageImpl;
- import org.apache.cxf.phase.PhaseInterceptor;
- import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
- import org.apache.wss4j.common.ext.WSSecurityException;
- import org.apache.wss4j.dom.handler.WSHandlerConstants;
- import org.openspcoop2.message.MessageUtils;
- import org.openspcoop2.message.OpenSPCoop2Message;
- import org.openspcoop2.message.OpenSPCoop2SoapMessage;
- import org.openspcoop2.message.constants.Costanti;
- import org.openspcoop2.message.constants.MessageType;
- import org.openspcoop2.message.constants.ServiceBinding;
- import org.openspcoop2.protocol.sdk.state.RequestInfo;
- import org.openspcoop2.security.SecurityException;
- import org.openspcoop2.security.keystore.KeystoreConstants;
- import org.openspcoop2.security.message.IMessageSecuritySender;
- import org.openspcoop2.security.message.MessageSecurityContext;
- import org.openspcoop2.security.message.constants.SecurityConstants;
- import org.openspcoop2.security.message.saml.SAMLBuilderConfig;
- import org.openspcoop2.security.message.saml.SAMLCallbackHandler;
- import org.openspcoop2.security.message.saml.SAMLUtilities;
- import org.openspcoop2.security.message.utils.AttachmentProcessingPart;
- import org.openspcoop2.security.message.utils.AttachmentsConfigReaderUtils;
- import org.openspcoop2.security.message.utils.EncryptionBean;
- import org.openspcoop2.security.message.utils.KeystoreUtils;
- import org.openspcoop2.security.message.utils.SignatureBean;
- import org.openspcoop2.utils.Utilities;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.id.IDUtilities;
- /**
- * Classe per la gestione della WS-Security (WSDoAllSender).
- *
- * @author Lorenzo Nardi (nardi@link.it)
- * @author Tommaso Burlon (tommaso.burlon@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class MessageSecuritySender_wss4j implements IMessageSecuritySender{
-
- @Override
- public void process(MessageSecurityContext wssContext,OpenSPCoop2Message messageParam,org.openspcoop2.utils.Map<Object> ctx) throws SecurityException{
- try{
-
- if(ServiceBinding.SOAP.equals(messageParam.getServiceBinding())==false){
- throw new SecurityException("WSS4J Engine usable only with SOAP Binding");
- }
- OpenSPCoop2SoapMessage message = messageParam.castAsSoap();
-
- RequestInfo requestInfo = null;
- if(ctx!=null && ctx.containsKey(org.openspcoop2.core.constants.Costanti.REQUEST_INFO)) {
- requestInfo = (RequestInfo) ctx.get(org.openspcoop2.core.constants.Costanti.REQUEST_INFO);
- }
-
-
- // ** Inizializzo handler CXF **/
-
- WSS4JOutInterceptor ohandler = new WSS4JOutInterceptor();
- PhaseInterceptor<SoapMessage> handler = ohandler.createEndingInterceptor();
- SoapMessage msgCtx = new SoapMessage(new MessageImpl());
- msgCtx.setVersion(MessageType.SOAP_12.equals(message.getMessageType()) ? org.apache.cxf.binding.soap.Soap12.getInstance() : org.apache.cxf.binding.soap.Soap11.getInstance());
- Exchange ex = new ExchangeImpl();
- ex.setInMessage(msgCtx);
- SOAPMessage soapMessage = MessageUtils.getSOAPMessage(message, false, message.getTransactionId());
- msgCtx.setContent(SOAPMessage.class, soapMessage);
- List<?> results = new ArrayList<>();
- msgCtx.put(WSHandlerConstants.RECV_RESULTS, results);
-
-
- // ** Localizzo attachments da trattare **/
-
- AttachmentProcessingPart app = AttachmentsConfigReaderUtils.getSecurityOnAttachments(wssContext);
-
-
- // ** Imposto configurazione nel messaggio **/
- // NOTA: farlo dopo getSecurityOnAttachments poichè si modifica la regola di quali attachments trattare.
-
- setOutgoingProperties(wssContext,msgCtx,messageParam,requestInfo,ctx);
-
-
- // ** Registro attachments da trattare **/
-
- List<Attachment> listAttachments = null;
- if(app!=null){
- listAttachments = org.openspcoop2.security.message.wss4j.WSSUtilities.readAttachments(app, message, msgCtx);
- if(listAttachments!=null && listAttachments.size()>0){
- msgCtx.setAttachments(listAttachments);
- }
- }
-
-
- // ** Applico sicurezza tramite CXF **/
-
- handler.handleMessage(msgCtx);
- wssContext.getLog().debug("Print wssSender results...");
- org.openspcoop2.security.message.wss4j.WSSUtilities.printWSResult(wssContext.getLog(), results);
-
-
- // ** Riporto modifica degli attachments **/
-
- org.openspcoop2.security.message.wss4j.WSSUtilities.updateAttachments(listAttachments, message, msgCtx);
-
- }
- catch(Exception e){
-
- String msg = Utilities.getInnerNotEmptyMessageException(e).getMessage();
-
- Throwable innerExc = Utilities.getLastInnerException(e);
- String innerMsg = null;
- if(innerExc!=null){
- innerMsg = innerExc.getMessage();
- }
-
- String messaggio = null;
- if(msg!=null){
- messaggio = new String(msg);
- if(innerMsg!=null && !innerMsg.equals(msg)){
- messaggio = messaggio + " ; " + innerMsg;
- }
- }
- else{
- if(innerMsg!=null){
- messaggio = innerMsg;
- }
- }
-
- // L'if scopre l'eventuale motivo preciso riguardo al fallimento della cifratura/firma.
- if(Utilities.existsInnerException(e, WSSecurityException.class)){
- Throwable t = Utilities.getLastInnerException(e);
- if(t instanceof WSSecurityException){
- if(messaggio!=null){
- messaggio = messaggio + " ; " + t.getMessage();
- }
- else{
- messaggio = t.getMessage();
- }
- }
- }
-
- SecurityException wssException = new SecurityException(messaggio, e);
- wssException.setMsgErrore(messaggio);
- throw wssException;
- }
-
- }
- private void setOutgoingProperties(MessageSecurityContext wssContext,SoapMessage msgCtx,OpenSPCoop2Message message, RequestInfo requestInfo,org.openspcoop2.utils.Map<Object> ctx) throws Exception{
- boolean mustUnderstand = false;
- boolean signatureUser = false;
- boolean user = false;
- Map<String,Object> wssOutgoingProperties = wssContext.getOutgoingProperties();
- if (wssOutgoingProperties != null && wssOutgoingProperties.size() > 0) {
-
- // preprocess per SAML
- SAMLUtilities.injectSignaturePropRefIdIntoSamlConfig(wssOutgoingProperties);
-
- // preprocess per multipropfile
- preprocessMultipropFile(wssContext, msgCtx, wssOutgoingProperties, requestInfo, ctx);
-
- for (String key : wssOutgoingProperties.keySet()) {
- Object oValue = wssOutgoingProperties.get(key);
- String value = null;
- if(oValue!=null && oValue instanceof String) {
- value = (String) oValue;
- }
- // if (SecurityConstants.ENCRYPTION_USER.equals(key) && SecurityConstants.USE_REQ_SIG_CERT.equals(value)) {
- // // value = ...;
- // }
-
- // src/site/xdoc/migration/wss4j20.xml:the "samlPropFile" and "samlPropRefId" configuration tags have been removed.
- // Per ottenere lo stesso effetto di poter utilizzare tale file di proprietà , si converta la proprietà nella nuova voce: 'samlCallbackRef'
- if(SecurityConstants.SAML_PROF_FILE.equals(key)){
- //System.out.println("CONVERT ["+key+"] ["+value+"] ...");
- SAMLBuilderConfig config = SAMLBuilderConfig.getSamlConfig(value, requestInfo);
- SAMLCallbackHandler samlCallbackHandler = new SAMLCallbackHandler(config);
- msgCtx.put(SecurityConstants.SAML_CALLBACK_REF, samlCallbackHandler);
- }
- else if(SecurityConstants.SAML_PROF_REF_ID.equals(key)){
- if(oValue!=null && oValue instanceof Properties) {
- Properties p = (Properties) oValue;
- SAMLBuilderConfig config = SAMLBuilderConfig.getSamlConfig(p, requestInfo);
- SAMLCallbackHandler samlCallbackHandler = new SAMLCallbackHandler(config);
- msgCtx.put(SecurityConstants.SAML_CALLBACK_REF, samlCallbackHandler);
- }
- else {
- throw new Exception("Property ["+key+"] with uncorrect type: "+(oValue!=null ? oValue.getClass().getName() : "value is null"));
- }
- }
- else if(SecurityConstants.ENCRYPTION_PARTS.equals(key) || SecurityConstants.SIGNATURE_PARTS.equals(key)){
- if(value!=null) {
- msgCtx.put(key, normalizeWss4jParts(value,message));
- }
- }
- else if(SecurityConstants.PASSWORD_CALLBACK_REF.equals(key)) {
- msgCtx.put(key, oValue);
- }
- else if(SecurityConstants.SIGNATURE_PROPERTY_REF_ID.equals(key) ||
- SecurityConstants.SIGNATURE_VERIFICATION_PROPERTY_REF_ID.equals(key) ||
- SecurityConstants.ENCRYPTION_PROPERTY_REF_ID.equals(key) ||
- SecurityConstants.DECRYPTION_PROPERTY_REF_ID.equals(key) ) {
- if(value!=null) {
- msgCtx.put(key, value);
- }
- else {
- String id = key+"_"+IDUtilities.getUniqueSerialNumber("wssSecurity.setOutgoingProperties");
- msgCtx.put(key, id);
- msgCtx.put(id, oValue);
- if(oValue!=null && oValue instanceof Properties) {
- Properties p = (Properties) oValue;
- p.put(KeystoreConstants.PROPERTY_REQUEST_INFO, requestInfo);
- }
- }
- }
- else if(SecurityConstants.ENCRYPT_ACTION_OLD.equals(key)) {
- // backward compatibility per adeguamento costante rispetto a wss4j 2.3.x
- msgCtx.put(SecurityConstants.ENCRYPTION_ACTION, value);
- }
- else{
- msgCtx.put(key, value);
- if(SecurityConstants.MUST_UNDERSTAND.equals(key)){
- mustUnderstand = true;
- }
- else if(SecurityConstants.SIGNATURE_USER.equals(key)){
- signatureUser = true;
- }
- else if(SecurityConstants.USER.equals(key)){
- user = true;
- }
- }
- }
- }
- if(!mustUnderstand){
- //Il mustUnderstand non e' stato specificato. Lo imposto a false.
- msgCtx.put(SecurityConstants.MUST_UNDERSTAND , SecurityConstants.FALSE);
- }
- if(wssContext.getActor()!=null){
- msgCtx.put(SecurityConstants.ACTOR, wssContext.getActor());
- }
- if(signatureUser && !user) {
- // fix: Caused by: org.apache.cxf.binding.soap.SoapFault: Empty username for specified action.
- // at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessageInternal(WSS4JOutInterceptor.java:230) ~[cxf-rt-ws-security-3.2.6.jar:3.1.7]
- // at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessage(WSS4JOutInterceptor.java:135) ~[cxf-rt-ws-security-3.2.6.jar:3.1.7]
- msgCtx.put(SecurityConstants.USER, (String) msgCtx.get(SecurityConstants.SIGNATURE_USER));
- }
- }
-
- private void preprocessMultipropFile(MessageSecurityContext wssContext,SoapMessage msgCtx,Map<String,Object> wssOutgoingProperties, RequestInfo requestInfo,org.openspcoop2.utils.Map<Object> ctx) throws FileNotFoundException, UtilsException, SecurityException, URISyntaxException {
-
- String forceSignatureUser = null;
- String forceEncryptionUser = null;
-
- HashMap<String, String> mapAliasToPassword = new HashMap<>();
- for (String key : wssOutgoingProperties.keySet()) {
- if(SecurityConstants.SIGNATURE_MULTI_PROPERTY_FILE.equals(key)) {
- SignatureBean bean = KeystoreUtils.getSenderSignatureBean(wssContext, ctx);
- if(bean.getMultiKeystore()==null) {
- throw new SecurityException("Multiproperty config not exists");
- }
- String keyAlias = bean.getUser();
- String internalAlias = bean.getMultiKeystore().getInternalConfigAlias(keyAlias);
- Properties p = new Properties();
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_PATH, bean.getMultiKeystore().getKeystorePath(internalAlias));
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_PASSWORD, bean.getMultiKeystore().getKeystorePassword(internalAlias));
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_TYPE, bean.getMultiKeystore().getKeystoreType(internalAlias));
- p.put(KeystoreConstants.PROPERTY_PROVIDER, KeystoreConstants.PROVIDER_GOVWAY);
- p.put(KeystoreConstants.PROPERTY_REQUEST_INFO, requestInfo);
- String id = SecurityConstants.SIGNATURE_PROPERTY_REF_ID+"_"+IDUtilities.getUniqueSerialNumber("wssSecurity.setOutgoingProperties");
- msgCtx.put(SecurityConstants.SIGNATURE_PROPERTY_REF_ID, id);
- msgCtx.put(id, p);
-
- String password = bean.getPassword();
- msgCtx.put(SecurityConstants.SIGNATURE_PASSWORD, bean.getPassword());
- mapAliasToPassword.put(keyAlias, password);
- forceSignatureUser = keyAlias;
- }
- else if(SecurityConstants.ENCRYPTION_MULTI_PROPERTY_FILE.equals(key)) {
- EncryptionBean bean = KeystoreUtils.getSenderEncryptionBean(wssContext, ctx);
- if(bean.getMultiKeystore()==null) {
- throw new SecurityException("Multiproperty config not exists");
- }
- String keyAlias = bean.getUser();
- String internalAlias = bean.getMultiKeystore().getInternalConfigAlias(keyAlias);
- Properties p = new Properties();
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_PATH, bean.getMultiKeystore().getKeystorePath(internalAlias));
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_PASSWORD, bean.getMultiKeystore().getKeystorePassword(internalAlias));
- p.put(KeystoreConstants.PROPERTY_KEYSTORE_TYPE, bean.getMultiKeystore().getKeystoreType(internalAlias));
- p.put(KeystoreConstants.PROPERTY_PROVIDER, KeystoreConstants.PROVIDER_GOVWAY);
- p.put(KeystoreConstants.PROPERTY_REQUEST_INFO, requestInfo);
- String id = SecurityConstants.ENCRYPTION_PROPERTY_REF_ID +"_"+IDUtilities.getUniqueSerialNumber("wssSecurity.setOutgoingProperties");
- msgCtx.put(SecurityConstants.ENCRYPTION_PROPERTY_REF_ID , id);
- msgCtx.put(id, p);
-
- String password = bean.getPassword();
- mapAliasToPassword.put(keyAlias, password);
- forceEncryptionUser = keyAlias;
- }
- }
-
- if (!mapAliasToPassword.isEmpty()) {
- CallbackHandler pwCallbackHandler = MessageSecurityContext.newCallbackHandler(mapAliasToPassword);
- msgCtx.put(SecurityConstants.PASSWORD_CALLBACK_REF, pwCallbackHandler);
- }
- if(forceSignatureUser!=null) {
- wssOutgoingProperties.remove(SecurityConstants.SIGNATURE_USER);
- wssOutgoingProperties.put(SecurityConstants.SIGNATURE_USER, forceSignatureUser);
- }
- if(forceEncryptionUser!=null) {
- wssOutgoingProperties.remove(SecurityConstants.ENCRYPTION_USER);
- wssOutgoingProperties.put(SecurityConstants.ENCRYPTION_USER, forceEncryptionUser);
- }
- }
-
- private String normalizeWss4jParts(String parts,OpenSPCoop2Message message){
- StringBuilder bf = new StringBuilder();
- String[]split = ((String)parts).split(";");
- for (int i = 0; i < split.length; i++) {
- if(i>0){
- bf.append(";");
- }
- String n = split[i].trim();
- if(n.contains("{"+SecurityConstants.NAMESPACE_ATTACH+"}")){
- if(n.startsWith("{"+SecurityConstants.PART_ELEMENT+"}")){
- bf.append("{"+SecurityConstants.PART_ELEMENT+"}"+SecurityConstants.CID_ATTACH_WSS4J);
- }
- else {
- bf.append("{"+SecurityConstants.PART_CONTENT+"}"+SecurityConstants.CID_ATTACH_WSS4J);
- }
- }
- else{
- bf.append(n);
- }
- }
- //System.out.println("PRIMA ["+parts+"] DOPO ["+bf.toString()+"]");
-
- String newParts = bf.toString();
-
- while(newParts.contains(SecurityConstants.SOAP_NAMESPACE_TEMPLATE)) {
- String namespace = MessageType.SOAP_11.equals(message.getMessageType()) ? Costanti.SOAP_ENVELOPE_NAMESPACE : Costanti.SOAP12_ENVELOPE_NAMESPACE;
- newParts = newParts.replace(SecurityConstants.SOAP_NAMESPACE_TEMPLATE, namespace);
- }
-
- return newParts;
- }
-
- }