From ba0929c6ab3147236ddf91b784127ebad6823748 Mon Sep 17 00:00:00 2001 From: Misagh Date: Sun, 31 Oct 2021 14:03:47 +0400 Subject: [PATCH] re-org access strategy rules for ticket validation # Conflicts: # core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyAuditableEnforcer.java # core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtils.java # core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceTestUtils.java # core/cas-server-core/src/main/java/org/apereo/cas/DefaultCentralAuthenticationService.java --- .../apereo/cas/audit/AuditableContext.java | 47 ++------ .../CasPersonDirectoryTestConfiguration.java | 1 + ...erviceAccessStrategyAuditableEnforcer.java | 50 +++++++- .../RegisteredServiceAccessStrategyUtils.java | 110 +++--------------- ...steredServiceAccessStrategyUtilsTests.java | 12 +- .../services/RegisteredServiceTestUtils.java | 8 ++ .../DefaultCentralAuthenticationService.java | 37 +++++- ...aultCentralAuthenticationServiceTests.java | 13 ++- .../flow/login/GenericSuccessViewAction.java | 6 +- 9 files changed, 129 insertions(+), 155 deletions(-) diff --git a/api/cas-server-core-api-audit/src/main/java/org/apereo/cas/audit/AuditableContext.java b/api/cas-server-core-api-audit/src/main/java/org/apereo/cas/audit/AuditableContext.java index 1d51566c4793..b2ccd8247a24 100644 --- a/api/cas-server-core-api-audit/src/main/java/org/apereo/cas/audit/AuditableContext.java +++ b/api/cas-server-core-api-audit/src/main/java/org/apereo/cas/audit/AuditableContext.java @@ -2,6 +2,7 @@ import org.apereo.cas.authentication.Authentication; import org.apereo.cas.authentication.AuthenticationResult; +import org.apereo.cas.authentication.principal.Principal; import org.apereo.cas.authentication.principal.Service; import org.apereo.cas.services.RegisteredService; import org.apereo.cas.ticket.ServiceTicket; @@ -27,6 +28,8 @@ public class AuditableContext { private final RegisteredService registeredService; + private final Principal principal; + private final Authentication authentication; private final ServiceTicket serviceTicket; @@ -39,44 +42,25 @@ public class AuditableContext { private final Object httpResponse; - /** - * Properties. - */ @Builder.Default private Map properties = new LinkedHashMap<>(0); - /** - * Get service. - * - * @return optional service - */ public Optional getService() { return Optional.ofNullable(service); } - /** - * Get registered service. - * - * @return optional registered service - */ public Optional getRegisteredService() { return Optional.ofNullable(registeredService); } - /** - * Get. - * - * @return optional authentication - */ public Optional getAuthentication() { return Optional.ofNullable(authentication); } - /** - * Get. - * - * @return optional service ticket - */ + public Optional getPrincipal() { + return Optional.ofNullable(this.principal); + } + public Optional getServiceTicket() { return Optional.ofNullable(serviceTicket); } @@ -89,29 +73,14 @@ public Optional getResponse() { return Optional.ofNullable(httpResponse); } - /** - * Get. - * - * @return optional authentication result - */ public Optional getAuthenticationResult() { return Optional.ofNullable(authenticationResult); } - /** - * Get. - * - * @return optional tgt - */ public Optional getTicketGrantingTicket() { return Optional.ofNullable(ticketGrantingTicket); } - - /** - * Get. - * - * @return optional properties - */ + public Map getProperties() { return properties; } diff --git a/core/cas-server-core-authentication-api/src/test/java/org/apereo/cas/config/CasPersonDirectoryTestConfiguration.java b/core/cas-server-core-authentication-api/src/test/java/org/apereo/cas/config/CasPersonDirectoryTestConfiguration.java index 8f5c26eba1d8..675cda2e3116 100644 --- a/core/cas-server-core-authentication-api/src/test/java/org/apereo/cas/config/CasPersonDirectoryTestConfiguration.java +++ b/core/cas-server-core-authentication-api/src/test/java/org/apereo/cas/config/CasPersonDirectoryTestConfiguration.java @@ -43,6 +43,7 @@ public List attributeRepositories() { public IPersonAttributeDao attributeRepository() { val attrs = CollectionUtils.wrap( "uid", CollectionUtils.wrap("uid"), + "mail", CollectionUtils.wrap("cas@apereo.org"), "eduPersonAffiliation", CollectionUtils.wrap("developer"), "groupMembership", CollectionUtils.wrap("adopters")); return new StubPersonAttributeDao((Map) attrs); diff --git a/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyAuditableEnforcer.java b/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyAuditableEnforcer.java index 4ff6d42dbbc2..79a67d21cb28 100644 --- a/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyAuditableEnforcer.java +++ b/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyAuditableEnforcer.java @@ -8,12 +8,14 @@ import org.apereo.cas.audit.BaseAuditableExecution; import org.apereo.cas.authentication.PrincipalException; import org.apereo.cas.configuration.CasConfigurationProperties; +import org.apereo.cas.util.CollectionUtils; import org.apereo.cas.util.scripting.WatchableGroovyScriptResource; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apereo.inspektr.audit.annotation.Audit; +import java.util.Map; import java.util.Optional; /** @@ -41,9 +43,10 @@ private static Optional byServiceTicketAndAuthnResultA val result = AuditableExecutionResult.of(context); try { val serviceTicket = context.getServiceTicket().orElseThrow(); - val authResult = context.getAuthenticationResult().orElseThrow(); - RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(serviceTicket, - authResult, providedRegisteredService.get()); + val authResult = context.getAuthenticationResult().orElseThrow().getAuthentication(); + RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(serviceTicket.getService(), + providedRegisteredService.get(), authResult.getPrincipal().getId(), + (Map) CollectionUtils.merge(authResult.getAttributes(), authResult.getPrincipal().getAttributes())); } catch (final PrincipalException | UnauthorizedServiceException e) { result.setException(e); } @@ -66,8 +69,10 @@ private static Optional byServiceAndRegisteredServiceA .ticketGrantingTicket(ticketGrantingTicket.get()) .build(); try { + val authResult = ticketGrantingTicket.get().getRoot().getAuthentication(); RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, - registeredService, ticketGrantingTicket.get()); + registeredService, authResult.getPrincipal().getId(), + (Map) CollectionUtils.merge(authResult.getAttributes(), authResult.getPrincipal().getAttributes())); } catch (final PrincipalException | UnauthorizedServiceException e) { result.setException(e); } @@ -114,6 +119,37 @@ private static Optional byServiceAndRegisteredService( return Optional.empty(); } + /** + * By service and registered service and principal optional. + * + * @param context the context + * @return the optional + */ + public static Optional byServiceAndRegisteredServiceAndPrincipal(final AuditableContext context) { + val providedService = context.getService(); + val providedRegisteredService = context.getRegisteredService(); + val providedPrincipal = context.getPrincipal(); + if (providedService.isPresent() && providedRegisteredService.isPresent() && providedPrincipal.isPresent()) { + val registeredService = providedRegisteredService.get(); + val service = providedService.get(); + val principal = providedPrincipal.get(); + + val result = AuditableExecutionResult.builder() + .registeredService(registeredService) + .service(service) + .build(); + + try { + RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, + registeredService, principal.getId(), principal.getAttributes()); + } catch (final PrincipalException | UnauthorizedServiceException e) { + result.setException(e); + } + return Optional.of(result); + } + return Optional.empty(); + } + private static Optional byServiceAndRegisteredServiceAndAuthentication(final AuditableContext context) { val providedService = context.getService(); val providedRegisteredService = context.getRegisteredService(); @@ -128,10 +164,11 @@ private static Optional byServiceAndRegisteredServiceA .service(service) .authentication(authentication) .build(); - try { RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, - registeredService, authentication); + registeredService, authentication.getPrincipal().getId(), + (Map) CollectionUtils.merge(authentication.getAttributes(), + authentication.getPrincipal().getAttributes())); } catch (final PrincipalException | UnauthorizedServiceException e) { result.setException(e); } @@ -148,6 +185,7 @@ public AuditableExecutionResult execute(final AuditableContext context) { return byExternalGroovyScript(context) .or(() -> byServiceTicketAndAuthnResultAndRegisteredService(context)) .or(() -> byServiceAndRegisteredServiceAndTicketGrantingTicket(context)) + .or(() -> byServiceAndRegisteredServiceAndPrincipal(context)) .or(() -> byServiceAndRegisteredServiceAndAuthentication(context)) .or(() -> byServiceAndRegisteredService(context)) .or(() -> byRegisteredService(context)) diff --git a/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtils.java b/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtils.java index 5b647f6b6178..456ba8537679 100644 --- a/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtils.java +++ b/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtils.java @@ -1,12 +1,7 @@ package org.apereo.cas.services; -import org.apereo.cas.authentication.Authentication; -import org.apereo.cas.authentication.AuthenticationResult; -import org.apereo.cas.authentication.CoreAuthenticationUtils; import org.apereo.cas.authentication.PrincipalException; import org.apereo.cas.authentication.principal.Service; -import org.apereo.cas.configuration.model.core.authentication.PrincipalAttributesCoreProperties; -import org.apereo.cas.ticket.ServiceTicket; import org.apereo.cas.ticket.TicketGrantingTicket; import lombok.experimental.UtilityClass; @@ -105,7 +100,8 @@ public static void ensureServiceSsoAccessIsAllowed(final RegisteredService regis * @param ticketGrantingTicket the ticket granting ticket * @param credentialsProvided the credentials provided */ - public static void ensureServiceSsoAccessIsAllowed(final RegisteredService registeredService, final Service service, + public static void ensureServiceSsoAccessIsAllowed(final RegisteredService registeredService, + final Service service, final TicketGrantingTicket ticketGrantingTicket, final boolean credentialsProvided) { @@ -136,11 +132,14 @@ public static void ensureServiceSsoAccessIsAllowed(final RegisteredService regis * @param attributes the attributes * @return the boolean */ - static boolean ensurePrincipalAccessIsAllowedForService(final Service service, - final RegisteredService registeredService, - final String principalId, - final Map> attributes) { + public static boolean ensurePrincipalAccessIsAllowedForService(final Service service, + final RegisteredService registeredService, + final String principalId, + final Map> attributes) { ensureServiceAccessIsAllowed(service, registeredService); + LOGGER.trace("Checking access strategy for service [{}], requested by [{}] with attributes [{}].", + service != null ? service.getId() : "unknown", principalId, attributes); + if (!registeredService.getAccessStrategy().doPrincipalAttributesAllowServiceAccess(principalId, (Map) attributes)) { LOGGER.warn("Cannot grant access to service [{}]; it is not authorized for use by [{}].", service != null ? service.getId() : "unknown", principalId); @@ -148,100 +147,17 @@ static boolean ensurePrincipalAccessIsAllowedForService(final Service service, val message = String.format("Cannot grant service access to %s", principalId); val exception = new UnauthorizedServiceForPrincipalException(message, registeredService, principalId, attributes); handlerErrors.put(UnauthorizedServiceForPrincipalException.class.getSimpleName(), exception); - throw new PrincipalException(UnauthorizedServiceForPrincipalException.CODE_UNAUTHZ_SERVICE, handlerErrors, new HashMap<>(0)); + throw new PrincipalException(UnauthorizedServiceForPrincipalException.CODE_UNAUTHZ_SERVICE, + handlerErrors, new HashMap<>(0)); } return true; } - /** - * Ensure service access is allowed. - * - * @param service the service - * @param registeredService the registered service - * @param authentication the authentication - * @return the true if access is granted. false otherwise - * @throws UnauthorizedServiceException the unauthorized service exception - * @throws PrincipalException the principal exception - */ - public static boolean ensurePrincipalAccessIsAllowedForService(final Service service, - final RegisteredService registeredService, - final Authentication authentication) - throws UnauthorizedServiceException, PrincipalException { - - ensureServiceAccessIsAllowed(service, registeredService); - - val principal = authentication.getPrincipal(); - val principalAttributes = new HashMap<>(principal.getAttributes()); - val merger = CoreAuthenticationUtils.getAttributeMerger(PrincipalAttributesCoreProperties.MergingStrategyTypes.MULTIVALUED); - val context = RegisteredServiceAttributeReleasePolicyContext.builder() - .registeredService(registeredService) - .service(service) - .principal(principal) - .build(); - val policyAttributes = registeredService.getAttributeReleasePolicy().getAttributes(context); - val result = CoreAuthenticationUtils.mergeAttributes(principalAttributes, policyAttributes, merger); - LOGGER.trace("Merged principal attributes [{}] with attributes from release policy [{}]. Result: [{}]", - principalAttributes, policyAttributes, result); - result.putAll(authentication.getAttributes()); - return ensurePrincipalAccessIsAllowedForService(service, registeredService, principal.getId(), result); - } - - /** - * 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 - */ - 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 - */ - 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 - */ - static void ensurePrincipalAccessIsAllowedForService(final ServiceTicket serviceTicket, - final AuthenticationResult context, - final RegisteredService registeredService) - throws UnauthorizedServiceException, PrincipalException { - ensurePrincipalAccessIsAllowedForService(serviceTicket.getService(), registeredService, context.getAuthentication()); - } /** - * Returns a predicate that determined whether a service has expired. + * Gets registered service expiration policy predicate. * - * @return true if the service is still valid. false if service has expired. + * @return the registered service expiration policy predicate */ public static Predicate getRegisteredServiceExpirationPolicyPredicate() { return service -> { diff --git a/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtilsTests.java b/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtilsTests.java index 0151ad14d490..44573ab0ba58 100644 --- a/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtilsTests.java +++ b/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceAccessStrategyUtilsTests.java @@ -1,8 +1,8 @@ package org.apereo.cas.services; import org.apereo.cas.authentication.PrincipalException; -import org.apereo.cas.ticket.ServiceTicket; import org.apereo.cas.ticket.TicketGrantingTicket; +import org.apereo.cas.util.CollectionUtils; import lombok.val; import org.junit.jupiter.api.Tag; @@ -10,6 +10,7 @@ import java.time.LocalDate; import java.time.ZoneOffset; +import java.util.Map; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -46,12 +47,11 @@ public void verifySsoAccess() { @Test public void verifyPrincipalAccess() { val service = RegisteredServiceTestUtils.getRegisteredService(); - val st = mock(ServiceTicket.class); - when(st.getService()).thenReturn(RegisteredServiceTestUtils.getService()); - val tgt = mock(TicketGrantingTicket.class); - when(tgt.getAuthentication()).thenReturn(RegisteredServiceTestUtils.getAuthentication()); + val authentication = RegisteredServiceTestUtils.getAuthentication(); assertThrows(PrincipalException.class, () -> - RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(st, service, tgt)); + RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService( + RegisteredServiceTestUtils.getService(), service, authentication.getPrincipal().getId(), + (Map) CollectionUtils.merge(authentication.getAttributes(), authentication.getPrincipal().getAttributes()))); } } diff --git a/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceTestUtils.java b/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceTestUtils.java index 685bfca90fd6..985f1a8a4acd 100644 --- a/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceTestUtils.java +++ b/core/cas-server-core-services/src/test/java/org/apereo/cas/services/RegisteredServiceTestUtils.java @@ -420,6 +420,14 @@ public static List getRegisteredServicesForTests() { svc24.setAccessStrategy(new DefaultRegisteredServiceAccessStrategy(new HashMap<>())); list.add(svc24); + val svc25 = RegisteredServiceTestUtils.getRegisteredService("accessStrategyMapped"); + svc25.setAttributeReleasePolicy(new ReturnMappedAttributeReleasePolicy( + Map.of("sAMAccountName", "uid", + "mail", "groovy { return attributes['sAMAccountName'][0] + '@example.org'}"))); + svc25.setAccessStrategy(new DefaultRegisteredServiceAccessStrategy( + Map.of("mail", Set.of(".*")))); + list.add(svc25); + return list; } } diff --git a/core/cas-server-core/src/main/java/org/apereo/cas/DefaultCentralAuthenticationService.java b/core/cas-server-core/src/main/java/org/apereo/cas/DefaultCentralAuthenticationService.java index 8c0bf3bb8cf7..5a4777be02d7 100644 --- a/core/cas-server-core/src/main/java/org/apereo/cas/DefaultCentralAuthenticationService.java +++ b/core/cas-server-core/src/main/java/org/apereo/cas/DefaultCentralAuthenticationService.java @@ -14,6 +14,7 @@ import org.apereo.cas.authentication.CoreAuthenticationUtils; import org.apereo.cas.authentication.DefaultAuthenticationBuilder; import org.apereo.cas.authentication.exceptions.MixedPrincipalException; +import org.apereo.cas.authentication.principal.Principal; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.authentication.principal.Service; import org.apereo.cas.authentication.principal.ServiceMatchingStrategy; @@ -56,6 +57,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.transaction.annotation.Transactional; +import java.util.Map; import java.util.Objects; /** @@ -119,10 +121,9 @@ public ServiceTicket grantServiceTicket(final String ticketGrantingTicketId, fin val selectedService = resolveServiceFromAuthenticationRequest(service); val registeredService = this.servicesManager.findServiceBy(selectedService); - enforceRegisteredServiceAccess(selectedService, ticketGrantingTicket, registeredService); - val currentAuthentication = evaluatePossibilityOfMixedPrincipals(authenticationResult, ticketGrantingTicket); - RegisteredServiceAccessStrategyUtils.ensureServiceSsoAccessIsAllowed(registeredService, selectedService, ticketGrantingTicket, credentialProvided); + RegisteredServiceAccessStrategyUtils.ensureServiceSsoAccessIsAllowed(registeredService, + selectedService, ticketGrantingTicket, credentialProvided); evaluateProxiedServiceIfNeeded(selectedService, ticketGrantingTicket, registeredService); getAuthenticationSatisfiedByPolicy(currentAuthentication, new ServiceContext(selectedService, registeredService)); @@ -130,6 +131,17 @@ public ServiceTicket grantServiceTicket(final String ticketGrantingTicketId, fin val latestAuthentication = ticketGrantingTicket.getRoot().getAuthentication(); AuthenticationCredentialsThreadLocalBinder.bindCurrent(latestAuthentication); val principal = latestAuthentication.getPrincipal(); + val releasePolicyContext = RegisteredServiceAttributeReleasePolicyContext.builder() + .registeredService(registeredService) + .service(service) + .principal(principal) + .build(); + val policyAttributes = registeredService.getAttributeReleasePolicy().getAttributes(releasePolicyContext); + val accessPrincipal = principalFactory.createPrincipal(principal.getId(), + (Map) CollectionUtils.merge(principal.getAttributes(), + latestAuthentication.getAttributes(), policyAttributes)); + enforceRegisteredServiceAccess(selectedService, registeredService, accessPrincipal); + val factory = (ServiceTicketFactory) this.ticketFactory.get(ServiceTicket.class); val serviceTicket = factory.create(ticketGrantingTicket, selectedService, credentialProvided, ServiceTicket.class); this.ticketRegistry.updateTicket(ticketGrantingTicket); @@ -308,7 +320,10 @@ public Assertion validateServiceTicket(final String serviceTicketId, final Servi val finalAuthentication = builder.build(); - enforceRegisteredServiceAccess(finalAuthentication, selectedService, registeredService); + val accessPrincipal = principalFactory.createPrincipal(finalAuthentication.getPrincipal().getId(), + (Map) CollectionUtils.merge(principal.getAttributes(), authentication.getAttributes(), + finalAuthentication.getPrincipal().getAttributes(), finalAuthentication.getAttributes())); + enforceRegisteredServiceAccess(selectedService, registeredService, accessPrincipal); AuthenticationCredentialsThreadLocalBinder.bindCurrent(finalAuthentication); @@ -367,7 +382,19 @@ private void enforceRegisteredServiceAccess(final Authentication authentication, accessResult.throwExceptionIfNeeded(); } - private void enforceRegisteredServiceAccess(final Service service, final TicketGrantingTicket ticket, final RegisteredService registeredService) { + private void enforceRegisteredServiceAccess(final Service service, final RegisteredService registeredService, + final Principal principal) { + val audit = AuditableContext.builder() + .service(service) + .principal(principal) + .registeredService(registeredService) + .build(); + val accessResult = this.registeredServiceAccessStrategyEnforcer.execute(audit); + accessResult.throwExceptionIfNeeded(); + } + + private void enforceRegisteredServiceAccess(final Service service, final TicketGrantingTicket ticket, + final RegisteredService registeredService) { val audit = AuditableContext.builder() .service(service) .ticketGrantingTicket(ticket) diff --git a/core/cas-server-core/src/test/java/org/apereo/cas/DefaultCentralAuthenticationServiceTests.java b/core/cas-server-core/src/test/java/org/apereo/cas/DefaultCentralAuthenticationServiceTests.java index b5447f4a1a27..15a571eda4c5 100644 --- a/core/cas-server-core/src/test/java/org/apereo/cas/DefaultCentralAuthenticationServiceTests.java +++ b/core/cas-server-core/src/test/java/org/apereo/cas/DefaultCentralAuthenticationServiceTests.java @@ -248,6 +248,17 @@ public void verifyValidateServiceTicketWithValidService() { assertNotNull(getCentralAuthenticationService().validateServiceTicket(serviceTicket.getId(), getService())); } + @Test + public void verifyValidateServiceTicketWithMappedAttrPolicy() { + val ctx = CoreAuthenticationTestUtils.getAuthenticationResult(getAuthenticationSystemSupport()); + val ticketGrantingTicket = getCentralAuthenticationService().createTicketGrantingTicket(ctx); + val operativeService = getService("accessStrategyMapped"); + val serviceTicket = getCentralAuthenticationService().grantServiceTicket(ticketGrantingTicket.getId(), + operativeService, ctx); + assertNotNull(getCentralAuthenticationService().validateServiceTicket(serviceTicket.getId(), operativeService)); + } + + @Test public void verifyValidateServiceTicketFailsTicket() { val ctx = CoreAuthenticationTestUtils.getAuthenticationResult(getAuthenticationSystemSupport()); @@ -404,7 +415,7 @@ public void verifyValidateServiceTicketReturnAllAttributes() { val assertion = getCentralAuthenticationService().validateServiceTicket(serviceTicket.getId(), service); val auth = assertion.getPrimaryAuthentication(); - assertEquals(3, auth.getPrincipal().getAttributes().size()); + assertEquals(4, auth.getPrincipal().getAttributes().size()); } @Test diff --git a/support/cas-server-support-actions/src/main/java/org/apereo/cas/web/flow/login/GenericSuccessViewAction.java b/support/cas-server-support-actions/src/main/java/org/apereo/cas/web/flow/login/GenericSuccessViewAction.java index f777ebb9aa37..aa2e0ad9f691 100644 --- a/support/cas-server-support-actions/src/main/java/org/apereo/cas/web/flow/login/GenericSuccessViewAction.java +++ b/support/cas-server-support-actions/src/main/java/org/apereo/cas/web/flow/login/GenericSuccessViewAction.java @@ -10,6 +10,7 @@ import org.apereo.cas.services.ServicesManager; import org.apereo.cas.ticket.InvalidTicketException; import org.apereo.cas.ticket.TicketGrantingTicket; +import org.apereo.cas.util.CollectionUtils; import org.apereo.cas.web.support.WebUtils; import lombok.RequiredArgsConstructor; @@ -20,6 +21,7 @@ import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -76,7 +78,9 @@ protected Event doExecute(final RequestContext requestContext) { .stream() .filter(registeredService -> { try { - return RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, registeredService, authn); + return RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, + registeredService, authn.getPrincipal().getId(), + (Map) CollectionUtils.merge(authn.getAttributes(), authn.getPrincipal().getAttributes())); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); return false;