Enabling documentation within WebApi2 help page - asp.net-web-api

I have a simple webapi2 project.
The only information I can seem to find myself refers to the older webapi1
From my controller if I have
/// <summary>
/// Gets a list of not very interesting information
/// </summary>
/// <returns>The list</returns>
[ResponseType(typeof(ExampleModel))]
public IHttpActionResult Get()
{
var data = new List<ExampleModel>()
{
new ExampleModel()
{
Date = DateTime.Now,
Name = "Tom"
},
new ExampleModel()
{
Date = DateTime.Now.AddDays(-20),
Name = "Bob"
}
};
why is no information appearing when I try browse to the help page. I am told No documentation available.
Is there a magic switch somewhere that will turn on automated population of this data?

if you referring to displaying the xml comments, then you can find my answer here:
ASP.NET Web API Help Page documentation using Xml comments on controllers
Be sure to uncomment this code in Areas/HelpPage/App_Start/HelpPageConfig.cs
// Uncomment the following to use the documentation from XML documentation file.
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
Also make sure the xml file goes in App_Data not bin where it defaults to in project properties

Related

Unable to fix veracode cwe id 918 flaw (SSRF) when using API gateway pattern in a Microservices architecture

I am using API Gateway Pattern in a Micro services architecture in which the Front End Angular app makes an HTTP request to my API Gateway project which is simply a ASP.net Core 3.1 Web API project. Currently I only have 2 micro services and an API Gateway and all of them are of type ASP.net Core 3.1 Web API project. The API Gateway project has all the controllers of my micro services. The purpose of the API Gateway is just to receive the request from Front end and make an HTTP Request to the appropriate Micro service.
Now in the AccountController.cs of my API Gateway project, I have the following code
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
_uri = new Uri(uriString: $"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
using var result = await _client.GetAsync(_uri);
var content = await result.Content.ReadAsStringAsync();
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
After searching about the SSRF issue on stackoverflow I found the following recommendation at Veracode community.
Veracode Static Analysis will report a flaw with CWE 918 if it can
detect that data from outside of the application (like an HTTP Request
from a user, but also a file that may have been uploaded by a user,
database data, webservice data, etc) is able to change the nature of a
network request.
On Stackoverflow I found the following fix
For CWE ID 918 it is hard to make Veracode recognize your fix unless you have static URL. You need to validate all your inputs that become parts of your request URL.
That means I had to sanitize my input parameters OrganizationId and AccountId before appending them to the request URL.
Also another question on the veracode community suggested
The only thing that Veracode Static Analysis will automatically detect as a remediation for this flaw category is to change the input to be hardcoded
and they proposed a solution for the query string
The given example appears to take a model identifier and put it in the
URL used in an internal request. We would recommend validating the ID
per the rules you have for this datatype (typically this should only
be alphanumeric and less than 255 characters) and URLencode it before
appending it to a URL.
After all those stuff, I have made the following changes to my code
Made sure OrganizationId and AccountId Guid are not empty
URL Encoded the string
Here is the code after changes
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
if (organizationId != Guid.Empty && accountId != Guid.Empty)
{
string url = HttpUtility.UrlEncode($"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
using var result = await _client.GetAsync(url);
var content = await result.Content.ReadAsStringAsync();
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
return BadRequest();
}
Thats All I could do to sanitize my input parameters OrganizationId and AccountId but after all those changes veracode still identifies a SSRF flaw on line
using var result = await _client.GetAsync(url);
I found a hack to fix this issue, I just appended the query string parameters to the Base Address of httpClient and veracode stopped giving me error.
Here is how the solution looks like
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
if (organizationId != Guid.Empty && accountId != Guid.Empty)
{
var httpClient = new HttpClient();
//Appended the parameters in base address to
//to fix veracode flaw issue
httpClient.BaseAddress = new Uri($"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
//passing empty string in GetStringAsync to make sure
//veracode doesn't treat it like modifying url
var content = await httpClient.GetStringAsync("");
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
return BadRequest();
}

How to Automate SharePoint Record Updates

So we have an inventory list with details about each item, mostly drop down menus and check boxes, some comments and descriptions. These records are in SharePoint. Sometimes we need to update multiple items in there in addition to a large number of other steps and I am trying to automate most of these steps including the updates to their SharePoint record. What is the best way to go about this in PowerShell from any remote computer?
Would I connect to the database, find the record and and update the record there? Is there an easier way? I tried finding PowerShell CLI tools for SharePoint but I don't see them available anywhere.
For example, I might want to update this field here:
I think the the best Automate update list item in SharePoint remotely is using CSOM(C# code) API.
Here is a demo about update list item for your reference:
// Starting with ClientContext, the constructor requires a URL to the
// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");
// Assume that the web has a list named "Announcements".
List announcementsList = context.Web.Lists.GetByTitle("Announcements");
// Assume there is a list item with ID=1.
ListItem listItem = announcementsList.GetItemById(1);
// Write a new value to the Body field of the Announcement item.
listItem["Body"] = "This is my new value!!";
listItem.Update();
context.ExecuteQuery();
For do authentication to access SharePoint, we can do as below:
/// <summary>
/// set authentication of SharePoint online
/// </summary>
/// <param name="clientContext"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
public static void setOnlineCredential(ClientContext clientContext,string userName,string password)
{
//set the user name and password
SecureString secureString = new SecureString();
foreach (char c in password.ToCharArray())
{
secureString.AppendChar(c);
}
clientContext.Credentials = new SharePointOnlineCredentials(userName, secureString);
}
/// <summary>
/// set authentication of SharePoint on-premise
/// </summary>
/// <param name="clientContext"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <param name="domain"></param>
public static void setClientCredential(ClientContext clientContext, string userName, string password, string domain)
{
clientContext.Credentials = new NetworkCredential(userName, password, domain);
}
If you want to use PowerShell, We can use PowerShell to use CSOM as this article talked: CSOM SharePoint PowerShell Reference and Example Codes and we just need to modify the code above to be PowerShell code

Web API Help Pages and API Explorer returning 0 descriptions

I have this project that is just a Web API project. At some point in the past I removed the HelpPages and I made the app use OWIN.
Now I have been asked to add API HelpPages back in which I have done.
I have set my Startup class to look a bit like this:
public void Configuration(IAppBuilder app)
{
// Needs to be first
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
var httpConfig = new HttpConfiguration();
// Register all areas
AreaRegistration.RegisterAllAreas();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
app.UseWebApi(httpConfig);
}
So that my route for the help pages is working.
As far as I can tell, that should just work but the problem is that the ApiExplorer doesn't pull back any descriptions.
In my ConfigureWebApi method I remove formatting, I have commented that out but and still it doesn't work, here is the method:
private void ConfigureWebApi(HttpConfiguration config)
{
// Web API configuration and services
var formatters = config.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var serializerSettings = jsonFormatter.SerializerSettings;
// Remove XML formatting
formatters.Remove(config.Formatters.XmlFormatter);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
jsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
// Configure our JSON output
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
serializerSettings.Formatting = Formatting.Indented;
serializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
serializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I actually edited the HelpController and put a breakpoint on the return view line which is how I know the ApiExplorer has no descriptions:
public ActionResult Index()
{
var docProdivder = Configuration.Services.GetDocumentationProvider();
var desciptions = Configuration.Services.GetApiExplorer().ApiDescriptions;
ViewBag.DocumentationProvider = docProdivder;
return View(desciptions);
}
I read somewhere that if I do this:
public void Configuration(IAppBuilder app)
{
// Needs to be first
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
var httpConfig = new HttpConfiguration();
var exploerer = new ApiExplorer(httpConfig);
var descriptions = exploerer.ApiDescriptions;
// Register all areas
AreaRegistration.RegisterAllAreas();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
app.UseWebApi(httpConfig);
}
I should see the descriptions, but it still doesn't work.
So then I read somewhere else to set my project to output the xml description file and configure the HelpPageConfig file to use the documentProvider. I generated the Xml description file and can verify that my descriptions are in there, here is a snippet:
<member name="T:Melanite.Controllers.CollectionsController">
<summary>
Controller for all collection related functions
</summary>
</member>
<member name="M:Melanite.Controllers.CollectionsController.#ctor">
<summary>
Default constructor
</summary>
</member>
<member name="M:Melanite.Controllers.CollectionsController.Get(System.Int32)">
<summary>
Get all the collections for the given center
</summary>
<param name="centerId">The id of the center that the collection belongs to</param>
<returns>A list of collections</returns>
</member>
<member name="M:Melanite.Controllers.CollectionsController.Get(System.Int32,System.DateTime)">
<summary>
Get all the collections for the given center on a specific date
</summary>
<param name="centerId">The id of the center that the collection belongs to</param>
<param name="date">The planned collection date for the collections</param>
<returns>A list of collections</returns>
</member>
I uncommented out the lines in the HelpPageConfig like this:
// Uncomment the following to use the documentation from XML documentation file.
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
and made sure that the XML file was in the App_Data folder. The names are all correct, but when I run my project I still get no descriptions from the ApiExplorer.
So, as you can see I am at my wits end. I hope that someone has come across this before and knows how to fix it. If you do, please help!
I have the same problem. If I added
GlobalConfiguration.Configure(WebApiConfig.Register)
in Startup class (I don't use global.asax) everything worked properly. I hope this will help you, too.
If you don't have access to WebApiConfig.Register, which I didn't with my Owin WebApi project, the following code seems to work for me.
GlobalConfiguration.Configure((config) => { config.MapHttpAttributeRoutes(); });

How do I set a response cookie on HttpReponseMessage?

I would like to create a demo login service in web api and need to set a cookie on the response. How do I do that? Or are there any better way to do authorization?
Add a reference to System.Net.Http.Formatting.dll and use the AddCookies extension method defined in the HttpResponseHeadersExtensions class.
Here is a blog post describing this approach, and the MSDN topic.
If that assembly isn't an option for you, here's my older answer from before this was an option:
Older answer follows
I prefer an approach that stays within the realm of HttpResponseMessage without bleeding into the HttpContext which isn't as unit testable and does not always apply depending on the host:
/// <summary>
/// Adds a Set-Cookie HTTP header for the specified cookie.
/// WARNING: support for cookie properties is currently VERY LIMITED.
/// </summary>
internal static void SetCookie(this HttpResponseHeaders headers, Cookie cookie) {
Requires.NotNull(headers, "headers");
Requires.NotNull(cookie, "cookie");
var cookieBuilder = new StringBuilder(HttpUtility.UrlEncode(cookie.Name) + "=" + HttpUtility.UrlEncode(cookie.Value));
if (cookie.HttpOnly) {
cookieBuilder.Append("; HttpOnly");
}
if (cookie.Secure) {
cookieBuilder.Append("; Secure");
}
headers.Add("Set-Cookie", cookieBuilder.ToString());
}
Then you can include a cookie in the response like this:
HttpResponseMessage response;
response.Headers.SetCookie(new Cookie("name", "value"));
You can add the cookie to the HttpContext.Current.Response.Cookies collection.
var cookie = new HttpCookie("MyCookie", DateTime.Now.ToLongTimeString());
HttpContext.Current.Response.Cookies.Add(cookie);

Silverlight 4 dynamically downloaded satellite assembly problem

I am dynamically downloading a XAP file that has an embedded resource assembly, with a single resource file (ApplicationStrings.fr-CA.resx). I am using WebClient to pull down the XAP file and using the following code to load the assembly, based on work done by Jeff Prosise in this post: http://www.wintellect.com/CS/blogs/jprosise/archive/2010/06/21/dynamic-localization-in-silverlight.aspx.
Note that I also manually create the XAP file from the fr-CA folder with assembly and the ApplicationManifest.xaml, as described by Guy Smith-Ferrier's steps listed in his presentation here http://www.guysmithferrier.com/post/2010/10/Building-Localized-XAP-Resource-Files-For-Silverlight-4.aspx.
// Get the application manifest from the downloaded XAP
StreamResourceInfo sri = new StreamResourceInfo(e.Result, null);
XmlReader reader = XmlReader.Create(Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream);
AssemblyPartCollection parts = new AssemblyPartCollection();
// Enumerate the assemblies in the downloaded XAP
if (reader.Read())
{
reader.ReadStartElement();
if (reader.ReadToNextSibling("Deployment.Parts"))
{
while (reader.ReadToFollowing("AssemblyPart"))
{
parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") });
}
}
}
// Load the satellite assemblies
foreach (AssemblyPart part in parts)
{
if (part.Source.ToLower().Contains("resources"))
{
Stream assembly = Application.GetResourceStream(sri, new Uri(part.Source, UriKind.Relative)).Stream;
part.Load(assembly);
}
}
// Change the culture
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
The assembly seems to load ok, and I have matched up namespaces with the default resource file (ApplicationStrings.resx) with the downloaded resource file (ApplicationStrings.fr-CA.resx). As seen the code, the culture is set for the current thread.
However, calls to ApplicationStrings.ResourceManager.GetString(...) do not return the resources for the set culture. For example, the following should return a string for the new culture (fr-CA), but always returns the default culture (en-US).
/// <summary>
/// Looks up a localized string similar to User Name:.
/// </summary>
public static string Label_UserName {
get {
return ResourceManager.GetString("Label_UserName", resourceCulture);
}
}
Any suggestions? Thanks.
** UPDATE
I figured it out...I had forgotten to reset my supported locals in my satellite assembly project file:
<SupportedCultures>fr-CA</SupportedCultures>
I also made my folder structure exactly as it is for the default resources in my main Silverlight application.

Resources