1 /** 2 * Methods to generate `security.d`, allowing the client to use the security schemes in the OpenAPI 3 * Specification. 4 */ 5 module openapi_client.security; 6 7 import std.array : appender, split, Appender; 8 import std.file : mkdir, mkdirRecurse, write; 9 import std.path : buildNormalizedPath, dirName; 10 import std.string : tr; 11 import std.stdio : writeln; 12 13 import openapi : OasDocument, OasServer, OasServerVariable, OasSecurityScheme; 14 import openapi_client.util : wordWrapText, toUpperCamelCase; 15 16 17 /** 18 * Writes a utility class containing information about the REST API servers to contact. 19 */ 20 void writeSecurityFiles(OasDocument oasDocument, string targetDir, string packageRoot) { 21 auto buffer = appender!string(); 22 string moduleName = packageRoot ~ ".security"; 23 with (buffer) { 24 put("// File automatically generated from OpenAPI spec.\n"); 25 put("module " ~ moduleName ~ ";\n"); 26 put("\n"); 27 put("import openapi_client.apirequest : ApiRequest;\n"); 28 put("import openapi;\n"); 29 put("\n"); 30 put("import std.base64 : Base64;\n"); 31 put("import std.conv : to;\n"); 32 put("import std.array : Appender;\n"); 33 put("\n"); 34 put("class Security {\n\n"); 35 put(" /**\n"); 36 put(" * The currently active security method to be applied to requests.\n"); 37 put(" */\n"); 38 put(" static void delegate(ApiRequest) applySecurityF = null;\n\n"); 39 foreach (string securitySchemeName, OasSecurityScheme securityScheme; 40 oasDocument.components.securitySchemes) { 41 if (securityScheme.type == "http") { 42 if (securityScheme.scheme == "basic") { 43 put(" /**\n"); 44 put(" * Enable and configure the use of HTTP Basic Authentication.\n"); 45 put(" *\n"); 46 put(" * See_Also: https://en.wikipedia.org/wiki/Basic_access_authentication\n"); 47 put(" */\n"); 48 put(" static void configure" ~ toUpperCamelCase(securitySchemeName) 49 ~ "(string username, string password) {\n"); 50 put(" applySecurityF = (ApiRequest request) {\n"); 51 put(" auto buffer = new Appender!string();\n"); 52 put(" auto credentials = cast(immutable(ubyte)[])(username ~ \":\" ~ password);\n"); 53 put(" Base64.encode(credentials, buffer);\n"); 54 put(" request.setHeaderParam(\"Authorization\", \"Basic \" ~ buffer.data);\n"); 55 put(" };\n"); 56 put(" }\n\n"); 57 } else if (securityScheme.scheme == "bearer") { 58 put(" /**\n"); 59 put(" * Enable and configure the use of an OAuth2.0 Bearer token for HTTP Authentication.\n"); 60 put(" *\n"); 61 put(" * See_Also: https://datatracker.ietf.org/doc/html/rfc6750\n"); 62 put(" */\n"); 63 put(" static void configure" ~ toUpperCamelCase(securitySchemeName) 64 ~ "(string token) {\n"); 65 put(" applySecurityF = (ApiRequest request) {\n"); 66 put(" request.setHeaderParam(\"Authorization\", \"Bearer \" ~ token);\n"); 67 put(" };\n"); 68 put(" }\n\n"); 69 } else { 70 writeln("Warning: Unsupported security scheme type=http, scheme=", securityScheme.scheme); 71 } 72 } else if (securityScheme.type == "apiKey") { 73 if (!securityScheme.in_ || !securityScheme.name) { 74 throw new Exception("SecurityScheme '" ~ securitySchemeName 75 ~ "', is missing required parameter 'in' or 'name'."); 76 } 77 put(" /**\n"); 78 put(" * Enable and configure an API Key for authentication.\n"); 79 put(" *\n"); 80 put(" * See_Also: https://swagger.io/specification/#security-scheme-object\n"); 81 put(" */\n"); 82 put(" static void configure" ~ toUpperCamelCase(securitySchemeName) 83 ~ "(string apiKey) {\n"); 84 put(" applySecurityF = (ApiRequest request) {\n"); 85 if (securityScheme.in_ == "header") { 86 put(" request.setHeaderParam(\"" ~ securityScheme.name ~ "\", apiKey);\n"); 87 } else if (securityScheme.in_ == "query") { 88 put(" request.setQueryParam(\"" ~ securityScheme.name ~ "\", apiKey);\n"); 89 } else { 90 put(" throw new Exception(\"Security apiKey unsupported in: \" ~ securityScheme.in_);\n"); 91 } 92 put(" };\n"); 93 put(" }\n\n"); 94 } else { 95 writeln("Warning: Unsupported security scheme type '", securityScheme.type, "'."); 96 } 97 } 98 put(" /**\n"); 99 put(" * Apply the currently selected security method to a request.\n"); 100 put(" */\n"); 101 put(" static void apply(ApiRequest request) {\n"); 102 put(" if (applySecurityF !is null)\n"); 103 put(" applySecurityF(request);\n"); 104 put(" }\n\n"); 105 put("}\n"); 106 } 107 string fileName = buildNormalizedPath(targetDir, tr(moduleName, ".", "/") ~ ".d"); 108 mkdirRecurse(dirName(fileName)); 109 write(fileName, buffer[]); 110 }