/** Backing bean for registration related actions */
@ViewScoped
@ManagedBean(name = "registrationBean")
public class RegistrationBean extends BaseBean implements Serializable {

  private static final long serialVersionUID = -1626833133436182182L;

  private static final Log4jLogger logger = LoggerFactory.getLogger(RegistrationBean.class);

  private String verificationCode;
  private boolean acceptTerms;
  private VOOrganization organization;
  private String password;
  private String supplierId;
  protected User user;
  transient UserBean userBean;

  public RegistrationBean() {
    setSessionAttribute(Constants.CAPTCHA_INPUT_STATUS, Boolean.FALSE);
    init();
  }

  void init() {
    HttpServletRequest httpRequest = getRequest();
    Boolean isSamlRequest = (Boolean) getRequest().getAttribute(Constants.REQ_ATTR_IS_SAML_FORWARD);
    if (Boolean.TRUE.equals(isSamlRequest)) {
      String userId = (String) httpRequest.getAttribute(Constants.REQ_PARAM_USER_ID);
      getUser().setUserId(userId);
    } else if (!isInternalMode()) {
      getUserBean().showRegistration();
    }
  }

  /**
   * Get a new organization object.
   *
   * @return the new organization object.
   */
  public VOOrganization getOrganization() {

    if (organization == null) {
      organization = new VOOrganization();
      FacesContext fc = FacesContext.getCurrentInstance();
      Locale locale = fc.getViewRoot().getLocale();
      organization.setLocale(locale.toString());
    }
    return organization;
  }

  /**
   * Get the password.
   *
   * @return the password.
   */
  public String getPassword() {
    return password;
  }

  public String getSupplierId() {
    if (supplierId == null) {
      supplierId = getRequest().getParameter(Constants.REQ_PARAM_SUPPLIER_ID);
    }

    return supplierId;
  }

  /**
   * Get a new user object.
   *
   * @return the new user object.
   */
  public User getUser() {

    if (user == null) {
      user = new User(new VOUserDetails());
      FacesContext fc = FacesContext.getCurrentInstance();
      Locale locale = fc.getViewRoot().getLocale();
      user.setLocale(locale.toString());
    }
    return user;
  }

  public String getVerificationCode() {
    return verificationCode;
  }

  public boolean isAcceptTerms() {
    return acceptTerms;
  }

  public boolean isInternalMode() {
    return getUserBean().isInternalAuthMode();
  }

  UserBean getUserBean() {
    if (userBean == null) {
      userBean = ui.findUserBean();
    }
    return userBean;
  }

  /**
   * A yet unknown Internet user registers as a new organization at the platform.
   *
   * @return the logical outcome.
   * @throws NonUniqueBusinessKeyException Thrown if the organizationId is not unique
   * @throws ValidationException Thrown if the validation in the service layer failed
   * @throws ObjectNotFoundException Thrown if the organization contains a supplierId which doesn't
   *     exist in the database
   * @throws MailOperationException
   * @throws RegistrationException Thrown if no supplier is specified or in case the specified
   *     organization is not a supplier.
   */
  public String register()
      throws NonUniqueBusinessKeyException, ValidationException, ObjectNotFoundException,
          MailOperationException, RegistrationException {
    if (logger.isDebugLoggingEnabled()) {}

    String mId = getMarketplaceId();
    String parameter = getRequest().getParameter(Constants.REQ_PARAM_SERVICE_KEY);
    String outcome = BaseBean.OUTCOME_SUCCESS;

    Long serviceKey = null;
    if (parameter != null && parameter.trim().length() > 0) {
      serviceKey = Long.valueOf(parameter);
    }
    // FIXME: Must be fixed in identity service.
    if (!isInternalMode()) {
      // A confirmation mail must be send, not a user created mail.
      // If no password is given it will be generated
      password = "";
    }
    try {
      organization =
          getAccountingService()
              .registerCustomer(
                  getOrganization(),
                  user.getVOUserDetails(),
                  password,
                  serviceKey,
                  mId,
                  getSupplierId());
    } catch (NonUniqueBusinessKeyException ex) {
      if (isInternalMode()) {
        throw ex;
      }
      ex.setMessageKey(BaseBean.ERROR_USER_ALREADY_EXIST);
      ExceptionHandler.execute(ex, true);
      return BaseBean.OUTCOME_ERROR;
    }
    if (logger.isDebugLoggingEnabled()) {}

    return outcome;
  }

  public void setAcceptTerms(final boolean acceptTerms) {
    this.acceptTerms = acceptTerms;
  }

  /**
   * Set the password.
   *
   * @param password the password to be set
   */
  public void setPassword(final String password) {
    this.password = password;
  }

  public void setSupplierId(String supplierId) {
    this.supplierId = supplierId;
  }

  public void setVerificationCode(final String verificationCode) {
    this.verificationCode = verificationCode;
  }

  /**
   * Add a validation error to the context if the acceptTerms is not set.
   *
   * @param context the context
   * @param toValidate checkbox which is validated
   * @param value the value to validate
   */
  public void validateAcceptTerm(
      final FacesContext context, final UIComponent toValidate, final Object value) {
    Boolean accept = (Boolean) value;
    if (!accept.booleanValue()) {
      ((UISelectBoolean) toValidate).setValid(false);
      addMessage(
          toValidate.getClientId(context), FacesMessage.SEVERITY_ERROR, ERROR_REGISTRATION_TERMS);
    }
  }
}
/** @author qiu */
@Interceptors({InvocationDateContainer.class, ExceptionMapper.class})
@LocalBean
public class UserLicenseServiceLocalBean {

  @EJB(beanInterface = UserLicenseDao.class)
  UserLicenseDao userLicenseDao;

  @EJB(beanInterface = CommunicationServiceLocal.class)
  CommunicationServiceLocal cs;

  @EJB(beanInterface = ConfigurationServiceLocal.class)
  ConfigurationServiceLocal configService;

  private static final Log4jLogger logger =
      LoggerFactory.getLogger(UserLicenseServiceLocalBean.class);

  @RolesAllowed("PLATFORM_OPERATOR")
  public long countRegisteredUsers() {
    return userLicenseDao.countRegisteredUsers();
  }

  /**
   * Check is user number bigger than max value.
   *
   * @throws MailOperationException
   */
  public boolean checkUserNum() throws MailOperationException {
    long currentNum = countRegisteredUsers();
    long maxNum =
        configService.getLongConfigurationSetting(
            ConfigurationKey.MAX_NUMBER_ALLOWED_USERS, Configuration.GLOBAL_CONTEXT);
    if (currentNum > maxNum) {
      sendMailToOperators(currentNum, maxNum);
      logger.logInfo(
          Log4jLogger.SYSTEM_LOG,
          LogMessageIdentifier.INFO_USER_NUM_EXCEEDED,
          String.valueOf(maxNum),
          String.valueOf(currentNum));
    }
    return true;
  }

  private void sendMailToOperators(long currentNum, long maxNum) throws MailOperationException {
    List<PlatformUser> recipients = userLicenseDao.getPlatformOperators();
    SendMailStatus<PlatformUser> mailStatus =
        cs.sendMail(
            EmailType.USER_NUM_EXCEEDED,
            new Object[] {Long.valueOf(maxNum), Long.valueOf(currentNum)},
            null,
            recipients.toArray(new PlatformUser[recipients.size()]));
    if (mailStatus != null) {
      for (SendMailStatusItem<PlatformUser> sendMailStatusItem : mailStatus.getMailStatus()) {
        if (sendMailStatusItem.errorOccurred()) {
          MailOperationException mpe = new MailOperationException();
          logger.logWarn(
              Log4jLogger.SYSTEM_LOG,
              sendMailStatusItem.getException(),
              LogMessageIdentifier.WARN_MAIL_USER_NUM_EXCEEDED_FAILED);
          throw mpe;
        }
      }
    }
  }
}
예제 #3
0
/** @author groch */
public class LdapConnector {

  private static final Log4jLogger logger = LoggerFactory.getLogger(LdapConnector.class);
  private final LdapAccessServiceLocal ldapAccess;
  private Set<String> missingMandatoryLdapProps;
  private Properties dirProperties;
  private String baseDN;
  private Map<SettingType, String> attrMap;

  private static final int LOCAL_LENGTH = 2;

  /** @param ldapAccess */
  public LdapConnector(final LdapAccessServiceLocal ldapAccess, final Properties allProps) {
    super();
    this.ldapAccess = ldapAccess;
    init(allProps);
  }

  /** Sets the dirProperties and attrMap */
  public void init(final Properties props) {
    this.dirProperties = new Properties();
    this.attrMap = new HashMap<SettingType, String>();

    // extract different types of properties + check if all mandatory
    // settings are available
    this.missingMandatoryLdapProps = new HashSet<String>(SettingType.LDAP_ATTRIBUTES_MANDATORY);

    if (props != null) {
      for (Object propKey : props.keySet()) {
        String key = String.valueOf(propKey);
        SettingType settingType = SettingType.valueOf(key);
        String value = props.getProperty(key);
        if (settingType.getDirContextKey() != null) {
          this.dirProperties.put(settingType.getDirContextKey(), value);
        } else if (SettingType.LDAP_ATTRIBUTES.contains(settingType)) {
          this.attrMap.put(settingType, value);
        } else if (SettingType.LDAP_BASE_DN.equals(settingType)) {
          this.baseDN = value;
        }
        this.missingMandatoryLdapProps.remove(key);
      }
    }
  }

