Beispiel #1
0
 public BaseMessage setUser(User user) {
   if (user == null) {
     this.setUser(Principals.nobodyUser());
   } else {
     this.userId = user.getName();
     this.effectiveUserId =
         user.isSystemAdmin() ? Principals.systemUser().getName() : user.getName();
   }
   return this;
 }
Beispiel #2
0
  /**
   * Just checks the basic S3 groups for membership of the userId. Caller must ensure that the
   * userId is a valid ID in the system. That is outside the scope of this method.
   *
   * @param userId
   * @param group
   * @return
   */
  public static boolean isUserMember(String userId, ObjectStorageProperties.S3_GROUP group) {
    if (group == null) {
      return false;
    }

    if (ObjectStorageProperties.S3_GROUP.ALL_USERS_GROUP.equals(group)) {
      return true;
    }

    if (ObjectStorageProperties.S3_GROUP.AUTHENTICATED_USERS_GROUP.equals(group)
        && !Strings.isNullOrEmpty(userId)
        && !userId.equals(Principals.nobodyUser().getUserId())) {
      return true;
    }

    boolean isSystemAdmin = false;
    try {
      isSystemAdmin =
          (Principals.systemUser().getUserId().equals(userId)
              || Accounts.lookupSystemAdmin().getUserId().equals(userId));
    } catch (AuthException e) {
      // Fall through
      LOG.debug(
          "Got auth exception trying to lookup system admin user for group membership check in ec2-bundle-read",
          e);
    }

    boolean isAWSExecReadUser = false;
    try {
      isAWSExecReadUser = Accounts.lookupAwsExecReadAdmin(false).getUserId().equals(userId);
    } catch (AuthException e) {
      // Fall through
      LOG.debug(
          "Got auth exception trying to lookup aws-exec-read admin user for group membership check in ec2-bundle-read",
          e);
    }

    if (ObjectStorageProperties.S3_GROUP.AWS_EXEC_READ.equals(group) && isAWSExecReadUser) {
      return true;
    }

    // System only (or euca/admin) in the ec2-bundle-read group
    if (ObjectStorageProperties.S3_GROUP.EC2_BUNDLE_READ.equals(group) && isSystemAdmin) {
      return true;
    }

    // System or euca/admin only in logging
    if (ObjectStorageProperties.S3_GROUP.LOGGING_GROUP.equals(group) && isSystemAdmin) {
      return true;
    }

    return false;
  }
  /*
   * Simply determines if the userId is a member of the groupId, very simplistic only for ALL_USERS and AUTHENTICATED_USERS, not arbitrary groups.
   * Arbitrary groups are not yet supported in Walrus bucket policies/IAM policies.
   */
  public static boolean isUserMember(String userId, String groupId) {
    if (groupId == null) {
      return false;
    }

    if (groupId.equals(WalrusProperties.ALL_USERS_GROUP)) {
      return true;
    }

    if (groupId.equals(WalrusProperties.AUTHENTICATED_USERS_GROUP)
        && userId != null
        && !"".equals(userId)
        && !userId.equals(Principals.nobodyUser().getUserId())) {
      return true;
    }

    return false;
  }
  /**
   * Evaluates the authorization for the operation requested, evaluates IAM, ACL, and bucket policy
   * (bucket policy not yet supported).
   *
   * @param request
   * @param bucketResourceEntity
   * @param objectResourceEntity
   * @param resourceAllocationSize the size for the quota check(s) if applicable
   * @return
   */
  public <T extends ObjectStorageRequestType> boolean operationAllowed(
      @Nonnull T request,
      @Nullable final S3AccessControlledEntity bucketResourceEntity,
      @Nullable final S3AccessControlledEntity objectResourceEntity,
      long resourceAllocationSize)
      throws IllegalArgumentException {
    /*
     * Process the operation's authz requirements based on the request type annotations
     */
    Ats requestAuthzProperties = Ats.from(request);
    ObjectStorageProperties.Permission[] requiredBucketACLPermissions = null;
    ObjectStorageProperties.Permission[] requiredObjectACLPermissions = null;
    Boolean allowOwnerOnly = null;
    RequiresACLPermission requiredACLs = requestAuthzProperties.get(RequiresACLPermission.class);
    if (requiredACLs != null) {
      requiredBucketACLPermissions = requiredACLs.bucket();
      requiredObjectACLPermissions = requiredACLs.object();
      allowOwnerOnly = requiredACLs.ownerOnly();
    } else {
      // No ACL annotation is ok, maybe a admin only op
    }

    String[] requiredActions = null;
    RequiresPermission perms = requestAuthzProperties.get(RequiresPermission.class);
    if (perms != null) {
      requiredActions = perms.value();
    }

    Boolean allowAdmin = (requestAuthzProperties.get(AdminOverrideAllowed.class) != null);
    Boolean allowOnlyAdmin =
        (requestAuthzProperties.get(AdminOverrideAllowed.class) != null)
            && requestAuthzProperties.get(AdminOverrideAllowed.class).adminOnly();

    // Must have at least one of: admin-only, owner-only, ACL, or IAM.
    if (requiredBucketACLPermissions == null
        && requiredObjectACLPermissions == null
        && requiredActions == null
        && !allowAdmin) {
      // Insufficient permission set on the message type.
      LOG.error(
          "Insufficient permission annotations on type: "
              + request.getClass().getName()
              + " cannot evaluate authorization");
      return false;
    }

    String resourceType = null;
    if (requestAuthzProperties.get(ResourceType.class) != null) {
      resourceType = requestAuthzProperties.get(ResourceType.class).value();
    }

    // Use these variables to isolate where all the AuthExceptions can happen on account/user
    // lookups
    User requestUser = null;
    String securityToken = null;
    Account requestAccount = null;
    AuthContextSupplier authContext = null;
    try {
      // Use context if available as it saves a DB lookup
      try {
        Context ctx = Contexts.lookup(request.getCorrelationId());
        requestUser = ctx.getUser();
        securityToken = ctx.getSecurityToken();
        requestAccount = requestUser.getAccount();
        authContext = ctx.getAuthContext();
      } catch (NoSuchContextException e) {
        requestUser = null;
        securityToken = null;
        requestAccount = null;
        authContext = null;
      }

      // This is not an expected path, but if no context found use the request credentials itself
      if (requestUser == null && !Strings.isNullOrEmpty(request.getEffectiveUserId())) {
        requestUser = Accounts.lookupUserById(request.getEffectiveUserId());
        requestAccount = requestUser.getAccount();
      }

      if (requestUser == null) {
        if (!Strings.isNullOrEmpty(request.getAccessKeyID())) {
          if (securityToken != null) {
            requestUser = SecurityTokenManager.lookupUser(request.getAccessKeyID(), securityToken);
          } else {
            requestUser = Accounts.lookupUserByAccessKeyId(request.getAccessKeyID());
          }
          requestAccount = requestUser.getAccount();
        } else {
          // Set to anonymous user since all else failed
          requestUser = Principals.nobodyUser();
          requestAccount = requestUser.getAccount();
        }
      }
    } catch (AuthException e) {
      LOG.error(
          "Failed to get user for request, cannot verify authorization: " + e.getMessage(), e);
      return false;
    }

    if (allowAdmin && requestUser.isSystemAdmin()) {
      // Admin override
      return true;
    }

    if (authContext == null) {
      authContext =
          Permissions.createAuthContextSupplier(
              requestUser, Collections.<String, String>emptyMap());
    }

    Account resourceOwnerAccount = null;
    if (resourceType == null) {
      LOG.error("No resource type found in request class annotations, cannot process.");
      return false;
    } else {
      try {
        // Ensure we have the proper resource entities present and get owner info
        if (PolicySpec.S3_RESOURCE_BUCKET.equals(resourceType)) {
          // Get the bucket owner.
          if (bucketResourceEntity == null) {
            LOG.error(
                "Could not check access for operation due to no bucket resource entity found");
            return false;
          } else {
            resourceOwnerAccount =
                Accounts.lookupAccountByCanonicalId(bucketResourceEntity.getOwnerCanonicalId());
          }
        } else if (PolicySpec.S3_RESOURCE_OBJECT.equals(resourceType)) {
          if (objectResourceEntity == null) {
            LOG.error(
                "Could not check access for operation due to no object resource entity found");
            return false;
          } else {
            resourceOwnerAccount =
                Accounts.lookupAccountByCanonicalId(objectResourceEntity.getOwnerCanonicalId());
          }
        }
      } catch (AuthException e) {
        LOG.error("Exception caught looking up resource owner. Disallowing operation.", e);
        return false;
      }
    }

    // Get the resourceId based on IAM resource type
    String resourceId = null;
    if (resourceId == null) {
      if (PolicySpec.S3_RESOURCE_BUCKET.equals(resourceType)) {
        resourceId = request.getBucket();
      } else if (PolicySpec.S3_RESOURCE_OBJECT.equals(resourceType)) {
        resourceId = request.getFullResource();
      }
    }

    if (allowAdmin
        && requestUser.isSystemUser()
        && iamPermissionsAllow(
            authContext, requiredActions, resourceType, resourceId, resourceAllocationSize)) {
      // Admin override
      return true;
    }

    if (requiredBucketACLPermissions == null && requiredObjectACLPermissions == null) {
      throw new IllegalArgumentException(
          "No requires-permission actions found in request class annotations, cannot process.");
    }

    /* ACL Checks: Is the user's account allowed? */
    Boolean aclAllow = false;
    if (requiredBucketACLPermissions != null && requiredBucketACLPermissions.length > 0) {
      // Check bucket ACLs

      if (bucketResourceEntity == null) {
        // There are bucket ACL requirements but no bucket entity to check. fail.
        // Don't bother with other checks, this is an invalid state
        LOG.error("Null bucket resource, cannot evaluate bucket ACL");
        return false;
      }

      // Evaluate the bucket ACL, any matching grant gives permission
      for (ObjectStorageProperties.Permission permission : requiredBucketACLPermissions) {
        aclAllow =
            aclAllow || bucketResourceEntity.can(permission, requestAccount.getCanonicalId());
      }
    }

    // Check object ACLs, if any
    if (requiredObjectACLPermissions != null && requiredObjectACLPermissions.length > 0) {
      if (objectResourceEntity == null) {
        // There are object ACL requirements but no object entity to check. fail.
        // Don't bother with other checks, this is an invalid state
        LOG.error("Null bucket resource, cannot evaluate bucket ACL");
        return false;
      }
      for (ObjectStorageProperties.Permission permission : requiredObjectACLPermissions) {
        aclAllow =
            aclAllow || objectResourceEntity.can(permission, requestAccount.getCanonicalId());
      }
    }

    /* Resource owner only? if so, override any previous acl decisions
     * It is not expected that owneronly is set as well as other ACL permissions,
     * Regular owner permissions (READ, WRITE, READ_ACP, WRITE_ACP) are handled by the regular acl checks.
     * OwnerOnly should be only used for operations not covered by the other Permissions (e.g. logging, or versioning)
     */
    aclAllow =
        (allowOwnerOnly
            ? resourceOwnerAccount.getAccountNumber().equals(requestAccount.getAccountNumber())
            : aclAllow);
    if (aclAllow && isUserAnonymous(requestUser)) {
      // Skip the IAM checks for anonymous access since they will always fail and aren't valid for
      // anonymous users.
      return true;
    } else {
      Boolean iamAllow =
          iamPermissionsAllow(
              authContext, requiredActions, resourceType, resourceId, resourceAllocationSize);
      // Must have both acl and iam allow (account & user)
      return aclAllow && iamAllow;
    }
  }
 /**
  * Does the current request have an authenticated user? Or is it anonymous?
  *
  * @return
  */
 protected static boolean isUserAnonymous(User usr) {
   return Principals.nobodyUser().equals(usr);
 }