use of org.structr.common.SecurityContext in project structr by structr.
the class ScriptingTest method testSystemProperties.
@Test
public void testSystemProperties() {
try {
final Principal user = createTestNode(Principal.class);
// create new node
TestOne t1 = createTestNode(TestOne.class, user);
final SecurityContext userContext = SecurityContext.getInstance(user, AccessMode.Frontend);
final App userApp = StructrApp.getInstance(userContext);
try (final Tx tx = userApp.tx()) {
final ActionContext userActionContext = new ActionContext(userContext, null);
assertEquals("node should be of type TestOne", "TestOne", Scripting.replaceVariables(userActionContext, t1, "${(get(this, 'type'))}"));
try {
assertEquals("setting the type should fail", "TestTwo", Scripting.replaceVariables(userActionContext, t1, "${(set(this, 'type', 'TestThree'), get(this, 'type'))}"));
fail("setting a system property should fail");
} catch (FrameworkException fx) {
}
assertEquals("setting the type should work after setting it with unlock_system_properties_once", "TestFour", Scripting.replaceVariables(userActionContext, t1, "${(unlock_system_properties_once(this), set(this, 'type', 'TestFour'), get(this, 'type'))}"));
tx.success();
}
} catch (FrameworkException ex) {
logger.warn("", ex);
fail("Unexpected exception");
}
}
use of org.structr.common.SecurityContext in project structr by structr.
the class SchemaImporter method analyzeSchema.
public void analyzeSchema() {
final App app = StructrApp.getInstance();
final FileBasedHashLongMap<NodeInfo> nodeIdMap = new FileBasedHashLongMap<>(userHome + File.separator + ".structrSchemaAnalyzer");
final DatabaseService graphDb = app.getDatabaseService();
final ConfigurationProvider configuration = Services.getInstance().getConfigurationProvider();
final Set<NodeInfo> nodeTypes = new LinkedHashSet<>();
final Set<RelationshipInfo> relationships = new LinkedHashSet<>();
final Map<String, SchemaNode> schemaNodes = new LinkedHashMap<>();
final Map<String, List<TypeInfo>> typeInfoTypeMap = new LinkedHashMap<>();
final List<TypeInfo> reducedTypeInfos = new LinkedList<>();
final List<TypeInfo> typeInfos = new LinkedList<>();
Iterator<Relationship> relIterator = null;
Iterator<Node> nodeIterator = null;
info("Fetching all nodes iterator..");
try (final Tx tx = app.tx()) {
nodeIterator = Iterables.filter(new StructrAndSpatialPredicate(false, false, true), graphDb.getAllNodes()).iterator();
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Starting to analyze nodes..");
bulkGraphOperation(SecurityContext.getSuperUserInstance(), nodeIterator, 100000, "Analyzing nodes", new BulkGraphOperation<Node>() {
@Override
public void handleGraphObject(final SecurityContext securityContext, final Node node) throws FrameworkException {
final NodeInfo nodeInfo = new NodeInfo(node);
// hashcode of nodeInfo is derived from its property and type signature!
nodeTypes.add(nodeInfo);
// add node ID to our new test datastructure
nodeIdMap.add(nodeInfo, node.getId());
}
});
info("Identifying common base classes..");
try (final Tx tx = app.tx(true, false, false)) {
// nodeTypes now contains all existing node types and their property sets
identifyCommonBaseClasses(app, nodeTypes, nodeIdMap, typeInfos);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Collecting type information..");
try (final Tx tx = app.tx(true, false, false)) {
// group type infos by type
collectTypeInfos(typeInfos, typeInfoTypeMap);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Aggregating type information..");
try (final Tx tx = app.tx(true, false, false)) {
// reduce type infos with more than one type
reduceTypeInfos(typeInfoTypeMap, reducedTypeInfos);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Identifying property sets..");
try (final Tx tx = app.tx(true, false, false)) {
// intersect property sets of type infos
intersectPropertySets(reducedTypeInfos);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Sorting result..");
try (final Tx tx = app.tx(true, false, false)) {
// sort type infos
Collections.sort(reducedTypeInfos, new HierarchyComparator(false));
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
final Map<String, TypeInfo> reducedTypeInfoMap = new LinkedHashMap<>();
for (final TypeInfo info : reducedTypeInfos) {
final String type = info.getPrimaryType();
// map TypeInfo to type for later use
reducedTypeInfoMap.put(type, info);
info("Starting with setting of type and ID for type {}", type);
bulkGraphOperation(SecurityContext.getSuperUserInstance(), info.getNodeIds().iterator(), 10000, "Setting type and ID", new BulkGraphOperation<Long>() {
@Override
public void handleGraphObject(SecurityContext securityContext, Long nodeId) throws FrameworkException {
final Node node = graphDb.getNodeById(nodeId);
node.setProperty(GraphObject.id.dbName(), NodeServiceCommand.getNextUuid());
node.setProperty(GraphObject.type.dbName(), type);
}
});
}
info("Fetching all relationships iterator..");
try (final Tx tx = app.tx(true, false, false)) {
relIterator = Iterables.filter(new StructrAndSpatialPredicate(false, false, true), graphDb.getAllRelationships()).iterator();
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
info("Starting with analyzing relationships..");
bulkGraphOperation(SecurityContext.getSuperUserInstance(), relIterator, 10000, "Analyzing relationships", new BulkGraphOperation<Relationship>() {
@Override
public void handleGraphObject(SecurityContext securityContext, Relationship rel) throws FrameworkException {
final Node startNode = rel.getStartNode();
final Node endNode = rel.getEndNode();
// make sure node has been successfully identified above
if (startNode.hasProperty("type") && endNode.hasProperty("type")) {
final String relationshipType = rel.getType().name();
final String startNodeType = (String) startNode.getProperty("type");
final String endNodeType = (String) endNode.getProperty("type");
relationships.add(new RelationshipInfo(startNodeType, endNodeType, relationshipType));
// create combined type on imported relationship
if (startNodeType != null && endNodeType != null) {
final String combinedType = getCombinedType(startNodeType, relationshipType, endNodeType);
logger.debug("Combined relationship type {} found for rel type {}, start node type {}, end node type {}", new Object[] { combinedType, relationshipType, startNodeType, endNodeType });
rel.setProperty(GraphObject.type.dbName(), combinedType);
}
// create ID on imported relationship
rel.setProperty(GraphObject.id.dbName(), NodeServiceCommand.getNextUuid());
}
}
});
info("Grouping relationships..");
// group relationships by type
final Map<String, List<RelationshipInfo>> relTypeInfoMap = new LinkedHashMap<>();
for (final RelationshipInfo relInfo : relationships) {
// final String relType = relInfo.getRelType();
final String combinedType = getCombinedType(relInfo.getStartNodeType(), relInfo.getRelType(), relInfo.getEndNodeType());
List<RelationshipInfo> infos = relTypeInfoMap.get(combinedType);
if (infos == null) {
infos = new LinkedList<>();
relTypeInfoMap.put(combinedType, infos);
}
infos.add(relInfo);
}
info("Aggregating relationship information..");
final List<RelationshipInfo> reducedRelationshipInfos = new ArrayList<>();
if (Settings.InheritanceDetection.getValue()) {
// reduce relationship infos into one
for (final List<RelationshipInfo> infos : relTypeInfoMap.values()) {
reducedRelationshipInfos.addAll(reduceNodeTypes(infos, reducedTypeInfoMap));
}
} else {
reducedRelationshipInfos.addAll(relationships);
}
info("Starting with schema node creation..");
bulkGraphOperation(SecurityContext.getSuperUserInstance(), reducedTypeInfos.iterator(), 100000, "Creating schema nodes", new BulkGraphOperation<TypeInfo>() {
@Override
public void handleGraphObject(SecurityContext securityContext, TypeInfo typeInfo) throws FrameworkException {
final String type = typeInfo.getPrimaryType();
if (!"ReferenceNode".equals(type)) {
final Map<String, Class> props = typeInfo.getPropertySet();
final PropertyMap propertyMap = new PropertyMap();
// add properties
for (final Map.Entry<String, Class> propertyEntry : props.entrySet()) {
final String propertyName = propertyEntry.getKey();
final Class propertyType = propertyEntry.getValue();
// handle array types differently
String propertyTypeName = propertyType.getSimpleName();
if (propertyType.isArray()) {
// remove "[]" from the end and append "Array" to match the appropriate parser
propertyTypeName = propertyTypeName.substring(0, propertyTypeName.length() - 2).concat("Array");
}
propertyMap.put(new StringProperty("_".concat(propertyName)), propertyTypeName);
}
// set node type which is in "name" property
propertyMap.put(AbstractNode.name, type);
// check if there is an existing Structr entity with the same type
// and make the dynamic class extend the existing class if yes.
final Class existingType = configuration.getNodeEntityClass(type);
if (existingType != null) {
propertyMap.put(SchemaNode.extendsClass, existingType.getName());
} else if (!typeInfo.getOtherTypes().isEmpty()) {
// only the first supertype is supported
propertyMap.put(SchemaNode.extendsClass, typeInfo.getSuperclass(reducedTypeInfoMap));
}
final SchemaNode existingNode = app.nodeQuery(SchemaNode.class).andName(type).getFirst();
if (existingNode != null) {
for (final Entry<PropertyKey, Object> entry : propertyMap.entrySet()) {
existingNode.setProperty(entry.getKey(), entry.getValue());
}
schemaNodes.put(type, existingNode);
} else {
// create schema node
schemaNodes.put(type, app.create(SchemaNode.class, propertyMap));
}
}
}
});
info("Starting with schema relationship creation..");
bulkGraphOperation(SecurityContext.getSuperUserInstance(), reducedRelationshipInfos.iterator(), 100000, "Creating schema relationships", new BulkGraphOperation<RelationshipInfo>() {
@Override
public void handleGraphObject(SecurityContext securityContext, RelationshipInfo template) throws FrameworkException {
final String startNodeType = template.getStartNodeType();
final String endNodeType = template.getEndNodeType();
if (startNodeType != null && endNodeType != null) {
final SchemaNode startNode = schemaNodes.get(startNodeType);
final SchemaNode endNode = schemaNodes.get(endNodeType);
if (startNode != null && endNode != null) {
final String relationshipType = template.getRelType();
final PropertyMap propertyMap = new PropertyMap();
propertyMap.put(SchemaRelationshipNode.sourceId, startNode.getUuid());
propertyMap.put(SchemaRelationshipNode.targetId, endNode.getUuid());
propertyMap.put(SchemaRelationshipNode.relationshipType, relationshipType);
app.create(SchemaRelationshipNode.class, propertyMap);
} else {
info("Unable to create schema relationship node for {} -> {}, no schema nodes found", startNodeType, endNodeType);
}
}
}
});
info("Starting with index rebuild..");
// rebuild index
app.command(BulkRebuildIndexCommand.class).execute(Collections.EMPTY_MAP);
}
use of org.structr.common.SecurityContext in project structr by structr.
the class JsonRestServlet method doPost.
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="POST">
@Override
protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final List<RestMethodResult> results = new LinkedList<>();
final SecurityContext securityContext;
final Authenticator authenticator;
final Resource resource;
try {
assertInitialized();
// first thing to do!
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// get reader before initalizing security context
final String input = IOUtils.toString(request.getReader());
// isolate request authentication in a transaction
try (final Tx tx = StructrApp.getInstance().tx()) {
authenticator = config.getAuthenticator();
securityContext = authenticator.initializeAndExamineRequest(request, response);
tx.success();
}
final App app = StructrApp.getInstance(securityContext);
final IJsonInput jsonInput = cleanAndParseJsonString(app, input);
if (securityContext != null) {
// isolate resource authentication
try (final Tx tx = app.tx()) {
resource = ResourceHelper.applyViewTransformation(request, securityContext, ResourceHelper.optimizeNestedResourceChain(securityContext, request, resourceMap, propertyView), propertyView);
authenticator.checkResourceAccess(securityContext, request, resource.getResourceSignature(), propertyView.get(securityContext));
tx.success();
}
// isolate doPost
boolean retry = true;
while (retry) {
if (resource.createPostTransaction()) {
try (final Tx tx = app.tx()) {
for (JsonInput propertySet : jsonInput.getJsonInputs()) {
results.add(resource.doPost(convertPropertySetToMap(propertySet)));
}
tx.success();
retry = false;
} catch (RetryException ddex) {
retry = true;
}
} else {
try {
for (JsonInput propertySet : jsonInput.getJsonInputs()) {
results.add(resource.doPost(convertPropertySetToMap(propertySet)));
}
retry = false;
} catch (RetryException ddex) {
retry = true;
}
}
}
// set default value for property view
propertyView.set(securityContext, config.getDefaultPropertyView());
// isolate write output
try (final Tx tx = app.tx()) {
if (!results.isEmpty()) {
final RestMethodResult result = results.get(0);
final int resultCount = results.size();
if (result != null) {
if (resultCount > 1) {
for (final RestMethodResult r : results) {
final GraphObject objectCreated = r.getContent().get(0);
if (!result.getContent().contains(objectCreated)) {
result.addContent(objectCreated);
}
}
// remove Location header if more than one object was
// written because it may only contain a single URL
result.addHeader("Location", null);
}
result.commitResponse(gson.get(), response);
}
}
tx.success();
}
} else {
// isolate write output
try (final Tx tx = app.tx()) {
new RestMethodResult(HttpServletResponse.SC_FORBIDDEN).commitResponse(gson.get(), response);
tx.success();
}
}
} catch (FrameworkException frameworkException) {
// set status & write JSON output
response.setStatus(frameworkException.getStatus());
gson.get().toJson(frameworkException, response.getWriter());
response.getWriter().println();
} catch (JsonSyntaxException jsex) {
logger.warn("POST: Invalid JSON syntax", jsex.getMessage());
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "JsonSyntaxException in POST: " + jsex.getMessage()));
} catch (JsonParseException jpex) {
logger.warn("Unable to parse JSON string", jpex.getMessage());
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "JsonParseException in POST: " + jpex.getMessage()));
} catch (UnsupportedOperationException uoe) {
logger.warn("POST not supported");
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "POST not supported: " + uoe.getMessage()));
} catch (Throwable t) {
logger.warn("Exception in POST", t);
int code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "JsonSyntaxException in POST: " + t.getMessage()));
} finally {
try {
// response.getWriter().flush();
response.getWriter().close();
} catch (Throwable t) {
logger.warn("Unable to flush and close response: {}", t.getMessage());
}
}
}
use of org.structr.common.SecurityContext in project structr by structr.
the class JsonRestServlet method doGetOrHead.
private void doGetOrHead(final HttpServletRequest request, final HttpServletResponse response, final boolean returnContent) throws ServletException, IOException {
SecurityContext securityContext = null;
Authenticator authenticator = null;
Result result = null;
Resource resource = null;
try {
// first thing to do!
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// isolate request authentication in a transaction
try (final Tx tx = StructrApp.getInstance().tx()) {
authenticator = config.getAuthenticator();
securityContext = authenticator.initializeAndExamineRequest(request, response);
tx.success();
}
final App app = StructrApp.getInstance(securityContext);
// set default value for property view
propertyView.set(securityContext, config.getDefaultPropertyView());
// evaluate constraints and measure query time
double queryTimeStart = System.nanoTime();
// isolate resource authentication
try (final Tx tx = app.tx()) {
resource = ResourceHelper.applyViewTransformation(request, securityContext, ResourceHelper.optimizeNestedResourceChain(securityContext, request, resourceMap, propertyView), propertyView);
authenticator.checkResourceAccess(securityContext, request, resource.getResourceSignature(), propertyView.get(securityContext));
tx.success();
}
// add sorting & paging
String pageSizeParameter = request.getParameter(REQUEST_PARAMETER_PAGE_SIZE);
String pageParameter = request.getParameter(REQUEST_PARAMETER_PAGE_NUMBER);
String sortOrder = request.getParameter(REQUEST_PARAMETER_SORT_ORDER);
String sortKeyName = request.getParameter(REQUEST_PARAMETER_SORT_KEY);
String outputDepth = request.getParameter(REQUEST_PARAMTER_OUTPUT_DEPTH);
boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
int pageSize = Services.parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
int page = Services.parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
int depth = Services.parseInt(outputDepth, config.getOutputNestingDepth());
String baseUrl = request.getRequestURI();
PropertyKey sortKey = null;
// set sort key
if (sortKeyName != null) {
Class<? extends GraphObject> type = resource.getEntityClass();
if (type == null) {
// fallback to default implementation
// if no type can be determined
type = AbstractNode.class;
}
sortKey = StructrApp.getConfiguration().getPropertyKeyForDatabaseName(type, sortKeyName, false);
}
// isolate doGet
boolean retry = true;
while (retry) {
try (final Tx tx = app.tx()) {
result = resource.doGet(sortKey, sortDescending, pageSize, page);
tx.success();
retry = false;
} catch (RetryException ddex) {
retry = true;
}
}
if (result == null) {
throw new FrameworkException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Unable to retrieve result, check database connection");
}
if (returnContent) {
if (!(resource instanceof StaticRelationshipResource) && !result.isPrimitiveArray() && !result.isEmpty()) {
result.setIsCollection(resource.isCollectionResource());
result.setIsPrimitiveArray(resource.isPrimitiveArray());
}
PagingHelper.addPagingParameter(result, pageSize, page);
// timing..
double queryTimeEnd = System.nanoTime();
// store property view that will be used to render the results
result.setPropertyView(propertyView.get(securityContext));
// allow resource to modify result set
resource.postProcessResultSet(result);
DecimalFormat decimalFormat = new DecimalFormat("0.000000000", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
result.setQueryTime(decimalFormat.format((queryTimeEnd - queryTimeStart) / 1000000000.0));
if (outputDepth != null) {
result.setOutputNestingDepth(depth);
}
String accept = request.getHeader("Accept");
if (accept != null && accept.contains("text/html")) {
final StreamingHtmlWriter htmlStreamer = new StreamingHtmlWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("text/html; charset=utf-8");
final Writer writer = response.getWriter();
htmlStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
} else {
final StreamingJsonWriter jsonStreamer = new StreamingJsonWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("application/json; charset=utf-8");
final Writer writer = response.getWriter();
jsonStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
}
}
response.setStatus(HttpServletResponse.SC_OK);
} catch (FrameworkException frameworkException) {
// set status & write JSON output
response.setStatus(frameworkException.getStatus());
gson.get().toJson(frameworkException, response.getWriter());
response.getWriter().println();
} catch (JsonSyntaxException jsex) {
logger.warn("JsonSyntaxException in GET", jsex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Json syntax exception in GET: " + jsex.getMessage()));
} catch (JsonParseException jpex) {
logger.warn("JsonParseException in GET", jpex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Parser exception in GET: " + jpex.getMessage()));
} catch (Throwable t) {
logger.warn("Exception in GET (URI: {})", securityContext != null ? securityContext.getCompoundRequestURI() : "(null SecurityContext)");
logger.warn(" => Error thrown: ", t);
int code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Exception in GET: " + t.getMessage()));
} finally {
try {
// response.getWriter().flush();
response.getWriter().close();
} catch (Throwable t) {
logger.warn("Unable to flush and close response: {}", t.getMessage());
}
}
}
use of org.structr.common.SecurityContext in project structr by structr.
the class AbstractNode method grant.
@Override
public final void grant(Permission permission, Principal principal) throws FrameworkException {
if (!isGranted(Permission.accessControl, securityContext)) {
throw new FrameworkException(403, "Access control not permitted");
}
Security secRel = getSecurityRelationship(principal);
if (secRel == null) {
try {
// ensureCardinality is not neccessary here
final SecurityContext securityContext = SecurityContext.getSuperUserInstance();
securityContext.disableEnsureCardinality();
secRel = StructrApp.getInstance(securityContext).create(principal, (NodeInterface) this, Security.class);
} catch (FrameworkException ex) {
logger.error("Could not create security relationship!", ex);
}
}
// only access rel if it existss or was created successfully
if (secRel != null) {
secRel.addPermission(permission);
}
}
Aggregations