  /**
   * Validate that a value entered by a user is empty or equal to the value from the remote LDAP
   * system.
   *
   * @param attrMap the map with all configured LDAP attributes
   * @param setting the LDAP attribute the check
   * @param userValue the value entered by a the user
   * @param ldapValue value from the LDAP system
   * @throws ValidationException
   */
  private void validateLdapPropertyValue(
      Map<SettingType, String> attrMap, SettingType setting, String userValue, String ldapValue)
      throws ValidationException {
    if (attrMap.containsKey(setting)
        && userValue != null
        && userValue.length() != 0
        && !userValue.equals(ldapValue)) {
      // sessionCtx.setRollbackOnly();
      ValidationException vf =
          new ValidationException(
              ReasonEnum.LDAP_VALUE_MISMATCH,
              null,
              new Object[] {ldapValue, setting.toString(), userValue});
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_VALIDATION_PARAMETER_LDAP_FOUND_ERROR,
          "User Value");
      throw vf;
    }
  }

  /**
   * Validate the LDAP properties by performing a search request.
   *
   * @param baseDN the baseDN
   * @return the read attribute
   * @throws ValidationException Thrown in case the LDAP access failed or no record was found
   */
  public VOUserDetails validateLdapProperties(VOUserDetails user) throws ValidationException {

    LdapVOUserDetailsMapper mapper = new LdapVOUserDetailsMapper(user, this.attrMap);
    VOUserDetails tmpUser = new VOUserDetails();
    tmpUser.setAdditionalName(user.getAdditionalName());
    tmpUser.setEMail(user.getEMail());
    tmpUser.setFirstName(user.getFirstName());
    tmpUser.setLastName(user.getLastName());
    tmpUser.setLocale(user.getLocale());

    try {

      String dnName =
          ldapAccess.dnSearch(
              this.dirProperties,
              this.baseDN,
              this.attrMap.get(SettingType.LDAP_ATTR_UID) + "=" + user.getUserId());

      if (dnName == null) {
        // sessionCtx.setRollbackOnly();
        ValidationException vf =
            new ValidationException(
                ReasonEnum.LDAP_USER_NOT_FOUND, null, new Object[] {user.getUserId()});
        logger.logError(
            Log4jLogger.SYSTEM_LOG,
            vf,
            LogMessageIdentifier.ERROR_LDAP_SEARCH_OF_USER_FAILED,
            user.getUserId());
        throw vf;
      }

      List<VOUserDetails> result =
          ldapAccess.search(
              this.dirProperties,
              this.baseDN,
              this.attrMap.get(SettingType.LDAP_ATTR_UID) + "=" + user.getUserId(),
              mapper,
              true);
      int size = result.size();
      if (size == 1) {
        user = result.get(0);
        if (user.getLocale() != null
            && !user.getLocale().isEmpty()
            && user.getLocale().length() > LOCAL_LENGTH) {
          user.setLocale(user.getLocale().substring(0, LOCAL_LENGTH));
        }
        validateLdapPropertyValue(
            this.attrMap,
            SettingType.LDAP_ATTR_ADDITIONAL_NAME,
            tmpUser.getAdditionalName(),
            user.getAdditionalName());
        validateLdapPropertyValue(
            this.attrMap, SettingType.LDAP_ATTR_EMAIL, tmpUser.getEMail(), user.getEMail());
        validateLdapPropertyValue(
            this.attrMap,
            SettingType.LDAP_ATTR_FIRST_NAME,
            tmpUser.getFirstName(),
            user.getFirstName());
        validateLdapPropertyValue(
            this.attrMap,
            SettingType.LDAP_ATTR_LAST_NAME,
            tmpUser.getLastName(),
            user.getLastName());
        validateLdapPropertyValue(
            this.attrMap, SettingType.LDAP_ATTR_LOCALE, tmpUser.getLocale(), user.getLocale());

        return result.get(0);
      } else if (size == 0) {
        // sessionCtx.setRollbackOnly();
        ValidationException vf =
            new ValidationException(
                ReasonEnum.LDAP_USER_NOT_FOUND, null, new Object[] {user.getUserId()});
        logger.logError(
            Log4jLogger.SYSTEM_LOG,
            vf,
            LogMessageIdentifier.ERROR_VALIDATION_PARAMETER_LDAP_FOUND_ERROR,
            "LDAP User");
        throw vf;
      } else {
        // sessionCtx.setRollbackOnly();
        ValidationException vf =
            new ValidationException(
                ReasonEnum.LDAP_USER_NOT_UNIQUE, null, new Object[] {user.getUserId()});
        logger.logError(
            Log4jLogger.SYSTEM_LOG,
            vf,
            LogMessageIdentifier.ERROR_VALIDATION_PARAMETER_LDAP_FOUND_ERROR,
            "LDAP User");
        throw vf;
      }
    } catch (NameNotFoundException nnfe) {
      // sessionCtx.setRollbackOnly();
      ValidationException vf =
          new ValidationException(
              ReasonEnum.LDAP_BASE_DN_INVALID, null, new Object[] {this.baseDN});
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_LDAP_ACCESS_FAILED,
          nnfe.getMessage());
      throw vf;
    } catch (NamingException e1) {
      // sessionCtx.setRollbackOnly();
      Object[] params = new Object[] {dirProperties.get(Context.PROVIDER_URL), e1.getMessage()};
      ValidationException vf =
          new ValidationException(ReasonEnum.LDAP_CONNECTION_REFUSED, null, params);
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_LDAP_SYSTEM_CONNECTION_REFUSED,
          "LDAPuser");
      throw vf;
    }
  }

  public void ensureAllMandatoryLdapPropertiesPresent() throws ValidationException {
    if (!missingMandatoryLdapProps.isEmpty()) {
      ValidationException vf =
          new ValidationException(
              ReasonEnum.LDAP_MANDATORY_PROPERTY_MISSING,
              null,
              new Object[] {this.missingMandatoryLdapProps.toString()});
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_MANDATORY_LDAP_PARAMETER_MISSING,
          this.missingMandatoryLdapProps.toString());
      throw vf;
    }
  }

  public boolean canConnect() throws ValidationException {

    try {
      // now try to connect
      String dnName =
          ldapAccess.dnSearch(
              this.dirProperties, this.baseDN, this.attrMap.get(SettingType.LDAP_ATTR_UID) + "=*");

      if (dnName == null) {

        return false;
      }

      return true;

    } catch (NameNotFoundException nnfe) {
      // sessionCtx.setRollbackOnly();
      ValidationException vf =
          new ValidationException(
              ReasonEnum.LDAP_BASE_DN_INVALID, null, new Object[] {this.baseDN});
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_LDAP_ACCESS_FAILED,
          nnfe.getMessage());
      throw vf;
    } catch (NamingException e1) {
      // sessionCtx.setRollbackOnly();
      Object[] params =
          new Object[] {this.dirProperties.get(Context.PROVIDER_URL), e1.getMessage()};
      ValidationException vf =
          new ValidationException(ReasonEnum.LDAP_CONNECTION_REFUSED, null, params);
      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          vf,
          LogMessageIdentifier.ERROR_LDAP_SYSTEM_CONNECTION_REFUSED,
          "LDAPuser");
      throw vf;
    }
  }

  /** @return the dirProperties */
  public Properties getDirProperties() {
    return dirProperties;
  }

  /** @return the baseDN */
  public String getBaseDN() {
    return baseDN;
  }

  /** @return the attrMap */
  public Map<SettingType, String> getAttrMap() {
    return attrMap;
  }
}
/**
 * Retrieves the provisioning service adapter according to the concrete technical product WSDL.
 *
 * @author Mike J&auml;ger
 */
public class ProvisioningServiceAdapterFactory {

  private static final Log4jLogger logger =
      LoggerFactory.getLogger(ProvisioningServiceAdapterFactory.class);

  public static ProvisioningServiceAdapter getProvisioningServiceAdapter(
      TechnicalProduct techProduct, Integer wsTimeout) throws TechnicalServiceNotAliveException {
    ProvisioningServiceAdapter adapter = null;
    try {
      String username = techProduct.getProvisioningUsername();
      String password = techProduct.getProvisioningPassword();
      WSPortConnector portConnector =
          new WSPortConnector(techProduct.getProvisioningURL(), username, password);

      WSPortDescription portDescription = portConnector.getPortDescription();

      String targetVersionFromWsdl = portDescription.getVersion();
      SupportedProvisioningVersions supportedVersion =
          SupportedProvisioningVersions.getForVersionString(targetVersionFromWsdl);
      if (supportedVersion == null) {
        String targetNamespaceFromWsdl = portDescription.getTargetNamespace();
        supportedVersion =
            SupportedProvisioningVersions.getForNamespaceString(targetNamespaceFromWsdl);
        if (supportedVersion == null) {
          throw new TechnicalServiceNotAliveException(
              TechnicalServiceNotAliveException.Reason.TARGET_NAMESPACE);
        }
      }
      Class<?> serviceClass = supportedVersion.getServiceClass();
      adapter = getAdapterForVersion(supportedVersion);
      URL localWsdlURL = adapter.getLocalWSDL();

      try {
        final Object port = portConnector.getPort(localWsdlURL, serviceClass, wsTimeout);
        adapter.setProvisioningService(port);
      } catch (WebServiceException e) {
        TechnicalServiceNotAliveException tse =
            new TechnicalServiceNotAliveException(
                TechnicalServiceNotAliveException.Reason.ENDPOINT, e);
        logger.logWarn(
            Log4jLogger.SYSTEM_LOG,
            tse,
            LogMessageIdentifier.WARN_EX_TECHNICAL_SERVICE_NOT_ALIVE_EXCEPTION_ENDPOINT);
        throw tse;
      }

    } catch (TechnicalServiceNotAliveException e) {
      logger.logWarn(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.WARN_TECH_SERVICE_NOT_AVAILABLE,
          techProduct.getTechnicalProductId());
      throw e;
    } catch (WSDLException e) {
      TechnicalServiceNotAliveException ex =
          new TechnicalServiceNotAliveException(
              TechnicalServiceNotAliveException.Reason.CONNECTION_REFUSED, e.getCause());
      logger.logWarn(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.WARN_TECH_SERVICE_NOT_ALIVE_CONNECTION_REFUSED);
      throw ex;
    } catch (Exception e) {
      TechnicalServiceNotAliveException ex =
          new TechnicalServiceNotAliveException(
              TechnicalServiceNotAliveException.Reason.CONNECTION_REFUSED, e);
      logger.logWarn(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.WARN_TECH_SERVICE_NOT_ALIVE_CONNECTION_REFUSED);
      throw ex;
    }

    return adapter;
  }

  /**
   * Initialized a provisioning service adapter for the version matching the the version retrieved
   * from wsdl.
   *
   * @param supportedVersion
   * @return
   */
  private static ProvisioningServiceAdapter getAdapterForVersion(
      SupportedProvisioningVersions supportedVersion) {
    switch (supportedVersion) {
      case VERSION_1_0:
        return new ProvisioningServiceAdapterV1_0();
      case VERSION_1_8:
        return new ProvisioningServiceAdapterV1_8();

      default:
        return new ProvisioningServiceAdapterV1_8();
    }
  }
}
/** @author kulle */
public class ReportDataConverter {

  static final Log4jLogger logger = LoggerFactory.getLogger(ReportDataConverter.class);
  private final SubscriptionDao dao;

  private static final String[] REPORTS_DATE_FIELDS =
      new String[] {
        "ACTIVATIONDATE", "ASSIGNMENTDATE", "BILLINGDATE",
        "DEACTIVATIONDATE", "OCCURRENCETIME", "PROCESSINGTIME",
        "PERIODSTARTTIME", "PERIODENDTIME", "REGISTRATIONDATE"
      };
  private static final Set<String> dateColumnNames =
      new HashSet<String>(Arrays.asList(REPORTS_DATE_FIELDS));

