// ----- private methods -----
  private void updateAccessInformation(
      final SecurityContext securityContext, final PropertyContainer propertyContainer)
      throws FrameworkException {

    try {

      final Principal user = securityContext.getUser(false);
      String modifiedById = null;

      if (user != null) {

        if (user instanceof SuperUser) {

          // "virtual" UUID of superuser
          modifiedById = Principal.SUPERUSER_ID;

        } else {

          modifiedById = user.getUuid();
        }

        propertyContainer.setProperty(AbstractNode.lastModifiedBy.dbName(), modifiedById);
      }

      if (!securityContext.dontModifyAccessTime()) {

        propertyContainer.setProperty(
            AbstractNode.lastModifiedDate.dbName(), System.currentTimeMillis());
      }

    } catch (Throwable t) {

      // fail without throwing an exception here
      logger.warn("", t);
    }
  }
예제 #2
0
  @Override
  public void render(SecurityContext securityContext, RenderContext renderContext, int depth)
      throws FrameworkException {

    if (isDeleted()
        || isHidden()
        || !displayForLocale(renderContext)
        || !displayForConditions(securityContext, renderContext)) {
      return;
    }

    String id = getUuid();
    EditMode edit = renderContext.getEditMode(securityContext.getUser(false));
    boolean inBody = renderContext.inBody();
    StringBuilder buffer = renderContext.getBuffer();

    String _contentType = getProperty(contentType);

    // fetch content with variable replacement
    String _content =
        getPropertyWithVariableReplacement(securityContext, renderContext, Content.content);

    if (!(EditMode.RAW.equals(edit))
        && (_contentType == null || ("text/plain".equals(_contentType)))) {

      _content = escapeForHtml(_content);
    }

    if (EditMode.CONTENT.equals(edit)
        && inBody
        && securityContext.isAllowed(this, Permission.write)) {

      if ("text/javascript".equals(_contentType)) {

        // Javascript will only be given some local vars
        // TODO: Is this neccessary?
        buffer
            .append("// data-structr-type='")
            .append(getType())
            .append("'\n// data-structr-id='")
            .append(id)
            .append("'\n");

      } else if ("text/css".equals(_contentType)) {

        // CSS will only be given some local vars
        // TODO: Is this neccessary?
        buffer
            .append("/* data-structr-type='")
            .append(getType())
            .append("'*/\n/* data-structr-id='")
            .append(id)
            .append("'*/\n");

      } else {

        //				// In edit mode, add an artificial 'span' tag around content nodes within body to make
        // them editable
        //				buffer.append("<span data-structr-raw-value=\"").append(getProperty(Content.content))
        //					//.append("\"
        // data-structr-content-type=\"").append(StringUtils.defaultString(getProperty(Content.contentType), ""))
        //					.append("\" data-structr-type=\"").append(getType())
        //					.append("\" data-structr-id=\"").append(id).append("\">");

        //				int l = buffer.length();
        //				buffer.replace(l-1, l, " data-structr-raw-value=\""
        //					.concat(getProperty(Content.content))
        //					.concat("\" data-structr-type=\"").concat(getType())
        //					.concat("\" data-structr-id=\"").concat(id).concat("\">"));

        buffer.append(
            "<!--data-structr-id=\""
                .concat(id)
                .concat("\" data-structr-raw-value=\"")
                .concat(getProperty(Content.content).replaceAll("\n", "\\\\n"))
                .concat("\"-->"));
        // .concat("\"
        // data-structr-raw-value=\"").concat(getProperty(Content.content)).concat("\"-->"));

      }
    }

    // No contentType-specific rendering in DATA edit mode
    // if (!edit.equals(EditMode.DATA)) {

    // examine content type and apply converter

    if (_contentType != null) {

      Adapter<String, String> converter = contentConverters.get(_contentType);

      if (converter != null) {

        try {

          // apply adapter
          _content = converter.adapt(_content);
        } catch (FrameworkException fex) {

          logger.log(Level.WARNING, "Unable to convert content: {0}", fex.getMessage());
        }
      }
    }

    // replace newlines with <br /> for rendering
    if (((_contentType == null) || _contentType.equals("text/plain"))
        && (_content != null)
        && !_content.isEmpty()) {

      _content = _content.replaceAll("[\\n]{1}", "<br>");
    }
    // }

    if (_content != null) {

      // buffer.append(indent(depth, true)).append(_content);

      // insert whitespace to make element clickable
      if (EditMode.CONTENT.equals(edit) && _content.length() == 0) {
        _content = "--- empty ---";
      }

      buffer.append(_content);
    }

    if (EditMode.CONTENT.equals(edit)
        && inBody
        && !("text/javascript".equals(getProperty(contentType)))
        && !("text/css".equals(getProperty(contentType)))) {

      //			buffer.append("</span>");
      buffer.append("<!---->");
    }
  }
예제 #3
0
  public Principal getCurrentUser() {

    return (securityContext == null ? null : securityContext.getUser(false));
  }
