From ef53014d3fdc1a1d5b586f4f25ec0692f97547dc Mon Sep 17 00:00:00 2001 From: John ODonnell Date: Mon, 2 Oct 2023 14:40:15 -0400 Subject: [PATCH] Update C# client tests for Generator version bump --- .github/workflows/main.yml | 2 +- bin/test_integration | 27 +- docker-compose.yml | 2 +- templates/csharp-netcore/ApiClient.mustache | 724 ------------------ templates/csharp-netcore/ClientUtils.mustache | 232 ------ .../Api/AuthnApiTests.cs | 24 +- 6 files changed, 29 insertions(+), 982 deletions(-) delete mode 100644 templates/csharp-netcore/ApiClient.mustache delete mode 100755 templates/csharp-netcore/ClientUtils.mustache rename test/{csharp-netcore => csharp}/Api/AuthnApiTests.cs (84%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 23af2212..e482e251 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,4 +26,4 @@ jobs: uses: actions/checkout@v2 - name: run integration test script - run: ./bin/test_integration -l csharp-netcore + run: ./bin/test_integration -l csharp diff --git a/bin/test_integration b/bin/test_integration index 732f4d89..3671cc8a 100755 --- a/bin/test_integration +++ b/bin/test_integration @@ -17,8 +17,8 @@ USAGE MANDATORY -l|--language Specify a client language to test. - Testable languages include - csharp-netcore and python. + Testable languages include: + ${supported_langs[@]} OPTIONS -e|--enterprise Run tests against Conjur Enterprise. @@ -52,7 +52,7 @@ else sudo_prefix="" fi -declare -a supported_langs=("csharp-netcore" "java" "python") +declare -a supported_langs=("csharp" "python") language="" test="" @@ -100,13 +100,12 @@ done if [[ -z "$language" ]]; then echo "Missing required --language option" echo "Valid language arguments:" - echo " csharp-netcore" - echo " python" + printf ' %s\n' "${supported_langs[@]}" exit 1 fi if [[ $enterprise -eq 1 ]]; then - if [[ "$language" == "csharp-netcore" ]]; then + if [[ "$language" == "csharp" ]]; then echo "Enterprise tests for C# Conjur client not supported!" exit 1 fi @@ -145,26 +144,26 @@ configure_env() { fi } -run_csharp-netcore_tests(){ +run_csharp_tests(){ if [[ -n "$test" ]]; then test_params="--filter \"ClassName=Org.OpenAPITools.Test.$test\"" fi # Overwrite the autogenerated tests with the manually written tests - $sudo_prefix rm -rf ./out/$appliance/csharp-netcore/src/Org.OpenAPITools.Test/Api - $sudo_prefix rm -rf ./out/$appliance/csharp-netcore/src/Org.OpenAPITools.Test/Model - $sudo_prefix cp -r ./test/csharp-netcore/* ./out/$appliance/csharp-netcore/src/Org.OpenAPITools.Test/ + $sudo_prefix rm -rf ./out/$appliance/csharp/src/Org.OpenAPITools.Test/Api + $sudo_prefix rm -rf ./out/$appliance/csharp/src/Org.OpenAPITools.Test/Model + $sudo_prefix cp -r ./test/csharp/* ./out/$appliance/csharp/src/Org.OpenAPITools.Test/ docker run --rm --network $docker_network \ - -v ${PWD}/out/${appliance}/csharp-netcore:/src \ - -e CONJUR_HTTP_APPLIANCE_URL=http://conjur \ + -v ${PWD}/out/${appliance}/csharp:/src \ + -e CONJUR_HTTP_APPLIANCE_URL=http://conjur \ -e CONJUR_HTTPS_APPLIANCE_URL=https://conjur-https \ -e CONJUR_ACCOUNT=dev \ -e CONJUR_AUTHN_LOGIN=admin \ -e CONJUR_CA_BUNDLE=/opt/conjur-openapi-spec/config/https/ca.crt \ --env-file .env \ - -w /src \ - mcr.microsoft.com/dotnet/sdk:2.1 \ + -w /src \ + mcr.microsoft.com/dotnet/sdk:7.0 \ bash -c "dotnet test $test_params" } diff --git a/docker-compose.yml b/docker-compose.yml index aabd942b..5b4ba2de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,7 +76,7 @@ services: - ./config/https/:/config test-dotnet: - image: mcr.microsoft.com/dotnet/sdk:2.1 + image: mcr.microsoft.com/dotnet/sdk:7.0 command: ['sleep', '999d'] depends_on: - conjur diff --git a/templates/csharp-netcore/ApiClient.mustache b/templates/csharp-netcore/ApiClient.mustache deleted file mode 100644 index fa38645b..00000000 --- a/templates/csharp-netcore/ApiClient.mustache +++ /dev/null @@ -1,724 +0,0 @@ -{{>partial_header}} - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.IO; -{{^netStandard}} -{{^supportsUWP}} -using System.Web; -{{/supportsUWP}} -{{/netStandard}} -using System.Linq; -using System.Net; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters; -using System.Text; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using RestSharp; -using RestSharp.Deserializers; -using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; -using RestSharpMethod = RestSharp.Method; - -namespace {{packageName}}.Client -{ - /// - /// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON. - /// - internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer - { - private readonly IReadableConfiguration _configuration; - private static readonly string _contentType = "application/json"; - private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings - { - // OpenAPI generated types generally hide default constructors. - ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, - ContractResolver = new DefaultContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy - { - OverrideSpecifiedNames = true - } - } - }; - - public CustomJsonCodec(IReadableConfiguration configuration) - { - _configuration = configuration; - } - - public CustomJsonCodec(JsonSerializerSettings serializerSettings, IReadableConfiguration configuration) - { - _serializerSettings = serializerSettings; - _configuration = configuration; - } - - public string Serialize(object obj) - { - var result = JsonConvert.SerializeObject(obj, _serializerSettings); - return result; - } - - public T Deserialize(IRestResponse response) - { - var result = (T) Deserialize(response, typeof(T)); - return result; - } - - /// - /// Deserialize the JSON string into a proper object. - /// - /// The HTTP response. - /// Object type. - /// Object representation of the JSON string. - internal object Deserialize(IRestResponse response, Type type) - { - IList headers = response.Headers; - if (type == typeof(byte[])) // return byte array - { - return response.RawBytes; - } - - // TODO: ? if (type.IsAssignableFrom(typeof(Stream))) - if (type == typeof(Stream)) - { - if (headers != null) - { - var filePath = String.IsNullOrEmpty(_configuration.TempFolderPath) - ? Path.GetTempPath() - : _configuration.TempFolderPath; - var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$"); - foreach (var header in headers) - { - var match = regex.Match(header.ToString()); - if (match.Success) - { - string fileName = filePath + ClientUtils.SanitizeFilename(match.Groups[1].Value.Replace("\"", "").Replace("'", "")); - File.WriteAllBytes(fileName, response.RawBytes); - return new FileStream(fileName, FileMode.Open); - } - } - } - var stream = new MemoryStream(response.RawBytes); - return stream; - } - - if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object - { - return DateTime.Parse(response.Content, null, System.Globalization.DateTimeStyles.RoundtripKind); - } - - if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type - { - return Convert.ChangeType(response.Content, type); - } - - // at this point, it must be a model (json) - try - { - return JsonConvert.DeserializeObject(response.Content, type, _serializerSettings); - } - catch (Exception e) - { - throw new ApiException(500, e.Message); - } - } - - public string RootElement { get; set; } - public string Namespace { get; set; } - public string DateFormat { get; set; } - - public string ContentType - { - get { return _contentType; } - set { throw new InvalidOperationException("Not allowed to set content type."); } - } - } - {{! NOTE: Any changes related to RestSharp should be done in this class. All other client classes are for extensibility by consumers.}} - /// - /// Provides a default implementation of an Api client (both synchronous and asynchronous implementatios), - /// encapsulating general REST accessor use cases. - /// - {{>visibility}} partial class ApiClient : ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}} - { - private readonly String _baseUrl; - - /// - /// Allows for extending request processing for generated code. - /// - /// The RestSharp request object - partial void InterceptRequest(IRestRequest request); - - /// - /// Allows for extending response processing for generated code. - /// - /// The RestSharp request object - /// The RestSharp response object - partial void InterceptResponse(IRestRequest request, IRestResponse response); - - /// - /// Initializes a new instance of the , defaulting to the global configurations' base url. - /// - public ApiClient() - { - _baseUrl = {{packageName}}.Client.GlobalConfiguration.Instance.BasePath; - } - - /// - /// Initializes a new instance of the - /// - /// The target service's base path in URL format. - /// - public ApiClient(String basePath) - { - if (string.IsNullOrEmpty(basePath)) - throw new ArgumentException("basePath cannot be empty"); - - _baseUrl = basePath; - } - - /// - /// Constructs the RestSharp version of an http method - /// - /// Swagger Client Custom HttpMethod - /// RestSharp's HttpMethod instance. - /// - private RestSharpMethod Method(HttpMethod method) - { - RestSharpMethod other; - switch (method) - { - case HttpMethod.Get: - other = RestSharpMethod.GET; - break; - case HttpMethod.Post: - other = RestSharpMethod.POST; - break; - case HttpMethod.Put: - other = RestSharpMethod.PUT; - break; - case HttpMethod.Delete: - other = RestSharpMethod.DELETE; - break; - case HttpMethod.Head: - other = RestSharpMethod.HEAD; - break; - case HttpMethod.Options: - other = RestSharpMethod.OPTIONS; - break; - case HttpMethod.Patch: - other = RestSharpMethod.PATCH; - break; - default: - throw new ArgumentOutOfRangeException("method", method, null); - } - - return other; - } - - /// - /// Provides all logic for constructing a new RestSharp . - /// At this point, all information for querying the service is known. Here, it is simply - /// mapped into the RestSharp request. - /// - /// The http verb. - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// [private] A new RestRequest instance. - /// - private RestRequest NewRequest( - HttpMethod method, - String path, - RequestOptions options, - IReadableConfiguration configuration) - { - if (path == null) throw new ArgumentNullException("path"); - if (options == null) throw new ArgumentNullException("options"); - if (configuration == null) throw new ArgumentNullException("configuration"); - - RestRequest request = new RestRequest(Method(method)) - { - Resource = path, - JsonSerializer = new CustomJsonCodec(configuration) - }; - - if (options.PathParameters != null) - { - foreach (var pathParam in options.PathParameters) - { - request.AddParameter(pathParam.Key, pathParam.Value, ParameterType.UrlSegment); - } - } - - if (options.QueryParameters != null) - { - foreach (var queryParam in options.QueryParameters) - { - foreach (var value in queryParam.Value) - { - request.AddQueryParameter(queryParam.Key, value); - } - } - } - - if (configuration.DefaultHeaders != null) - { - foreach (var headerParam in configuration.DefaultHeaders) - { - request.AddHeader(headerParam.Key, headerParam.Value); - } - } - - if (options.HeaderParameters != null) - { - foreach (var headerParam in options.HeaderParameters) - { - foreach (var value in headerParam.Value) - { - request.AddHeader(headerParam.Key, value); - } - } - } - - if (options.FormParameters != null) - { - foreach (var formParam in options.FormParameters) - { - request.AddParameter(formParam.Key, formParam.Value); - } - } - - if (options.Data != null) - { - if (options.HeaderParameters != null) - { - var contentTypes = options.HeaderParameters["Content-Type"]; - if (contentTypes == null || contentTypes.Any(header => header.Contains("application/json"))) - { - request.RequestFormat = DataFormat.Json; - } - else - { - // TODO: Generated client user should add additional handlers. RestSharp only supports XML and JSON, with XML as default. - request.RequestFormat = DataFormat.Xml; - } - } - else - { - // Here, we'll assume JSON APIs are more common. XML can be forced by adding produces/consumes to openapi spec explicitly. - request.RequestFormat = DataFormat.Json; - } - - request.AddParameter("text/plain", options.Data, ParameterType.RequestBody); - } - - if (options.FileParameters != null) - { - foreach (var fileParam in options.FileParameters) - { - var bytes = ClientUtils.ReadAsBytes(fileParam.Value); - var fileStream = fileParam.Value as FileStream; - if (fileStream != null) - request.Files.Add(FileParameter.Create(fileParam.Key, bytes, System.IO.Path.GetFileName(fileStream.Name))); - else - request.Files.Add(FileParameter.Create(fileParam.Key, bytes, "no_file_name_provided")); - } - } - - if (options.Cookies != null && options.Cookies.Count > 0) - { - foreach (var cookie in options.Cookies) - { - request.AddCookie(cookie.Name, cookie.Value); - } - } - - return request; - } - - private ApiResponse ToApiResponse(IRestResponse response) - { - T result = response.Data; - string rawContent = response.Content; - - var transformed = new ApiResponse(response.StatusCode, new Multimap({{#caseInsensitiveResponseHeaders}}StringComparer.OrdinalIgnoreCase{{/caseInsensitiveResponseHeaders}}), result, rawContent) - { - ErrorText = response.ErrorMessage, - Cookies = new List() - }; - - if (response.Headers != null) - { - foreach (var responseHeader in response.Headers) - { - transformed.Headers.Add(responseHeader.Name, ClientUtils.ParameterToString(responseHeader.Value)); - } - } - - if (response.Cookies != null) - { - foreach (var responseCookies in response.Cookies) - { - transformed.Cookies.Add( - new Cookie( - responseCookies.Name, - responseCookies.Value, - responseCookies.Path, - responseCookies.Domain) - ); - } - } - - return transformed; - } - - private ApiResponse Exec(RestRequest req, IReadableConfiguration configuration) - { - RestClient client = new RestClient(_baseUrl); - - client.ClearHandlers(); - var existingDeserializer = req.JsonSerializer as IDeserializer; - if (existingDeserializer != null) - { - client.AddHandler(() => existingDeserializer, "application/json", "text/json", "text/x-json", "text/javascript", "*+json"); - } - else - { - client.AddHandler(() => new CustomJsonCodec(configuration), "application/json", "text/json", "text/x-json", "text/javascript", "*+json"); - } - - client.AddHandler(() => new XmlDeserializer(), "application/xml", "text/xml", "*+xml", "*"); - - client.Timeout = configuration.Timeout; - - if (configuration.UserAgent != null) - { - client.UserAgent = configuration.UserAgent; - } - - if (configuration.ClientCertificates != null) - { - client.ClientCertificates = configuration.ClientCertificates; - } - - InterceptRequest(req); - - var response = client.Execute(req); - - InterceptResponse(req, response); - - var result = ToApiResponse(response); - if (response.ErrorMessage != null) - { - result.ErrorText = response.ErrorMessage; - } - - if (response.Cookies != null && response.Cookies.Count > 0) - { - if(result.Cookies == null) result.Cookies = new List(); - foreach (var restResponseCookie in response.Cookies) - { - var cookie = new Cookie( - restResponseCookie.Name, - restResponseCookie.Value, - restResponseCookie.Path, - restResponseCookie.Domain - ) - { - Comment = restResponseCookie.Comment, - CommentUri = restResponseCookie.CommentUri, - Discard = restResponseCookie.Discard, - Expired = restResponseCookie.Expired, - Expires = restResponseCookie.Expires, - HttpOnly = restResponseCookie.HttpOnly, - Port = restResponseCookie.Port, - Secure = restResponseCookie.Secure, - Version = restResponseCookie.Version - }; - - result.Cookies.Add(cookie); - } - } - return result; - } - - {{#supportsAsync}} - private async Task> ExecAsync(RestRequest req, IReadableConfiguration configuration) - { - RestClient client = new RestClient(_baseUrl); - - client.ClearHandlers(); - var existingDeserializer = req.JsonSerializer as IDeserializer; - if (existingDeserializer != null) - { - client.AddHandler(() => existingDeserializer, "application/json", "text/json", "text/x-json", "text/javascript", "*+json"); - } - else - { - client.AddHandler(() => new CustomJsonCodec(configuration), "application/json", "text/json", "text/x-json", "text/javascript", "*+json"); - } - - client.AddHandler(() => new XmlDeserializer(), "application/xml", "text/xml", "*+xml", "*"); - - client.Timeout = configuration.Timeout; - - if (configuration.UserAgent != null) - { - client.UserAgent = configuration.UserAgent; - } - - if (configuration.ClientCertificates != null) - { - client.ClientCertificates = configuration.ClientCertificates; - } - - InterceptRequest(req); - - var response = await client.ExecuteAsync(req); - - InterceptResponse(req, response); - - var result = ToApiResponse(response); - if (response.ErrorMessage != null) - { - result.ErrorText = response.ErrorMessage; - } - - if (response.Cookies != null && response.Cookies.Count > 0) - { - if(result.Cookies == null) result.Cookies = new List(); - foreach (var restResponseCookie in response.Cookies) - { - var cookie = new Cookie( - restResponseCookie.Name, - restResponseCookie.Value, - restResponseCookie.Path, - restResponseCookie.Domain - ) - { - Comment = restResponseCookie.Comment, - CommentUri = restResponseCookie.CommentUri, - Discard = restResponseCookie.Discard, - Expired = restResponseCookie.Expired, - Expires = restResponseCookie.Expires, - HttpOnly = restResponseCookie.HttpOnly, - Port = restResponseCookie.Port, - Secure = restResponseCookie.Secure, - Version = restResponseCookie.Version - }; - - result.Cookies.Add(cookie); - } - } - return result; - } - - #region IAsynchronousClient - /// - /// Make a HTTP GET request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> GetAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Get, path, options, config), config); - } - - /// - /// Make a HTTP POST request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> PostAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Post, path, options, config), config); - } - - /// - /// Make a HTTP PUT request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> PutAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Put, path, options, config), config); - } - - /// - /// Make a HTTP DELETE request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> DeleteAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Delete, path, options, config), config); - } - - /// - /// Make a HTTP HEAD request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> HeadAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Head, path, options, config), config); - } - - /// - /// Make a HTTP OPTION request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> OptionsAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Options, path, options, config), config); - } - - /// - /// Make a HTTP PATCH request (async). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public Task> PatchAsync(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return ExecAsync(NewRequest(HttpMethod.Patch, path, options, config), config); - } - #endregion IAsynchronousClient - {{/supportsAsync}} - - #region ISynchronousClient - /// - /// Make a HTTP GET request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Get(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Get, path, options, config), config); - } - - /// - /// Make a HTTP POST request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Post(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Post, path, options, config), config); - } - - /// - /// Make a HTTP PUT request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Put(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Put, path, options, config), config); - } - - /// - /// Make a HTTP DELETE request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Delete(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Delete, path, options, config), config); - } - - /// - /// Make a HTTP HEAD request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Head(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Head, path, options, config), config); - } - - /// - /// Make a HTTP OPTION request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Options(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Options, path, options, config), config); - } - - /// - /// Make a HTTP PATCH request (synchronous). - /// - /// The target path (or resource). - /// The additional request options. - /// A per-request configuration object. It is assumed that any merge with - /// GlobalConfiguration has been done before calling this method. - /// A Task containing ApiResponse - public ApiResponse Patch(string path, RequestOptions options, IReadableConfiguration configuration = null) - { - var config = configuration ?? GlobalConfiguration.Instance; - return Exec(NewRequest(HttpMethod.Patch, path, options, config), config); - } - #endregion ISynchronousClient - } -} - diff --git a/templates/csharp-netcore/ClientUtils.mustache b/templates/csharp-netcore/ClientUtils.mustache deleted file mode 100755 index b4bdda2a..00000000 --- a/templates/csharp-netcore/ClientUtils.mustache +++ /dev/null @@ -1,232 +0,0 @@ -{{>partial_header}} - -using System; -using System.Collections; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Runtime.Serialization; -{{#useCompareNetObjects}} -using KellermanSoftware.CompareNetObjects; -{{/useCompareNetObjects}} - -namespace {{packageName}}.Client -{ - /// - /// Utility functions providing some benefit to API client consumers. - /// - public static class ClientUtils - { - {{#useCompareNetObjects}} - /// - /// An instance of CompareLogic. - /// - public static CompareLogic compareLogic; - - /// - /// Static contstructor to initialise compareLogic. - /// - static ClientUtils() - { - compareLogic = new CompareLogic(); - } - - {{/useCompareNetObjects}} - /// - /// Sanitize filename by removing the path - /// - /// Filename - /// Filename - public static string SanitizeFilename(string filename) - { - Match match = Regex.Match(filename, @".*[/\\](.*)$"); - return match.Success ? match.Groups[1].Value : filename; - } - - /// - /// Convert params to key/value pairs. - /// Use collectionFormat to properly format lists and collections. - /// - /// The swagger-supported collection format, one of: csv, tsv, ssv, pipes, multi - /// Key name. - /// Value object. - /// A multimap of keys with 1..n associated values. - public static Multimap ParameterToMultiMap(string collectionFormat, string name, object value) - { - var parameters = new Multimap(); - - if (value is ICollection collection && collectionFormat == "multi") - { - foreach (var item in collection) - { - parameters.Add(name, ParameterToString(item)); - } - } - else - { - parameters.Add(name, ParameterToString(value)); - } - - return parameters; - } - - /// - /// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime. - /// If parameter is a list, join the list with ",". - /// Otherwise just return the string. - /// - /// The parameter (header, path, query, form). - /// An optional configuration instance, providing formatting options used in processing. - /// Formatted string. - public static string ParameterToString(object obj, IReadableConfiguration configuration = null) - { - if (obj is DateTime dateTime) - // Return a formatted date string - Can be customized with Configuration.DateTimeFormat - // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o") - // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 - // For example: 2009-06-15T13:45:30.0000000 - return dateTime.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat); - if (obj is DateTimeOffset dateTimeOffset) - // Return a formatted date string - Can be customized with Configuration.DateTimeFormat - // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o") - // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 - // For example: 2009-06-15T13:45:30.0000000 - return dateTimeOffset.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat); - if (obj is bool boolean) - return boolean ? "true" : "false"; - if (obj is ICollection collection) - return string.Join(",", collection.Cast()); - if (obj is Enum enumeration){ - EnumMemberAttribute attr = obj.GetType() - .GetField(obj.ToString()) - .GetCustomAttributes(typeof(EnumMemberAttribute), false) - .SingleOrDefault() as EnumMemberAttribute; - - return attr == null ? obj.ToString() : attr.Value; - } - - return Convert.ToString(obj); - } - - /// - /// URL encode a string - /// Credit/Ref: https://github.com/restsharp/RestSharp/blob/master/RestSharp/Extensions/StringExtensions.cs#L50 - /// - /// String to be URL encoded - /// Byte array - public static string UrlEncode(string input) - { - const int maxLength = 32766; - - if (input == null) - { - throw new ArgumentNullException("input"); - } - - if (input.Length <= maxLength) - { - return Uri.EscapeDataString(input); - } - - StringBuilder sb = new StringBuilder(input.Length * 2); - int index = 0; - - while (index < input.Length) - { - int length = Math.Min(input.Length - index, maxLength); - string subString = input.Substring(index, length); - - sb.Append(Uri.EscapeDataString(subString)); - index += subString.Length; - } - - return sb.ToString(); - } - - /// - /// Encode string in base64 format. - /// - /// String to be encoded. - /// Encoded string. - public static string Base64Encode(string text) - { - return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(text)); - } - - /// - /// Convert stream to byte array - /// - /// Input stream to be converted - /// Byte array - public static byte[] ReadAsBytes(Stream inputStream) - { - using (var ms = new MemoryStream()) - { - inputStream.CopyTo(ms); - return ms.ToArray(); - } - } - - /// - /// Select the Content-Type header's value from the given content-type array: - /// if JSON type exists in the given array, use it; - /// otherwise use the first one defined in 'consumes' - /// - /// The Content-Type array to select from. - /// The Content-Type header to use. - public static String SelectHeaderContentType(String[] contentTypes) - { - if (contentTypes.Length == 0) - return null; - - foreach (var contentType in contentTypes) - { - if (IsJsonMime(contentType)) - return contentType; - } - - return contentTypes[0]; // use the first content type specified in 'consumes' - } - - /// - /// Select the Accept header's value from the given accepts array: - /// if JSON exists in the given array, use it; - /// otherwise use all of them (joining into a string) - /// - /// The accepts array to select from. - /// The Accept header to use. - public static String SelectHeaderAccept(String[] accepts) - { - if (accepts.Length == 0) - return null; - - if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase)) - return "application/json"; - - return String.Join(",", accepts); - } - - /// - /// Provides a case-insensitive check that a provided content type is a known JSON-like content type. - /// - public static readonly Regex JsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"); - - /// - /// Check if the given MIME is a JSON MIME. - /// JSON MIME examples: - /// application/json - /// application/json; charset=UTF8 - /// APPLICATION/JSON - /// application/vnd.company+json - /// - /// MIME - /// Returns True if MIME type is json. - public static bool IsJsonMime(String mime) - { - if (String.IsNullOrWhiteSpace(mime)) return false; - - return JsonRegex.IsMatch(mime) || mime.Equals("application/json-patch+json"); - } - } -} diff --git a/test/csharp-netcore/Api/AuthnApiTests.cs b/test/csharp/Api/AuthnApiTests.cs similarity index 84% rename from test/csharp-netcore/Api/AuthnApiTests.cs rename to test/csharp/Api/AuthnApiTests.cs index da03f50e..d8277404 100644 --- a/test/csharp-netcore/Api/AuthnApiTests.cs +++ b/test/csharp/Api/AuthnApiTests.cs @@ -63,9 +63,13 @@ public AuthenticationApiTests() ApiResponse res = instance.GetAccessTokenWithHttpInfo(account, login, APIKey, "base64"); Dictionary APIToken = new Dictionary(); - APIToken.Add("Authorization", $"token=\"{res.RawContent}\""); + APIToken.Add("conjurAuth", $"token=\"{res.RawContent}\""); + Dictionary APITokenPrefix = new Dictionary(); + APITokenPrefix.Add("conjurAuth", "Token"); + config.ApiKey = APIToken; + config.ApiKeyPrefix = APITokenPrefix; instance.Configuration = config; } @@ -110,15 +114,15 @@ public void ChangePasswordTest() instance.GetAPIKey(account); } - /// - /// Test UpdateAuthenticatorConfig - /// - [Fact] - public void EnableAuthenticatorServiceTest() - { - var response = instance.EnableAuthenticatorInstanceWithHttpInfo(ServiceAuthenticators.Ldap, "test", account, enabled: true); - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } + // /// + // /// Test UpdateAuthenticatorConfig + // /// + // [Fact] + // public void EnableAuthenticatorServiceTest() + // { + // var response = instance.EnableAuthenticatorInstanceWithHttpInfo(ServiceAuthenticators.Ldap, "test", account, enabled: true); + // Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + // } }