// ----- 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); } }
@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("<!---->"); } }
public Principal getCurrentUser() { return (securityContext == null ? null : securityContext.getUser(false)); }
@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); } }
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; }