  public ReportDataConverter(SubscriptionDao dao) {
    this.dao = dao;
  }

  public void convertToXml(
      List<ReportResultData> reportData, List<Object> result, Map<String, String> xmlMap)
      throws XPathExpressionException, ParserConfigurationException {

    Document document = newEmptyDocument();
    Map<String, String> lastSubIdMap = dao.retrieveLastValidSubscriptionIdMap();

    for (ReportResultData data : reportData) {
      Element row = document.createElement("row");
      for (int columnIndex = 0; columnIndex < data.getColumnCount(); columnIndex++) {
        String columnName = data.getColumnName().get(columnIndex);
        Object value = data.getColumnValue().get(columnIndex);
        Element node = document.createElement(columnName.toUpperCase());
        if (value != null) {

          if (columnName.equalsIgnoreCase("SUBSCRIPTIONID")) {
            String id = lastSubIdMap.get(value);
            if (id != null) {
              value = id;
            }
          } else if (columnName.equalsIgnoreCase("PRODUCTID")) {
            String productId = (String) value;
            String[] split = productId.split("#");
            value = split[0];
          } else if (dateColumnNames.contains(columnName.toUpperCase()) && value instanceof Long) {
            Long dateFieldValue = (Long) value;

            value =
                DateConverter.convertLongToDateTimeFormat(
                    dateFieldValue.longValue(),
                    TimeZone.getDefault(),
                    DateConverter.DTP_WITHOUT_MILLIS);
          }
          readColumnValue(document, xmlMap, columnName, value, data, columnIndex, node);
        } else {
          int columnType = data.getColumnType().get(columnIndex).intValue();
          if (columnType == Types.VARCHAR
              || columnType == Types.CLOB
              || (columnType == Types.BIGINT
                  && dateColumnNames.contains(columnName.toUpperCase()))) {
            node.appendChild(document.createTextNode(""));
          } else {
            node.appendChild(document.createTextNode("null"));
          }
        }
        row.appendChild(node);
      }
      result.add(row);
    }
  }

  private Document newEmptyDocument() throws ParserConfigurationException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();
    return builder.newDocument();
  }

  private void readColumnValue(
      Document doc,
      Map<String, String> xmlFieldXPaths,
      String columnName,
      Object value,
      ReportResultData reportData,
      int index,
      Element node)
      throws XPathExpressionException {
    if ("RESULTXML".equalsIgnoreCase(columnName)
        || "PROCESSINGRESULT".equalsIgnoreCase(columnName)) {
      Document columnValueAsDoc = parseXML((String) reportData.getColumnValue().get(index));

      if (xmlFieldXPaths.containsKey(columnName.toLowerCase())) {
        String xpathEvaluationResult =
            XMLConverter.getNodeTextContentByXPath(
                columnValueAsDoc, xmlFieldXPaths.get(columnName));
        // don't store null values but empty strings instead, to ensure
        // proper display on client side
        if (xpathEvaluationResult == null) {
          xpathEvaluationResult = "";
        }
        node.appendChild(doc.createTextNode(xpathEvaluationResult));
      } else {
        appendXMLStructureToNode(node, columnValueAsDoc);
      }
    } else {
      node.appendChild(doc.createTextNode(value.toString()));
    }
  }

  private Document parseXML(String xmlAsString) {
    try {
      return XMLConverter.convertToDocument(xmlAsString, false);
    } catch (Exception e) {
      throw new SaaSSystemException("Parsing failed for:\n" + xmlAsString, e);
    }
  }

  /**
   * Clones the document parameter and appends the result to the given parent node.
   *
   * @param parentNode The node to append the document to.
   * @param doc The document to be appended.
   */
  private void appendXMLStructureToNode(Element parentNode, Document doc) {
    if (doc != null) {
      Node cloneNode = doc.getFirstChild().cloneNode(true);
      cloneNode = parentNode.getOwnerDocument().importNode(cloneNode, true);
      parentNode.appendChild(cloneNode);
    }
  }
}
/**
 * Filter which checks that a request which tries to access a protected URL has an active session
 * containing a user value object. If this is not the case a login is performed and on success the
 * user value object is stored in the session.
 */
public class AuthorizationFilter extends BaseBesFilter {

  static final String PARAM_LOGIN_USER_ID = "loginForm:loginUserId";
  private static final String PARAM_LOGIN_PASSWORD = "******";

  private static final Log4jLogger logger = LoggerFactory.getLogger(AuthorizationFilter.class);

  /**
   * Check if the current URL is protected and the current session doesn't contain a user object. If
   * this is the case perform a login.
   *
   * <p>The doFilter method of the Filter is called by the container each time a request/response
   * pair is passed through the chain due to a client request for a resource at the end of the
   * chain.
   *
   * @throws IOException
   * @throws ServletException
   */
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {

    HttpServletRequest httpRequest =
        new IgnoreCharacterEncodingHttpRequestWrapper((HttpServletRequest) request);
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    AuthorizationRequestData rdo = initializeRequestDataObject(httpRequest);

    try {
      if (isPublicAccess(rdo, httpRequest)) {
        proceedWithFilterChain(chain, httpRequest, httpResponse);
      } else {
        handleProtectedUrlAndChangePwdCase(chain, httpRequest, httpResponse, rdo);
      }
    } catch (ServletException e) {

      // relogin is not possible in this case,
      // no SAML response to extract userid and generate password.
      if (authSettings.isServiceProvider()) {
        throw e;
      }

      if (e.getCause() instanceof ViewExpiredException) {
        // if we were logged in but a logout occurs from a different
        // browser tab, we get this exception - so redirect to the
        // same page to stay on it (Bug 7552)
        final StringBuffer url =
            new StringBuffer(rdo.getRelativePath() == null ? "" : rdo.getRelativePath());
        reLogginUserIfRequired(httpRequest, httpResponse, rdo, url);
        sendRedirect(httpRequest, httpResponse, url.toString());
      } else {
        throw e;
      }
    }
  }

  private void rollbackDefaultTimeout(HttpServletRequest httpRequest) {
    HttpSession session = httpRequest.getSession();
    Integer attributeInt = (Integer) session.getAttribute(Constants.SESS_ATTR_DEFAULT_TIMEOUT);
    if (attributeInt != null) {
      session.setMaxInactiveInterval(attributeInt.intValue());
      session.removeAttribute(Constants.SESS_ATTR_DEFAULT_TIMEOUT);
    }
  }

  /**
   * Returns true if one of the following conditions is matching:<br>
   * 1) the landing page is requested and defined as public <br>
   * 2) the requested URL matches the public URL-pattern
   */
  boolean isPublicAccess(AuthorizationRequestData rdo, HttpServletRequest request) {

    // first, check if landing page is public
    if (rdo.isLandingPage()) {
      LandingpageConfigurationService service = lookupLandingpageConfigurationService(request);
      try {
        LandingpageType type = service.loadLandingpageType(rdo.getMarketplaceId());
        return type.isDefault();
      } catch (Exception e) {
        return false;
      }
    }

    // second, check url pattern of request
    return rdo.isPublicURL(publicUrlPattern);
  }

  private LandingpageConfigurationService lookupLandingpageConfigurationService(
      HttpServletRequest httpRequest) {
    ServiceAccess serviceAccess = ServiceAccess.getServiceAcccessFor(httpRequest.getSession());
    return serviceAccess.getService(LandingpageConfigurationService.class);
  }

  private void appendParam(StringBuffer url, String param, String value, String encoding) {
    if (url.indexOf("?") > -1) url.append('&');
    else url.append('?');
    url.append(param);
    url.append("=");
    try {
      url.append(URLEncoder.encode(value, encoding));
    } catch (UnsupportedEncodingException e) {
      throw new SaaSSystemException(e);
    }
  }

