You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2016/10/24 13:06:40 UTC

[55/83] [abbrv] usergrid git commit: Adding paging to get all orgs endpoint. Enhance Akka cluster so it properly downs nodes that are restarted but still ok on the network. Don't load all orgs when validating sysadmin creds.

Adding paging to get all orgs endpoint.  Enhance Akka cluster so it properly downs nodes that are restarted but still ok on the network. Don't load all orgs when validating sysadmin creds.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/016b7fa6
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/016b7fa6
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/016b7fa6

Branch: refs/heads/asf-site
Commit: 016b7fa633bbb41ad89f90b8789bfda36587c112
Parents: 72dcd48
Author: Michael Russo <mr...@apigee.com>
Authored: Fri Sep 9 18:09:19 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Fri Sep 9 18:09:19 2016 -0700

----------------------------------------------------------------------
 .../actorsystem/ActorSystemManagerImpl.java     |  15 ++-
 .../actorsystem/ClusterListener.java            | 106 +++++++++++++++++++
 .../organizations/OrganizationsResource.java    |  43 ++++++--
 .../security/SecuredResourceFilterFactory.java  |   6 ++
 .../usergrid/rest/applications/SecurityIT.java  |  29 +++++
 .../test/resource/endpoints/NamedResource.java  |   9 ++
 .../cassandra/ManagementServiceImpl.java        |   3 +-
 .../shiro/principals/AdminUserPrincipal.java    |  25 +----
 8 files changed, 200 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ActorSystemManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ActorSystemManagerImpl.java b/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ActorSystemManagerImpl.java
index 3f00327..5a36656 100644
--- a/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ActorSystemManagerImpl.java
+++ b/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ActorSystemManagerImpl.java
@@ -161,6 +161,11 @@ public class ActorSystemManagerImpl implements ActorSystemManager {
 
     }
 
