package org.apereo.cas.authentication.support; import org.apereo.cas.CasViewConstants; import org.apereo.cas.authentication.ProtocolAttributeEncoder; import org.apereo.cas.services.RegisteredService; import org.apereo.cas.services.RegisteredServiceCipherExecutor; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.util.services.DefaultRegisteredServiceCipherExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Abstract class to define common attribute encoding operations. * * @author Misagh Moayyed * @since 4.1.0 */ public abstract class AbstractProtocolAttributeEncoder implements ProtocolAttributeEncoder { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractProtocolAttributeEncoder.class); /** * The Services manager. */ protected ServicesManager servicesManager; private RegisteredServiceCipherExecutor cipherExecutor; /** * Instantiates a new attribute encoder with the default * cipher as {@link DefaultRegisteredServiceCipherExecutor}. * * @param servicesManager the services manager */ public AbstractProtocolAttributeEncoder(final ServicesManager servicesManager) { this(servicesManager, new DefaultRegisteredServiceCipherExecutor()); } /** * Instantiates a new Abstract cas attribute encoder. * * @param servicesManager the services manager * @param cipherExecutor the cipher executor */ public AbstractProtocolAttributeEncoder(final ServicesManager servicesManager, final RegisteredServiceCipherExecutor cipherExecutor) { this.servicesManager = servicesManager; this.cipherExecutor = cipherExecutor; } @Override public Map<String, Object> encodeAttributes(final Map<String, Object> attributes, final RegisteredService registeredService) { LOGGER.debug("Starting to encode attributes for release to service [{}]", registeredService); final Map<String, Object> newEncodedAttributes = new HashMap<>(attributes); final Map<String, String> cachedAttributesToEncode = initialize(newEncodedAttributes); if (registeredService != null && registeredService.getAccessStrategy().isServiceAccessAllowed()) { encodeAttributesInternal(newEncodedAttributes, cachedAttributesToEncode, this.cipherExecutor, registeredService); LOGGER.debug("[{}] encoded attributes are available for release to [{}]: [{}]", newEncodedAttributes.size(), registeredService, newEncodedAttributes.keySet()); } else { LOGGER.debug("Service [{}] is not found/enabled in the service registry so no encoding has taken place.", registeredService); } return newEncodedAttributes; } /** * Initialize the cipher with the public key * and then start to encrypt select attributes. * * @param attributes the attributes * @param cachedAttributesToEncode the cached attributes to encode * @param cipher the cipher object initialized per service public key * @param registeredService the registered service */ protected abstract void encodeAttributesInternal(Map<String, Object> attributes, Map<String, String> cachedAttributesToEncode, RegisteredServiceCipherExecutor cipher, RegisteredService registeredService); /** * Initialize the encoding process. Removes the * {@link CasViewConstants#MODEL_ATTRIBUTE_NAME_PRINCIPAL_CREDENTIAL} * and * {@link CasViewConstants#MODEL_ATTRIBUTE_NAME_PROXY_GRANTING_TICKET} * from the authentication attributes originally and into a cache object, so it * can later on be encrypted if needed. * * @param attributes the new encoded attributes * @return a map of attributes that are to be encoded and encrypted */ protected Map<String, String> initialize(final Map<String, Object> attributes) { final Map<String, String> cachedAttributesToEncode = new HashMap<>(attributes.size()); final String messageFormat = "Removed [{}] as an authentication attribute and cached it locally."; Collection<?> collection = (Collection<?>) attributes.remove(CasViewConstants.MODEL_ATTRIBUTE_NAME_PRINCIPAL_CREDENTIAL); if (collection != null && collection.size() == 1) { cachedAttributesToEncode.put(CasViewConstants.MODEL_ATTRIBUTE_NAME_PRINCIPAL_CREDENTIAL, collection.iterator().next().toString()); LOGGER.debug(messageFormat, CasViewConstants.MODEL_ATTRIBUTE_NAME_PRINCIPAL_CREDENTIAL); } collection = (Collection<?>) attributes.remove(CasViewConstants.MODEL_ATTRIBUTE_NAME_PROXY_GRANTING_TICKET); if (collection != null && collection.size() == 1) { cachedAttributesToEncode.put(CasViewConstants.MODEL_ATTRIBUTE_NAME_PROXY_GRANTING_TICKET, collection.iterator().next().toString()); LOGGER.debug(messageFormat, CasViewConstants.MODEL_ATTRIBUTE_NAME_PROXY_GRANTING_TICKET); } return cachedAttributesToEncode; } public void setCipherExecutor(final RegisteredServiceCipherExecutor cipherExecutor) { this.cipherExecutor = cipherExecutor; } }