diff --git a/src/CodeGeneration/ApiGenerator/ApiGenerator.cs b/src/CodeGeneration/ApiGenerator/ApiGenerator.cs index 52abfbc19ef..e52b4c975b0 100644 --- a/src/CodeGeneration/ApiGenerator/ApiGenerator.cs +++ b/src/CodeGeneration/ApiGenerator/ApiGenerator.cs @@ -35,9 +35,6 @@ public class ApiGenerator "indices.freeze.json", "indices.unfreeze.json", "xpack.ml.set_upgrade_mode.json", - "security.create_api_key.json", - "security.get_api_key.json", - "security.invalidate_api_key.json", "xpack.monitoring.bulk.json", // these API's are not ready for primetime yet @@ -179,7 +176,15 @@ private static Dictionary CreateCommonApiQueryParame return ApiQueryParametersPatcher.Patch(null, commonParameters, null, false); } - private static string CreateMethodName(string apiEndpointKey) => PascalCase(apiEndpointKey); + private static string CreateMethodName(string apiEndpointKey) + { + var pascalCased = PascalCase(apiEndpointKey); + if (pascalCased.StartsWith("Security")) + { + pascalCased = "Xpack" + pascalCased; + } + return pascalCased; + } private static string DoRazor(string name, string template, RestApiSpec model) => Razor.CompileRenderAsync(name, template, model).GetAwaiter().GetResult(); diff --git a/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs b/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs index e642a18c064..ef9b8204091 100644 --- a/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs +++ b/src/Elasticsearch.Net/Domain/RequestParameters/RequestParameters.Generated.cs @@ -2718,6 +2718,34 @@ public partial class StopRollupJobRequestParameters : RequestParametersBlock for (at maximum) the specified duration while waiting for the job to stop. Defaults to 30s. public TimeSpan Timeout { get => Q("timeout"); set => Q("timeout", value); } } + ///Request options for XpackSecurityCreateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
+ public partial class CreateApiKeyRequestParameters : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.PUT; + /// + /// If `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh + /// to make this operation visible to search, if `false` then do nothing with refreshes. + /// + public Refresh? Refresh { get => Q("refresh"); set => Q("refresh", value); } + } + ///Request options for XpackSecurityGetApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html
+ public partial class GetApiKeyRequestParameters : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.GET; + ///API key id of the API key to be retrieved + public string Id { get => Q("id"); set => Q("id", value); } + ///API key name of the API key to be retrieved + public string Name { get => Q("name"); set => Q("name", value); } + ///user name of the user who created this API key to be retrieved + public string Username { get => Q("username"); set => Q("username", value); } + ///realm name of the user who created this API key to be retrieved + public string RealmName { get => Q("realm_name"); set => Q("realm_name", value); } + } + ///Request options for XpackSecurityInvalidateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html
+ public partial class InvalidateApiKeyRequestParameters : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.DELETE; + } ///Request options for XpackSecurityAuthenticate
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html
public partial class AuthenticateRequestParameters : RequestParameters { diff --git a/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs b/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs index a83cddfc1c1..9d5e2723991 100644 --- a/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs +++ b/src/Elasticsearch.Net/ElasticLowLevelClient.Generated.cs @@ -4052,6 +4052,44 @@ public TResponse XpackRollupStopJob(string id, StopRollupJobRequestPa ///A func that allows you to describe the querystring parameters & request specific connection settings. public Task XpackRollupStopJobAsync(string id, StopRollupJobRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(POST, Url($"_xpack/rollup/job/{id.NotNull("id")}/_stop"), ctx, null, _params(requestParameters)); + ///PUT on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse XpackSecurityCreateApiKey(PostData body, CreateApiKeyRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(PUT, Url($"_security/api_key"), body, _params(requestParameters)); + ///PUT on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task XpackSecurityCreateApiKeyAsync(PostData body, CreateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(PUT, Url($"_security/api_key"), ctx, body, _params(requestParameters)); + ///POST on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse XpackSecurityCreateApiKeyPost(PostData body, CreateApiKeyRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(POST, Url($"_security/api_key"), body, _params(requestParameters)); + ///POST on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task XpackSecurityCreateApiKeyPostAsync(PostData body, CreateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(POST, Url($"_security/api_key"), ctx, body, _params(requestParameters)); + ///GET on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse XpackSecurityGetApiKey(GetApiKeyRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(GET, Url($"_security/api_key"), null, _params(requestParameters)); + ///GET on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task XpackSecurityGetApiKeyAsync(GetApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(GET, Url($"_security/api_key"), ctx, null, _params(requestParameters)); + ///DELETE on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html + ///The api key request to invalidate API key(s) + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public TResponse XpackSecurityInvalidateApiKey(PostData body, InvalidateApiKeyRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequest(DELETE, Url($"_security/api_key"), body, _params(requestParameters)); + ///DELETE on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html + ///The api key request to invalidate API key(s) + ///A func that allows you to describe the querystring parameters & request specific connection settings. + public Task XpackSecurityInvalidateApiKeyAsync(PostData body, InvalidateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) + where TResponse : class, IElasticsearchResponse, new() => this.DoRequestAsync(DELETE, Url($"_security/api_key"), ctx, body, _params(requestParameters)); ///GET on /_xpack/security/_authenticate https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html ///A func that allows you to describe the querystring parameters & request specific connection settings. public TResponse XpackSecurityAuthenticate(AuthenticateRequestParameters requestParameters = null) diff --git a/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs b/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs index bb6e6d7b943..6652d72c20d 100644 --- a/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs +++ b/src/Elasticsearch.Net/IElasticLowLevelClient.Generated.cs @@ -3284,6 +3284,36 @@ public partial interface IElasticLowLevelClient ///The ID of the job to stop ///A func that allows you to describe the querystring parameters & request specific connection settings. Task XpackRollupStopJobAsync(string id, StopRollupJobRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///PUT on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse XpackSecurityCreateApiKey(PostData body, CreateApiKeyRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///PUT on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task XpackSecurityCreateApiKeyAsync(PostData body, CreateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///POST on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse XpackSecurityCreateApiKeyPost(PostData body, CreateApiKeyRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///POST on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html + ///The api key request to create an API key + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task XpackSecurityCreateApiKeyPostAsync(PostData body, CreateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///GET on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse XpackSecurityGetApiKey(GetApiKeyRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///GET on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task XpackSecurityGetApiKeyAsync(GetApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); + ///DELETE on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html + ///The api key request to invalidate API key(s) + ///A func that allows you to describe the querystring parameters & request specific connection settings. + TResponse XpackSecurityInvalidateApiKey(PostData body, InvalidateApiKeyRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); + ///DELETE on /_security/api_key https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html + ///The api key request to invalidate API key(s) + ///A func that allows you to describe the querystring parameters & request specific connection settings. + Task XpackSecurityInvalidateApiKeyAsync(PostData body, InvalidateApiKeyRequestParameters requestParameters = null, CancellationToken ctx = default(CancellationToken)) where TResponse : class, IElasticsearchResponse, new(); ///GET on /_xpack/security/_authenticate https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html ///A func that allows you to describe the querystring parameters & request specific connection settings. TResponse XpackSecurityAuthenticate(AuthenticateRequestParameters requestParameters = null) where TResponse : class, IElasticsearchResponse, new(); diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyPrivileges.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyPrivileges.cs new file mode 100644 index 00000000000..1b86ee74b09 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyPrivileges.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +namespace Nest +{ + public interface IApiKeyPrivileges + { + /// + /// A list of names. + /// + IEnumerable Names { get; set; } + + /// + /// A list of privileges. + /// + IEnumerable Privileges { get; set; } + } + + public class ApiKeyPrivileges : IApiKeyPrivileges + { + /// + public IEnumerable Names { get; set; } + + /// + public IEnumerable Privileges { get; set; } + } + + public class ApiKeyPrivilegesDescriptor + : DescriptorPromiseBase> + { + public ApiKeyPrivilegesDescriptor() : base(new List()) { } + + public ApiKeyPrivilegesDescriptor Index(Func selector) => + Assign(selector, (a, v) => a.Add(v.InvokeOrDefault(new ApiKeyPrivilegeDescriptor()))); + + public class ApiKeyPrivilegeDescriptor + : DescriptorBase, IApiKeyPrivileges + { + /// + IEnumerable IApiKeyPrivileges.Names { get; set; } + + /// + IEnumerable IApiKeyPrivileges.Privileges { get; set; } + + /// + public ApiKeyPrivilegeDescriptor Privileges(params string[] privileges) => Assign(privileges, (a, v) => a.Privileges = v); + + /// + public ApiKeyPrivilegeDescriptor Privileges(IEnumerable privileges) => Assign(privileges, (a, v) => a.Privileges = v); + + /// + public ApiKeyPrivilegeDescriptor Names(params string[] resources) => Assign(resources, (a, v) => a.Names = v); + + /// + public ApiKeyPrivilegeDescriptor Names(IEnumerable resources) => Assign(resources, (a, v) => a.Names = v); + } + } +} diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRole.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRole.cs new file mode 100644 index 00000000000..c9abd4ebbf1 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRole.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nest +{ + public interface IApiKeyRole + { + /// + /// A list of clusters + /// + [JsonProperty("cluster")] + IEnumerable Cluster { get; set; } + + /// + /// A list of API key privileges for indices. + /// + [JsonProperty("index")] + IEnumerable Index { get; set; } + } + + public class ApiKeyRole : IApiKeyRole + { + /// + [JsonProperty("cluster")] + public IEnumerable Cluster { get; set; } + + /// + [JsonProperty("index")] + public IEnumerable Index { get; set; } + } + + public class ApiKeyRoleDescriptor + : DescriptorBase, IApiKeyRole + { + /// + IEnumerable IApiKeyRole.Cluster { get; set; } + + /// + IEnumerable IApiKeyRole.Index { get; set; } + + /// + public ApiKeyRoleDescriptor Cluster(params string[] cluster) => Assign(cluster, (a, v) => a.Cluster = v); + + /// + public ApiKeyRoleDescriptor Cluster(IEnumerable cluster) => Assign(cluster, (a, v) => a.Cluster = v); + + /// + public ApiKeyRoleDescriptor Indices(Func>> selector + ) => Assign(selector, (a, v) => a.Index = v?.Invoke(new ApiKeyPrivilegesDescriptor())?.Value); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRoles.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRoles.cs new file mode 100644 index 00000000000..71caad7c7e0 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ApiKeyRoles.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nest +{ + [JsonConverter(typeof(VerbatimDictionaryKeysJsonConverter))] + public interface IApiKeyRoles : IIsADictionary { } + + public class ApiKeyRoles : IsADictionaryBase, IApiKeyRoles + { + public ApiKeyRoles() { } + + internal ApiKeyRoles(IDictionary backingDictionary) : base(backingDictionary) { } + + public void Add(string role, IApiKeyRole apiKeyRole) => BackingDictionary.Add(role, apiKeyRole); + } + + public class ApiKeyRolesDescriptor : IsADictionaryDescriptorBase + { + public ApiKeyRolesDescriptor() : base(new ApiKeyRoles()) { } + + public ApiKeyRolesDescriptor Role(string name, Func selector) => + Assign(selector, (a, v) => a.Add(name, v.InvokeOrDefault(new ApiKeyRoleDescriptor()))); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyRequest.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyRequest.cs new file mode 100644 index 00000000000..34812d5aac4 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyRequest.cs @@ -0,0 +1,63 @@ +using System; +using Newtonsoft.Json; + +namespace Nest +{ + public partial interface ICreateApiKeyRequest + { + /// + /// Optional expiration for the API key being generated. + /// If expiration is not provided then the API keys do not expire. + /// + [JsonProperty("expiration")] + Time Expiration { get; set; } + + /// + /// Name for this API key + /// + [JsonProperty("name")] + string Name { get; set; } + + /// + /// Optional role descriptors for this API key, if not provided then permissions of authenticated user are applied. + /// + [JsonProperty("role_descriptors")] + IApiKeyRoles Roles { get; set; } + } + + public partial class CreateApiKeyRequest + { + /// + public Time Expiration { get; set; } + + /// + public string Name { get; set; } + + /// + public IApiKeyRoles Roles { get; set; } = new ApiKeyRoles(); // Ensure not null, as server expects {} + } + + [DescriptorFor("XpackSecurityCreateApiKey")] + public partial class CreateApiKeyDescriptor + { + /// + Time ICreateApiKeyRequest.Expiration { get; set; } + + /// + string ICreateApiKeyRequest.Name { get; set; } + + /// + IApiKeyRoles ICreateApiKeyRequest.Roles { get; set; } = new ApiKeyRoles(); // Ensure not null, as server expects {} + + /// + public CreateApiKeyDescriptor Expiration(Time expiration) => Assign(expiration, (a, v) => a.Expiration = v); + + /// + public CreateApiKeyDescriptor Name(string name) => Assign(name, (a, v) => a.Name = v); + + /// + public CreateApiKeyDescriptor Roles(Func> selector) => + Assign(selector, + (a, v) => a.Roles = v?.Invoke(new ApiKeyRolesDescriptor())?.Value ?? new ApiKeyRoles()); // Ensure not null, as server expects {} + } +} diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyResponse.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyResponse.cs new file mode 100644 index 00000000000..ec5b9e11738 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/CreateApiKeyResponse.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nest +{ + public interface ICreateApiKeyResponse : IResponse + { + /// + /// Id for the API key + /// + [JsonProperty("id")] + string Id { get; } + + /// + /// Name of the API key + /// + [JsonProperty("name")] + string Name { get; } + + /// + /// Optional expiration time for the API key in milliseconds + /// + [JsonProperty("expiration")] + [JsonConverter(typeof(EpochMillisecondsDateTimeJsonConverter))] + DateTimeOffset? Expiration { get; } + + /// + /// Generated API key + /// + [JsonProperty("api_key")] + string ApiKey { get; } + } + + public class CreateApiKeyResponse : ResponseBase, ICreateApiKeyResponse + { + /// + public string Id { get; internal set; } + + /// + public string Name { get; internal set; } + + /// + public DateTimeOffset? Expiration { get; internal set; } + + /// + public string ApiKey { get; internal set; } + } +} diff --git a/src/Nest/XPack/Security/ApiKey/CreateApiKey/ElasticClient-CreateApiKey.cs b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ElasticClient-CreateApiKey.cs new file mode 100644 index 00000000000..ef30796ed3c --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/CreateApiKey/ElasticClient-CreateApiKey.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Elasticsearch.Net; + +namespace Nest +{ + public partial interface IElasticClient + { + /// + /// Creates an API key for access without requiring basic authentication. + /// + ICreateApiKeyResponse CreateApiKey(Func selector = null); + + /// + ICreateApiKeyResponse CreateApiKey(ICreateApiKeyRequest request); + + /// + Task CreateApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ); + + /// + Task CreateApiKeyAsync(ICreateApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ); + } + + public partial class ElasticClient + { + /// + public ICreateApiKeyResponse CreateApiKey(Func selector = null + ) => CreateApiKey(selector.InvokeOrDefault(new CreateApiKeyDescriptor())); + + /// + public ICreateApiKeyResponse CreateApiKey(ICreateApiKeyRequest request) => + Dispatcher.Dispatch( + request, + LowLevelDispatch.XpackSecurityCreateApiKeyDispatch + ); + + /// + public Task CreateApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ) => CreateApiKeyAsync(selector.InvokeOrDefault(new CreateApiKeyDescriptor()), cancellationToken); + + /// + public Task CreateApiKeyAsync(ICreateApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ) => Dispatcher + .DispatchAsync( + request, + cancellationToken, + LowLevelDispatch.XpackSecurityCreateApiKeyDispatchAsync + ); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/GetApiKey/ElasticClient-GetApiKey.cs b/src/Nest/XPack/Security/ApiKey/GetApiKey/ElasticClient-GetApiKey.cs new file mode 100644 index 00000000000..6e9357a51d1 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/GetApiKey/ElasticClient-GetApiKey.cs @@ -0,0 +1,62 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Elasticsearch.Net; + +namespace Nest +{ + public partial interface IElasticClient + { + /// + /// Retrieves information for one or more API keys. + /// + IGetApiKeyResponse GetApiKey(Func selector = null); + + /// + IGetApiKeyResponse GetApiKey(IGetApiKeyRequest request); + + /// + Task GetApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ); + + /// + Task GetApiKeyAsync(IGetApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ); + } + + public partial class ElasticClient + { + /// + public IGetApiKeyResponse GetApiKey(Func selector = null + ) => + GetApiKey(selector.InvokeOrDefault(new GetApiKeyDescriptor())); + + /// + public IGetApiKeyResponse GetApiKey(IGetApiKeyRequest request) => + Dispatcher.Dispatch( + request, + (p, d) => LowLevelDispatch.XpackSecurityGetApiKeyDispatch(p) + ); + + /// + public Task GetApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ) => + GetApiKeyAsync(selector.InvokeOrDefault(new GetApiKeyDescriptor()), cancellationToken); + + /// + public Task GetApiKeyAsync(IGetApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ) => + Dispatcher + .DispatchAsync( + request, + cancellationToken, + (p, d, c) => LowLevelDispatch.XpackSecurityGetApiKeyDispatchAsync(p, c) + ); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyRequest.cs b/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyRequest.cs new file mode 100644 index 00000000000..7c3cea8b760 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyRequest.cs @@ -0,0 +1,9 @@ +namespace Nest +{ + public partial interface IGetApiKeyRequest { } + + public partial class GetApiKeyRequest { } + + [DescriptorFor("XpackSecurityGetApiKey")] + public partial class GetApiKeyDescriptor { } +} diff --git a/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyResponse.cs b/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyResponse.cs new file mode 100644 index 00000000000..e221a92efaa --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/GetApiKey/GetApiKeyResponse.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nest +{ + public interface IGetApiKeyResponse : IResponse + { + /// + /// The list of API keys that were retrieved for this request. + /// + [JsonProperty("api_keys")] + IReadOnlyCollection ApiKeys { get; } + } + + public class GetApiKeyResponse : ResponseBase, IGetApiKeyResponse + { + /// + public IReadOnlyCollection ApiKeys { get; internal set; } = EmptyReadOnly.Collection; + } + + public class ApiKeys + { + /// + /// Id for the API key + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Name of the API key + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Creation time for the API key + /// + [JsonProperty("creation")] + [JsonConverter(typeof(EpochMillisecondsDateTimeJsonConverter))] + public DateTimeOffset Creation { get; set; } + + /// + /// Optional expiration time for the API key in milliseconds + /// + [JsonProperty("expiration")] + [JsonConverter(typeof(EpochMillisecondsDateTimeJsonConverter))] + public DateTimeOffset? Expiration { get; set; } + + /// + /// Invalidation status for the API key. If the key has been invalidated, it has a value of true. Otherwise, it is false. + /// + [JsonProperty("invalidated")] + public bool Invalidated { get; set; } + + /// + /// Principal for which this API key was created + /// + [JsonProperty("username")] + public string Username { get; set; } + + /// + /// Realm name of the principal for which this API key was created + /// + [JsonProperty("realm")] + public string Realm { get; set; } + } +} diff --git a/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/ElasticClient-InvalidateApiKey.cs b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/ElasticClient-InvalidateApiKey.cs new file mode 100644 index 00000000000..1104d7fc509 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/ElasticClient-InvalidateApiKey.cs @@ -0,0 +1,62 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Elasticsearch.Net; + +namespace Nest +{ + public partial interface IElasticClient + { + /// + /// Invalidates one or more API keys. + /// + IInvalidateApiKeyResponse InvalidateApiKey(Func selector = null); + + /// + IInvalidateApiKeyResponse InvalidateApiKey(IInvalidateApiKeyRequest request); + + /// + Task InvalidateApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ); + + /// + Task InvalidateApiKeyAsync(IInvalidateApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ); + } + + public partial class ElasticClient + { + /// + public IInvalidateApiKeyResponse InvalidateApiKey(Func selector = null + ) => + InvalidateApiKey(selector.InvokeOrDefault(new InvalidateApiKeyDescriptor())); + + /// + public IInvalidateApiKeyResponse InvalidateApiKey(IInvalidateApiKeyRequest request) => + Dispatcher.Dispatch( + request, + LowLevelDispatch.XpackSecurityInvalidateApiKeyDispatch + ); + + /// + public Task InvalidateApiKeyAsync( + Func selector = null, + CancellationToken cancellationToken = default(CancellationToken) + ) => + InvalidateApiKeyAsync(selector.InvokeOrDefault(new InvalidateApiKeyDescriptor()), cancellationToken); + + /// + public Task InvalidateApiKeyAsync(IInvalidateApiKeyRequest request, + CancellationToken cancellationToken = default(CancellationToken) + ) => + Dispatcher + .DispatchAsync( + request, + cancellationToken, + LowLevelDispatch.XpackSecurityInvalidateApiKeyDispatchAsync + ); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyRequest.cs b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyRequest.cs new file mode 100644 index 00000000000..f1b4ed1bb64 --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyRequest.cs @@ -0,0 +1,74 @@ +using Newtonsoft.Json; + +namespace Nest +{ + public partial interface IInvalidateApiKeyRequest + { + /// + /// An API key id. This parameter cannot be used with any of Name, RealmName or Username are used. + /// + [JsonProperty("id")] + string Id { get; set; } + + /// + /// An API key name. This parameter cannot be used with any of Id, RealmName or Username are used. + /// + [JsonProperty("name")] + string Name { get; set; } + + /// + /// The name of an authentication realm. This parameter cannot be used with either Id or Name. + /// + [JsonProperty("realm_name")] + string RealmName { get; set; } + + /// + /// The username of a user. This parameter cannot be used with either Id or Name. + /// + [JsonProperty("username")] + string Username { get; set; } + } + + public partial class InvalidateApiKeyRequest + { + /// + public string Id { get; set; } + + /// + public string Name { get; set; } + + /// + public string RealmName { get; set; } + + /// + public string Username { get; set; } + } + + [DescriptorFor("XpackSecurityInvalidateApiKey")] + public partial class InvalidateApiKeyDescriptor + { + /// + string IInvalidateApiKeyRequest.Id { get; set; } + + /// + string IInvalidateApiKeyRequest.Name { get; set; } + + /// + string IInvalidateApiKeyRequest.RealmName { get; set; } + + /// + string IInvalidateApiKeyRequest.Username { get; set; } + + /// + public InvalidateApiKeyDescriptor Id(string id) => Assign(id, (a, v) => a.Id = v); + + /// + public InvalidateApiKeyDescriptor Name(string name) => Assign(name, (a, v) => a.Name = v); + + /// + public InvalidateApiKeyDescriptor RealmName(string realmName) => Assign(realmName, (a, v) => a.RealmName = v); + + /// + public InvalidateApiKeyDescriptor Username(string username) => Assign(username, (a, v) => a.Username = v); + } +} diff --git a/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyResponse.cs b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyResponse.cs new file mode 100644 index 00000000000..47427b282da --- /dev/null +++ b/src/Nest/XPack/Security/ApiKey/InvalidateApiKey/InvalidateApiKeyResponse.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using Elasticsearch.Net; +using Newtonsoft.Json; + +namespace Nest +{ + public interface IInvalidateApiKeyResponse : IResponse + { + /// + /// The ids of the API keys that were invalidated as part of this request. + /// + [JsonProperty("invalidated_api_keys")] + IReadOnlyCollection InvalidatedApiKeys { get; } + + /// + /// The ids of the API keys that were already invalidated. + /// + [JsonProperty("previously_invalidated_api_keys")] + IReadOnlyCollection PreviouslyInvalidatedApiKeys { get; } + + /// + /// The number of errors that were encountered when invalidating the API keys. + /// + [JsonProperty("error_count")] + int? ErrorCount { get; } + + /// + /// Details about these errors. This field is not present in the response when there are no errors. + /// + [JsonProperty("error_details")] + IReadOnlyCollection ErrorDetails { get; } + } + + public class InvalidateApiKeyResponse : ResponseBase, IInvalidateApiKeyResponse + { + /// + public IReadOnlyCollection InvalidatedApiKeys { get; internal set; } = EmptyReadOnly.Collection; + + /// + public IReadOnlyCollection PreviouslyInvalidatedApiKeys { get; internal set; } = EmptyReadOnly.Collection; + + /// + public int? ErrorCount { get; internal set; } + + /// + public IReadOnlyCollection ErrorDetails { get; internal set; } = EmptyReadOnly.Collection; + } +} diff --git a/src/Nest/_Generated/_Descriptors.generated.cs b/src/Nest/_Generated/_Descriptors.generated.cs index 6f2307e0e6a..d42f19f87b4 100644 --- a/src/Nest/_Generated/_Descriptors.generated.cs +++ b/src/Nest/_Generated/_Descriptors.generated.cs @@ -4962,6 +4962,40 @@ public StopRollupJobDescriptor(Id id) : base(r=>r.Required("id", id)){} ///Block for (at maximum) the specified duration while waiting for the job to stop. Defaults to 30s. public StopRollupJobDescriptor Timeout(Time timeout) => Qs("timeout", timeout); } + ///descriptor for XpackSecurityCreateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
+ public partial class CreateApiKeyDescriptor : RequestDescriptorBase, ICreateApiKeyRequest + { + // values part of the url path + + // Request parameters + + ///If `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes. + public CreateApiKeyDescriptor Refresh(Refresh? refresh) => Qs("refresh", refresh); + } + ///descriptor for XpackSecurityGetApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html
+ public partial class GetApiKeyDescriptor : RequestDescriptorBase, IGetApiKeyRequest + { + // values part of the url path + + // Request parameters + + ///API key id of the API key to be retrieved + public GetApiKeyDescriptor Id(string id) => Qs("id", id); + ///API key name of the API key to be retrieved + public GetApiKeyDescriptor Name(string name) => Qs("name", name); + ///user name of the user who created this API key to be retrieved + public GetApiKeyDescriptor Username(string username) => Qs("username", username); + ///realm name of the user who created this API key to be retrieved + public GetApiKeyDescriptor RealmName(string realmName) => Qs("realm_name", realmName); + } + ///descriptor for XpackSecurityInvalidateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html
+ public partial class InvalidateApiKeyDescriptor : RequestDescriptorBase, IInvalidateApiKeyRequest + { + // values part of the url path + + // Request parameters + + } ///descriptor for XpackSecurityAuthenticate
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html
public partial class AuthenticateDescriptor : RequestDescriptorBase, IAuthenticateRequest { diff --git a/src/Nest/_Generated/_LowLevelDispatch.generated.cs b/src/Nest/_Generated/_LowLevelDispatch.generated.cs index 47a3d4a3c90..10c4c9712bd 100644 --- a/src/Nest/_Generated/_LowLevelDispatch.generated.cs +++ b/src/Nest/_Generated/_LowLevelDispatch.generated.cs @@ -4642,6 +4642,70 @@ internal partial class LowLevelDispatch throw InvalidDispatch("XpackRollupStopJob", p, new [] { POST }, "/_xpack/rollup/job/{id}/_stop"); } + internal TResponse XpackSecurityCreateApiKeyDispatch(IRequest p,SerializableData body) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case PUT: + return _lowLevel.XpackSecurityCreateApiKey(body,p.RequestParameters); + case POST: + return _lowLevel.XpackSecurityCreateApiKeyPost(body,p.RequestParameters); + } + throw InvalidDispatch("XpackSecurityCreateApiKey", p, new [] { PUT, POST }, "/_security/api_key"); + } + + internal Task XpackSecurityCreateApiKeyDispatchAsync(IRequest p,SerializableData body, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case PUT: + return _lowLevel.XpackSecurityCreateApiKeyAsync(body,p.RequestParameters,ct); + case POST: + return _lowLevel.XpackSecurityCreateApiKeyPostAsync(body,p.RequestParameters,ct); + } + throw InvalidDispatch("XpackSecurityCreateApiKey", p, new [] { PUT, POST }, "/_security/api_key"); + } + + internal TResponse XpackSecurityGetApiKeyDispatch(IRequest p) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case GET: + return _lowLevel.XpackSecurityGetApiKey(p.RequestParameters); + } + throw InvalidDispatch("XpackSecurityGetApiKey", p, new [] { GET }, "/_security/api_key"); + } + + internal Task XpackSecurityGetApiKeyDispatchAsync(IRequest p, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case GET: + return _lowLevel.XpackSecurityGetApiKeyAsync(p.RequestParameters,ct); + } + throw InvalidDispatch("XpackSecurityGetApiKey", p, new [] { GET }, "/_security/api_key"); + } + + internal TResponse XpackSecurityInvalidateApiKeyDispatch(IRequest p,SerializableData body) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case DELETE: + return _lowLevel.XpackSecurityInvalidateApiKey(body,p.RequestParameters); + } + throw InvalidDispatch("XpackSecurityInvalidateApiKey", p, new [] { DELETE }, "/_security/api_key"); + } + + internal Task XpackSecurityInvalidateApiKeyDispatchAsync(IRequest p,SerializableData body, CancellationToken ct) where TResponse : class, IElasticsearchResponse, new() + { + switch(p.HttpMethod) + { + case DELETE: + return _lowLevel.XpackSecurityInvalidateApiKeyAsync(body,p.RequestParameters,ct); + } + throw InvalidDispatch("XpackSecurityInvalidateApiKey", p, new [] { DELETE }, "/_security/api_key"); + } + internal TResponse XpackSecurityAuthenticateDispatch(IRequest p) where TResponse : class, IElasticsearchResponse, new() { switch(p.HttpMethod) diff --git a/src/Nest/_Generated/_Requests.generated.cs b/src/Nest/_Generated/_Requests.generated.cs index ae618a6f728..6483e1bb956 100644 --- a/src/Nest/_Generated/_Requests.generated.cs +++ b/src/Nest/_Generated/_Requests.generated.cs @@ -1371,6 +1371,23 @@ public CountRequest(Indices index, Types type) : base(r=>r.Optional("index", ind public long? TerminateAfter { get => Q("terminate_after"); set => Q("terminate_after", value); } } [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public partial interface ICreateApiKeyRequest : IRequest + { + } + ///Request parameters for XpackSecurityCreateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
+ public partial class CreateApiKeyRequest : PlainRequestBase, ICreateApiKeyRequest + { + protected ICreateApiKeyRequest Self => this; + // values part of the url path + + // Request parameters + /// + /// If `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh + /// to make this operation visible to search, if `false` then do nothing with refreshes. + /// + public Refresh? Refresh { get => Q("refresh"); set => Q("refresh", value); } + } + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public partial interface ICreateAutoFollowPatternRequest : IRequest { Name Name { get; } @@ -2838,6 +2855,26 @@ public GetAnomalyRecordsRequest(Id job_id) : base(r=>r.Required("job_id", job_id // Request parameters } [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public partial interface IGetApiKeyRequest : IRequest + { + } + ///Request parameters for XpackSecurityGetApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html
+ public partial class GetApiKeyRequest : PlainRequestBase, IGetApiKeyRequest + { + protected IGetApiKeyRequest Self => this; + // values part of the url path + + // Request parameters + ///API key id of the API key to be retrieved + public string Id { get => Q("id"); set => Q("id", value); } + ///API key name of the API key to be retrieved + public string Name { get => Q("name"); set => Q("name", value); } + ///user name of the user who created this API key to be retrieved + public string Username { get => Q("username"); set => Q("username", value); } + ///realm name of the user who created this API key to be retrieved + public string RealmName { get => Q("realm_name"); set => Q("realm_name", value); } + } + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public partial interface IGetAutoFollowPatternRequest : IRequest { Name Name { get; } @@ -4028,6 +4065,18 @@ public IndicesStatsRequest(Indices index, IndicesStatsMetric metric) : base(r=>r public bool? IncludeSegmentFileSizes { get => Q("include_segment_file_sizes"); set => Q("include_segment_file_sizes", value); } } [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public partial interface IInvalidateApiKeyRequest : IRequest + { + } + ///Request parameters for XpackSecurityInvalidateApiKey
https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html
+ public partial class InvalidateApiKeyRequest : PlainRequestBase, IInvalidateApiKeyRequest + { + protected IInvalidateApiKeyRequest Self => this; + // values part of the url path + + // Request parameters + } + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public partial interface IInvalidateUserAccessTokenRequest : IRequest { } diff --git a/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyTests.cs b/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyTests.cs new file mode 100644 index 00000000000..f98aefc8fb4 --- /dev/null +++ b/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyTests.cs @@ -0,0 +1,299 @@ +using System; +using System.Threading.Tasks; +using Elastic.Xunit.XunitPlumbing; +using Elasticsearch.Net; +using FluentAssertions; +using Nest; +using Tests.Core.ManagedElasticsearch.Clusters; +using Tests.Framework; +using Tests.Framework.EndpointTests.TestState; +using Tests.Framework.Integration; + +namespace Tests.XPack.ApiKey +{ + [SkipVersion("<6.7.0", "Security Api Keys are modelled against 6.7.0")] + public class SecurityApiKeyTests : CoordinatedIntegrationTestBase + { + private const string PutRoleStep = nameof(PutRoleStep); + private const string PutUserStep = nameof(PutUserStep); + private const string PutPrivilegesStep = nameof(PutPrivilegesStep); + private const string CreateApiKeyWithRolesStep = nameof(CreateApiKeyWithRolesStep); + private const string CreateApiKeyWithNoRolesStep = nameof(CreateApiKeyWithNoRolesStep); + private const string GetApiKeyStep = nameof(GetApiKeyStep); + private const string InvalidateApiKeyStep = nameof(InvalidateApiKeyStep); + + public SecurityApiKeyTests(XPackCluster cluster, EndpointUsage usage) : base(new CoordinatedUsage(cluster, usage) + { + { + PutRoleStep, u => + u.Calls( + v => new PutRoleRequest($"role-{v}") + { + Cluster = new[] { "all" }, + Indices = new IIndicesPrivileges[] + { + new IndicesPrivileges + { + Names = "*", + Privileges = new [] { "all" } + } + }, + Applications = new IApplicationPrivileges[] + { + new ApplicationPrivileges + { + Application = $"app-{v}", + Privileges = new [] { "*" }, + Resources = new [] { "*" } + } + } + }, + (v, d) => d + .Cluster("all") + .Indices(i => i.Add(p => p.Names("*").Privileges("all"))) + .Applications(i => i.Add(p => p.Application($"app-{v}").Privileges("*").Resources("*"))) + , + (v, c, f) => c.PutRole($"role-{v}", f), + (v, c, f) => c.PutRoleAsync($"role-{v}", f), + (v, c, r) => c.PutRole(r), + (v, c, r) => c.PutRoleAsync(r) + ) + }, + { + PutUserStep, u => + u.Calls( + v => new PutUserRequest($"user-{v}") + { + Password = "password", + Roles = new[] { $"role-{v}", "superuser" }, + FullName = "API key user" + }, + (v, d) => d + .Password("password") + .Roles($"role-{v}", "superuser") + .FullName("API key user") + , + (v, c, f) => c.PutUser($"user-{v}", f), + (v, c, f) => c.PutUserAsync($"user-{v}", f), + (v, c, r) => c.PutUser(r), + (v, c, r) => c.PutUserAsync(r) + ) + }, + { + PutPrivilegesStep, u => + u.Calls( + v => new PutPrivilegesRequest + { + Applications = new AppPrivileges + { + { + $"app-{v}", new Privileges + { + { + $"read", new PrivilegesActions + { + Actions = new[] { "data:read/*" } + } + }, + { + $"write", new PrivilegesActions + { + Actions = new[] { "data:write/*" } + } + } + } + } + } + }, + (v, d) => d + .Applications(a => a + .Application($"app-{v}", pr => pr + .Privilege($"read", ac => ac + .Actions("data:read/*") + ) + .Privilege($"write", ac => ac + .Actions("data:write/*") + ) + ) + ) + , + (v, c, f) => c.PutPrivileges(f), + (v, c, f) => c.PutPrivilegesAsync(f), + (v, c, r) => c.PutPrivileges(r), + (v, c, r) => c.PutPrivilegesAsync(r) + ) + }, + { + CreateApiKeyWithRolesStep, u => + u.Calls( + v => new CreateApiKeyRequest + { + Name = v, + Expiration = "1d", + Roles = new ApiKeyRoles + { + { + "role-a", new ApiKeyRole + { + Cluster = new[] { "all" }, + Index = new [] + { + new ApiKeyPrivileges + { + Names = new [] { "index-a*" }, + Privileges = new[] { "read" } + } + } + } + }, + { + "role-b", new ApiKeyRole + { + Cluster = new[] { "all" }, + Index = new [] + { + new ApiKeyPrivileges + { + Names = new [] { "index-b*" }, + Privileges = new[] { "read" } + } + } + } + } + }, + RequestConfiguration = new RequestConfiguration + { + BasicAuthenticationCredentials = new BasicAuthenticationCredentials + { + Username = $"user-{v}", + Password = "password" + } + } + }, + (v, d) => d + .Name(v) + .Expiration("1d") + .Roles(r => r.Role("role-a", o => o.Cluster("all").Indices(i => i.Index(k => k.Names("index-a").Privileges("read")))) + .Role("role-b", o => o.Cluster("all").Indices(i => i.Index(k => k.Names("index-b").Privileges("read"))))) + .RequestConfiguration(r => r.BasicAuthentication($"user-{v}", "password")) + , + (v, c, f) => c.CreateApiKey(f), + (v, c, f) => c.CreateApiKeyAsync(f), + (v, c, r) => c.CreateApiKey(r), + (v, c, r) => c.CreateApiKeyAsync(r) + ) + }, + { + CreateApiKeyWithNoRolesStep, u => + u.Calls( + v => new CreateApiKeyRequest + { + Name = v, + Expiration = "1d", + RequestConfiguration = new RequestConfiguration + { + BasicAuthenticationCredentials = new BasicAuthenticationCredentials + { + Username = $"user-{v}", + Password = "password" + } + } + }, + (v, d) => d + .Name(v) + .Expiration("1d") + .RequestConfiguration(r => r.BasicAuthentication($"user-{v}", "password")) + , + (v, c, f) => c.CreateApiKey(f), + (v, c, f) => c.CreateApiKeyAsync(f), + (v, c, r) => c.CreateApiKey(r), + (v, c, r) => c.CreateApiKeyAsync(r) + ) + }, + { + GetApiKeyStep, u => + u.Calls( + v => new GetApiKeyRequest + { + Name = v, + RequestConfiguration = new RequestConfiguration + { + BasicAuthenticationCredentials = new BasicAuthenticationCredentials + { + Username = $"user-{v}", + Password = "password" + } + } + }, + (v, d) => d + .Name(v) + .RequestConfiguration(r => r.BasicAuthentication($"user-{v}", "password")) + , + (v, c, f) => c.GetApiKey(f), + (v, c, f) => c.GetApiKeyAsync(f), + (v, c, r) => c.GetApiKey(r), + (v, c, r) => c.GetApiKeyAsync(r) + ) + }, + { + InvalidateApiKeyStep, u => + u.Calls( + v => new InvalidateApiKeyRequest + { + Name = v, + RequestConfiguration = new RequestConfiguration + { + BasicAuthenticationCredentials = new BasicAuthenticationCredentials + { + Username = $"user-{v}", + Password = "password" + } + } + }, + (v, d) => d + .Name(v) + .RequestConfiguration(r => r.BasicAuthentication($"user-{v}", "password")) + , + (v, c, f) => c.InvalidateApiKey(f), + (v, c, f) => c.InvalidateApiKeyAsync(f), + (v, c, r) => c.InvalidateApiKey(r), + (v, c, r) => c.InvalidateApiKeyAsync(r) + ) + } + }) { } + + [I] public async Task SecurityCreateApiKeyResponse() => await Assert(CreateApiKeyWithRolesStep, r => + { + r.IsValid.Should().BeTrue(); + r.Id.Should().NotBeNullOrEmpty(); + r.Name.Should().NotBeNullOrEmpty(); + r.Expiration.Should().NotBeNull(); + r.ApiKey.Should().NotBeNullOrEmpty(); + }); + + [I] public async Task SecurityGetApiKeyResponse() => await Assert(GetApiKeyStep, r => + { + r.IsValid.Should().BeTrue(); + r.ApiKeys.Should().NotBeNullOrEmpty(); + + foreach (var apiKey in r.ApiKeys) + { + apiKey.Id.Should().NotBeNullOrEmpty(); + apiKey.Name.Should().NotBeNullOrEmpty(); + apiKey.Creation.Should().BeBefore(DateTimeOffset.UtcNow); + apiKey.Expiration.Should().BeAfter(DateTimeOffset.UtcNow); + apiKey.Invalidated.Should().Be(false); + apiKey.Username.Should().NotBeNullOrEmpty(); + apiKey.Realm.Should().NotBeNullOrEmpty(); + } + }); + + [I] public async Task SecurityInvalidateApiKeyResponse() => await Assert(InvalidateApiKeyStep, r => + { + r.IsValid.Should().BeTrue(); + r.ErrorCount.Should().Be(0); + r.PreviouslyInvalidatedApiKeys.Should().BeEmpty(); + r.InvalidatedApiKeys.Should().HaveCount(2); + }); + } +} diff --git a/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyUrlTests.cs b/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyUrlTests.cs new file mode 100644 index 00000000000..12400724c51 --- /dev/null +++ b/src/Tests/Tests/XPack/Security/ApiKey/SecurityApiKeyUrlTests.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using Elastic.Xunit.XunitPlumbing; +using Nest; +using Tests.Framework; + +namespace Tests.XPack.Security.ApiKey +{ + public class SecurityApiKeyUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await UrlTester.DELETE("/_security/api_key") + .Fluent(c => c.InvalidateApiKey()) + .Request(c => c.InvalidateApiKey(new InvalidateApiKeyRequest())) + .FluentAsync(c => c.InvalidateApiKeyAsync()) + .RequestAsync(c => c.InvalidateApiKeyAsync(new InvalidateApiKeyRequest())); + } + + public class SecurityGetApiKeyUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await UrlTester.GET("/_security/api_key") + .Fluent(c => c.GetApiKey()) + .Request(c => c.GetApiKey(new GetApiKeyRequest())) + .FluentAsync(c => c.GetApiKeyAsync()) + .RequestAsync(c => c.GetApiKeyAsync(new GetApiKeyRequest())); + } + + public class SecurityCreateApiKeyUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await UrlTester.PUT("/_security/api_key") + .Fluent(c => c.CreateApiKey()) + .Request(c => c.CreateApiKey(new CreateApiKeyRequest())) + .FluentAsync(c => c.CreateApiKeyAsync()) + .RequestAsync(c => c.CreateApiKeyAsync(new CreateApiKeyRequest())); + } +}