package org.apereo.cas.services;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.Authentication;
import org.apereo.cas.authentication.AuthenticationResult;
import org.apereo.cas.authentication.PrincipalException;
import org.apereo.cas.authentication.principal.Principal;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.ticket.ServiceTicket;
import org.apereo.cas.ticket.TicketGrantingTicket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* This is {@link RegisteredServiceAccessStrategyUtils} that encapsulates common
* operations relevant to registered service access strategy and authorizations.
* This is a support utility class that acts as a façade around common authorization
* and access strategy presented in CAS.
*
* @author Misagh Moayyed
* @author Dmitriy Kopylenko
* @since 5.0.0
*/
public final class RegisteredServiceAccessStrategyUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(RegisteredServiceAccessStrategyUtils.class);
private RegisteredServiceAccessStrategyUtils() {
}
/**
* Ensure service access is allowed.
*
* @param registeredService the registered service
*/
public static void ensureServiceAccessIsAllowed(final RegisteredService registeredService) {
ensureServiceAccessIsAllowed(registeredService != null ? registeredService.getName() : StringUtils.EMPTY, registeredService);
}
/**
* Ensure service access is allowed.
*
* @param service the service
* @param registeredService the registered service
*/
public static void ensureServiceAccessIsAllowed(final String service, final RegisteredService registeredService) {
if (registeredService == null) {
final String msg = String.format("Unauthorized Service Access. Service [%s] is not found in service registry.", service);
LOGGER.warn(msg);
throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, msg);
}
if (!registeredService.getAccessStrategy().isServiceAccessAllowed()) {
final String msg = String.format("Unauthorized Service Access. Service [%s] is not enabled in service registry.", service);
LOGGER.warn(msg);
throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, msg);
}
}
/**
* Ensure service access is allowed.
*
* @param service the service
* @param registeredService the registered service
*/
public static void ensureServiceAccessIsAllowed(final Service service, final RegisteredService registeredService) {
ensureServiceAccessIsAllowed(service.getId(), registeredService);
}
/**
* Ensure service access is allowed.
*
* @param service the service
* @param registeredService the registered service
* @param authentication the authentication
* @throws UnauthorizedServiceException the unauthorized service exception
* @throws PrincipalException the principal exception
*/
public static void ensurePrincipalAccessIsAllowedForService(final Service service,
final RegisteredService registeredService,
final Authentication authentication)
throws UnauthorizedServiceException, PrincipalException {
ensureServiceAccessIsAllowed(service, registeredService);
final Principal principal = authentication.getPrincipal();
final Map<String, Object> principalAttrs = registeredService.getAttributeReleasePolicy().getAttributes(principal, service, registeredService);
if (!registeredService.getAccessStrategy().doPrincipalAttributesAllowServiceAccess(principal.getId(), principalAttrs)) {
LOGGER.warn("Cannot grant access to service [{}] because it is not authorized for use by [{}].", service.getId(), principal);
final Map<String, Class<? extends Exception>> handlerErrors = new HashMap<>();
handlerErrors.put(UnauthorizedServiceForPrincipalException.class.getSimpleName(),
UnauthorizedServiceForPrincipalException.class);
throw new PrincipalException(UnauthorizedServiceForPrincipalException.CODE_UNAUTHZ_SERVICE, handlerErrors, new HashMap<>());
}
}
/**
* Ensure service access is allowed.
*
* @param serviceTicket the service ticket
* @param registeredService the registered service
* @param ticketGrantingTicket the ticket granting ticket
* @throws UnauthorizedServiceException the unauthorized service exception
* @throws PrincipalException the principal exception
*/
public static void ensurePrincipalAccessIsAllowedForService(final ServiceTicket serviceTicket,
final RegisteredService registeredService,
final TicketGrantingTicket ticketGrantingTicket)
throws UnauthorizedServiceException, PrincipalException {
ensurePrincipalAccessIsAllowedForService(serviceTicket.getService(),
registeredService, ticketGrantingTicket.getAuthentication());
}
/**
* Ensure service access is allowed. Determines the final authentication object
* by looking into the chained authentications of the ticket granting ticket.
*
* @param service the service
* @param registeredService the registered service
* @param ticketGrantingTicket the ticket granting ticket
* @throws UnauthorizedServiceException the unauthorized service exception
* @throws PrincipalException the principal exception
*/
public static void ensurePrincipalAccessIsAllowedForService(final Service service, final RegisteredService registeredService,
final TicketGrantingTicket ticketGrantingTicket)
throws UnauthorizedServiceException, PrincipalException {
ensurePrincipalAccessIsAllowedForService(service, registeredService, ticketGrantingTicket.getRoot().getAuthentication());
}
/**
* Ensure service access is allowed.
*
* @param serviceTicket the service ticket
* @param context the context
* @param registeredService the registered service
* @throws UnauthorizedServiceException the unauthorized service exception
* @throws PrincipalException the principal exception
*/
public static void ensurePrincipalAccessIsAllowedForService(final ServiceTicket serviceTicket,
final AuthenticationResult context,
final RegisteredService registeredService)
throws UnauthorizedServiceException, PrincipalException {
ensurePrincipalAccessIsAllowedForService(serviceTicket.getService(), registeredService, context.getAuthentication());
}
/**
* Ensure service sso access is allowed.
*
* @param registeredService the registered service
* @param service the service
* @param ticketGrantingTicket the ticket granting ticket
*/
public static void ensureServiceSsoAccessIsAllowed(final RegisteredService registeredService, final Service service,
final TicketGrantingTicket ticketGrantingTicket) {
if (!registeredService.getAccessStrategy().isServiceAccessAllowedForSso()) {
LOGGER.debug("Service [{}] is configured to not use SSO", service.getId());
if (ticketGrantingTicket.getProxiedBy() != null) {
LOGGER.warn("ServiceManagement: Service [{}] is not allowed to use SSO for proxying.", service.getId());
throw new UnauthorizedSsoServiceException();
}
if (ticketGrantingTicket.getProxiedBy() == null && ticketGrantingTicket.getCountOfUses() > 0) {
LOGGER.warn("ServiceManagement: Service [{}] is not allowed to use SSO.", service.getId());
throw new UnauthorizedSsoServiceException();
}
}
LOGGER.debug("Current authentication via ticket [{}] allows service [{}] to participate in the existing SSO session",
ticketGrantingTicket.getId(), service.getId());
}
}