/* * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * * Licensed under the EUPL, Version 1.2 or - as soon 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * 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. * * This product combines work with different licenses. See the "NOTICE" text file for details on the * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative * works that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata; import java.util.ArrayList; import java.util.List; import at.gv.egiz.eaaf.core.impl.data.Triple; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import org.opensaml.core.xml.XMLObject; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.ext.saml2mdattr.EntityAttributes; import org.opensaml.saml.metadata.resolver.filter.FilterException; import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.metadata.AttributeConsumingService; import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.saml2.metadata.Extensions; import org.opensaml.saml.saml2.metadata.RequestedAttribute; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml.saml2.metadata.ServiceName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Metadata filter that inject requested attributes based on Metadata * EntityCategories. * * @author tlenz * */ public class PvpEntityCategoryFilter implements MetadataFilter { private static final Logger log = LoggerFactory.getLogger(PvpEntityCategoryFilter.class); private boolean isUsed = false; /** * Filter to map PVP EntityCategories into a set of single PVP attributes. * * @param isUsed if true PVP EntityCategories are mapped, otherwise they are * ignored * */ public PvpEntityCategoryFilter(final boolean isUsed) { this.isUsed = isUsed; } /* * (non-Javadoc) * * @see * org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml * .XMLObject) */ @Override public XMLObject filter(final XMLObject metadata) throws FilterException { if (isUsed) { log.trace("Map PVP EntityCategory to single PVP Attributes ... "); final String entityId = null; try { if (metadata instanceof EntitiesDescriptor) { log.trace("Find EnitiesDescriptor ... "); final EntitiesDescriptor entitiesDesc = (EntitiesDescriptor) metadata; if (entitiesDesc.getEntityDescriptors() != null) { for (final EntityDescriptor el : entitiesDesc.getEntityDescriptors()) { resolveEntityCategoriesToAttributes(el); } } } else if (metadata instanceof EntityDescriptor) { log.trace("Find EntityDescriptor"); resolveEntityCategoriesToAttributes((EntityDescriptor) metadata); } else { throw new Pvp2MetadataException("pvp2.26", new Object[] { "Invalid Metadata file Root element is no Entities- or EntityDescriptor" }); } } catch (final Exception e) { log.warn("SAML2 Metadata processing FAILED: Can not resolve EntityCategories for metadata: " + entityId, e); } } else { log.trace("Filter to map PVP EntityCategory to single PVP Attributes is deactivated"); } return metadata; } private void resolveEntityCategoriesToAttributes(final EntityDescriptor metadata) { log.debug("Resolving EntityCategorie for Entity: " + metadata.getEntityID() + " ..."); final Extensions extensions = metadata.getExtensions(); if (extensions != null) { final List listOfExt = extensions.getUnknownXMLObjects(); if (listOfExt != null && !listOfExt.isEmpty()) { log.trace("Find #" + listOfExt.size() + " 'Extension' elements "); for (final XMLObject el : listOfExt) { log.trace("Find ExtensionElement: " + el.getElementQName().toString()); if (el instanceof EntityAttributes) { final EntityAttributes entityAttrElem = (EntityAttributes) el; if (entityAttrElem.getAttributes() != null) { log.trace("Find EntityAttributes. Start attribute processing ..."); for (final Attribute entityAttr : entityAttrElem.getAttributes()) { if (entityAttr.getName().equals(PvpConstants.ENTITY_CATEGORY_ATTRIBITE)) { if (!entityAttr.getAttributeValues().isEmpty()) { final String entityAttrValue = entityAttr.getAttributeValues().get(0).getDOM().getTextContent(); if (PvpConstants.EGOVTOKEN.equals(entityAttrValue)) { log.debug( "Find 'EGOVTOKEN' EntityAttribute. Adding single pvp attributes ... "); addAttributesToEntityDescriptor(metadata, buildAttributeList(PvpConstants.EGOVTOKEN_PVP_ATTRIBUTES), entityAttrValue); } else if (PvpConstants.CITIZENTOKEN.equals(entityAttrValue)) { log.debug( "Find 'CITIZENTOKEN' EntityAttribute. Adding single pvp attributes ... "); addAttributesToEntityDescriptor(metadata, buildAttributeList(PvpConstants.CITIZENTOKEN_PVP_ATTRIBUTES), entityAttrValue); } else { log.info("EntityAttributeValue: " + entityAttrValue + " is UNKNOWN!"); } } else { log.info("EntityAttribute: No attribute value"); } } else { log.info("EntityAttribute: " + entityAttr.getName() + " is NOT supported"); } } } else { log.info( "Can NOT resolve EntityAttributes! Reason: Only EntityAttributes are supported!"); } } } } else { log.trace("'Extension' element is 'null' or empty"); } } else { log.trace("No 'Extension' element found"); } } private void addAttributesToEntityDescriptor(final EntityDescriptor metadata, final List attrList, final String entityAttr) { final SPSSODescriptor spSsoDesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); if (spSsoDesc != null) { if (spSsoDesc.getAttributeConsumingServices() == null || spSsoDesc.getAttributeConsumingServices().isEmpty()) { log.trace("No 'AttributeConsumingServices' found. Added it ..."); final AttributeConsumingService attributeService = Saml2Utils.createSamlObject(AttributeConsumingService.class); attributeService.setIndex(0); attributeService.setIsDefault(true); final ServiceName serviceName = Saml2Utils.createSamlObject(ServiceName.class); serviceName.setValue("Default Service"); serviceName.setXMLLang("en"); attributeService.getNames().add(serviceName); if (attrList != null && !attrList.isEmpty()) { attributeService.getRequestAttributes().addAll(attrList); log.info("Add " + attrList.size() + " attributes for 'EntityAttribute': " + entityAttr); } spSsoDesc.getAttributeConsumingServices().add(attributeService); } else { log.debug("Find 'AttributeConsumingServices'. Starting updating process ... "); for (final AttributeConsumingService el : spSsoDesc.getAttributeConsumingServices()) { log.debug("Update 'AttributeConsumingService' with Index: " + el.getIndex()); // load currently requested attributes final List currentlyReqAttr = new ArrayList<>(); for (final RequestedAttribute reqAttr : el.getRequestAttributes()) { currentlyReqAttr.add(reqAttr.getName()); } // check against EntityAttribute List for (final RequestedAttribute entityAttrListEl : attrList) { if (!currentlyReqAttr.contains(entityAttrListEl.getName())) { el.getRequestAttributes().add(entityAttrListEl); } else { log.debug("'AttributeConsumingService' already contains attr: " + entityAttrListEl.getName()); } } } } } else { log.info("Can ONLY add 'EntityAttributes' to 'SPSSODescriptor'"); } } private List buildAttributeList( final List> attrSet) { final List requestedAttributes = new ArrayList<>(); for (final Triple el : attrSet) { requestedAttributes .add(PvpAttributeBuilder.buildReqAttribute(el.getFirst(), el.getSecond(), el.getThird())); } return requestedAttributes; } }