keycloak-d4science-spi-parent/avatar-realm-resource/src/main/java/org/gcube/keycloak/avatar/storage/s3/MinioAvatarStorageProvider....

126 lines
4.1 KiB
Java

package org.gcube.keycloak.avatar.storage.s3;
import java.io.InputStream;
import org.gcube.keycloak.avatar.storage.AvatarStorageProvider;
import org.jboss.logging.Logger;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.ErrorResponseException;
public class MinioAvatarStorageProvider implements AvatarStorageProvider {
private static final Logger logger = Logger.getLogger(MinioAvatarStorageProvider.class);
private static final String AVATAR_FOLDER = "avatar";
private static final int CHUNK_SIZE = 5242880;
private final Configuration configuration;
public MinioAvatarStorageProvider(Configuration configuration) {
this.configuration = configuration;
}
@Override
public void saveAvatarImage(RealmModel realmModel, UserModel userModel, InputStream input) {
execute(minioClient -> minioClient
.putObject(PutObjectArgs.builder().bucket(configuration.rootBucket).object(getAvatarFilePath(
realmModel, userModel)).stream(input, -1, CHUNK_SIZE).build()));
}
@Override
public InputStream loadAvatarImage(RealmModel realmModel, UserModel userModel) {
logger.debug("Loading avatar from S3");
return execute(new Executor<InputStream>() {
public InputStream execute(MinioClient minioClient) throws Exception {
try {
return minioClient
.getObject(GetObjectArgs.builder().bucket(configuration.rootBucket).object(getAvatarFilePath(
realmModel, userModel)).build());
} catch (ErrorResponseException e) {
if (e.response().code() == 404) {
logger.debugf("Avatar file not found for user '%s' in realm '%s'", userModel.getUsername(), realmModel.getName());
return null;
} else {
throw e;
}
}
};
});
}
@Override
public void deleteAvatarImage(RealmModel realmModel, UserModel userModel) {
logger.debug("Deeleting avatar from S3");
execute(minioClient -> {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(configuration.rootBucket)
.object(getAvatarFilePath(realmModel, userModel)).build());
return true;
});
}
@Override
public void close() {
// NOOP
}
public String getAvatarFilePath(RealmModel realmModel, UserModel userModel) {
return AVATAR_FOLDER + "/" + realmModel.getName() + "/" + userModel.getUsername();
}
public <T> T execute(Executor<T> executor) {
try {
MinioClient minioClient = MinioClient.builder()
.endpoint(configuration.getServerUrl())
.credentials(configuration.getAccessKey(), configuration.getSecretKey())
.build();
return executor.execute(minioClient);
} catch (Exception e) {
throw new RuntimeException("Executing operation on S3 persistnce", e);
}
}
public static class Configuration {
private final String serverUrl;
private final String accessKey;
private final String secretKey;
private final String rootBucket;
public Configuration(String serverUrl, String accessKey, String secretKey, String rootBucket) {
this.serverUrl = serverUrl;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.rootBucket = rootBucket;
}
public String getServerUrl() {
return serverUrl;
}
public String getAccessKey() {
return accessKey;
}
public String getSecretKey() {
return secretKey;
}
public String getRootBucket() {
return rootBucket;
}
}
public interface Executor<T> {
T execute(MinioClient minioClient) throws Exception;
}
}