@Override public boolean supports(final Service service) { val svc = this.servicesManager.findServiceBy(service); val res = svc != null && service.getId().startsWith(this.callbackUrl); LOGGER.trace("Authentication request is{} identified as an OAuth request", BooleanUtils.toString(res, StringUtils.EMPTY, " not")); return res; }
/** * Fetch service either by numeric id or service id pattern. * * @param id the id * @return the registered service */ @ReadOperation(produces = {ActuatorMediaType.V2_JSON, "application/vnd.cas.services+yaml", MediaType.APPLICATION_JSON_VALUE}) public RegisteredService fetchService(@Selector final String id) { if (NumberUtils.isDigits(id)) { return this.servicesManager.findServiceBy(Long.parseLong(id)); } return this.servicesManager.findServiceBy(id); } }
@Override public Set<AuthenticationHandler> resolve(final Set<AuthenticationHandler> candidateHandlers, final AuthenticationTransaction transaction) { val service = transaction.getService(); val registeredService = this.servicesManager.findServiceBy(service); val requiredHandlers = registeredService.getRequiredHandlers(); LOGGER.debug("Authentication transaction requires [{}] for service [{}]", requiredHandlers, service); val handlerSet = new LinkedHashSet<AuthenticationHandler>(candidateHandlers); LOGGER.info("Candidate authentication handlers examined this transaction are [{}]", handlerSet); val it = handlerSet.iterator(); while (it.hasNext()) { val handler = it.next(); val handlerName = handler.getName(); if (!(handler instanceof HttpBasedServiceCredentialsAuthenticationHandler) && !requiredHandlers.contains(handlerName)) { LOGGER.debug("Authentication handler [{}] is not required for this transaction and is removed", handlerName); it.remove(); } } LOGGER.debug("Authentication handlers for this transaction are [{}]", handlerSet); return handlerSet; } }
/** * Overrideable method to determine which credentials to use to grant a * proxy granting ticket. Default is to use the pgtUrl. * * @param service the webapp service requesting proxy * @param request the HttpServletRequest object. * @return the credentials or null if there was an error or no credentials * provided. */ protected Credential getServiceCredentialsFromRequest(final WebApplicationService service, final HttpServletRequest request) { val pgtUrl = request.getParameter(CasProtocolConstants.PARAMETER_PROXY_CALLBACK_URL); if (StringUtils.isNotBlank(pgtUrl)) { try { val registeredService = this.servicesManager.findServiceBy(service); verifyRegisteredServiceProperties(registeredService, service); return new HttpBasedServiceCredential(new URL(pgtUrl), registeredService); } catch (final Exception e) { LOGGER.error("Error constructing [{}]", CasProtocolConstants.PARAMETER_PROXY_CALLBACK_URL, e); } } return null; }
/** * Resolve registered service in request context. * * @param requestContext the request context * @return the registered service */ protected RegisteredService resolveRegisteredServiceInRequestContext(final RequestContext requestContext) { val resolvedService = resolveServiceFromAuthenticationRequest(requestContext); if (resolvedService != null) { val service = this.servicesManager.findServiceBy(resolvedService); RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(resolvedService, service); return service; } LOGGER.debug("Authentication request is not accompanied by a service given none is specified"); return null; } }
/** * Gets registered service from request. * Reading the request body by the argument extractor here may cause the underlying request stream * to close. If there are any underlying controllers or components that expect to read * or parse the request body, like those that handle ticket validation, they would fail given the * {@link HttpServletRequest#getReader()} is consumed by the argument extractor here and not available anymore. * Therefor, any of the inner components of the extractor might have to cache the request body * as an attribute, etc so they can re-process and re-extract as needed. * * @param request the request * @return the registered service from request */ private Optional<RegisteredService> getRegisteredServiceFromRequest(final HttpServletRequest request) { val service = this.argumentExtractor.extractService(request); if (service != null) { val resolved = authenticationRequestServiceSelectionStrategies.resolveService(service); return Optional.ofNullable(this.servicesManager.findServiceBy(resolved)); } return Optional.empty(); } }
@Bean @ConditionalOnMissingBean(name = "requestedContextValidator") public RequestedContextValidator requestedContextValidator() { return (assertion, request) -> { LOGGER.debug("Locating the primary authentication associated with this service request [{}]", assertion.getService()); val service = servicesManager.getIfAvailable().findServiceBy(assertion.getService()); RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(assertion.getService(), service); return Pair.of(Boolean.TRUE, Optional.empty()); }; } }
/** * Prepare cas response attributes for view model. * * @param model the model */ protected void prepareCasResponseAttributesForViewModel(final Map<String, Object> model) { val service = authenticationRequestServiceSelectionStrategies.resolveService(getServiceFrom(model)); val registeredService = this.servicesManager.findServiceBy(service); val principalAttributes = getCasPrincipalAttributes(model, registeredService); val attributes = new HashMap<String, Object>(principalAttributes); LOGGER.trace("Processed principal attributes from the output model to be [{}]", principalAttributes.keySet()); val protocolAttributes = getCasProtocolAuthenticationAttributes(model, registeredService); attributes.putAll(protocolAttributes); LOGGER.debug("Final collection of attributes for the response are [{}].", attributes.keySet()); putCasResponseAttributesIntoModel(model, attributes, registeredService, this.attributesRenderer); }
/** * Prepare saml attributes. Combines both principal and authentication * attributes. * * @param model the model * @return the final map * @since 4.1.0 */ private Map<String, Object> prepareSamlAttributes(final Map<String, Object> model, final Service service) { val registeredService = this.servicesManager.findServiceBy(service); val authnAttributes = getCasProtocolAuthenticationAttributes(model, registeredService); LOGGER.debug("Retrieved authentication attributes [{}] from the model", authnAttributes); val attributesToReturn = new HashMap<String, Object>(); attributesToReturn.putAll(getPrincipalAttributesAsMultiValuedAttributes(model)); attributesToReturn.putAll(authnAttributes); LOGGER.debug("Beginning to encode attributes [{}] for service [{}]", attributesToReturn, registeredService.getServiceId()); val finalAttributes = this.protocolAttributeEncoder.encodeAttributes(attributesToReturn, registeredService); LOGGER.debug("Final collection of attributes are [{}]", finalAttributes); return finalAttributes; }
/** * Finalize profile response. * * @param accessTokenTicket the access token ticket * @param map the map * @param principal the authentication principal */ protected void finalizeProfileResponse(final AccessToken accessTokenTicket, final Map<String, Object> map, final Principal principal) { val service = accessTokenTicket.getService(); val registeredService = servicesManager.findServiceBy(service); if (registeredService instanceof OAuthRegisteredService) { val oauth = (OAuthRegisteredService) registeredService; map.put(OAuth20Constants.CLIENT_ID, oauth.getClientId()); map.put(CasProtocolConstants.PARAMETER_SERVICE, service.getId()); } } }
@Override public Collection<SingleLogoutRequest> handle(final WebApplicationService singleLogoutService, final String ticketId, final TicketGrantingTicket ticketGrantingTicket) { if (singleLogoutService.isLoggedOutAlready()) { LOGGER.debug("Service [{}] is already logged out.", singleLogoutService); return new ArrayList<>(0); } val selectedService = (WebApplicationService) this.authenticationRequestServiceSelectionStrategies.resolveService(singleLogoutService); LOGGER.trace("Processing logout request for service [{}]...", selectedService); val registeredService = this.servicesManager.findServiceBy(selectedService); LOGGER.debug("Service [{}] supports single logout and is found in the registry as [{}]. Proceeding...", selectedService.getId(), registeredService.getName()); val logoutUrls = this.singleLogoutServiceLogoutUrlBuilder.determineLogoutUrl(registeredService, selectedService); LOGGER.debug("Prepared logout url [{}] for service [{}]", logoutUrls, selectedService); if (logoutUrls == null || logoutUrls.isEmpty()) { LOGGER.debug("Service [{}] does not support logout operations given no logout url could be determined.", selectedService); return new ArrayList<>(0); } LOGGER.trace("Creating logout request for [{}] and ticket id [{}]", selectedService, ticketId); return createLogoutRequests(ticketId, selectedService, registeredService, logoutUrls, ticketGrantingTicket); }
@Override public boolean supports(final Set<AuthenticationHandler> handlers, final AuthenticationTransaction transaction) { val service = transaction.getService(); if (service != null) { val registeredService = this.servicesManager.findServiceBy(service); LOGGER.trace("Located registered service definition [{}] for this authentication transaction", registeredService); if (registeredService == null || !registeredService.getAccessStrategy().isServiceAccessAllowed()) { LOGGER.warn("Service [{}] is not allowed to use SSO.", service); throw new UnauthorizedSsoServiceException(); } return !registeredService.getRequiredHandlers().isEmpty(); } return false; }
@Override public Pair<Boolean, Optional<MultifactorAuthenticationProvider>> validateAuthenticationContext(final Assertion assertion, final HttpServletRequest request) { LOGGER.debug("Locating the primary authentication associated with this service request [{}]", assertion.getService()); val registeredService = servicesManager.findServiceBy(assertion.getService()); val authentication = assertion.getPrimaryAuthentication(); val requestedContext = multifactorTriggerSelectionStrategy.resolve(request, registeredService, authentication, assertion.getService()); if (requestedContext.isEmpty()) { LOGGER.debug("No particular authentication context is required for this request"); return Pair.of(Boolean.TRUE, Optional.empty()); } return authenticationContextValidator.validate(authentication, requestedContext.get(), registeredService); } }
@Override @Audit(action = "OAUTH2_USER_PROFILE_DATA", actionResolverName = "OAUTH2_USER_PROFILE_DATA_ACTION_RESOLVER", resourceResolverName = "OAUTH2_USER_PROFILE_DATA_RESOURCE_RESOLVER") public Map<String, Object> createFrom(final AccessToken accessToken, final J2EContext context) { val service = accessToken.getService(); val registeredService = this.servicesManager.findServiceBy(service); val principal = getAccessTokenAuthenticationPrincipal(accessToken, context, registeredService); val map = new HashMap<String, Object>(); map.put(OAuth20UserProfileViewRenderer.MODEL_ATTRIBUTE_ID, principal.getId()); val attributes = principal.getAttributes(); map.put(OAuth20UserProfileViewRenderer.MODEL_ATTRIBUTE_ATTRIBUTES, attributes); finalizeProfileResponse(accessToken, map, principal); return map; }
@Override public void authorize(final HttpServletRequest request, final Service service, final Assertion assertion) { val registeredService = this.servicesManager.findServiceBy(service); RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(service, registeredService); if (registeredService.getRequiredHandlers() != null && !registeredService.getRequiredHandlers().isEmpty()) { LOGGER.debug("Evaluating service [{}] to ensure required authentication handlers can satisfy assertion", service); val attributes = assertion.getPrimaryAuthentication().getAttributes(); if (attributes.containsKey(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS)) { val assertedHandlers = CollectionUtils.toCollection( attributes.get(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS)); val matchesAll = assertedHandlers.containsAll(registeredService.getRequiredHandlers()); if (!matchesAll) { throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, StringUtils.EMPTY); } } } } }
/** * Get the relying party id for a service. * * @param service the service to get an id for * @param configuration the configuration * @return relying party id */ public String getRelyingPartyIdentifier(final Service service, final WsFederationConfiguration configuration) { val relyingPartyIdentifier = configuration.getRelyingPartyIdentifier(); if (service != null) { val registeredService = this.servicesManager.findServiceBy(service); RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(service, registeredService); if (RegisteredServiceProperty.RegisteredServiceProperties.WSFED_RELYING_PARTY_ID.isAssignedTo(registeredService)) { LOGGER.debug("Determined relying party identifier from service [{}] to be [{}]", service, relyingPartyIdentifier); return RegisteredServiceProperty.RegisteredServiceProperties.WSFED_RELYING_PARTY_ID.getPropertyValue(registeredService).getValue(); } } LOGGER.debug("Determined relying party identifier to be [{}]", relyingPartyIdentifier); return relyingPartyIdentifier; } }
@Override public boolean supports(final WebApplicationService singleLogoutService) { val selectedService = (WebApplicationService) this.authenticationRequestServiceSelectionStrategies.resolveService(singleLogoutService); val registeredService = this.servicesManager.findServiceBy(selectedService); if (registeredService != null && registeredService.getAccessStrategy().isServiceAccessAllowed() && registeredService.getLogoutType() != RegisteredServiceLogoutType.NONE) { return supportsInternal(singleLogoutService, registeredService); } return false; }
@Override protected Event doExecute(final RequestContext context) throws Exception { final Service service = WebUtils.getService(context); final RegisteredService registeredService = this.servicesManager.findServiceBy(service); if (registeredService == null) { final String msg = String.format("Service Management: Unauthorized Service Access. " + "Service [%s] does not match entries in service registry.", service.getId()); logger.warn(msg); throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, msg); } if (!registeredService.getAccessStrategy().isServiceAccessAllowed()) { final String msg = String.format("Service Management: Access to service [%s] " + "is disabled by the service registry.", service.getId()); logger.warn(msg); WebUtils.putUnauthorizedRedirectUrlIntoFlowScope(context, registeredService.getAccessStrategy().getUnauthorizedRedirectUrl()); throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, msg); } return success(); } }
@Override protected Event doExecute(final RequestContext requestContext) { val service = this.serviceSelectionStrategy.resolveService(WebUtils.getService(requestContext)); if (service != null) { val registeredService = this.servicesManager.findServiceBy(service); RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(service, registeredService); if (registeredService instanceof SamlRegisteredService) { val samlService = SamlRegisteredService.class.cast(registeredService); val adaptor = SamlRegisteredServiceServiceProviderMetadataFacade.get(resolver, samlService, service.getId()); if (adaptor.isEmpty()) { throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, "Cannot find metadata linked to " + service.getId()); } val mdui = MetadataUIUtils.locateMetadataUserInterfaceForEntityId(adaptor.get().getEntityDescriptor(), service.getId(), registeredService, WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext)); WebUtils.putServiceUserInterfaceMetadata(requestContext, mdui); } } return success(); } }
@Audit( action = "TICKET_GRANTING_TICKET", actionResolverName = "CREATE_TICKET_GRANTING_TICKET_RESOLVER", resourceResolverName = "CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER") @Override public TicketGrantingTicket createTicketGrantingTicket(final AuthenticationResult authenticationResult) throws AuthenticationException, AbstractTicketException { val authentication = authenticationResult.getAuthentication(); val service = authenticationResult.getService(); AuthenticationCredentialsThreadLocalBinder.bindCurrent(authentication); if (service != null) { val selectedService = resolveServiceFromAuthenticationRequest(service); LOGGER.debug("Resolved service [{}] from the authentication request", selectedService); val registeredService = this.servicesManager.findServiceBy(selectedService); enforceRegisteredServiceAccess(authentication, service, registeredService); } val factory = (TicketGrantingTicketFactory) this.ticketFactory.get(TicketGrantingTicket.class); val ticketGrantingTicket = factory.create(authentication, TicketGrantingTicket.class); this.ticketRegistry.addTicket(ticketGrantingTicket); doPublishEvent(new CasTicketGrantingTicketCreatedEvent(this, ticketGrantingTicket)); return ticketGrantingTicket; }