+    private String getClusterName(){
+        // better to not change this so rolling restarts of usergrid are unaffected
+        return "ClusterSystem";
+    }
+
 
     private void initAkka() {
         logger.info("Initializing Akka");
@@ -188,6 +193,10 @@ public class ActorSystemManagerImpl implements ActorSystemManager {
 
         clusterSystem = createClusterSystem( config );
 
+        // register our cluster listener
+        clusterSystem.actorOf(Props.create(ClusterListener.class),
+            "clusterListener");
+
         createClientActors( clusterSystem );
 
         mediator = DistributedPubSub.get( clusterSystem ).mediator();
@@ -213,7 +222,7 @@ public class ActorSystemManagerImpl implements ActorSystemManager {
 
                     // we are testing, create seeds-by-region map for one region, one seed
 
-                    String seed = "akka.tcp://ClusterSystem" + "@" + hostname + ":" + port;
+                    String seed = "akka.tcp://"+getClusterName()+ "@" + hostname + ":" + port;
                     seedsByRegion.put( currentRegion, seed );
                     logger.info( "Akka testing, only starting one seed" );
 
@@ -237,7 +246,7 @@ public class ActorSystemManagerImpl implements ActorSystemManager {
                             regionPort = port; // unless we are testing
                         }
 
-                        String seed = "akka.tcp://ClusterSystem" + "@" + hostname + ":" + regionPort;
+                        String seed = "akka.tcp://"+getClusterName()+ "@" + hostname + ":" + regionPort;
 
                         logger.info( "Adding seed [{}] for region [{}]", seed, region );
 
@@ -327,7 +336,7 @@ public class ActorSystemManagerImpl implements ActorSystemManager {
     private ActorSystem createClusterSystem( Config config ) {
 
         // there is only 1 akka system for a Usergrid cluster
-        final String clusterName = "ClusterSystem";
+        final String clusterName = getClusterName();
 
         if ( clusterSystem == null) {
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ClusterListener.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ClusterListener.java b/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ClusterListener.java
new file mode 100644
index 0000000..44473a7
--- /dev/null
+++ b/stack/corepersistence/actorsystem/src/main/java/org/apache/usergrid/persistence/actorsystem/ClusterListener.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.usergrid.persistence.actorsystem;
+
+
+import akka.actor.UntypedActor;
+import akka.cluster.Cluster;
+import akka.cluster.ClusterEvent;
+import com.google.common.collect.ListMultimap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClusterListener extends UntypedActor {
+
+    private static final Logger logger = LoggerFactory.getLogger( ClusterListener.class );
+
+    private final Cluster cluster = Cluster.get(getContext().system());
+
+    private final ListMultimap<String, String> seedsByRegion;
+
+    private final String currentRegion;
+
+    public ClusterListener( ListMultimap<String, String> seedsByRegion, String currentRegion ){
+
+        this.seedsByRegion = seedsByRegion;
+        this.currentRegion = currentRegion;
+    }
+
+    @Override
+    public void preStart() {
+        // subscribe to all cluster events that we might take action/logging on
+        cluster.subscribe(getSelf(),
+            ClusterEvent.initialStateAsEvents(),
+            ClusterEvent.MemberEvent.class,
+            ClusterEvent.UnreachableMember.class,
+            ClusterEvent.MemberUp.class,
+            ClusterEvent.MemberWeaklyUp.class);
+    }
+
+    @Override
+    public void postStop() {
+        // purposely do not unsubscribe so other actors will continue to receive cluster events
+        cluster.unsubscribe(getSelf());
+    }
+
+    @Override
+    public void onReceive(Object message) throws Exception {
+
+        if (message instanceof ClusterEvent.MemberUp) {
+                ClusterEvent.MemberUp event = (ClusterEvent.MemberUp) message;
+                logger.info("Member is Up: {}, hostname: {}", event.member(),  event.member().address().host().get() );
+
+        } else if (message instanceof ClusterEvent.UnreachableMember) {
+            ClusterEvent.UnreachableMember event = (ClusterEvent.UnreachableMember) message;
+            logger.info("Member detected as unreachable: {}", event.member());
+
+            String hostname = event.member().address().host().get();
+
+            // invoke a ping because InetAddress requires root privleges which the JVM often does not have
+            boolean networkReachable =
+                java.lang.Runtime.getRuntime().exec("ping -c 1 "+hostname).waitFor() == 0;
+            if(networkReachable){
+
+                logger.info("Unreachable member {} is accessible on the network, " +
+                    "application must have died. Marking member down", event.member());
+
+                cluster.down(event.member().address());
+            }else{
+
+                logger.warn("Unreachable member {} is not accessible on the network, " +
+                    "there must be a network issue. Not marking member down", event.member());
+
+            }
+
+        } else if (message instanceof ClusterEvent.MemberRemoved) {
+            ClusterEvent.MemberRemoved event = (ClusterEvent.MemberRemoved) message;
+            logger.info("Member is Removed: {}", event.member());
+
+        } else if (message instanceof ClusterEvent.MemberEvent) {
+            ClusterEvent.MemberEvent event = (ClusterEvent.MemberEvent) message;
+            if(logger.isTraceEnabled()){
+                logger.trace("MemberEvent occurred for member: {}, Event: {}", event.member(), event.toString());
+            }
+
+        } else {
+            unhandled(message);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/rest/src/main/java/org/apache/usergrid/rest/management/organizations/OrganizationsResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/organizations/OrganizationsResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/management/organizations/OrganizationsResource.java
index 6105ce6..84320b0 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/organizations/OrganizationsResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/organizations/OrganizationsResource.java
@@ -20,17 +20,15 @@ package org.apache.usergrid.rest.management.organizations;
 import com.fasterxml.jackson.jaxrs.json.annotation.JSONP;
 import com.google.common.base.Preconditions;
 import org.apache.commons.lang.StringUtils;
-import org.apache.shiro.SecurityUtils;
 import org.apache.usergrid.management.ApplicationCreator;
 import org.apache.usergrid.management.OrganizationInfo;
 import org.apache.usergrid.management.OrganizationOwnerInfo;
 import org.apache.usergrid.management.exceptions.ManagementException;
+import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.rest.AbstractContextResource;
 import org.apache.usergrid.rest.ApiResponse;
 import org.apache.usergrid.rest.RootResource;
 import org.apache.usergrid.rest.security.annotations.RequireSystemAccess;
-import org.apache.usergrid.security.shiro.principals.PrincipalIdentifier;
-import org.apache.usergrid.security.shiro.utils.SubjectUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -43,7 +41,8 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriInfo;
 import java.util.*;
 
-import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotEmpty;
+import static org.apache.usergrid.persistence.Schema.PROPERTY_PATH;
 
 
 @Component( "org.apache.usergrid.rest.management.organizations.OrganizationsResource" )
@@ -71,11 +70,40 @@ public class OrganizationsResource extends AbstractContextResource {
 
     @GET
     @RequireSystemAccess
-    public ApiResponse getAllOrganizations() throws Exception{
+    @Produces(MediaType.APPLICATION_JSON)
+    public ApiResponse getAllOrganizations(@Context UriInfo ui) throws Exception{
 
         ApiResponse response = createApiResponse();
-        //TODO this needs paging at some point
-        List<OrganizationInfo> orgs = management.getOrganizations(null, 10000);
+
+        String cursor = ui.getQueryParameters().getFirst("cursor");
+        String limitString = ui.getQueryParameters().getFirst("limit");
+        int limit = 10;
+        if( isNotEmpty(limitString)){
+            try {
+                limit = Integer.valueOf(limitString);
+            }catch (NumberFormatException e){
+                // do nothing let it be default
+            }
+        }
+        limit = limit < 1000 ? limit : 10;
+
+
+
+        EntityManager em = emf.getManagementEntityManager();
+        Query query = new Query();
+        query.setCursor(cursor);
+        query.setLimit(limit);
+        Results results = em.searchCollection(em.getApplicationRef(), Schema.COLLECTION_GROUPS, query);
+
+        List<OrganizationInfo> orgs = new ArrayList<>( results.size() );
+        OrganizationInfo orgInfo;
+        for ( Entity entity : results.getEntities() ) {
+
+            String path = ( String ) entity.getProperty( PROPERTY_PATH );
+            orgInfo = new OrganizationInfo( entity.getUuid(), path );
+            orgs.add( orgInfo );
+        }
+
         List<Object> jsonOrgList = new ArrayList<>();
 
         for(OrganizationInfo org: orgs){
@@ -92,6 +120,7 @@ public class OrganizationsResource extends AbstractContextResource {
         }
 
         response.setProperty("organizations", jsonOrgList);
+        response.setCursor(results.getCursor());
 
         return response;
     }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/rest/src/main/java/org/apache/usergrid/rest/security/SecuredResourceFilterFactory.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/security/SecuredResourceFilterFactory.java b/stack/rest/src/main/java/org/apache/usergrid/rest/security/SecuredResourceFilterFactory.java
index ede6c35..f1f6c17 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/security/SecuredResourceFilterFactory.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/security/SecuredResourceFilterFactory.java
@@ -471,6 +471,11 @@ public class SecuredResourceFilterFactory implements DynamicFeature {
                 logger.debug( "PathPermissionsFilter.authorize" );
             }
 
+            if ( isServiceAdmin() || isBasicAuthServiceAdmin(request)){
+                // superuser can do anything, short circuit here and allow the request
+                return;
+            }
+
             final String PATH_MSG = "---- Checked permissions for path --------------------------------------------\n"
                 + "Requested path: {} \n"
                 + "Requested action: {} \n" + "Requested permission: {} \n"
@@ -504,6 +509,7 @@ public class SecuredResourceFilterFactory implements DynamicFeature {
 
                 Subject currentUser = SubjectUtils.getSubject();
 
+                // TODO is this right?
                 if ( currentUser == null ) {
                     return;
                 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/rest/src/test/java/org/apache/usergrid/rest/applications/SecurityIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/SecurityIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/SecurityIT.java
index cbc8e38..510e245 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/SecurityIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/SecurityIT.java
@@ -19,6 +19,8 @@ package org.apache.usergrid.rest.applications;
 
 import org.apache.usergrid.rest.test.resource.AbstractRestIT;
 import org.apache.usergrid.rest.test.resource.model.ApiResponse;
+import org.apache.usergrid.rest.test.resource.model.Entity;
+import org.apache.usergrid.rest.test.resource.model.QueryParameters;
 import org.apache.usergrid.utils.UUIDUtils;
 import org.junit.Test;
 
@@ -26,6 +28,7 @@ import javax.ws.rs.WebApplicationException;
 import java.util.UUID;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 /**
  * These tests will execute requests against certain paths (with or without credentials) to ensure access is being
@@ -110,5 +113,31 @@ public class SecurityIT extends AbstractRestIT {
 
     }
 
+    @Test
+    public void testSysadminNoCredentials(){
+
+        int responseStatus = 0;
+        try{
+            this.pathResource("system/database/setup").put(false,  new Entity());
+        } catch (WebApplicationException ex) {
+            responseStatus = ex.getResponse().getStatus();
+        }
+        assertEquals(401, responseStatus);
+
+    }
+
+    @Test
+    public void testSysadminWithCredentials(){
+
+        try{
+            QueryParameters queryParameters = new QueryParameters();
+            queryParameters.addParam("access_token", clientSetup.getSuperuserToken().getAccessToken());
+            this.pathResource("system/database/setup").put(false,  new Entity(), queryParameters);
+        } catch (WebApplicationException ex) {
+            fail("Request should have been successful");
+        }
+
+    }
+
 
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/endpoints/NamedResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/endpoints/NamedResource.java b/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/endpoints/NamedResource.java
index ad014d9..472b5a0 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/endpoints/NamedResource.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/endpoints/NamedResource.java
@@ -343,6 +343,15 @@ public class NamedResource implements UrlResource {
             javax.ws.rs.client.Entity.entity(data, type), ApiResponse.class);
     }
 
+    public ApiResponse put(boolean useToken, org.apache.usergrid.rest.test.resource.model.Entity entity, QueryParameters queryParameters ) {
+        WebTarget resource = getTarget(useToken);
+        if( queryParameters != null ) {
+            resource = addParametersToResource(resource, queryParameters);
+        }
+        return resource.request().put(
+            javax.ws.rs.client.Entity.entity(entity, MediaType.APPLICATION_JSON_TYPE), ApiResponse.class);
+    }
+
     public ApiResponse put(boolean useToken, org.apache.usergrid.rest.test.resource.model.Entity entity ) {
         WebTarget resource = getTarget(useToken);
         return resource.request().put(

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index 98cfedf..d1e3edf 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@ -783,8 +783,7 @@ public class ManagementServiceImpl implements ManagementService {
         List<OrganizationInfo> orgs = new ArrayList<>( results.size() );
         OrganizationInfo orgInfo;
         for ( Entity entity : results.getEntities() ) {
-            // TODO T.N. temporary hack to deal with duplicate orgs. Revert this
-            // commit after migration
+
             String path = ( String ) entity.getProperty( PROPERTY_PATH );
 
             if ( organizations.containsValue( path ) ) {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/016b7fa6/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
index a594d1e..b761b89 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
@@ -96,30 +96,7 @@ public class AdminUserPrincipal extends UserPrincipal {
 
             grant(info, SubjectUtils.getPermissionFromPath(emf.getManagementAppId(), "get,put,post,delete", "/**"));
 
-            // get all organizations
-            try {
-
-                Map<UUID, String> allOrganizations = management.getOrganizations();
-
-                if (allOrganizations != null) {
-
-                    for (UUID id : allOrganizations.keySet()) {
-                        grant(info, "organizations:admin,access,get,put,post,delete:" + id);
-                    }
-                    organizationSet.putAll(allOrganizations);
-
-                    Map<UUID, String> allApplications =
-                        management.getApplicationsForOrganizations(allOrganizations.keySet());
-
-                    if ((allApplications != null) && ! allApplications.isEmpty()) {
-                        grant(info, "applications:admin,access,get,put,post,delete:" + StringUtils
-                            .join(allApplications.keySet(), ','));
-                        applicationSet.putAll(allApplications);
-                    }
-                }
-            } catch (Exception e) {
-                logger.error("Unable to construct superuser permissions", e);
-            }
+            // don't need to load organizations here for superuser/sysadmin because it has access to everything
         }
 
         else {