use of com.netflix.spinnaker.fiat.model.UserPermission in project fiat by spinnaker.
the class RolesController method putUserPermission.
@RequestMapping(value = "/{userId:.+}", method = RequestMethod.PUT)
public void putUserPermission(@PathVariable String userId, @RequestBody @NonNull List<String> externalRoles) {
List<Role> convertedRoles = externalRoles.stream().map(extRole -> new Role().setSource(Role.Source.EXTERNAL).setName(extRole)).collect(Collectors.toList());
ExternalUser extUser = new ExternalUser().setId(ControllerSupport.convert(userId)).setExternalRoles(convertedRoles);
try {
UserPermission userPermission = permissionsResolver.resolveAndMerge(extUser);
log.debug("Updated user permissions (userId: {}, roles: {}, suppliedExternalRoles: {})", userId, userPermission.getRoles().stream().map(Role::getName).collect(Collectors.toList()), externalRoles);
permissionsRepository.put(userPermission);
} catch (PermissionResolutionException pre) {
throw new UserPermissionModificationException(pre);
}
}
use of com.netflix.spinnaker.fiat.model.UserPermission in project fiat by spinnaker.
the class RedisPermissionsRepository method getUnrestrictedUserPermission.
private UserPermission getUnrestrictedUserPermission() {
String serverLastModified = NO_LAST_MODIFIED;
byte[] bServerLastModified = redisRead(new TimeoutContext("checkLastModified", clock, configProps.getRepository().getCheckLastModifiedTimeout()), c -> c.get(SafeEncoder.encode(unrestrictedLastModifiedKey())));
if (bServerLastModified == null || bServerLastModified.length == 0) {
log.debug("no last modified time available in redis for user {} using default of {}", UNRESTRICTED, NO_LAST_MODIFIED);
} else {
serverLastModified = SafeEncoder.encode(bServerLastModified);
}
try {
UserPermission userPermission = unrestrictedPermission.get(serverLastModified);
if (userPermission != null && !serverLastModified.equals(NO_LAST_MODIFIED)) {
fallbackLastModified.set(serverLastModified);
}
return userPermission;
} catch (Throwable ex) {
log.error("failed reading user {} from cache for key {}", UNRESTRICTED, serverLastModified, ex);
String fallback = fallbackLastModified.get();
if (fallback != null) {
UserPermission fallbackPermission = unrestrictedPermission.getIfPresent(fallback);
if (fallbackPermission != null) {
log.warn("serving fallback permission for user {} from key {} as {}", UNRESTRICTED, fallback, fallbackPermission);
return fallbackPermission;
}
log.warn("no fallback entry remaining in cache for key {}", fallback);
}
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
throw new IntegrationException(ex);
}
}
use of com.netflix.spinnaker.fiat.model.UserPermission 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);
}
}
use of com.netflix.spinnaker.fiat.model.UserPermission 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;
}
use of com.netflix.spinnaker.fiat.model.UserPermission in project fiat by spinnaker.
the class AuthorizeController method getUserPermissionOrDefault.
private Optional<UserPermission> getUserPermissionOrDefault(String userId) {
String authenticatedUserId = AuthenticatedRequest.getSpinnakerUser().orElse(null);
UserPermission userPermission = permissionsRepository.get(ControllerSupport.convert(userId)).orElse(null);
if (userPermission != null) {
registry.counter(getUserPermissionCounterId.withTag("success", true).withTag("fallback", false)).increment();
return Optional.of(userPermission);
}
/*
* User does not have any stored permissions but the requested userId matches the
* X-SPINNAKER-USER header value, likely a request that has not transited gate.
*/
if (userId.equalsIgnoreCase(authenticatedUserId) && (configProps.isAllowPermissionResolverFallback() || configProps.isDefaultToUnrestrictedUser())) {
Optional<UserPermission> unrestricted = permissionsRepository.get(UnrestrictedResourceConfig.UNRESTRICTED_USERNAME);
if (!unrestricted.isPresent()) {
log.error("Error resolving fallback permissions: lookup of unrestricted user failed. Access to anonymous resources will fail");
}
/*
* First, attempt to resolve via the permissionsResolver.
*/
if (configProps.isAllowPermissionResolverFallback()) {
UserPermission resolvedUserPermission = permissionsResolver.resolve(ControllerSupport.convert(authenticatedUserId));
if (resolvedUserPermission.getAllResources().stream().anyMatch(Objects::nonNull)) {
log.debug("Resolved fallback permissions for user {}", authenticatedUserId);
userPermission = resolvedUserPermission;
unrestricted.ifPresent(userPermission::merge);
}
}
/*
* If user permissions are not resolved, default to those of the unrestricted user.
*/
if (userPermission == null && configProps.isDefaultToUnrestrictedUser()) {
if (unrestricted.isPresent()) {
log.debug("Falling back to unrestricted user permissions for user {}", authenticatedUserId);
userPermission = new UserPermission().setId(authenticatedUserId).merge(unrestricted.get());
}
}
log.debug("Returning fallback permissions (user: {}, accounts: {}, roles: {})", userId, (userPermission != null) ? userPermission.getAccounts() : Collections.emptyList(), (userPermission != null) ? userPermission.getRoles().stream().map(Role::getName).collect(Collectors.toList()) : Collections.emptyList());
} else {
log.debug("Not populating fallback. userId: {}, authenticatedUserId: {}, allowPermissionResolverFallback: {}, defaultToUnrestrictedUser: {}", userId, authenticatedUserId, configProps.isAllowPermissionResolverFallback(), configProps.isDefaultToUnrestrictedUser());
}
registry.counter(getUserPermissionCounterId.withTag("success", userPermission != null).withTag("fallback", true)).increment();
return Optional.ofNullable(userPermission);
}
Aggregations