Search in sources :

Example 1 with ResourceType

use of com.netflix.spinnaker.fiat.model.resources.ResourceType in project fiat by spinnaker.

the class FiatPermissionEvaluator method permissionContains.

private boolean permissionContains(UserPermission.View permission, String resourceName, ResourceType resourceType, Authorization authorization) {
    if (permission == null) {
        return false;
    }
    if (permission.isAdmin()) {
        // grant access regardless of whether an explicit permission to the resource exists
        return true;
    }
    Function<Set<? extends Authorizable>, Boolean> containsAuth = resources -> resources.stream().anyMatch(view -> {
        Set<Authorization> authorizations = Optional.ofNullable(view.getAuthorizations()).orElse(Collections.emptySet());
        return view.getName().equalsIgnoreCase(resourceName) && authorizations.contains(authorization);
    });
    if (resourceType.equals(ResourceType.ACCOUNT)) {
        boolean authorized = containsAuth.apply(permission.getAccounts());
        // Todo(jonsie): Debug transitory access denied issue, remove when not necessary
        if (!authorized) {
            Map<String, Set<Authorization>> accounts = permission.getAccounts().stream().collect(Collectors.toMap(Account.View::getName, Account.View::getAuthorizations));
            log.debug("Authorization={} denied to account={} for user permission={}, found={}", authorization.toString(), resourceName, permission.getName(), accounts.toString());
        }
        return authorized;
    } else if (resourceType.equals(ResourceType.APPLICATION)) {
        boolean applicationHasPermissions = permission.getApplications().stream().anyMatch(a -> a.getName().equalsIgnoreCase(resourceName));
        if (!applicationHasPermissions && permission.isAllowAccessToUnknownApplications()) {
            // allow access to any applications w/o explicit permissions
            return true;
        }
        return permission.isLegacyFallback() || containsAuth.apply(permission.getApplications());
    } else if (resourceType.equals(ResourceType.SERVICE_ACCOUNT)) {
        return permission.getServiceAccounts().stream().anyMatch(view -> view.getName().equalsIgnoreCase(resourceName));
    } else if (resourceType.equals(ResourceType.BUILD_SERVICE)) {
        return permission.isLegacyFallback() || containsAuth.apply(permission.getBuildServices());
    } else if (permission.getExtensionResources() != null && permission.getExtensionResources().containsKey(resourceType)) {
        val extensionResources = permission.getExtensionResources().get(resourceType);
        return permission.isLegacyFallback() || containsAuth.apply(extensionResources);
    } else {
        return false;
    }
}
Also used : Arrays(java.util.Arrays) Authorizable(com.netflix.spinnaker.fiat.model.resources.Authorizable) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Autowired(org.springframework.beans.factory.annotation.Autowired) Callable(java.util.concurrent.Callable) ExponentialBackOff(org.springframework.util.backoff.ExponentialBackOff) Cache(com.github.benmanes.caffeine.cache.Cache) Id(com.netflix.spectator.api.Id) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) StringUtils(org.apache.commons.lang3.StringUtils) Map(java.util.Map) UserDetails(org.springframework.security.core.userdetails.UserDetails) SecurityContextHolder(org.springframework.security.core.context.SecurityContextHolder) Nonnull(javax.annotation.Nonnull) Caffeine(com.github.benmanes.caffeine.cache.Caffeine) AuthenticatedRequest(com.netflix.spinnaker.security.AuthenticatedRequest) BackOffExecution(org.springframework.util.backoff.BackOffExecution) lombok.val(lombok.val) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) Set(java.util.Set) PermissionEvaluator(org.springframework.security.access.PermissionEvaluator) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) TimeUnit(java.util.concurrent.TimeUnit) HttpStatus(org.springframework.http.HttpStatus) Slf4j(lombok.extern.slf4j.Slf4j) Component(org.springframework.stereotype.Component) CaffeineStatsCounter(com.netflix.spinnaker.kork.telemetry.caffeine.CaffeineStatsCounter) RetrofitError(retrofit.RetrofitError) IntegrationException(com.netflix.spinnaker.kork.exceptions.IntegrationException) Registry(com.netflix.spectator.api.Registry) Optional(java.util.Optional) Account(com.netflix.spinnaker.fiat.model.resources.Account) UserPermission(com.netflix.spinnaker.fiat.model.UserPermission) Authorization(com.netflix.spinnaker.fiat.model.Authorization) Authentication(org.springframework.security.core.Authentication) Collections(java.util.Collections) Authorization(com.netflix.spinnaker.fiat.model.Authorization) lombok.val(lombok.val) Account(com.netflix.spinnaker.fiat.model.resources.Account) Set(java.util.Set) Authorizable(com.netflix.spinnaker.fiat.model.resources.Authorizable) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 2 with ResourceType