예제 #4
0
  @Override
  protected void doGet(final HttpServletRequest request, final HttpServletResponse response) {

    final Authenticator auth = config.getAuthenticator();
    final SecurityContext securityContext;
    final App app;

    try {
      String path = request.getPathInfo();

      // check for registration (has its own tx because of write access
      if (checkRegistration(auth, request, response, path)) {

        return;
      }

      // isolate request authentication in a transaction
      try (final Tx tx = StructrApp.getInstance().tx()) {
        securityContext = auth.initializeAndExamineRequest(request, response);
        tx.success();
      }

      app = StructrApp.getInstance(securityContext);

      try (final Tx tx = app.tx()) {

        // Ensure access mode is frontend
        securityContext.setAccessMode(AccessMode.Frontend);

        request.setCharacterEncoding("UTF-8");

        // Important: Set character encoding before calling response.getWriter() !!, see Servlet
        // Spec 5.4
        response.setCharacterEncoding("UTF-8");

        boolean dontCache = false;

        logger.log(Level.FINE, "Path info {0}", path);

        // don't continue on redirects
        if (response.getStatus() == 302) {
          return;
        }

        Principal user = securityContext.getUser(false);
        if (user != null) {

          // Don't cache if a user is logged in
          dontCache = true;
        }

        final RenderContext renderContext =
            RenderContext.getInstance(request, response, getEffectiveLocale(request));

        renderContext.setResourceProvider(config.getResourceProvider());

        EditMode edit = renderContext.getEditMode(user);

        DOMNode rootElement = null;
        AbstractNode dataNode = null;

        String[] uriParts = PathHelper.getParts(path);
        if ((uriParts == null) || (uriParts.length == 0)) {

          // find a visible page
          rootElement = findIndexPage(securityContext);

          logger.log(Level.FINE, "No path supplied, trying to find index page");

        } else {

          if (rootElement == null) {

            rootElement = findPage(securityContext, request, path);

          } else {
            dontCache = true;
          }
        }

        if (rootElement == null) { // No page found

          // Look for a file
          File file = findFile(securityContext, request, path);
          if (file != null) {

            streamFile(securityContext, file, request, response, edit);
            return;
          }

          // store remaining path parts in request
          Matcher matcher = threadLocalUUIDMatcher.get();
          boolean requestUriContainsUuids = false;

          for (int i = 0; i < uriParts.length; i++) {

            request.setAttribute(uriParts[i], i);
            matcher.reset(uriParts[i]);

            // set to "true" if part matches UUID pattern
            requestUriContainsUuids |= matcher.matches();
          }

          if (!requestUriContainsUuids) {

            // Try to find a data node by name
            dataNode = findFirstNodeByName(securityContext, request, path);

          } else {

            dataNode = findNodeByUuid(securityContext, PathHelper.getName(path));
          }

          if (dataNode != null) {

            // Last path part matches a data node
            // Remove last path part and try again searching for a page
            // clear possible entry points
            request.removeAttribute(POSSIBLE_ENTRY_POINTS);

            rootElement =
                findPage(
                    securityContext,
                    request,
                    StringUtils.substringBeforeLast(path, PathHelper.PATH_SEP));

            renderContext.setDetailsDataObject(dataNode);

            // Start rendering on data node
            if (rootElement == null && dataNode instanceof DOMNode) {

              rootElement = ((DOMNode) dataNode);
            }
          }
        }

        // Still nothing found, do error handling
        if (rootElement == null) {

          // Check if security context has set an 401 status
          if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {

            try {

              UiAuthenticator.writeUnauthorized(response);

            } catch (IllegalStateException ise) {
            }

          } else {

            rootElement = notFound(response, securityContext);
          }
        }

        if (rootElement == null) {
          return;
        }

        if (EditMode.WIDGET.equals(edit) || dontCache) {

          setNoCacheHeaders(response);
        }

        if (!securityContext.isVisible(rootElement)) {

          rootElement = notFound(response, securityContext);
          if (rootElement == null) {
            return;
          }
        }

        if (securityContext.isVisible(rootElement)) {

          if (!EditMode.WIDGET.equals(edit)
              && !dontCache
              && notModifiedSince(request, response, rootElement, dontCache)) {

            ServletOutputStream out = response.getOutputStream();
            out.flush();
            // response.flushBuffer();
            out.close();

          } else {

            // prepare response
            response.setCharacterEncoding("UTF-8");

            String contentType = rootElement.getProperty(Page.contentType);

            if (contentType != null && contentType.equals("text/html")) {

              contentType = contentType.concat(";charset=UTF-8");
              response.setContentType(contentType);

            } else {

              // Default
              response.setContentType("text/html;charset=UTF-8");
            }

            response.setHeader("Strict-Transport-Security", "max-age=60");
            response.setHeader("X-Content-Type-Options", "nosniff");
            response.setHeader("X-Frame-Options", "SAMEORIGIN");
            response.setHeader("X-XSS-Protection", "1; mode=block");

            // async or not?
            boolean isAsync =
                HttpService.parseBoolean(
                    Services.getBaseConfiguration().getProperty(HttpService.ASYNC), true);
            if (isAsync) {

              final AsyncContext async = request.startAsync();
              final ServletOutputStream out = async.getResponse().getOutputStream();
              final AtomicBoolean finished = new AtomicBoolean(false);
              final DOMNode rootNode = rootElement;

              threadPool.submit(
                  new Runnable() {

                    @Override
                    public void run() {

                      try (final Tx tx = app.tx()) {

                        // final long start = System.currentTimeMillis();

                        // render
                        rootNode.render(securityContext, renderContext, 0);
                        finished.set(true);

                        // final long end = System.currentTimeMillis();
                        // System.out.println("Done in " + (end-start) + " ms");

                        tx.success();

                      } catch (Throwable t) {
                        t.printStackTrace();
                        final String errorMsg = t.getMessage();
                        try {
                          // response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                          response.sendError(
                              HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorMsg);
                          finished.set(true);
                        } catch (IOException ex) {
                          ex.printStackTrace();
                        }
                      }
                    }
                  });

              // start output write listener
              out.setWriteListener(
                  new WriteListener() {

                    @Override
                    public void onWritePossible() throws IOException {

                      try {

                        final Queue<String> queue = renderContext.getBuffer().getQueue();
                        while (out.isReady()) {

                          String buffer = null;

                          synchronized (queue) {
                            buffer = queue.poll();
                          }

                          if (buffer != null) {

                            out.print(buffer);

                          } else {

                            if (finished.get()) {

                              async.complete();
                              response.setStatus(HttpServletResponse.SC_OK);

                              // prevent this block from being called again
                              break;
                            }

                            Thread.sleep(1);
                          }
                        }

                      } catch (Throwable t) {
                        t.printStackTrace();
                      }
                    }

                    @Override
                    public void onError(Throwable t) {
                      t.printStackTrace();
                    }
                  });

            } else {

              final StringRenderBuffer buffer = new StringRenderBuffer();
              renderContext.setBuffer(buffer);

              // render
              rootElement.render(securityContext, renderContext, 0);

              response.getOutputStream().write(buffer.getBuffer().toString().getBytes("utf-8"));
              response.getOutputStream().flush();
              response.getOutputStream().close();
            }
          }

        } else {

          notFound(response, securityContext);
        }

        tx.success();

      } catch (FrameworkException fex) {
        fex.printStackTrace();
        logger.log(Level.SEVERE, "Exception while processing request", fex);
      }

    } catch (IOException | FrameworkException t) {

      t.printStackTrace();
      logger.log(Level.SEVERE, "Exception while processing request", t);
      UiAuthenticator.writeInternalServerError(response);
    }
  }
예제 #5
0
  public Object evaluate(
      final GraphObject entity,
      final String key,
      final Object data,
      final String defaultValue,
      final int depth)
      throws FrameworkException {

    Object value = constants.get(key);
    if (value == null) {

      // special HttpServletRequest handling
      if (data instanceof HttpServletRequest) {
        value = ((HttpServletRequest) data).getParameter(key);
      }

      // special handling of maps..
      if (data instanceof Map) {
        value = ((Map) data).get(key);
      }

      if (data != null) {

        if (data instanceof GraphObject) {

          value = ((GraphObject) data).evaluate(securityContext, key, defaultValue);

        } else {

          switch (key) {
            case "size":
              if (data instanceof Collection) {
                return ((Collection) data).size();
              }
              if (data.getClass().isArray()) {
                return ((Object[]) data).length;
              }
              break;
          }
        }

      } else {

        // "data-less" keywords to start the evaluation chain
        switch (key) {
          case "request":
            return securityContext.getRequest();

          case "host":
            return securityContext.getRequest().getServerName();

          case "port":
            return securityContext.getRequest().getServerPort();

          case "pathInfo":
          case "path_info":
            return securityContext.getRequest().getPathInfo();

          case "parameterMap":
          case "parameter_map":
            return securityContext.getRequest().getParameterMap();

          case "remoteAddress":
          case "remote_address":
            final String remoteAddress = securityContext.getRequest().getHeader("X-FORWARDED-FOR");
            if (remoteAddress == null) {
              return securityContext.getRequest().getRemoteAddr();
            }
            return remoteAddress;

          case "response":
            if (securityContext != null) {
              final HttpServletResponse response = securityContext.getResponse();
              if (response != null) {

                try {
                  // return output stream of HTTP response for streaming
                  return response.getOutputStream();

                } catch (IOException ioex) {
                  logger.warn("", ioex);
                }
              }
            }
            return null;

          case "now":
            return DatePropertyParser.format(new Date(), DateProperty.DEFAULT_FORMAT);

          case "me":
            return securityContext.getUser(false);

          case "element":
            logger.warn(
                "The \"element\" keyword is deprecated! Please use \"this\" instead. Used in {}",
                entity.getProperty(GraphObject.id));

          case "this":
            return entity;

          case "locale":
            return locale != null ? locale.toString() : null;
        }
      }
    }

    if (value == null && defaultValue != null) {
      return Function.numberOrString(defaultValue);
    }

    return value;
  }