  /** This method is not adapted used in SAML_SP case. */
  void reLogginUserIfRequired(
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo,
      StringBuffer url) {
    final String userId = httpRequest.getParameter(PARAM_LOGIN_USER_ID);
    if (!ADMStringUtils.isBlank(userId)) {
      // user login data was just provided by the login dialog
      try {
        ServiceAccess serviceAccess = ServiceAccess.getServiceAcccessFor(httpRequest.getSession());
        IdentityService identityService = serviceAccess.getService(IdentityService.class);
        rdo.setUserId(userId);
        rdo.setPassword(httpRequest.getParameter(PARAM_LOGIN_PASSWORD));
        VOUser voUser = readTechnicalUserFromDb(identityService, rdo);
        serviceAccess.login(voUser, rdo.getPassword(), httpRequest, httpResponse);
        httpRequest
            .getSession()
            .setAttribute(Constants.SESS_ATTR_USER, identityService.getCurrentUserDetails());
      } catch (Exception e2) {
        httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN);
        // open marketplace login dialog again and fill in
        // userId
        appendParam(
            url,
            Constants.REQ_PARAM_AUTO_OPEN_MP_LOGIN_DIALOG,
            Boolean.TRUE.toString(),
            httpRequest.getCharacterEncoding());
        appendParam(url, Constants.REQ_PARAM_USER_ID, userId, httpRequest.getCharacterEncoding());
      }
    }
  }

  private void proceedWithFilterChain(
      FilterChain chain, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
      throws IOException, ServletException {

    BesServletRequestReader.param2Attr(httpRequest, Constants.REQ_PARAM_SUB_KEY);
    BesServletRequestReader.param2Attr(httpRequest, Constants.REQ_PARAM_CONTEXT_PATH);
    BesServletRequestReader.param2Attr(httpRequest, Constants.REQ_PARAM_SUPPLIER_ID);
    BesServletRequestReader.param2Attr(httpRequest, Constants.REQ_ATTR_SERVICE_LOGIN_TYPE);
    BesServletRequestReader.param2Attr(httpRequest, Constants.REQ_ATTR_ERROR_KEY);

    chain.doFilter(httpRequest, httpResponse);
  }

  protected void handleProtectedUrlAndChangePwdCase(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws IOException, ServletException {

    if (logger.isDebugLoggingEnabled()) {
      logger.logDebug("Access to protected URL='" + rdo.getRelativePath() + "'");
    }

    ServiceAccess serviceAccess = ServiceAccess.getServiceAcccessFor(httpRequest.getSession());

    try {
      if (rdo.isAccessToServiceUrl()) {
        /*
         * We must NOT read the request parameters for service URLs
         * because this would cause a state switch of the request.
         * Afterwards the rewriting of a POST request may fail because
         * the parameters can't be accessed via the request input
         * stream.
         */
        httpRequest = handleServiceUrl(chain, httpRequest, httpResponse, rdo);
        if (httpRequest == null) {
          return;
        }
      } else if (ADMStringUtils.isBlank(rdo.getUserId())) {
        if (authSettings.isServiceProvider()) {
          if (isSamlForward(httpRequest)) {
            SAMLCredentials samlCredentials = new SAMLCredentials(httpRequest);
            rdo.setUserId(samlCredentials.getUserId());
            if (rdo.getUserId() == null) {
              httpRequest.setAttribute(
                  Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_INVALID_SAML_RESPONSE);
              forward(errorPage, httpRequest, httpResponse);
            }
          }
        } else {
          rdo.setUserId(httpRequest.getParameter(Constants.REQ_PARAM_USER_ID));
        }
      }

      // continue if user is already logged-in
      if (handleLoggedInUser(chain, httpRequest, httpResponse, serviceAccess, rdo)) {
        return;
      }

      // the httpRequest was already processed and we forwarded to the
      // corresponding page therefore we must not try to login again
      if (httpRequest.getAttribute(Constants.REQ_ATTR_ERROR_KEY) != null) {
        chain.doFilter(httpRequest, httpResponse);
        return;
      }

      refreshData(authSettings, rdo, httpRequest, httpResponse);

      // user not logged in, check user-name and password before login
      // don't do a trim on password because it may have
      // leading/trailing/only blanks

      if (authSettings.isServiceProvider()) {
        rollbackDefaultTimeout(httpRequest);
        if (ADMStringUtils.isBlank(rdo.getUserId())) {
          httpRequest.setAttribute(
              Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_INVALID_SAML_RESPONSE);
          if (isSamlForward(httpRequest)) {
            forward(errorPage, httpRequest, httpResponse);
          } else {
            forwardToLoginPage(rdo.getRelativePath(), true, httpRequest, httpResponse, chain);
          }
          return;
        }
      } else {
        if (ADMStringUtils.isBlank(rdo.getUserId()) || !rdo.isPasswordSet()) {
          if (!rdo.isMarketplace()
              && (!ADMStringUtils.isBlank(rdo.getUserId()) || rdo.isPasswordSet())) {
            // login data not complete, user or password empty
            httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN);
          }
          forwardToLoginPage(rdo.getRelativePath(), true, httpRequest, httpResponse, chain);
          return;
        }
      }

      IdentityService identityService = serviceAccess.getService(IdentityService.class);
      VOUser voUser;
      try {
        voUser = readTechnicalUserFromDb(identityService, rdo);
      } catch (ObjectNotFoundException e) {
        handleUserNotRegistered(chain, httpRequest, httpResponse, rdo);
        return;
      } catch (SaaSApplicationException e) {
        setErrorAttributesAndForward(errorPage, httpRequest, httpResponse, e);
        return;
      }

      if (!authSettings.isServiceProvider()) {
        if (isAccountLocked(httpRequest, httpResponse, voUser)) {
          return;
        }
      }

      final boolean operationSucceeded;
      if (!authSettings.isServiceProvider() && rdo.isRequestedToChangePwd()) {
        operationSucceeded =
            handleChangeUserPasswordRequest(chain, httpRequest, httpResponse, rdo, identityService);
      } else {
        operationSucceeded =
            loginUser(chain, httpRequest, httpResponse, voUser, rdo, identityService);
      }
      if (!operationSucceeded) {
        return;
      }
      rdo.setUserDetails(identityService.getCurrentUserDetails());

      // read user details value object and store it in the session, DON'T
      // use old session, because it might have been invalidated
      httpRequest.getSession().setAttribute(Constants.SESS_ATTR_USER, rdo.getUserDetails());

      if (isPageForbiddenToAccess(httpRequest, rdo, serviceAccess)) {
        forward(insufficientAuthoritiesUrl, httpRequest, httpResponse);
      }
      // check if user must change his password
      if (!authSettings.isServiceProvider()
          && (rdo.getUserDetails().getStatus() == UserAccountStatus.PASSWORD_MUST_BE_CHANGED)) {
        forwardToPwdPage(rdo.getUserDetails().getUserId(), httpRequest, httpResponse);
      } else {
        redirectToPrimarilyRequestedUrl(chain, httpRequest, httpResponse, serviceAccess, rdo);
      }

    } catch (NumberFormatException e) {
      handleNumberFormatException(chain, httpRequest, httpResponse, e, rdo);
    } catch (ServletException e) {
      handleServletException(httpRequest, httpResponse, e);
    } catch (MarketplaceRemovedException e) {
      handleMarketplaceRemovedException(httpRequest, httpResponse);
    }
  }

  private boolean isPageForbiddenToAccess(
      HttpServletRequest httpRequest, AuthorizationRequestData rdo, ServiceAccess serviceAccess) {
    @SuppressWarnings("unchecked")
    List<PageAuthorization> pageAuthorizationList =
        ((List<PageAuthorization>)
            httpRequest.getSession().getAttribute(Constants.SESS_ATTR_PAGE_AUTHORIZATION));
    if (pageAuthorizationList == null) {
      PageAuthorizationBuilder builder = new PageAuthorizationBuilder(serviceAccess);
      pageAuthorizationList = builder.buildPageAuthorizationList(new User(rdo.getUserDetails()));
      httpRequest
          .getSession()
          .setAttribute(Constants.SESS_ATTR_PAGE_AUTHORIZATION, pageAuthorizationList);
    }

    for (PageAuthorization page : pageAuthorizationList) {
      if (page.getCurrentPageLink().equalsIgnoreCase(httpRequest.getServletPath())) {
        return !page.isAuthorized();
      }
    }
    return false;
  }

  private void handleNumberFormatException(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      NumberFormatException e,
      AuthorizationRequestData rdo)
      throws ServletException, IOException {
    logger.logError(
        Log4jLogger.SYSTEM_LOG,
        e,
        LogMessageIdentifier.ERROR_PARSE_SUBSCRIPTION_KEY_FAILED,
        rdo.getSubscriptionKey());
    if (authSettings.isServiceProvider()) {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_SUBSCRIPTION_KEY);
      forward(errorPage, httpRequest, httpResponse);
    } else {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN);
      forwardToLoginPage(rdo.getRelativePath(), false, httpRequest, httpResponse, chain);
    }
  }

  private void handleCommunicationException(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws ServletException, IOException {
    httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN_IMPOSSIBLE);
    if (authSettings.isServiceProvider()) {
      forward(errorPage, httpRequest, httpResponse);
    } else {
      forwardToLoginPage(rdo.getRelativePath(), false, httpRequest, httpResponse, chain);
    }
  }

  private void handleServletException(
      HttpServletRequest httpRequest, HttpServletResponse httpResponse, ServletException e)
      throws IOException, ServletException {
    EJBException ejbEx = ExceptionHandler.getEJBException(e);
    if (ejbEx != null
        && ejbEx.getCause() instanceof Exception
        && ejbEx.getCausedByException() instanceof AccessException) {
      String forwardErrorPage;
      if (BesServletRequestReader.isMarketplaceRequest(httpRequest)) {
        forwardErrorPage = Marketplace.MARKETPLACE_ROOT + Constants.INSUFFICIENT_AUTHORITIES_URI;
      } else {
        forwardErrorPage = Constants.INSUFFICIENT_AUTHORITIES_URI;
      }
      JSFUtils.sendRedirect(httpResponse, httpRequest.getContextPath() + forwardErrorPage);
    } else {
      // make sure we do not catch exceptions cause by
      // ViewExpiredException here, they'll be handled directly in the
      // doFilter()
      throw e;
    }
  }

  private void handleLoginException(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws ServletException, IOException {
    if (authSettings.isServiceProvider()) {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_INVALID_SAML_RESPONSE);
      forward(errorPage, httpRequest, httpResponse);
    } else {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN);
      forwardToLoginPage(rdo.getRelativePath(), true, httpRequest, httpResponse, chain);
    }
  }

  private void handleMarketplaceRemovedException(
      HttpServletRequest httpRequest, HttpServletResponse httpResponse)
      throws ServletException, IOException {
    httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_MARKETPLACE_REMOVED);
    forward(errorPage, httpRequest, httpResponse);
  }

  private void handleUserNotRegistered(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws IOException, ServletException {
    if (authSettings.isServiceProvider()) {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN_SAML_SP);
      forward(errorPage, httpRequest, httpResponse);
    } else {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_LOGIN);
      forwardToLoginPage(rdo.getRelativePath(), false, httpRequest, httpResponse, chain);
    }
  }

  private void setErrorAttributesAndForward(
      String forwardUrl,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      SaaSApplicationException e)
      throws ServletException, IOException {
    BesServletRequestReader.setErrorAttributes(httpRequest, e);
    forward(forwardUrl, httpRequest, httpResponse);
  }

  private void refreshData(
      AuthenticationSettings authSettings,
      AuthorizationRequestData rdo,
      HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException, MarketplaceRemovedException {

    if (authSettings.isServiceProvider()) {

      rdo.setTenantID(getTenantID(rdo, request));

      if (!isSamlForward(request)) {
        return;
      }

      rdo.refreshData(request);

      SAMLCredentials samlCredentials = new SAMLCredentials(request);

      if (rdo.getUserId() == null) {
        rdo.setUserId(samlCredentials.getUserId());
      }

      if (rdo.getPassword() == null) {
        String generatedPassword = samlCredentials.generatePassword();
        if (generatedPassword == null) {
          request.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_SAML_TIMEOUT);
          forward(errorPage, request, response);
        }
        rdo.setPassword(generatedPassword);

        // if generated password is null, then timeout!!!
      }
    } else {
      rdo.refreshData(request);
      // store some parameters if the login fails (needed for login.xhtml)
      request.setAttribute(Constants.REQ_PARAM_USER_ID, rdo.getUserId());
    }
  }

  public String getTenantID(AuthorizationRequestData ard, HttpServletRequest httpRequest)
      throws MarketplaceRemovedException {
    String tenantID;
    if (ard.isMarketplace()) {
      tenantID = getTenantIDFromMarketplace(httpRequest, ard);
    } else {
      tenantID = getTenantIDFromRequest(httpRequest);
    }
    if (StringUtils.isNotBlank(tenantID)) {
      httpRequest.getSession().setAttribute(REQ_PARAM_TENANT_ID, tenantID);
    } else {
      tenantID = (String) httpRequest.getSession().getAttribute(REQ_PARAM_TENANT_ID);
    }
    if (StringUtils.isBlank(tenantID)) {
      logger.logDebug("TenantID is missing. Using default.");
      tenantID =
          getConfigurationService(httpRequest)
              .getVOConfigurationSetting(SSO_DEFAULT_TENANT_ID, GLOBAL_CONTEXT)
              .getValue();
      httpRequest.getSession().setAttribute(REQ_PARAM_TENANT_ID, tenantID);
    }
    return tenantID;
  }

  private String getTenantIDFromMarketplace(
      HttpServletRequest httpRequest, AuthorizationRequestData ard)
      throws MarketplaceRemovedException {
    String marketplaceId = ard.getMarketplaceId();
    String tenantID = null;
    if (StringUtils.isNotBlank(marketplaceId)) {
      tenantID =
          getMarketplaceServiceCache(httpRequest).getConfiguration(marketplaceId).getTenantId();
      if (StringUtils.isBlank(tenantID)) {
        try {
          tenantID =
              getMarketplaceService(httpRequest).getMarketplaceById(marketplaceId).getTenantId();
        } catch (ObjectNotFoundException e) {
          throw new MarketplaceRemovedException();
        }
      }
    }
    return tenantID;
  }

  private String getTenantIDFromRequest(HttpServletRequest request) {
    return request.getParameter(REQ_PARAM_TENANT_ID);
  }

  private HttpServletRequest handleServiceUrl(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws IOException, ServletException {

    VOMarketplace mpl;
    try {
      mpl = determineMarketplaceForSubscription(httpRequest, rdo);
    } catch (ObjectNotFoundException e) {

      logger.logError(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.ERROR_SUBSCRIPTION_NOT_FOUND,
          rdo.getSubscriptionKey());
      BesServletRequestReader.setErrorAttributes(httpRequest, e);

      handleSubscriptionNotFound(chain, httpRequest, httpResponse, rdo);
      return null;
    }

    // Bug 9588: Marketplace may have been deleted
    if (mpl != null) {
      httpRequest.setAttribute(
          Constants.REQ_ATTR_SERVICE_LOGIN_TYPE, Constants.REQ_ATTR_LOGIN_TYPE_MPL);

      httpRequest
          .getSession()
          .setAttribute(Constants.REQ_PARAM_MARKETPLACE_ID, mpl.getMarketplaceId());
    } else {
      httpRequest.setAttribute(
          Constants.REQ_ATTR_SERVICE_LOGIN_TYPE, Constants.REQ_ATTR_LOGIN_TYPE_NO_MPL);
    }

    String contextPath = rdo.getContextPath();
    if (!ADMStringUtils.isBlank(httpRequest.getQueryString())) {
      contextPath += "?" + httpRequest.getQueryString();
    }
    httpRequest.setAttribute(Constants.REQ_PARAM_SUB_KEY, rdo.getSubscriptionKey());
    httpRequest.setAttribute(Constants.REQ_PARAM_CONTEXT_PATH, contextPath);

    return processServiceUrl(
        httpRequest, httpResponse, chain, rdo.getSubscriptionKey(), contextPath, rdo);
  }

  private void handleSubscriptionNotFound(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo)
      throws IOException, ServletException {
    if (authSettings.isServiceProvider()) {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_SUBSCRIPTION_NOT_FOUND);
      forward(errorPage, httpRequest, httpResponse);
    } else {
      forwardToLoginPage(rdo.getRelativePath(), false, httpRequest, httpResponse, chain);
    }
  }

  /** Retrieve the marketplace for the given subscription in order to login */
  private VOMarketplace determineMarketplaceForSubscription(
      HttpServletRequest httpRequest, AuthorizationRequestData rdo) throws ObjectNotFoundException {
    Map<String, VOMarketplace> cachedMarketplaces =
        getMarketplaceMapFromSession(httpRequest.getSession());
    VOMarketplace mpl = cachedMarketplaces.get(rdo.getSubscriptionKey());
    if (mpl == null) {
      MarketplaceService marketplaceService =
          ServiceAccess.getServiceAcccessFor(httpRequest.getSession())
              .getService(MarketplaceService.class);
      mpl =
          marketplaceService.getMarketplaceForSubscription(
              ADMStringUtils.parseUnsignedLong(rdo.getSubscriptionKey()), "en");

      // Bug 9588: Marketplace may have been deleted
      if (mpl != null) {
        cachedMarketplaces.put(rdo.getSubscriptionKey(), mpl);
      }
    }
    return mpl;
  }

  private boolean isAccountLocked(
      HttpServletRequest httpRequest, HttpServletResponse httpResponse, VOUser voUser)
      throws ServletException, IOException {

    if (voUser.getStatus() == UserAccountStatus.LOCKED_NOT_CONFIRMED) {
      httpRequest.setAttribute(
          Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_USER_LOCKED_NOT_CONFIRMED);
      forward(errorPage, httpRequest, httpResponse);
      return true;
    }

    if (voUser.getStatus() != null
        && voUser.getStatus().getLockLevel() > UserAccountStatus.LOCK_LEVEL_LOGIN) {
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_USER_LOCKED);
      sendRedirect(httpRequest, httpResponse, errorPage);
      return true;
    }

    return false;
  }

  boolean handleLoggedInUser(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      ServiceAccess serviceAccess,
      AuthorizationRequestData rdo)
      throws ServletException, IOException {

    VOUserDetails userDetails = rdo.getUserDetails();
    if (userDetails != null) {
      httpRequest.getSession().setAttribute(PORTAL_HAS_BEEN_REQUESTED, !rdo.isMarketplace());

      // if the user wants to use another organization he must login
      // again (the service sessions are destroyed as well)

      // don't let a user with status PASSWORD_MUST_BE_CHANGED see any
      // site but the one to change the pwd
      if (!authSettings.isServiceProvider()) {
        if (userDetails.getStatus() == UserAccountStatus.PASSWORD_MUST_BE_CHANGED
            && !rdo.isRequestedToChangePwd()) {
          forwardToPwdPage(userDetails.getUserId(), httpRequest, httpResponse);
          return true;
        }
      }

      // TODO stavreva: check this again
      if (authSettings.isServiceProvider() || !rdo.isRequestedToChangePwd()) {
        long t = System.currentTimeMillis();
        if (ADMStringUtils.isBlank(httpRequest.getServletPath())
            || httpRequest.getServletPath().startsWith(MenuBean.LINK_DEFAULT)) {
          String defaultUrl = getDefaultUrl(serviceAccess, rdo, httpRequest);
          forward(defaultUrl, httpRequest, httpResponse);
        }

        if (loginPage.equalsIgnoreCase(httpRequest.getServletPath())) {
          sendRedirect(httpRequest, httpResponse, MenuBean.LINK_DEFAULT);
        }

        if (isPageForbiddenToAccess(httpRequest, rdo, serviceAccess)) {
          forward(insufficientAuthoritiesUrl, httpRequest, httpResponse);
        }
        chain.doFilter(httpRequest, httpResponse);
        if (logger.isDebugLoggingEnabled()) {
          logger.logDebug(
              "URL='"
                  + rdo.getRelativePath()
                  + "' processed in "
                  + (System.currentTimeMillis() - t)
                  + "ms");
        }
        return true;
      }
    }

    return false;
  }

  VOUser readTechnicalUserFromDb(IdentityService service, AuthorizationRequestData ard)
      throws ObjectNotFoundException, OperationNotPermittedException, OrganizationRemovedException {
    VOUser voUser = new VOUser();
    voUser.setUserId(ard.getUserId());
    voUser.setTenantId(ard.getTenantID());
    voUser = service.getUser(voUser);
    return voUser;
  }

  protected boolean loginUser(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      VOUser voUser,
      AuthorizationRequestData rdo,
      IdentityService identityService)
      throws ServletException, IOException {

    HttpSession session = httpRequest.getSession();
    boolean onlyServiceLogin = BesServletRequestReader.onlyServiceLogin(session);
    String forwardUrl = (String) session.getAttribute(Constants.SESS_ATTR_FORWARD_URL);
    SessionBean sessionBean = (SessionBean) session.getAttribute(Constants.SESS_ATTR_SESSION_BEAN);

    ServiceAccess serviceAccess = ServiceAccess.getServiceAcccessFor(session);

    if (onlyServiceLogin) {
      session.setAttribute(Constants.SESS_ATTR_ONLY_SERVICE_LOGIN, Boolean.TRUE);
    }

    if (!ADMStringUtils.isBlank(forwardUrl)) {
      session.setAttribute(Constants.SESS_ATTR_FORWARD_URL, forwardUrl);
    }

    if (sessionBean != null) {
      session.setAttribute(Constants.SESS_ATTR_SESSION_BEAN, sessionBean);
    }

    if (!ADMStringUtils.isBlank(rdo.getMarketplaceId())) {
      session.setAttribute(Constants.REQ_PARAM_MARKETPLACE_ID, rdo.getMarketplaceId());
    }

    // authenticate the user
    // IMPORTANT: Changes to this method must also be applied to
    // UserBean.login()
    try {
      serviceAccess.login(voUser, rdo.getPassword(), httpRequest, httpResponse);
    } catch (CommunicationException e) {
      handleCommunicationException(chain, httpRequest, httpResponse, rdo);
      return false;
    } catch (LoginException e) {
      logger.logInfo(
          Log4jLogger.ACCESS_LOG,
          LogMessageIdentifier.INFO_USER_LOGIN_INVALID,
          httpRequest.getRemoteHost(),
          Integer.toString(httpRequest.getRemotePort()),
          StringUtils.isNotBlank(voUser.getUserId()) ? voUser.getUserId() : "",
          IPResolver.resolveIpAddress(httpRequest),
          voUser.getTenantId());
      try {
        voUser = identityService.getUser(voUser);
      } catch (ObjectNotFoundException e1) {
        handleUserNotRegistered(chain, httpRequest, httpResponse, rdo);
        return false;
      } catch (SaaSApplicationException e1) {
        setErrorAttributesAndForward(errorPage, httpRequest, httpResponse, e1);
        return false;
      }

      if (voUser.getStatus() != null
          && voUser.getStatus().getLockLevel() > UserAccountStatus.LOCK_LEVEL_LOGIN) {
        httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_USER_LOCKED);
        forward(errorPage, httpRequest, httpResponse);
        return false;
      }

      handleLoginException(chain, httpRequest, httpResponse, rdo);
      return false;
    }

    if (!rdo.isMarketplace()
        && !rdo.isAccessToServiceUrl() // BE09588 Login is OK if a
        // service is accessed, whose
        // subscription has no
        // marketplace
        && identityService.getCurrentUserDetails().getOrganizationRoles().size() == 1
        && identityService
            .getCurrentUserDetails()
            .getOrganizationRoles()
            .contains(OrganizationRoleType.CUSTOMER)) {
      if (ADMStringUtils.isBlank(rdo.getMarketplaceId())) {
        if (redirectToMpUrl(httpRequest, httpResponse)) {
          setupUserDetail(httpRequest, rdo, identityService, session);
          return false;
        } else {
          httpRequest.setAttribute(
              Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_INVALID_MARKETPLACE_URL);
          forward(BaseBean.MARKETPLACE_ERROR_PAGE, httpRequest, httpResponse);
        }
      } else {
        setupUserDetail(httpRequest, rdo, identityService, session);
        forward(BaseBean.MARKETPLACE_START_SITE, httpRequest, httpResponse);
      }
      return false;
    }

    // get the service again because the credentials have been
    // changed (important for WS usage)
    identityService = serviceAccess.getService(IdentityService.class);
    try {
      identityService.refreshLdapUser();
    } catch (ValidationException e) {
      logger.logDebug(
          "Refresh of LDAP user failed, most likely due to missing/wrong LDAP settings");
    }

    logger.logInfo(
        Log4jLogger.ACCESS_LOG,
        LogMessageIdentifier.INFO_USER_LOGIN_SUCCESS,
        StringUtils.isNotBlank(voUser.getUserId()) ? voUser.getUserId() : "",
        IPResolver.resolveIpAddress(httpRequest),
        voUser.getTenantId());
    return true;
  }

  /**
   * @param httpRequest
   * @param rdo
   * @param identityService
   * @param session
   */
  private void setupUserDetail(
      HttpServletRequest httpRequest,
      AuthorizationRequestData rdo,
      IdentityService identityService,
      HttpSession session) {
    rdo.setUserDetails(identityService.getCurrentUserDetails());
    HttpSession httpSession = httpRequest.getSession(false);
    if (httpSession != null) {
      session.setAttribute(Constants.SESS_ATTR_USER, rdo.getUserDetails());
    }
  }

  void redirectToPrimarilyRequestedUrl(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      ServiceAccess serviceAccess,
      AuthorizationRequestData rdo)
      throws IOException, ServletException {

    String forwardUrl =
        (String) httpRequest.getSession().getAttribute(Constants.SESS_ATTR_FORWARD_URL);

    if (BesServletRequestReader.onlyServiceLogin(httpRequest.getSession())) {
      if (forwardUrl == null) {
        forwardUrl = Constants.SERVICE_BASE_URI + "/" + rdo.getSubscriptionKey() + "/";
      }
      JSFUtils.sendRedirect(httpResponse, httpRequest.getContextPath() + forwardUrl);
      return;
    }

    if (ADMStringUtils.isBlank(forwardUrl) || forwardUrl.startsWith(MenuBean.LINK_DEFAULT)) {
      forwardUrl = getDefaultUrl(serviceAccess, rdo, httpRequest);
    }

    if ((ADMStringUtils.isBlank(forwardUrl) || rdo.getRelativePath().startsWith(forwardUrl))
        && !rdo.isMarketplaceLoginPage()) {
      chain.doFilter(httpRequest, httpResponse);
    } else {
      JSFUtils.sendRedirect(httpResponse, httpRequest.getContextPath() + forwardUrl);
    }
  }

  /**
   * Invokes the validators and bean actions specified in the xhtml file to change the user's
   * password.
   *
   * @throws ServletException
   * @throws IOException
   * @throws DatatypeConfigurationException
   * @throws SAML2AuthnRequestException
   */
  protected boolean handleChangeUserPasswordRequest(
      FilterChain chain,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse,
      AuthorizationRequestData rdo,
      IdentityService identityService)
      throws IOException, ServletException {
    if (rdo.isRequestedToChangePwd()) {

      if (!PasswordValidator.validPasswordLength(rdo.getNewPassword())
          || !PasswordValidator.validPasswordLength(rdo.getNewPassword2())
          || !PasswordValidator.passwordsAreEqual(rdo.getNewPassword(), rdo.getNewPassword2())) {
        // Let JSF run the validators and return the response!
        chain.doFilter(httpRequest, httpResponse);
        return false;
      }

      // Run the validators and bean methods. Prevent JSF
      // from writing content to the response, otherwise the following
      // redirect's wouldn't work.
      HttpServletResponse resp =
          new HttpServletResponseWrapper(httpResponse) {
            @Override
            public void flushBuffer() throws IOException {}

            @Override
            public PrintWriter getWriter() throws IOException {
              return new PrintWriter(getOutputStream());
            }

            @Override
            public ServletOutputStream getOutputStream() throws IOException {
              return new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {}
              };
            }
          };
      chain.doFilter(httpRequest, resp);
      httpResponse.reset();
    }

    VOUser voUser = new VOUser();
    voUser.setUserId(rdo.getUserId());
    try {
      voUser = identityService.getUser(voUser);
    } catch (ObjectNotFoundException e) {
      handleUserNotRegistered(chain, httpRequest, httpResponse, rdo);
      return false;
    } catch (SaaSApplicationException e) {
      setErrorAttributesAndForward(errorPage, httpRequest, httpResponse, e);
      return false;
    }

    if (httpRequest.getAttribute(Constants.REQ_ATTR_ERROR_KEY) != null) {
      // Error occurred - check if user is locked now
      if (voUser.getStatus() != null
          && voUser.getStatus().getLockLevel() > UserAccountStatus.LOCK_LEVEL_LOGIN) {
        httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, BaseBean.ERROR_USER_LOCKED);
        sendRedirect(httpRequest, httpResponse, errorPage);
      } else {
        // Run it again to get error result on current response
        chain.doFilter(httpRequest, httpResponse);
      }

      return false;
    }

    if (voUser.getStatus() != UserAccountStatus.ACTIVE) {
      // the password change request failed
      // set the REQ_ATTR_ERROR_KEY to avoid an infinite loop
      httpRequest
          .getSession()
          .setAttribute(Constants.SESS_ATTR_USER, identityService.getCurrentUserDetails());
      httpRequest.setAttribute(Constants.REQ_ATTR_ERROR_KEY, "");
      if (rdo.isMarketplace()) {
        forward(BaseBean.MARKETPLACE_LOGIN, httpRequest, httpResponse);
      } else {
        forward(pwdPage, httpRequest, httpResponse);
      }
      return false;
    }

    rdo.setPassword(httpRequest.getParameter(BesServletRequestReader.REQ_PARAM_PASSWORD_NEW));
    rdo.getUserDetails().setStatus(UserAccountStatus.ACTIVE);
    return true;
  }

  /**
   * Forward the request to the change password page. For the marketplace portal the change password
   * is handled by the actual login page.
   *
   * @param userId the current user identifier
   * @param request the current HTTP servlet request
   * @param response the current HTTP servlet response
   * @throws IOException
   * @throws ServletException
   */
  private void forwardToPwdPage(
      String userId, HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    String actualPwdPage = getActualLoginPage(request, pwdPage, null);
    forward(actualPwdPage, request, response);
    return;
  }

  /**
   * If the user wants to access a service URL we must check if he is logged into the service.
   *
   * @return the given HTTP request, a request wrapper which must be used to perform the service
   *     login or null if the caller should continue with the filter chain
   * @throws IOException
   * @throws ServletException
   * @throws DatatypeConfigurationException
   * @throws SAML2AuthnRequestException
   * @throws Exception
   */
  private HttpServletRequest processServiceUrl(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain chain,
      String subKey,
      String contextPath,
      AuthorizationRequestData rdo)
      throws ServletException, IOException {

    HttpSession session = request.getSession();
    ServiceAccess serviceAccess = ServiceAccess.getServiceAcccessFor(session);

    if ("/".equals(contextPath) && !BesServletRequestReader.onlyServiceLogin(session)) {
      // if the user accesses a subscription from the my subscription list
      // we check the subscription key map in the session (this causes
      // some overhead - EJB call - and should NOT be done for every
      // service request)

      // preserve mId
      String mId = (String) session.getAttribute(Constants.REQ_PARAM_MARKETPLACE_ID);

      SessionListener.cleanup(session);

      session = request.getSession();
      session.setAttribute(Constants.REQ_PARAM_MARKETPLACE_ID, mId);
    }

    Map<String, VOSubscription> map = getSubMapFromSession(session);
    VOSubscription sub = map.get(subKey);
    VOUserDetails userDetails = (VOUserDetails) session.getAttribute(Constants.SESS_ATTR_USER);
    if (BesServletRequestReader.onlyServiceLogin(session)) {
      session.removeAttribute(Constants.SESS_ATTR_ONLY_SERVICE_LOGIN);

      // at least remove the user details from the session
      session.removeAttribute(Constants.SESS_ATTR_USER);
      if (userDetails != null) {
        session.setAttribute(Constants.REQ_PARAM_LOCALE, userDetails.getLocale());
      }
    }

    if (userDetails != null
        && userDetails.getStatus() != UserAccountStatus.PASSWORD_MUST_BE_CHANGED) {
      // the user is already logged in

      if (sub == null) {
        // the user is not logged in the service, we must call the
        // SSO bridge

        sub = getSubscription(serviceAccess, subKey);

        if (sub == null) {
          UserNotAssignedException e =
              new UserNotAssignedException(subKey, userDetails.getUserId());
          logger.logError(
              Log4jLogger.SYSTEM_LOG | Log4jLogger.AUDIT_LOG,
              e,
              LogMessageIdentifier.ERROR_ACTIVE_SUBSCRIPTION_FOR_CURRENT_USER_FAILED,
              subKey);
          setErrorAttributesAndForward(
              getDefaultUrl(serviceAccess, rdo, request), request, response, e);
          return null;

        } else if (sub.getStatus() != SubscriptionStatus.ACTIVE
            && sub.getStatus() != SubscriptionStatus.PENDING_UPD) {
          SubscriptionStateException e =
              new SubscriptionStateException(
                  "Subscription '" + subKey + "' not active or pending update.",
                  Reason.ONLY_ACTIVE);
          logger.logError(
              Log4jLogger.SYSTEM_LOG | Log4jLogger.AUDIT_LOG,
              e,
              LogMessageIdentifier.ERROR_SUBSCRIPTION_NOT_ACTIVE,
              subKey);
          setErrorAttributesAndForward(
              getDefaultUrl(serviceAccess, rdo, request), request, response, e);
          return null;

        } else if (!sub.getServiceBaseURL()
            .toLowerCase()
            .startsWith(request.getScheme().toLowerCase() + "://")) {
          setErrorAttributesAndForward(errorPage, request, response, new ServiceSchemeException());
          return null;
        }

        String userToken = ADMStringUtils.getRandomString(40);

        // create a service session database record (which is used by
        // the service to resolve the user token)
        try {
          synchronized (map) {
            createServiceSession(serviceAccess, subKey, session.getId(), userToken);
            // the map must be filled after the service session was
            // created otherwise the session listener cleanup method
            // might clear the list
            map.put(subKey, sub);
          }
        } catch (ObjectNotFoundException e) {
          handleSubscriptionNotFound(chain, request, response, rdo);
          return null;
        } catch (ServiceParameterException e) {
          setErrorAttributesAndForward(Constants.SERVICE_USAGE_ERROR_URI, request, response, e);
          return null;
        } catch (SaaSApplicationException e) {
          setErrorAttributesAndForward(errorPage, request, response, e);
          return null;
        }

        if (sub.getServiceAccessType() == ServiceAccessType.LOGIN) {
          // perform a redirect to the SSO bridge with the user token
          String url = removeEndingSlash(sub.getServiceBaseURL());
          if (sub.getServiceLoginPath() != null) {
            url += sub.getServiceLoginPath();
          }
          if (url.contains("?")) {
            url += "&";
          } else {
            url += "?";
          }
          SsoParameters ssoParameters = new SsoParameters();
          ssoParameters.setContextPath(contextPath);
          ssoParameters.setInstanceId(sub.getServiceInstanceId());
          ssoParameters.setLanguage(userDetails.getLocale());
          ssoParameters.setSubscriptionKey(subKey);
          ssoParameters.setBssId(request.getSession().getId());
          ssoParameters.setUsertoken(userToken);
          url += ssoParameters.getQueryString();
          JSFUtils.sendRedirect(response, url);
          return null;
        }

      } else {
        if (sub.getServiceAccessType() == ServiceAccessType.LOGIN) {
          // send a redirect to the service base URL, the service
          // session should be still active
          JSFUtils.sendRedirect(response, sub.getServiceBaseURL());
          return null;
        }

        // nothing to do (the user is logged in the platform and the
        // service) the rewriting is done by the subsequent filters in
        // the filter chain which is activated by the caller
      }
    } else {
      // the user is not logged in

      if (sub == null) {
        // the user is neither logged in platform nor in the
        // service,
        //
        // The later processing will forward to the service login
        // page processing. After the login there will be a redirect to
        // the primarily requested URL which will perform the service
        // login
        session.setAttribute(Constants.SESS_ATTR_ONLY_SERVICE_LOGIN, Boolean.TRUE);

      } else {
        // the user is logged in the service

        if (sub.getServiceAccessType() == ServiceAccessType.LOGIN) {
          // send a redirect to the service base URL, the service
          // session should be still active
          JSFUtils.sendRedirect(response, sub.getServiceBaseURL());
        } else {
          // don't perform any other checks continue with the
          // filter chain which will perform the rewriting
          chain.doFilter(request, response);
        }
        return null;
      }
    }
    return request;
  }

  /**
   * Get the map from the session which maps a subscription key to the subscription value object.
   *
   * @param session the current session.
   * @return the requested map.
   */
  @SuppressWarnings("unchecked")
  private Map<String, VOSubscription> getSubMapFromSession(HttpSession session) {
    Map<String, VOSubscription> map =
        (Map<String, VOSubscription>) session.getAttribute(Constants.SESS_ATTR_ACTIVE_SUB_MAP);
    if (map != null) {
      return map;
    }
    map = Collections.synchronizedMap(new HashMap<String, VOSubscription>());
    session.setAttribute(Constants.SESS_ATTR_ACTIVE_SUB_MAP, map);
    return map;
  }

  /**
   * Cache the marketplaces. If BES acts as reverse proxy, it is important that no SQL requests are
   * performed. Otherwise for each HTTP request (html, css, images, ajax) that is performed for the
   * target system several SQL requests would be performed on BES side. BES would be dead long time
   * before the target system gets busy.
   */
  @SuppressWarnings("unchecked")
  private Map<String, VOMarketplace> getMarketplaceMapFromSession(HttpSession session) {
    Map<String, VOMarketplace> map =
        (Map<String, VOMarketplace>) session.getAttribute(Constants.SESS_ATTR_MARKETPLACE_MAP);
    if (map != null) {
      return map;
    }
    map = new ConcurrentHashMap<>();
    session.setAttribute(Constants.SESS_ATTR_MARKETPLACE_MAP, map);
    return map;
  }

  /**
   * Helper method which performs an EJB call and gets the subscription value object for the given
   * subscription key.
   *
   * @param key the (hex)-key of the subscription.
   * @return the subscription value object.
   */
  private VOSubscription getSubscription(ServiceAccess serviceAccess, String key) {
    SubscriptionService subscriptionService = serviceAccess.getService(SubscriptionService.class);
    List<VOUserSubscription> list = subscriptionService.getSubscriptionsForCurrentUser();
    if (list != null) {
      for (VOSubscription vo : list) {
        if (key.equals(Long.toHexString(vo.getKey()))) {
          return vo;
        }
      }
    }
    return null;
  }

  private void createServiceSession(
      ServiceAccess serviceAccess, String subKey, String sessionId, String userToken)
      throws ObjectNotFoundException, ServiceParameterException, OperationNotPermittedException,
          ValidationException {
    SessionService service = serviceAccess.getService(SessionService.class);
    long subscriptionKey = ADMStringUtils.parseUnsignedLong(subKey);
    service.createServiceSession(subscriptionKey, sessionId, userToken);
  }

  private String removeEndingSlash(String baseUrl) {
    if (baseUrl.endsWith("/")) {
      baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
    }
    return baseUrl;
  }

  private boolean isSamlForward(HttpServletRequest httpRequest) {
    Boolean isSamlForward = (Boolean) httpRequest.getAttribute(Constants.REQ_ATTR_IS_SAML_FORWARD);
    return isSamlForward != null && isSamlForward.booleanValue();
  }
}
/** @author weiser */
public class UdaDefinitionAccess {

