CredentialService
using Polly;
using Relativity.Transfer.Dto;
using Relativity.Transfer.Resources;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace Relativity.Transfer
{
internal class CredentialService : RestServiceBase, ICredentialService
{
public CredentialService(RelativityConnectionInfo connectionInfo)
: base(connectionInfo)
{
}
public CredentialService(RelativityConnectionInfo connectionInfo, ITransferLog log)
: base(connectionInfo, log)
{
}
public CredentialService(RelativityConnectionInfo connectionInfo, ITransferLog log, int maxRetryAttempts, double timeoutSeconds)
: base(connectionInfo, log, maxRetryAttempts, timeoutSeconds)
{
}
public Task<IEnumerable<Credential>> GetCredentialsAsync(CancellationToken token)
{
return GetCredentialsAsync(null, token);
}
public async Task<IEnumerable<Credential>> GetCredentialsAsync(string condition, CancellationToken token)
{
using (MemoryCacheRepository cacheRepository = new MemoryCacheRepository(TransferCache.Default)) {
string key = CoreMemoryCacheKeys.CreateCredentialKey(base.ConnectionInfo.Host, condition);
List<Credential> credentials = cacheRepository.SelectByKey<List<Credential>>(key);
if (credentials == null) {
base.Log.LogDebug("Preparing to retrieve all credentials that match the '{Condition}' query condition from the '{Host}' Relativity instance.", condition, base.ConnectionInfo.Host);
HttpConnectionInfo httpConnectionInfo = new HttpConnectionInfo(base.ConnectionInfo);
RestClient restClient = new RestClient(httpConnectionInfo, base.Log, base.TimeoutSeconds, base.MaxRetryAttempts);
QueryDto query = QueryDto.CreateQuery(condition);
string content = SerializationHelper.SerializeToJson(query);
QueryResultSetDto<CredentialDto> credentialResults = await restClient.RequestPostAsync<QueryResultSetDto<CredentialDto>>("/relativity.rest/api/Relativity.Services.Credential.ICredentialModule/CredentialManager/QueryAsync", content, (int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt)), delegate(Exception exception, TimeSpan timespan, Context context) {
base.Log.LogError(exception, "Retry - {Timespan} - Failed to retrieve the credentials information from the '{Host}' Relativity instance.", timespan, base.ConnectionInfo.Host);
}, (HttpStatusCode code) => "query credentials", (HttpStatusCode code) => string.Format(CultureInfo.CurrentCulture, CoreStrings.CredentialHttpPostExceptionMessage, base.ConnectionInfo.Host), token).ConfigureAwait(false);
if (!credentialResults.Success)
throw new TransferException(credentialResults.CreateExceptionMessage());
credentials = (from x in credentialResults.Results
select CreateCredential(x.Artifact)).ToList();
base.Log.LogDebug("Successfully retrieved {CredentialCount} credentials that matched the '{Condition}' query condition from the '{Host}' Relativity instance.", credentials.Count, condition, base.ConnectionInfo.Host);
}
cacheRepository.Upsert(key, credentials);
return credentials;
}
}
public async Task<AsperaCredential> GetResourceServerAsperaCredentialAsync(int resourceServerArtifactId, CancellationToken token)
{
if (resourceServerArtifactId <= 0)
throw new ArgumentOutOfRangeException("resourceServerArtifactId");
if (!(await GetIsRelativityOneInstanceAsync(token).ConfigureAwait(false)))
return null;
using (MemoryCacheRepository cacheRepository = new MemoryCacheRepository(TransferCache.Default)) {
string key = CoreMemoryCacheKeys.CreateResourceServerAsperaCredentialsKey(base.ConnectionInfo.Host, resourceServerArtifactId);
AsperaCredential credentials = cacheRepository.SelectByKey<AsperaCredential>(key);
if (credentials == (AsperaCredential)null)
try {
base.Log.LogDebug("Preparing to retrieve the '{ResourceServiceArtifactId}' resource server Aspera credentials from the '{Host}' Relativity server.", resourceServerArtifactId, base.ConnectionInfo.Host);
HttpConnectionInfo httpConnectionInfo = new HttpConnectionInfo(base.ConnectionInfo);
RestClient restClient = new RestClient(httpConnectionInfo, base.Log, base.TimeoutSeconds, base.MaxRetryAttempts);
string content = SerializationHelper.SerializeToJson(new {
resourceServerArtifactId
});
AsperaCredentialsDto response = await restClient.RequestPostAsync<AsperaCredentialsDto>("/relativity.rest/api/Relativity.Services.ResourceServer.IResourceServerModule/Resource%20Server%20Manager/RetrieveAsperaCredentialsAsync", content, (int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt)), delegate(Exception exception, TimeSpan timespan, Context context) {
base.Log.LogError(exception, "Retry - {Timespan} - Failed to retrieve the resource server Aspera credentials.", timespan);
}, (HttpStatusCode code) => "query resource server Aspera credentials", (HttpStatusCode code) => string.Format(CultureInfo.CurrentCulture, CoreStrings.RetrieveAsperaCredentialsHttpPostExceptionMessage, resourceServerArtifactId, base.ConnectionInfo.Host), token).ConfigureAwait(false);
credentials = ((response == null) ? null : CreateAsperaCredential(response));
base.Log.LogDebug("Successfully retrieved the '{ArtifactId}' resource server Aspera credentials from the '{Host}' Relativity server", resourceServerArtifactId, base.ConnectionInfo.Host);
} catch (Exception e) {
if (ExceptionHelper.IsFatalException(e))
throw;
base.Log.LogWarning(e, "Failed to retrieve the Aspera transfer and node credentials from the resource server and suggests an unsupported version of Relativity.", Array.Empty<object>());
credentials = null;
}
if (credentials != (AsperaCredential)null)
cacheRepository.Upsert(key, credentials);
return credentials;
}
}
private static AsperaCredential CreateAsperaCredential(AsperaCredentialsDto dto)
{
if (dto == null)
throw new ArgumentNullException("dto");
AsperaCredential result = null;
if (dto.TransferCredential != null)
result = new AsperaCredential(CreateCredential(dto.TransferCredential));
return result;
}
private static Credential CreateCredential(CredentialDto dto)
{
if (dto.CredentialType == null) {
string message = string.Format(CultureInfo.CurrentCulture, CoreStrings.CredentialTypeExceptionMessage, dto.ArtifactId, dto.Name);
throw new TransferException(message, true);
}
return new Credential(dto.ArtifactId, dto.Name, dto.CredentialType.Name, dto.SecretValues);
}
}
}