/**
   * 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);
    }
  }
예제 #2
0
  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);
    }
  }