  private static final Log4jLogger logger = LoggerFactory.getLogger(UdaDefinitionAccess.class);

  DataService ds;
  SessionContext ctx;
  LocalizerServiceLocal localizer;

  public UdaDefinitionAccess(DataService ds, SessionContext sc) {
    this.ds = ds;
    this.ctx = sc;
  }

  public UdaDefinitionAccess(DataService ds, SessionContext sc, LocalizerServiceLocal localizer) {
    this.ds = ds;
    this.ctx = sc;
    this.localizer = localizer;
  }

  /**
   * Returns all {@link UdaDefinition}s owned by the passed {@link Organization}.
   *
   * @param owner the owner {@link Organization}
   * @return the list of {@link UdaDefinition}s
   */
  public List<UdaDefinition> getOwnUdaDefinitions(Organization owner) {

    List<UdaDefinition> list = owner.getUdaDefinitions();

    return list;
  }

  /**
   * Returns all {@link UdaDefinition}s that are readable for the passed {@link
   * OrganizationRoleType} depending on their {@link UdaConfigurationType}
   *
   * @param supplier the supplier to get the {@link UdaDefinition}s from
   * @param role the {@link OrganizationRoleType} the definition must be readable for
   * @return
   */
  public List<UdaDefinition> getReadableUdaDefinitionsFromSupplier(
      Organization supplier, OrganizationRoleType role) {

    List<UdaDefinition> udaDefinitions = supplier.getReadableUdaDefinitions(role);

    return udaDefinitions;
  }

