/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.support.wss.saml.callback; import com.eviware.soapui.impl.wsdl.support.wss.entries.AutomaticSAMLEntry; import org.apache.ws.security.WSConstants; import org.apache.ws.security.components.crypto.Crypto; import org.apache.ws.security.message.WSSecEncryptedKey; import org.apache.ws.security.saml.ext.SAMLCallback; import org.apache.ws.security.saml.ext.bean.ActionBean; import org.apache.ws.security.saml.ext.bean.AttributeBean; import org.apache.ws.security.saml.ext.bean.AttributeStatementBean; import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean; import org.apache.ws.security.saml.ext.bean.AuthenticationStatementBean; import org.apache.ws.security.saml.ext.bean.KeyInfoBean; import org.apache.ws.security.saml.ext.bean.KeyInfoBean.CERT_IDENTIFIER; import org.apache.ws.security.saml.ext.bean.SubjectBean; import org.apache.ws.security.saml.ext.bean.SubjectLocalityBean; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; /* * @author Erik R. Yverling * * A base implementation of a Callback Handler for a SAML assertion. By * default it creates an authentication assertion. * */ public abstract class AbstractSAMLCallbackHandler implements SAMLCallbackHandler { public enum Statement { AUTHN, ATTR, AUTHZ } ; protected String subjectName = null; protected String subjectQualifier = null; protected String confirmationMethod = null; protected X509Certificate[] certs; protected Statement statement = Statement.AUTHN; protected CERT_IDENTIFIER certIdentifier = CERT_IDENTIFIER.X509_CERT; protected byte[] ephemeralKey = null; protected String issuer = null; protected String subjectNameIDFormat = null; protected String subjectLocalityIpAddress = null; protected String subjectLocalityDnsAddress = null; protected String resource = null; protected List<?> customAttributeValues = null; private Crypto crypto; private String alias; private String customAttributeName; /** * Use this for signed assertion */ public AbstractSAMLCallbackHandler(Crypto crypto, String alias, String assertionTypeFriendlyName, String confirmationMethodFriendlyName) { this.crypto = crypto; this.alias = alias; setStatement(assertionTypeFriendlyName); setConfirmationMethod(confirmationMethodFriendlyName); } /** * Use this is for unsigned assertions */ public AbstractSAMLCallbackHandler(String assertionTypeFriendlyName, String confirmationMethodFriendlyName) { setStatement(assertionTypeFriendlyName); setConfirmationMethod(confirmationMethodFriendlyName); } @Override public void setCertIdentifier(CERT_IDENTIFIER certIdentifier) { this.certIdentifier = certIdentifier; } @Override public void setCerts(X509Certificate[] certs) { this.certs = certs; } @Override public byte[] getEphemeralKey() { return ephemeralKey; } @Override public void setIssuer(String issuer) { this.issuer = issuer; } @Override public void setSubjectName(String subjectName) { this.subjectName = subjectName; } @Override public void setSubjectQualifier(String subjectQualifier) { this.subjectQualifier = subjectQualifier; } @Override public void setSubjectNameIDFormat(String subjectNameIDFormat) { this.subjectNameIDFormat = subjectNameIDFormat; } @Override public void setSubjectLocality(String ipAddress, String dnsAddress) { this.subjectLocalityIpAddress = ipAddress; this.subjectLocalityDnsAddress = dnsAddress; } @Override public void setResource(String resource) { this.resource = resource; } @Override public void setCustomAttributeName(String customAttributeName) { this.customAttributeName = customAttributeName; } @Override public void setCustomAttributeValues(List<?> customAttributeValues) { this.customAttributeValues = customAttributeValues; } @Override public Crypto getCrypto() { return crypto; } @Override public void setCrypto(Crypto crypto) { this.crypto = crypto; } @Override public String getAlias() { return alias; } @Override public void setAlias(String alias) { this.alias = alias; } @Override public void setStatement(String statement) { if (statement.equals(AutomaticSAMLEntry.AUTHENTICATION_ASSERTION_TYPE)) { this.statement = Statement.AUTHN; } else if (statement.equals(AutomaticSAMLEntry.ATTRIBUTE_ASSERTION_TYPE)) { this.statement = Statement.ATTR; } else if (statement.equals(AutomaticSAMLEntry.AUTHORIZATION_ASSERTION_TYPE)) { this.statement = Statement.AUTHZ; } } /** * Note that the SubjectBean parameter should be null for SAML2.0 */ protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback callback) { if (statement == Statement.AUTHN) { AuthenticationStatementBean authBean = new AuthenticationStatementBean(); if (subjectBean != null) { authBean.setSubject(subjectBean); } if (subjectLocalityIpAddress != null || subjectLocalityDnsAddress != null) { SubjectLocalityBean subjectLocality = new SubjectLocalityBean(); subjectLocality.setIpAddress(subjectLocalityIpAddress); subjectLocality.setDnsAddress(subjectLocalityDnsAddress); authBean.setSubjectLocality(subjectLocality); } authBean.setAuthenticationMethod("Password"); callback.setAuthenticationStatementData(Collections.singletonList(authBean)); } else if (statement == Statement.ATTR) { AttributeStatementBean attrBean = new AttributeStatementBean(); if (subjectBean != null) { attrBean.setSubject(subjectBean); } AttributeBean attributeBean = new AttributeBean(); attributeBean.setSimpleName(customAttributeName); if (customAttributeValues != null) { attributeBean.setCustomAttributeValues(customAttributeValues); } // TODO This should be removed else { attributeBean.setAttributeValues(Collections.singletonList("user")); } attrBean.setSamlAttributes(Collections.singletonList(attributeBean)); callback.setAttributeStatementData(Collections.singletonList(attrBean)); } else { AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean(); if (subjectBean != null) { authzBean.setSubject(subjectBean); } ActionBean actionBean = new ActionBean(); actionBean.setContents("Read"); authzBean.setActions(Collections.singletonList(actionBean)); authzBean.setResource("endpoint"); authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT); authzBean.setResource(resource); callback.setAuthDecisionStatementData(Collections.singletonList(authzBean)); } } protected KeyInfoBean createKeyInfo() throws Exception { KeyInfoBean keyInfo = new KeyInfoBean(); if (statement == Statement.AUTHN) { keyInfo.setCertificate(certs[0]); keyInfo.setCertIdentifer(certIdentifier); } else if (statement == Statement.ATTR) { // Build a new Document DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilderFactory.setNamespaceAware(true); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); // Create an Encrypted Key WSSecEncryptedKey encrKey = new WSSecEncryptedKey(); encrKey.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER); encrKey.setUseThisCert(certs[0]); encrKey.prepare(doc, null); ephemeralKey = encrKey.getEphemeralKey(); Element encryptedKeyElement = encrKey.getEncryptedKeyElement(); // Append the EncryptedKey to a KeyInfo element Element keyInfoElement = doc.createElementNS(WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN); keyInfoElement.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS); keyInfoElement.appendChild(encryptedKeyElement); keyInfo.setElement(keyInfoElement); } return keyInfo; } }