io.flowly.auth.graph.AuthGraph.java Source code

Java tutorial

Introduction

Here is the source code for io.flowly.auth.graph.AuthGraph.java

Source

/*
 * Copyright (c) 2015 The original author or authors.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Apache License v2.0 
 *  which accompanies this distribution.
 *
 *  The Apache License v2.0 is available at
 *  http://opensource.org/licenses/Apache-2.0
 *
 *  You may elect to redistribute this code under this license.
 */

package io.flowly.auth.graph;

import com.thinkaurelius.titan.core.Multiplicity;
import com.thinkaurelius.titan.core.PropertyKey;
import com.thinkaurelius.titan.core.TitanFactory;
import com.thinkaurelius.titan.core.TitanGraph;
import com.thinkaurelius.titan.core.schema.TitanManagement;
import io.flowly.core.ObjectKeys;
import io.flowly.core.security.PasswordHash;
import io.flowly.core.security.Vault;
import io.vertx.core.file.FileSystem;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;

import java.util.Objects;

/**
 * Create a Titan graph by configuring the storage and indexing options.
 * Prepares the graph schema when the graph is created for the first time.
 *
 * @author <a>Uday Tatiraju</a>
 */
public class AuthGraph {
    private static final Logger logger = LoggerFactory.getLogger(AuthGraph.class);

    private TitanGraph graph;
    private Vault vault;

    public AuthGraph(JsonObject config, FileSystem fileSystem) throws Exception {
        prepareVault(config, fileSystem);
        prepareGraph(config);
    }

    public Graph getInstance() {
        return graph;
    }

    private void prepareVault(JsonObject config, FileSystem fileSystem) throws Exception {
        String path = Objects.requireNonNull(config.getString(ObjectKeys.VAULT_PATH),
                "Vault path must be specified.");
        String key = Objects.requireNonNull(config.getString(ObjectKeys.VAULT_KEY),
                "Vault key has to be specified");
        vault = new Vault(key.toCharArray(), path, fileSystem);
    }

    private void prepareGraph(JsonObject config) throws Exception {
        TitanFactory.Builder titanConfig = TitanFactory.build();

        // TODO: Use Cassandra.
        titanConfig.set(ObjectKeys.DB_STORAGE_BACKEND, "berkeleyje");
        titanConfig.set(ObjectKeys.DB_STORAGE_DIRECTORY, config.getString(ObjectKeys.DB_STORAGE_DIRECTORY));

        graph = titanConfig.open();
        configureSchema(graph);
    }

    // TODO: Create an upgradable schema by defining onCreate and onUpdate methods.
    // TODO: Read JSON files to create schema.
    private void configureSchema(TitanGraph graph) throws Exception {
        TitanManagement management = graph.openManagement();
        boolean schemaCreated = false;

        try {

            if (management.containsVertexLabel(Schema.V_USER)) {
                logger.info("Flowly auth graph schema created in a previous run.");
            } else {
                logger.info("Creating flowly auth graph schema...");

                // User vertex.
                management.makeVertexLabel(Schema.V_USER).make();
                PropertyKey userId = management.makePropertyKey(Schema.V_P_USER_ID).dataType(String.class).make();
                management.makePropertyKey(Schema.V_P_FIRST_NAME).dataType(String.class).make();
                management.makePropertyKey(Schema.V_P_LAST_NAME).dataType(String.class).make();
                management.makePropertyKey(Schema.V_P_MIDDLE_NAME).dataType(String.class).make();
                management.makePropertyKey(Schema.V_P_IS_INTERNAL).dataType(Boolean.class).make();
                management.makePropertyKey(Schema.V_P_PASSWORD).dataType(String.class).make();
                // Graph-level composite index (only supports equality operator).
                management.buildIndex(Schema.V_IDX_USER_ID, Vertex.class).addKey(userId).unique()
                        .buildCompositeIndex();

                // Group vertex
                management.makeVertexLabel(Schema.V_GROUP).make();
                PropertyKey groupId = management.makePropertyKey(Schema.V_P_GROUP_ID).dataType(String.class).make();
                management.buildIndex(Schema.V_IDX_GROUP_ID, Vertex.class).addKey(groupId).unique()
                        .buildCompositeIndex();

                // Common properties.
                management.makePropertyKey(Schema.V_P_NAME).dataType(String.class).make();
                management.makePropertyKey(Schema.V_P_DESCRIPTION).dataType(String.class).make();

                // Resource vertex
                management.makeVertexLabel(Schema.V_RESOURCE).make();
                PropertyKey resourceId = management.makePropertyKey(Schema.V_P_RESOURCE_ID).dataType(String.class)
                        .make();
                // Graph-level composite index (only supports equality operator).
                management.buildIndex(Schema.V_IDX_RESOURCE_ID, Vertex.class).addKey(resourceId).unique()
                        .buildCompositeIndex();

                // Member edge.
                management.makeEdgeLabel(Schema.E_MEMBER).multiplicity(Multiplicity.MULTI).make();

                // MemberOf edge.
                management.makeEdgeLabel(Schema.E_MEMBER_OF).multiplicity(Multiplicity.MULTI).make();

                // Permission edge.
                management.makeEdgeLabel(Schema.E_HAS_PERMISSION).multiplicity(Multiplicity.MULTI).make();
                management.makePropertyKey(Schema.E_P_RWX).dataType(Integer.class).make();

                schemaCreated = true;
                logger.info("Flowly auth graph schema created.");
            }

            management.commit();
        } catch (Exception ex) {
            management.rollback();
            logger.error("Unable to build Auth graph schema.", ex);
            throw ex;
        }

        // Create admin user vertex.
        if (schemaCreated) {
            createAdmin();
        }
    }

    private void createAdmin() throws Exception {
        try {
            Vertex adminVertex = graph.addVertex(T.label, Schema.V_USER, Schema.V_P_USER_ID,
                    ObjectKeys.ADMIN_USER_ID, Schema.V_P_PASSWORD,
                    PasswordHash.createHash(vault.getData(ObjectKeys.ADMIN_KEY)));
            createAdministratorsGroup(adminVertex);
            graph.tx().commit();

            logger.info("Administrators group and admin user created.");
        } catch (Exception ex) {
            graph.tx().rollback();
            logger.error("Unable to create Administrators group and admin user.", ex);
            throw ex;
        }
    }

    private void createAdministratorsGroup(Vertex admin) throws Exception {
        Vertex administrators = graph.addVertex(T.label, Schema.V_GROUP, Schema.V_P_GROUP_ID,
                ObjectKeys.ADMIN_GROUP_ID);

        administrators.addEdge(Schema.E_MEMBER, admin);
        admin.addEdge(Schema.E_MEMBER_OF, administrators);
    }
}