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;
}
}