use of com.netflix.spinnaker.fiat.model.resources.ResourceType in project fiat by spinnaker.

the class RedisPermissionsRepository method getFromRedis.

private Optional<UserPermission> getFromRedis(@NonNull String id) {
    try {
        TimeoutContext timeoutContext = new TimeoutContext(String.format("getPermission for user: %s", id), clock, configProps.getRepository().getGetPermissionTimeout());
        boolean userExists = UNRESTRICTED.equals(id) || redisRead(timeoutContext, c -> c.sismember(allUsersKey, SafeEncoder.encode(id)));
        if (!userExists) {
            log.debug("request for user {} not found in redis", id);
            return Optional.empty();
        }
        UserPermission userPermission = new UserPermission().setId(id);
        for (Resource r : resources) {
            ResourceType resourceType = r.getResourceType();
            Map<String, Resource> resourcePermissions = getUserResourceMapFromRedis(id, resourceType);
            if (resourcePermissions != null && !resourcePermissions.isEmpty()) {
                userPermission.addResources(resourcePermissions.values());
            }
        }
        if (!UNRESTRICTED.equals(id)) {
            userPermission.setAdmin(redisRead(timeoutContext, c -> c.sismember(adminKey, SafeEncoder.encode(id))));
            userPermission.merge(getUnrestrictedUserPermission());
        }
        return Optional.of(userPermission);
    } catch (Throwable t) {
        String message = String.format("Storage exception reading %s entry.", id);
        log.error(message, t);
        if (t instanceof SpinnakerException) {
            throw (SpinnakerException) t;
        }
        throw new PermissionReadException(message, t);
    }
}
Also used : java.util(java.util) net.jpountz.lz4(net.jpountz.lz4) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) BinaryJedisCommands(redis.clients.jedis.commands.BinaryJedisCommands) SafeEncoder(redis.clients.jedis.util.SafeEncoder) redis.clients.jedis(redis.clients.jedis) Duration(java.time.Duration) TypeReference(com.fasterxml.jackson.core.type.TypeReference) RetryRegistry(io.github.resilience4j.retry.RetryRegistry) RedisClientDelegate(com.netflix.spinnaker.kork.jedis.RedisClientDelegate) Caffeine(com.github.benmanes.caffeine.cache.Caffeine) LoadingCache(com.github.benmanes.caffeine.cache.LoadingCache) NonNull(lombok.NonNull) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) IOException(java.io.IOException) UnrestrictedResourceConfig(com.netflix.spinnaker.fiat.config.UnrestrictedResourceConfig) Instant(java.time.Instant) Collectors(java.util.stream.Collectors) ExecutionException(java.util.concurrent.ExecutionException) Resource(com.netflix.spinnaker.fiat.model.resources.Resource) Slf4j(lombok.extern.slf4j.Slf4j) IntegrationException(com.netflix.spinnaker.kork.exceptions.IntegrationException) ForkJoinPool(java.util.concurrent.ForkJoinPool) Role(com.netflix.spinnaker.fiat.model.resources.Role) Clock(java.time.Clock) SpinnakerException(com.netflix.spinnaker.kork.exceptions.SpinnakerException) UserPermission(com.netflix.spinnaker.fiat.model.UserPermission) SpinnakerException(com.netflix.spinnaker.kork.exceptions.SpinnakerException) Resource(com.netflix.spinnaker.fiat.model.resources.Resource) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) UserPermission(com.netflix.spinnaker.fiat.model.UserPermission)

Example 3 with ResourceType

use of com.netflix.spinnaker.fiat.model.resources.ResourceType in project fiat by spinnaker.

the class RedisPermissionsRepository method put.

