USERGRID-1300: move superuser localhost check into SecuredResourceFilterFactory
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/80241689 Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/80241689 Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/80241689 Branch: refs/heads/usergrid-1268-akka-211 Commit: 802416899ad00f87b06f621fd0c2ff7305aba417 Parents: de6ecb9 Author: Mike Dunker <[email protected]> Authored: Wed Jun 15 17:23:13 2016 -0700 Committer: Mike Dunker <[email protected]> Committed: Wed Jun 15 17:23:13 2016 -0700 ---------------------------------------------------------------------- .../main/resources/usergrid-default.properties | 4 ++ .../security/SecuredResourceFilterFactory.java | 72 ++++++++++++++++++-- 2 files changed, 71 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/80241689/stack/config/src/main/resources/usergrid-default.properties ---------------------------------------------------------------------- diff --git a/stack/config/src/main/resources/usergrid-default.properties b/stack/config/src/main/resources/usergrid-default.properties index 0fc31ef..d2141cf 100644 --- a/stack/config/src/main/resources/usergrid-default.properties +++ b/stack/config/src/main/resources/usergrid-default.properties @@ -535,6 +535,10 @@ [email protected] usergrid.sysadmin.login.password=test usergrid.sysadmin.login.allowed=true +# if usergrid.sysadmin.login.allowed=true, only allows sysadmin login if request is localhost +# if usergrid.sysadmin.login.allowed=false, this property has no effect +usergrid.sysadmin.localhost.only=false + # Set admin notification email properties # usergrid.sysadmin.email= http://git-wip-us.apache.org/repos/asf/usergrid/blob/80241689/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 bd1ab46..85e6210 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 @@ -45,6 +45,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.lang.reflect.Method; +import java.net.InetAddress; import java.util.Map; import java.util.Properties; @@ -68,6 +69,9 @@ public class SecuredResourceFilterFactory implements DynamicFeature { ManagementService management; + private static final int PRIORITY_SUPERUSER = 1; + private static final int PRIORITY_DEFAULT = 5000; + @Inject public SecuredResourceFilterFactory() { @@ -112,6 +116,7 @@ public class SecuredResourceFilterFactory implements DynamicFeature { @Override public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) { + Method am = resourceInfo.getResourceMethod(); if (logger.isTraceEnabled()) { @@ -119,20 +124,28 @@ public class SecuredResourceFilterFactory implements DynamicFeature { resourceInfo.getResourceClass().getSimpleName(), resourceInfo.getResourceMethod().getName()); } + boolean sysadminLocalhostOnly = + Boolean.parseBoolean(properties.getProperty("usergrid.sysadmin.localhost.only", "false")); + + if (sysadminLocalhostOnly) { + // priority = PRIORITY_SUPERUSER forces this to run first + featureContext.register( SysadminLocalhostFilter.class, PRIORITY_SUPERUSER ); + } + if ( am.isAnnotationPresent( RequireApplicationAccess.class ) ) { - featureContext.register( ApplicationFilter.class ); + featureContext.register( ApplicationFilter.class, PRIORITY_DEFAULT); } else if ( am.isAnnotationPresent( RequireOrganizationAccess.class ) ) { - featureContext.register( OrganizationFilter.class ); + featureContext.register( OrganizationFilter.class, PRIORITY_DEFAULT); } else if ( am.isAnnotationPresent( RequireSystemAccess.class ) ) { - featureContext.register( SystemFilter.class ); + featureContext.register( SystemFilter.class, PRIORITY_DEFAULT); } else if ( am.isAnnotationPresent( RequireAdminUserAccess.class ) ) { - featureContext.register( SystemFilter.AdminUserFilter.class ); + featureContext.register( SystemFilter.AdminUserFilter.class, PRIORITY_DEFAULT); } else if ( am.isAnnotationPresent( CheckPermissionsForPath.class ) ) { - featureContext.register( PathPermissionsFilter.class ); + featureContext.register( PathPermissionsFilter.class, PRIORITY_DEFAULT); } } @@ -228,6 +241,55 @@ public class SecuredResourceFilterFactory implements DynamicFeature { } @Resource + public static class SysadminLocalhostFilter extends AbstractFilter { + + @Inject + public SysadminLocalhostFilter( UriInfo uriInfo ) { + super(uriInfo); + } + + @Override + public void authorize( ContainerRequestContext request ) { + if (logger.isTraceEnabled()) { + logger.trace("SysadminLocalhostFilter.authorize"); + } + + if (!request.getSecurityContext().isUserInRole( ROLE_SERVICE_ADMIN )) { + // not a sysadmin request + return; + } + + boolean isLocalhost = false; + try { + byte[] address = InetAddress.getByName(request.getUriInfo().getBaseUri().getHost()).getAddress(); + if (address[0] == 127) { + // loopback address + isLocalhost = true; + } else if (address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0) { + // 0.0.0.0, used for requests like curl 0:8080 + isLocalhost = true; + } else { + // everything else + isLocalhost = false; + } + } + catch (Exception e) { + // couldn't parse host, so assume not localhost + logger.error("Unable to parse host for sysadmin request, request rejected: path = {}", + request.getUriInfo().getPath()); + } + + if (!isLocalhost) { + throw mappableSecurityException( "unauthorized", "No remote sysadmin access authorized" ); + } + + if (logger.isTraceEnabled()) { + logger.trace("SysadminLocalhostFilter.authorize - leaving"); + } + } + } + + @Resource public static class OrganizationFilter extends AbstractFilter { @Inject