  /**
   * Tries to save the passed list of {@link VOUdaDefinition}s. Checks if the passed values are
   * valid and permitted to be accessed.
   *
   * @param defs the {@link VOUdaDefinition}s to save
   * @param caller the calling (owning) {@link Organization}
   * @throws ValidationException in case of an invalid {@link VOUdaDefinition}
   * @throws OrganizationAuthoritiesException in case the calling {@link Organization} has
   *     insufficient roles to create {@link UdaDefinition}s of the set {@link UdaTargetType}.
   * @throws NonUniqueBusinessKeyException in case a {@link UdaDefinition} with the passed id and
   *     target type already exists for the owning {@link Organization}
   * @throws OperationNotPermittedException in case it was tries to update a {@link UdaDefinition}
   *     owned by another {@link Organization}.
   * @throws ConcurrentModificationException in case the {@link UdaDefinition} to update was
   *     concurrently changed
   * @throws ObjectNotFoundException in case on of the {@link UdaDefinition}s to update was not
   *     found
   */
  public void saveUdaDefinitions(List<VOUdaDefinition> defs, Organization caller)
      throws ValidationException, OrganizationAuthoritiesException, NonUniqueBusinessKeyException,
          OperationNotPermittedException, ConcurrentModificationException, ObjectNotFoundException {

    for (VOUdaDefinition voDef : defs) {
      // convert and validate
      UdaDefinition def;
      try {
        def = UdaAssembler.toUdaDefinition(voDef);
        def.setOrganization(caller);
      } catch (ValidationException e) {
        logger.logWarn(
            Log4jLogger.SYSTEM_LOG,
            e,
            LogMessageIdentifier.WARN_INVALID_UDA_DEFINITION,
            voDef.getUdaId());
        ctx.setRollbackOnly();
        throw e;
      }
      // check if target type is allowed for organization
      UdaTargetType type = def.getTargetType();
      if (!type.canSaveDefinition(caller.getGrantedRoleTypes())) {
        String roles = rolesToString(type.getRoles());
        OrganizationAuthoritiesException e =
            new OrganizationAuthoritiesException(
                "Insufficient authorization. Required role(s) '" + roles + "'.",
                new Object[] {roles});
        logger.logWarn(
            Log4jLogger.SYSTEM_LOG | Log4jLogger.AUDIT_LOG,
            e,
            LogMessageIdentifier.WARN_ORGANIZATION_ROLE_REQUIRED,
            Long.toString(caller.getKey()),
            roles);
        ctx.setRollbackOnly();
        throw e;
      }
      if (voDef.getKey() > 0) {
        updateDefinition(voDef, caller);
      } else {
        createDefinition(def);
      }
      UdaDefinition storedUda = (UdaDefinition) ds.find(def);
      if (storedUda == null) {
        return;
      }
      storeLocalizedAttributeName(storedUda.getKey(), voDef.getName(), voDef.getLanguage());
    }
  }

