SAMLCallbackHandler.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.saml;
- import java.io.IOException;
- import java.security.cert.X509Certificate;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import javax.security.auth.callback.Callback;
- import javax.security.auth.callback.CallbackHandler;
- import javax.security.auth.callback.UnsupportedCallbackException;
- import org.apache.wss4j.common.crypto.Crypto;
- import org.apache.wss4j.common.crypto.CryptoType;
- import org.apache.wss4j.common.saml.SAMLCallback;
- import org.apache.wss4j.common.saml.bean.AttributeBean;
- import org.apache.wss4j.common.saml.bean.AttributeStatementBean;
- import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
- import org.apache.wss4j.common.saml.bean.AuthenticationStatementBean;
- import org.apache.wss4j.common.saml.bean.ConditionsBean;
- import org.apache.wss4j.common.saml.bean.KeyInfoBean;
- import org.apache.wss4j.common.saml.bean.KeyInfoBean.CERT_IDENTIFIER;
- import org.apache.wss4j.common.saml.bean.SubjectBean;
- import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
- import org.apache.wss4j.common.saml.bean.SubjectLocalityBean;
- import org.apache.wss4j.common.saml.bean.Version;
- import org.apache.wss4j.common.saml.builder.SAML1Constants;
- import org.apache.wss4j.common.saml.builder.SAML2Constants;
- import org.joda.time.DateTime;
- /**
- * SAMLCallbackHandler
- *
- * @author Andrea Poli (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class SAMLCallbackHandler implements CallbackHandler {
-
- // ---- INSTANCE -----
-
- private SAMLBuilderConfig samlBuilderConfig = null;
- public SAMLCallbackHandler(SAMLBuilderConfig config) throws IOException{
- if(config==null){
- throw new IOException("SAMLBuilderConfig undefined");
- }
- this.samlBuilderConfig = config;
- }
-
- @Override
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-
- for (int i = 0; i < callbacks.length; i++) {
- if (callbacks[i] instanceof SAMLCallback) {
- SAMLCallback callback = (SAMLCallback) callbacks[i];
-
- DateTime now = new DateTime();
-
-
- // *** SamlVersion ***
-
- callback.setSamlVersion(this.samlBuilderConfig.getVersion());
-
-
- // *** Issuer ***
-
- callback.setIssuer(this.samlBuilderConfig.getIssuerValue());
- callback.setIssuerQualifier(this.samlBuilderConfig.getIssuerQualifier());
- callback.setIssuerFormat(this.samlBuilderConfig.getIssuerFormat());
-
-
- // *** Signature ***
-
- boolean signAssertion = this.samlBuilderConfig.isSignAssertion();
- callback.setSignAssertion(signAssertion);
- if(signAssertion){
-
- try{
- callback.setIssuerCrypto(this.samlBuilderConfig.getSignAssertionCrypto());
- }catch(Exception e){
- throw new IOException(e.getMessage(),e);
- }
- callback.setIssuerKeyName(this.samlBuilderConfig.getSignAssertionIssuerKeyName());
- callback.setIssuerKeyPassword(this.samlBuilderConfig.getSignAssertionIssuerKeyPassword());
-
- if(this.samlBuilderConfig.getSignAssertionSignatureDigestAlgorithm()!=null)
- callback.setSignatureDigestAlgorithm(this.samlBuilderConfig.getSignAssertionSignatureDigestAlgorithm());
- if(this.samlBuilderConfig.getSignAssertionSignatureAlgorithm()!=null)
- callback.setSignatureAlgorithm(this.samlBuilderConfig.getSignAssertionSignatureAlgorithm());
- if(this.samlBuilderConfig.getSignAssertionCanonicalizationAlgorithm()!=null)
- callback.setCanonicalizationAlgorithm(this.samlBuilderConfig.getSignAssertionCanonicalizationAlgorithm());
-
- callback.setSendKeyValue(this.samlBuilderConfig.isSignAssertionSendKeyValue());
-
- }
-
- // *** Subject ***
-
- SubjectBean subjectBean = null;
- if(this.samlBuilderConfig.isSubjectEnabled()){
- subjectBean = new SubjectBean();
-
- subjectBean.setSubjectName(this.samlBuilderConfig.getSubjectNameIDValue());
- subjectBean.setSubjectNameIDFormat(this.samlBuilderConfig.getSubjectNameIDFormat());
- subjectBean.setSubjectNameQualifier(this.samlBuilderConfig.getSubjectNameIDQualifier());
-
- subjectBean.setSubjectConfirmationMethod(this.samlBuilderConfig.getSubjectConfirmationMethod());
-
- SubjectConfirmationDataBean subjectConfirmationData = new SubjectConfirmationDataBean();
- DateTime subjectConfirmationMethod_notBefore = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getSubjectConfirmationDataNotBefore());
- DateTime subjectConfirmationMethod_notOnOrAfter = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getSubjectConfirmationDataNotOnOrAfter());
- subjectConfirmationData.setNotBefore(subjectConfirmationMethod_notBefore);
- subjectConfirmationData.setNotAfter(subjectConfirmationMethod_notOnOrAfter);
- subjectConfirmationData.setAddress(this.samlBuilderConfig.getSubjectConfirmationDataAddress());
- subjectConfirmationData.setInResponseTo(this.samlBuilderConfig.getSubjectConfirmationDataInResponseTo());
- subjectConfirmationData.setRecipient(this.samlBuilderConfig.getSubjectConfirmationDataRecipient());
- subjectBean.setSubjectConfirmationData(subjectConfirmationData);
-
- if (SAML2Constants.CONF_HOLDER_KEY.equals(this.samlBuilderConfig.getSubjectConfirmationMethod())
- || SAML1Constants.CONF_HOLDER_KEY.equals(this.samlBuilderConfig.getSubjectConfirmationMethod())) {
- try {
- KeyInfoBean keyInfo = createKeyInfo();
- subjectBean.setKeyInfo(keyInfo);
- } catch (Exception ex) {
- ex.printStackTrace(System.out);
- throw new IOException("Problem creating KeyInfo: " + ex.getMessage());
- }
- }
-
- callback.setSubject(subjectBean);
- }
-
-
- // *** ConditionsStatement ***
-
- if(this.samlBuilderConfig.isConditionsEnabled()){
-
- ConditionsBean conditions = new ConditionsBean();
-
- DateTime conditions_notBefore = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getConditionsDataNotBefore());
- DateTime conditions_notOnOrAfter = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getConditionsDataNotOnOrAfter());
- conditions.setNotBefore(conditions_notBefore);
- conditions.setNotAfter(conditions_notOnOrAfter);
-
- if(this.samlBuilderConfig.getConditionsAudienceURI()!=null){
-
- // per adesso viene gestita una unica audience uri
-
- List<AudienceRestrictionBean> lAudience = new ArrayList<AudienceRestrictionBean>();
-
- AudienceRestrictionBean arb = new AudienceRestrictionBean();
- List<String> uri = new ArrayList<>();
- uri.add(this.samlBuilderConfig.getConditionsAudienceURI());
- arb.setAudienceURIs(uri);
- lAudience.add(arb);
-
- conditions.setAudienceRestrictions(lAudience);
- }
-
- callback.setConditions(conditions);
- }
-
-
- // *** AuthenticationStatement ***
-
- AuthenticationStatementBean authBean = null;
- if(this.samlBuilderConfig.isAuthnStatementEnabled()){
-
- authBean = new AuthenticationStatementBean();
- authBean.setSubject(subjectBean); // necessario per saml 1.1
-
- DateTime authnStatement_instant = null;
- if(this.samlBuilderConfig.getAuthnStatementDataInstantDate()!=null) {
- authnStatement_instant = new DateTime(this.samlBuilderConfig.getAuthnStatementDataInstantDate());
- }
- else {
- authnStatement_instant = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getAuthnStatementDataInstant());
- }
- DateTime authnStatement_notOnOrAfter = null;
- if(this.samlBuilderConfig.getAuthnStatementDataNotOnOrAfterDate()!=null) {
- authnStatement_notOnOrAfter = new DateTime(this.samlBuilderConfig.getAuthnStatementDataNotOnOrAfterDate());
- }
- else {
- authnStatement_notOnOrAfter = SAMLUtilities.minutesOperator(now,this.samlBuilderConfig.getAuthnStatementDataNotOnOrAfter());
- }
- authBean.setAuthenticationInstant(authnStatement_instant);
- authBean.setSessionNotOnOrAfter(authnStatement_notOnOrAfter);
-
- if(this.samlBuilderConfig.getAuthnSubjectLocalityIpAddress()!=null || this.samlBuilderConfig.getAuthnSubjectLocalityDnsAddress()!=null) {
- SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
- subjectLocality.setIpAddress(this.samlBuilderConfig.getAuthnSubjectLocalityIpAddress());
- subjectLocality.setDnsAddress(this.samlBuilderConfig.getAuthnSubjectLocalityDnsAddress());
- authBean.setSubjectLocality(subjectLocality);
- }
-
- authBean.setAuthenticationMethod(this.samlBuilderConfig.getAuthnStatementClassRef());
-
- callback.setAuthenticationStatementData(Collections.singletonList(authBean));
- }
- if(authBean==null && !Version.SAML_20.equals(this.samlBuilderConfig.getVersion()) && subjectBean!=null){
- // Nelle asserzioni saml1x il subject deve viaggiare dentro authn o authz
- authBean = new AuthenticationStatementBean();
- authBean.setSubject(subjectBean); // necessario per saml 1.1
- callback.setAuthenticationStatementData(Collections.singletonList(authBean));
- }
-
-
- // *** AttributeBean ***
-
- List<SAMLBuilderConfigAttribute> listAttributes = this.samlBuilderConfig.getAttributes();
- if(listAttributes!=null && listAttributes.size()>0){
-
- AttributeStatementBean attrBean = new AttributeStatementBean();
- attrBean.setSubject(subjectBean); // necessario per saml 1.1
-
- List<AttributeBean> attributeBeans = new ArrayList<AttributeBean>();
-
- for (SAMLBuilderConfigAttribute configAttribute : listAttributes) {
- AttributeBean attributeBean = new AttributeBean();
- attributeBean.setSimpleName(configAttribute.getSimpleName());
- attributeBean.setQualifiedName(configAttribute.getQualifiedName());
- attributeBean.setNameFormat(configAttribute.getFormatName());
- attributeBean.setAttributeValues(configAttribute.getValues());
- attributeBeans.add(attributeBean);
- }
-
- attrBean.setSamlAttributes(attributeBeans);
- callback.setAttributeStatementData(Collections.singletonList(attrBean));
- }
-
- }
- }
- }
- /*
- SAML Holder of Key
- This mechanism protects messages with a signed SAML assertion (issued by a trusted authority)
- carrying client public key and authorization information with integrity and confidentiality protection using mutual certificates.
- The Holder-of-Key (HOK) method establishes the correspondence between a SOAP message and the SAML assertions added to the SOAP message.
- The attesting entity includes a signature that can be verified with the key information in the confirmation method of the subject statements
- of the SAML assertion referenced for key info for the signature.
- For more information about the Holder of Key method,
- read the SAML Token Profile document at http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0.pdf.
- Under this scenario, the service does not trust the client directly, but requires the client to send a SAML assertion issued by a particular SAML authority.
- The client knows the recipient’s public key, but does not share a direct trust relationship with the recipient.
- The recipient has a trust relationship with the authority that issues the SAML token.
- The request is signed with the client’s private key and encrypted with the server certificate.
- The response is signed using the server’s private key and encrypted using the key provided within the HOK SAML assertion.
- */
- protected KeyInfoBean createKeyInfo() throws Exception {
- Crypto crypto = this.samlBuilderConfig.getSubjectConfirmationMethodHolderOfKeyCrypto();
- CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
- cryptoType.setAlias(this.samlBuilderConfig.getSubjectConfirmationMethodHolderOfKeyCryptoCertificateAlias());
- X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
- KeyInfoBean keyInfo = new KeyInfoBean();
- keyInfo.setCertificate(certs[0]);
- keyInfo.setCertIdentifer(CERT_IDENTIFIER.X509_CERT);
- return keyInfo;
- }
- }