@Override
public RedisPermissionsRepository put(@NonNull UserPermission permission) {
    String userId = permission.getId();
    byte[] bUserId = SafeEncoder.encode(userId);
    List<ResourceType> resourceTypes = resources.stream().map(Resource::getResourceType).collect(Collectors.toList());
    Map<ResourceType, Map<String, Resource>> resourceTypeToRedisValue = new HashMap<>(resourceTypes.size());
    permission.getAllResources().forEach(resource -> {
        resourceTypeToRedisValue.computeIfAbsent(resource.getResourceType(), key -> new HashMap<>()).put(resource.getName(), resource);
    });
    try {
        Set<Role> existingRoles = new HashSet<>(getUserRoleMapFromRedis(userId).values());
        // These updates are pre-prepared to reduce work done during the multi-key pipeline
        List<PutUpdateData> updateData = new ArrayList<>();
        for (ResourceType rt : resourceTypes) {
            Map<String, Resource> redisValue = resourceTypeToRedisValue.get(rt);
            byte[] userResourceKey = userKey(userId, rt);
            PutUpdateData pud = new PutUpdateData();
            pud.userResourceKey = userResourceKey;
            if (redisValue == null || redisValue.size() == 0) {
                pud.compressedData = null;
            } else {
                pud.compressedData = lz4Compressor.compress(objectMapper.writeValueAsBytes(redisValue));
            }
            updateData.add(pud);
        }
        AtomicReference<Response<List<String>>> serverTime = new AtomicReference<>();
        redisClientDelegate.withMultiKeyPipeline(pipeline -> {
            if (permission.isAdmin()) {
                pipeline.sadd(adminKey, bUserId);
            } else {
                pipeline.srem(adminKey, bUserId);
            }
            permission.getRoles().forEach(role -> pipeline.sadd(roleKey(role), bUserId));
            existingRoles.stream().filter(it -> !permission.getRoles().contains(it)).forEach(role -> pipeline.srem(roleKey(role), bUserId));
            for (PutUpdateData pud : updateData) {
                if (pud.compressedData == null) {
                    pipeline.del(pud.userResourceKey);
                } else {
                    byte[] tempKey = SafeEncoder.encode(UUID.randomUUID().toString());
                    pipeline.set(tempKey, pud.compressedData);
                    pipeline.rename(tempKey, pud.userResourceKey);
                }
            }
            serverTime.set(pipeline.time());
            pipeline.sadd(allUsersKey, bUserId);
            pipeline.sync();
        });
        if (UNRESTRICTED.equals(userId)) {
            String lastModified = serverTime.get().get().get(0);
            redisClientDelegate.withCommandsClient(c -> {
                log.debug("set last modified for user {} to {}", UNRESTRICTED, lastModified);
                c.set(unrestrictedLastModifiedKey(), lastModified);
            });
        }
    } catch (Exception e) {
        log.error("Storage exception writing {} entry.", userId, e);
    }
    return this;
}
Also used : java.util(java.util) net.jpountz.lz4(net.jpountz.lz4) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) BinaryJedisCommands(redis.clients.jedis.commands.BinaryJedisCommands) SafeEncoder(redis.clients.jedis.util.SafeEncoder) redis.clients.jedis(redis.clients.jedis) Duration(java.time.Duration) TypeReference(com.fasterxml.jackson.core.type.TypeReference) RetryRegistry(io.github.resilience4j.retry.RetryRegistry) RedisClientDelegate(com.netflix.spinnaker.kork.jedis.RedisClientDelegate) Caffeine(com.github.benmanes.caffeine.cache.Caffeine) LoadingCache(com.github.benmanes.caffeine.cache.LoadingCache) NonNull(lombok.NonNull) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) IOException(java.io.IOException) UnrestrictedResourceConfig(com.netflix.spinnaker.fiat.config.UnrestrictedResourceConfig) Instant(java.time.Instant) Collectors(java.util.stream.Collectors) ExecutionException(java.util.concurrent.ExecutionException) Resource(com.netflix.spinnaker.fiat.model.resources.Resource) Slf4j(lombok.extern.slf4j.Slf4j) IntegrationException(com.netflix.spinnaker.kork.exceptions.IntegrationException) ForkJoinPool(java.util.concurrent.ForkJoinPool) Role(com.netflix.spinnaker.fiat.model.resources.Role) Clock(java.time.Clock) SpinnakerException(com.netflix.spinnaker.kork.exceptions.SpinnakerException) UserPermission(com.netflix.spinnaker.fiat.model.UserPermission) Resource(com.netflix.spinnaker.fiat.model.resources.Resource) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) AtomicReference(java.util.concurrent.atomic.AtomicReference) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) IntegrationException(com.netflix.spinnaker.kork.exceptions.IntegrationException) SpinnakerException(com.netflix.spinnaker.kork.exceptions.SpinnakerException) Role(com.netflix.spinnaker.fiat.model.resources.Role)