  private void storeLocalizedAttributeName(long key, String attributeName, String language) {
    if (attributeName == null || language == null) {
      return;
    }
    localizer.storeLocalizedResource(
        language, key, LocalizedObjectTypes.CUSTOM_ATTRIBUTE_NAME, attributeName);
  }

  /**
   * Persists that passed {@link UdaDefinition} and checks the business key uniqueness.
   *
   * @param def the {@link UdaDefinition} to persist
   * @throws NonUniqueBusinessKeyException in case a {@link UdaDefinition} with the same id and
   *     target type exist for the owning {@link Organization}
   */
  void createDefinition(UdaDefinition def) throws NonUniqueBusinessKeyException {

    try {
      ds.persist(def);
    } catch (NonUniqueBusinessKeyException e) {
      logger.logWarn(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.WARN_NON_UNIQUE_BUSINESS_KEY_UDA_DEFINITION);
      ctx.setRollbackOnly();
      throw e;
    }
  }

  /**
   * Updates an existing {@link UdaDefinition} - if it was not found, nothing will be done. Checks
   * if the caller is the owner, performs business key uniqueness check if the id has changed and
   * validates the passed {@link VOUdaDefinition}.
   *
   * @param voDef the updated {@link VOUdaDefinition}
   * @param owner the owning {@link Organization}
   * @throws OperationNotPermittedException in case the calling {@link Organization} is not the
   *     owner
   * @throws ValidationException in case the passed {@link VOUdaDefinition} is invalid
   * @throws ConcurrentModificationException in case the {@link UdaDefinition} to update has been
   *     changed concurrently
   * @throws NonUniqueBusinessKeyException in case the change leads to a non-unique business key
   * @throws ObjectNotFoundException in case the {@link UdaDefinition} to update was not found
   */
  void updateDefinition(VOUdaDefinition voDef, Organization owner)
      throws OperationNotPermittedException, ValidationException, ConcurrentModificationException,
          NonUniqueBusinessKeyException, ObjectNotFoundException {

    UdaDefinition existing = ds.getReference(UdaDefinition.class, voDef.getKey());
    PermissionCheck.owns(existing, owner, logger, ctx);
    // target type and encryption flag must not be changed as it will cause
    // inconsistencies for all depending UDAs

    voDef.setTargetType(existing.getTargetType().name());
    voDef.setEncrypted(existing.isEncrypted());

    // verify business key uniqueness
    UdaDefinition tempForUniquenessCheck = null;
    tempForUniquenessCheck = UdaAssembler.toUdaDefinition(voDef);

    tempForUniquenessCheck.setOrganization(owner);
    tempForUniquenessCheck.setKey(existing.getKey());
    try {
      ds.validateBusinessKeyUniqueness(tempForUniquenessCheck);
      UdaAssembler.updateUdaDefinition(existing, voDef);
    } catch (NonUniqueBusinessKeyException e) {
      logger.logWarn(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.WARN_NON_UNIQUE_BUSINESS_KEY_UDA_DEFINITION);
      ctx.setRollbackOnly();
      throw e;
    }
  }

