/** * Gets mfa request context. * * @param serviceMfaData service specific mfa settings * @param attributeValue the value found in the attribute * @param targetService the target service * @return the mfa request context */ private MultiFactorAuthenticationRequestContext getMfaRequestContext( final ServiceMfaData serviceMfaData, final String attributeValue, final WebApplicationService targetService) { final RegisteredService registeredService = this.servicesManager.findServiceBy(targetService); final RegisteredServiceWithAttributes service = RegisteredServiceWithAttributes.class.cast(registeredService); final String method = String.class.cast(service.getExtraAttributes().get("method")); if (match(serviceMfaData.getAttributePattern(), attributeValue)) { if (!this.authenticationMethodConfiguration.containsAuthenticationMethod( serviceMfaData.getAuthenticationMethod())) { logger.info( "MFA attribute [{}] with value [{}] is not supported by the authentication method configuration.", serviceMfaData.getAttributeName(), serviceMfaData.getAuthenticationMethod()); return null; } final int mfaMethodRank = this.authenticationMethodConfiguration .getAuthenticationMethod(serviceMfaData.getAuthenticationMethod()) .getRank(); final MultiFactorAuthenticationSupportingWebApplicationService svc = this.mfaServiceFactory.create( targetService.getId(), targetService.getId(), targetService.getArtifactId(), "POST".equals(method) ? ResponseType.POST : ResponseType.REDIRECT, serviceMfaData.getAuthenticationMethod(), MultiFactorAuthenticationSupportingWebApplicationService.AuthenticationMethodSource .PRINCIPAL_ATTRIBUTE); return new MultiFactorAuthenticationRequestContext(svc, mfaMethodRank); } logger.trace("{} did not match {}", attributeValue, serviceMfaData.getAttributePattern()); return null; }
@Override public final WebApplicationService extractService(final HttpServletRequest request) { final WebApplicationService targetService = getTargetService(request); if (targetService == null) { return null; } String authenticationMethod = this.getAuthenticationMethod(request, targetService); if (StringUtils.isBlank(authenticationMethod)) { return null; } authenticationMethod = this.authenticationMethodTranslator.translate(targetService, authenticationMethod); this.authenticationMethodVerifier.verifyAuthenticationMethod( authenticationMethod, targetService, request); // Grab the HTTP method for the response off of the request. final String method = request.getParameter(CONST_PARAM_METHOD); final MultiFactorAuthenticationSupportingWebApplicationService mfaService = this.mfaWebApplicationServiceFactory.create( targetService.getId(), targetService.getId(), targetService.getArtifactId(), "POST".equalsIgnoreCase(method) ? ResponseType.POST : ResponseType.REDIRECT, authenticationMethod, getAuthenticationMethodSource()); logger.debug( "Created multifactor authentication service instance for [{}] with [{}] as [{}] " + "and authentication method definition source [{}].", mfaService.getId(), CONST_PARAM_AUTHN_METHOD, mfaService.getAuthenticationMethod(), mfaService.getAuthenticationMethodSource()); return mfaService; }
/** * Handle the request. Specially, abides by the default behavior specified in the {@link * org.jasig.cas.web.ServiceValidateController} and then, invokes the {@link #getCommandClass()} * method to delegate the task of spec validation. * * @param request request object * @param response response object * @return A {@link ModelAndView} object pointing to either {@link #setSuccessView(String)} or * {@link #setFailureView(String)} * @throws Exception In case the authentication method cannot be retrieved by the binder from the * incoming request. */ @Override protected final ModelAndView handleRequestInternal( final HttpServletRequest request, final HttpServletResponse response) throws Exception { final WebApplicationService service = this.argumentExtractor.extractService(request); final String serviceTicketId = service != null ? service.getArtifactId() : null; final String authnMethod = getAuthenticationMethodFromRequest(request); if (service == null || serviceTicketId == null) { logger.debug( String.format( "Could not process request; Service: %s, Service Ticket Id: %s", service, serviceTicketId)); return generateErrorView("INVALID_REQUEST", "INVALID_REQUEST", authnMethod, null); } try { final Credential serviceCredentials = getServiceCredentialsFromRequest(request); String proxyGrantingTicketId = null; if (serviceCredentials != null) { try { proxyGrantingTicketId = this.centralAuthenticationService.delegateTicketGrantingTicket( serviceTicketId, serviceCredentials); } catch (final TicketException e) { logger.error("TicketException generating ticket for: " + serviceCredentials, e); } } final Assertion assertion = this.centralAuthenticationService.validateServiceTicket(serviceTicketId, service); final AbstractMultiFactorAuthenticationProtocolValidationSpecification validationSpecification = this.getCommandClass(); final ServletRequestDataBinder binder = new ServletRequestDataBinder(validationSpecification, "validationSpecification"); initBinder(request, binder); binder.bind(request); /** * The binder does not support field aliases. This means that the request parameter names must * exactly match the validation spec fields, or the match fails. Since the validation request * per the modified protocol will use 'authn_method', we could either create a matching field * inside the validation object, create a custom data binder object that does the conversion, * or simply bind the parameter manually. * * <p>This implementation opts for the latter choice. */ validationSpecification.setAuthenticationMethod(authnMethod); try { if (!validationSpecification.isSatisfiedBy(assertion)) { logger.debug( "ServiceTicket [" + serviceTicketId + "] does not satisfy validation specification."); return generateErrorView("INVALID_TICKET", "INVALID_TICKET_SPEC", authnMethod, null); } } catch (final UnrecognizedMultiFactorAuthenticationMethodException e) { logger.debug(e.getMessage(), e); return generateErrorView( e.getCode(), e.getMessage(), authnMethod, new Object[] {e.getAuthenticationMethod()}); } catch (final UnacceptableMultiFactorAuthenticationMethodException e) { logger.debug(e.getMessage(), e); return generateErrorView( e.getCode(), e.getMessage(), authnMethod, new Object[] {serviceTicketId, e.getAuthenticationMethod()}); } onSuccessfulValidation(serviceTicketId, assertion); final ModelAndView success = new ModelAndView(this.successView); success.addObject(MODEL_ASSERTION, assertion); if (serviceCredentials != null && proxyGrantingTicketId != null) { final String proxyIou = this.proxyHandler.handle(serviceCredentials, proxyGrantingTicketId); success.addObject(MODEL_PROXY_GRANTING_TICKET_IOU, proxyIou); } final String authnMethods = MultiFactorUtils.getFulfilledAuthenticationMethodsAsString(assertion); if (StringUtils.isNotBlank(authnMethods)) { success.addObject(MODEL_AUTHN_METHOD, authnMethods); } logger.debug(String.format("Successfully validated service ticket: %s", serviceTicketId)); return success; } catch (final TicketValidationException e) { return generateErrorView( e.getCode(), e.getCode(), authnMethod, new Object[] {serviceTicketId, e.getOriginalService().getId(), service.getId()}); } catch (final TicketException te) { return generateErrorView( te.getCode(), te.getCode(), authnMethod, new Object[] {serviceTicketId}); } catch (final UnauthorizedServiceException e) { return generateErrorView(e.getMessage(), e.getMessage(), authnMethod, null); } }
protected final ModelAndView handleRequestInternal( final HttpServletRequest request, final HttpServletResponse response) throws Exception { final WebApplicationService service = this.argumentExtractor.extractService(request); final String serviceTicketId = service != null ? service.getArtifactId() : null; if (service == null || serviceTicketId == null) { logger.debug( String.format( "Could not process request; Service: %s, Service Ticket Id: %s", service, serviceTicketId)); return generateErrorView("INVALID_REQUEST", "INVALID_REQUEST", null); } try { final Credentials serviceCredentials = getServiceCredentialsFromRequest(request); String proxyGrantingTicketId = null; // XXX should be able to validate AND THEN use if (serviceCredentials != null) { try { proxyGrantingTicketId = this.centralAuthenticationService.delegateTicketGrantingTicket( serviceTicketId, serviceCredentials); } catch (final TicketException e) { logger.error("TicketException generating ticket for: " + serviceCredentials, e); } } final Assertion assertion = this.centralAuthenticationService.validateServiceTicket(serviceTicketId, service); final ValidationSpecification validationSpecification = this.getCommandClass(); final ServletRequestDataBinder binder = new ServletRequestDataBinder(validationSpecification, "validationSpecification"); initBinder(request, binder); binder.bind(request); if (!validationSpecification.isSatisfiedBy(assertion)) { if (logger.isDebugEnabled()) { logger.debug( "ServiceTicket [" + serviceTicketId + "] does not satisfy validation specification."); } return generateErrorView("INVALID_TICKET", "INVALID_TICKET_SPEC", null); } onSuccessfulValidation(serviceTicketId, assertion); final ModelAndView success = new ModelAndView(this.successView); success.addObject(MODEL_ASSERTION, assertion); if (serviceCredentials != null && proxyGrantingTicketId != null) { final String proxyIou = this.proxyHandler.handle(serviceCredentials, proxyGrantingTicketId); success.addObject(MODEL_PROXY_GRANTING_TICKET_IOU, proxyIou); } if (logger.isDebugEnabled()) { logger.debug( String.format( "Successfully validated service ticket [%s] for service [%s]", serviceTicketId, service.getId())); } return success; } catch (final TicketValidationException e) { return generateErrorView( e.getCode(), e.getCode(), new Object[] {serviceTicketId, e.getOriginalService().getId(), service.getId()}); } catch (final TicketException te) { return generateErrorView(te.getCode(), te.getCode(), new Object[] {serviceTicketId}); } catch (final UnauthorizedServiceException e) { return generateErrorView(e.getMessage(), e.getMessage(), null); } }