Example 4 with ResourceType

use of com.netflix.spinnaker.fiat.model.resources.ResourceType in project fiat by spinnaker.

the class FiatPermissionEvaluator method hasPermission.

public boolean hasPermission(String username, Serializable resourceName, String resourceType, Object authorization) {
    if (!fiatStatus.isEnabled()) {
        return true;
    }
    if (resourceName == null || resourceType == null || authorization == null) {
        log.warn("Permission denied because at least one of the required arguments was null. resourceName={}, resourceType={}, " + "authorization={}", resourceName, resourceType, authorization);
        return false;
    }
    ResourceType r = ResourceType.parse(resourceType);
    Authorization a = null;
    // Service accounts don't have read/write authorizations.
    if (!r.equals(ResourceType.SERVICE_ACCOUNT)) {
        a = Authorization.valueOf(authorization.toString());
    }
    if (a == Authorization.CREATE) {
        throw new IllegalArgumentException("This method should not be called for `CREATE`. Please call the other implementation");
    }
    if (r.equals(ResourceType.APPLICATION) && StringUtils.isNotEmpty(resourceName.toString())) {
        resourceName = resourceName.toString();
    }
    UserPermission.View permission = getPermission(username);
    boolean hasPermission = permissionContains(permission, resourceName.toString(), r, a);
    authorizationFailure.set(hasPermission ? null : new AuthorizationFailure(a, r, resourceName.toString()));
    if (permission != null && permission.isLegacyFallback() && hasPermission) {
        // log any access that was granted as part of a legacy fallback.
        if (a == Authorization.READ) {
            // purposely logging at 'debug' as 'READ' will be sufficiently more verbose
            log.debug("Legacy fallback granted {} access (type: {}, resource: {})", a, r, resourceName);
        } else {
            log.warn("Legacy fallback granted {} access (type: {}, resource: {})", a, r, resourceName);
        }
    }
    return hasPermission;
}
Also used : Authorization(com.netflix.spinnaker.fiat.model.Authorization) ResourceType(com.netflix.spinnaker.fiat.model.resources.ResourceType) UserPermission(com.netflix.spinnaker.fiat.model.UserPermission)

Aggregations

UserPermission (com.netflix.spinnaker.fiat.model.UserPermission)4 ResourceType (com.netflix.spinnaker.fiat.model.resources.ResourceType)4 Caffeine (com.github.benmanes.caffeine.cache.Caffeine)3 IntegrationException (com.netflix.spinnaker.kork.exceptions.IntegrationException)3 AtomicReference (java.util.concurrent.atomic.AtomicReference)3 Function (java.util.function.Function)3 Collectors (java.util.stream.Collectors)3 Slf4j (lombok.extern.slf4j.Slf4j)3 TypeReference (com.fasterxml.jackson.core.type.TypeReference)2 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 LoadingCache (com.github.benmanes.caffeine.cache.LoadingCache)2 UnrestrictedResourceConfig (com.netflix.spinnaker.fiat.config.UnrestrictedResourceConfig)2 Authorization (com.netflix.spinnaker.fiat.model.Authorization)2 Resource (com.netflix.spinnaker.fiat.model.resources.Resource)2 Role (com.netflix.spinnaker.fiat.model.resources.Role)2 SpinnakerException (com.netflix.spinnaker.kork.exceptions.SpinnakerException)2 RedisClientDelegate (com.netflix.spinnaker.kork.jedis.RedisClientDelegate)2 RetryRegistry (io.github.resilience4j.retry.RetryRegistry)2 IOException (java.io.IOException)2 Clock (java.time.Clock)2