  /**
   * Deletes the passed list of {@link VOUdaDefinition}s - ignores the ones that are not found. For
   * the found ones, access permission and concurrent modification checks will be performed.
   *
   * @param defs the {@link VOUdaDefinition} to delete
   * @param caller the calling {@link Organization}
   * @throws OperationNotPermittedException
   * @throws ConcurrentModificationException
   */
  public void deleteUdaDefinitions(List<VOUdaDefinition> defs, Organization caller)
      throws OperationNotPermittedException, ConcurrentModificationException {

    for (VOUdaDefinition voDef : defs) {
      UdaDefinition existing = ds.find(UdaDefinition.class, voDef.getKey());
      if (existing == null) {
        // already deleted
        continue;
      }
      PermissionCheck.owns(existing, caller, logger, ctx);
      UdaAssembler.verifyVersionAndKey(existing, voDef);
      // cascade rule will cause deletion of udas as well
      ds.remove(existing);
    }
  }

  /**
   * Converts the role set to a comma separated string
   *
   * @param types the role set to convert
   * @return the resulting string
   */
  String rolesToString(Set<OrganizationRoleType> types) {
    String tmp = types.toString();
    return tmp.substring(1, tmp.length() - 1);
  }
}
예제 #8
0
public class ResourceLoader {

  private static final Log4jLogger LOGGER = LoggerFactory.getLogger(ResourceLoader.class);

  /**
   * Returns an input stream for reading the resource with the given name from the classloader of
   * the given class.
   *
   * @param clazz the class to use its classloader to find the resource
   * @param resource the name of the resource
   * @return the input stream for reading the resource
   * @throws SaaSSystemException if no classloader is found for the given class
   */
  public static InputStream getResourceAsStream(final Class<?> clazz, final String resource) {

    ClassLoader classLoader = getClassLoader(clazz);
    InputStream inputStream = getResourceAsStream(classLoader, resource);
    return inputStream;
  }

  private static ClassLoader getClassLoader(final Class<?> clazz) {
    ClassLoader classLoader = clazz.getClassLoader();
    assertClassLoader(clazz, classLoader);
    return classLoader;
  }

  private static void assertClassLoader(final Class<?> clazz, ClassLoader classLoader) {
    if (classLoader == null) {
      SaaSSystemException e = new SaaSSystemException("No classloader found for class " + clazz);
      LOGGER.logError(
          Log4jLogger.SYSTEM_LOG,
          e,
          LogMessageIdentifier.ERROR_CLASS_LOADER_NOT_FOUND,
          clazz.getName());
      throw e;
    }
  }

  private static InputStream getResourceAsStream(
      final ClassLoader classLoader, final String resource) {

    InputStream inputStream = classLoader.getResourceAsStream(resource);
    assertInputStream(resource, inputStream);
    return inputStream;
  }

  private static void assertInputStream(final String resource, final InputStream inputStream) {
    if (inputStream == null) {
      SaaSSystemException e = new SaaSSystemException("Unable to find resource " + resource);
      LOGGER.logError(
          Log4jLogger.SYSTEM_LOG, e, LogMessageIdentifier.ERROR_FIND_RESOURCE_FAILED, resource);
      throw e;
    }
  }

  public static byte[] load(final Class<?> clazz, final String resource) {
    return load(getResourceAsStream(clazz, resource));
  }

  public static byte[] load(InputStream inputStream) {
    try {
      byte[] bytes = new byte[inputStream.available()];
      int len = inputStream.read(bytes);
      if (len > -1) {
        return bytes;
      }
      return new byte[0];
    } catch (IOException e) {
      SaaSSystemException se =
          new SaaSSystemException("Unable to read input stream: " + e.getMessage(), e);
      LOGGER.logError(
          Log4jLogger.SYSTEM_LOG, se, LogMessageIdentifier.ERROR_FIND_INPUT_STREAM_FAILED);
      throw se;
    } finally {
      try {
        inputStream.close();
      } catch (IOException e) {
        SaaSSystemException se =
            new SaaSSystemException("Unable to close input stream: " + e.getMessage(), e);
        LOGGER.logError(
            Log4jLogger.SYSTEM_LOG, se, LogMessageIdentifier.ERROR_CLOSE_INPUT_STREAM_FAILED);
        throw se;
      }
    }
  }

  /**
   * @param clazz The class to be used to load the resource's URL object
   * @param resourceName The name of the resource
   * @return an URL object of the provided resource string, or null if the resource could not be
   *     found
   */
  public static URL getResource(final Class<?> clazz, final String resourceName) {
    ClassLoader classLoader = getClassLoader(clazz);
    URL resourceUrl = classLoader.getResource(resourceName);
    return resourceUrl;
  }
}
/** Assembler to handle VOLandingpage <=> Landingpage conversions. */
public class LandingpageAssembler extends BaseAssembler {

  private static final Log4jLogger logger = LoggerFactory.getLogger(LandingpageAssembler.class);

  /**
   * Creates a value object representing the current settings for the landingpage.
   *
   * @param domObj The technical landingpage to be represented as value object.
   * @return A value object representation of the given landingpage.
   */
  public static VOPublicLandingpage toVOLandingpage(PublicLandingpage domObj) {
    if (domObj == null) {
      return null;
    }

    VOPublicLandingpage voObj = new VOPublicLandingpage();
    updateValueObject(voObj, domObj);
    voObj.setMarketplaceId(domObj.getMarketplace().getMarketplaceId());
    voObj.setNumberServices(domObj.getNumberServices());
    voObj.setFillinCriterion(domObj.getFillinCriterion());

    // LandingpageProductAssembler is NOT called because of cyclic depency
    // between projects 'oscm-marketplaceservice-intsvc' and
    // 'oscm-serviceprovisioning-intsvc'. Please call the
    // LandingpageProductAssembler in LandingpageServiceBean!

    return voObj;
  }

  /**
   * Updates the fields in the Landingpage object to reflect the changes performed in the value
   * object.
   *
   * @param domObj The domain object to be updated.
   * @param voObj The value object.
   * @return The updated domain object.
   * @throws ValidationException Thrown if the validation of the value objects failed.
   * @throws ConcurrentModificationException Thrown if the object versions do not match.
   * @throws ValidationException Thrown if the attributes to copy at the value object do not meet
   *     all constraints.
   */
  public static PublicLandingpage updateLandingpage(
      PublicLandingpage domObj, VOPublicLandingpage voObj)
      throws ValidationException, ConcurrentModificationException {
    if (domObj == null || voObj == null) {
      IllegalArgumentException e = new IllegalArgumentException("Parameters must not be null");
      logger.logError(Log4jLogger.SYSTEM_LOG, e, LogMessageIdentifier.ERROR_PARAMETER_NULL);
      throw e;
    }
    if (domObj.getKey() != 0) {
      verifyVersionAndKey(domObj, voObj);
    }
    validate(voObj);
    copyAttributes(domObj, voObj);
    return domObj;
  }

  /**
   * Creates a new landing page domain object based on the given value object.
   *
   * @param voObj The value object.
   * @return The new domain object
   * @throws ValidationException
   */
  public static PublicLandingpage toLandingpage(VOPublicLandingpage voObj)
      throws ValidationException {
    final PublicLandingpage domObj = new PublicLandingpage();
    validate(voObj);
    copyAttributes(domObj, voObj);
    return domObj;
  }

  /**
   * Validates the given Landingpage object that reflects the settings in the given value object.
   *
   * @param voObj The value object containing the values to be validated.
   * @throws ValidationException Thrown if the attributes at the value object do not meet all
   *     constraints.
   */
  public static void validate(VOPublicLandingpage voObj) throws ValidationException {
    BLValidator.isNotNull("marketplaceId", voObj.getMarketplaceId());
    BLValidator.isNonNegativeNumber("numberServices", voObj.getNumberServices());
    BLValidator.isNotNull("fillinCriterion", voObj.getFillinCriterion());
    BLValidator.isNotNull("landingpageServices", voObj.getLandingpageServices());
  }

  /**
   * Copies all attributes in Landingpage object according to the values specified in the value
   * object.
   *
   * @param domObj The domain object from which the attributed of the value object should be copied
   *     in.
   * @param voObj The value object containing the values to be copied.
   */
  private static void copyAttributes(PublicLandingpage domObj, VOPublicLandingpage voObj) {
    domObj.setNumberServices(voObj.getNumberServices());
    domObj.setFillinCriterion(voObj.getFillinCriterion());
  }
}