I have a web api 2 application created with some controllers that uses authentication. This is written in .NET using C#. Then I am consuming this via an android application. The initial request works fine to validate the user and return true. It is on the 2nd URL request where I am calling a method via the web api 2 that uses authentication to work where everything bombs out with a Request.Path exception message.
Below are the android .java files in question.
HttpHelper class:
package com.example.helpers;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import android.util.Log;
public abstract class HttpHelper {
private final static String TAG = "HttpHelper";
private final static String API_URL = "http://10.0.2.2/application/api";
private static CookieStore sCookieStore;
public static String invokePost(String action, List<NameValuePair> params) {
try {
String url = API_URL + action + "/";
Log.d(TAG, "url is" + url);
HttpPost httpPost = new HttpPost(url);
if (params != null && params.size() > 0) {
HttpEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
httpPost.setEntity(entity);
}
return invoke(httpPost);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
public static String invokePost(String action) {
return invokePost(action, null);
}
public static String invokeGet(String action, List<NameValuePair> params) {
try {
StringBuilder sb = new StringBuilder(API_URL);
sb.append(action);
if (params != null) {
for (NameValuePair param : params) {
sb.append("?");
sb.append(param.getName());
sb.append("=");
sb.append(param.getValue());
}
}
Log.d(TAG, "url is" + sb.toString());
HttpGet httpGet = new HttpGet(sb.toString());
return invoke(httpGet);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
public static String invokeGet(String action) {
return invokeGet(action, null);
}
private static String invoke(HttpUriRequest request)
throws ClientProtocolException, IOException {
String result = null;
DefaultHttpClient httpClient = new DefaultHttpClient();
// restore cookie
if (sCookieStore != null) {
httpClient.setCookieStore((org.apache.http.client.CookieStore) sCookieStore);
}
HttpResponse response = httpClient.execute(request);
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
for (String s = reader.readLine(); s != null; s = reader.readLine()) {
builder.append(s);
}
result = builder.toString();
Log.d(TAG, "result is ( " + result + " )");
// store cookie
sCookieStore = (CookieStore) ((AbstractHttpClient) httpClient).getCookieStore();
return result;
}
}
Consuming Code:
@Override
protected String doInBackground(String... arg0) {
StringBuilder stringBuilder = new StringBuilder();
String authResult = HttpHelper.invokeGet("<validate_user_via_web_api>");
String nextResult = HttpHelper.invokeGet("<call_web_api_other_method>");
return stringBuilder.toString();
}
The value of sCookieStore
within the HttpHelper
class:
[[version: 0][name: .ASPXAUTH][value: <long_string_of_numbers_and_characters>][domain: 10.0.2.2][path: /][expiry: null]]
This is what gets stored in the sCookieStore
variable in the HttpHelper
class that gets applied to the httpClient
via the setCookieStore
.
And the code for web api 2. First the 'validate_user_via_web_api' /api/account?userName=&userPassword=:
using Application.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Security;
namespace Application.Controllers
{
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private AuthRepository _repo = null;
public AccountController()
{
_repo = new AuthRepository();
}
public bool Get(String userName, String userPassword)
{
Task<IdentityUser> iu = _repo.FindUser(userName, userPassword);
if (iu != null)
{
FormsAuthentication.SetAuthCookie(userName, false);
return true;
}
return false;
}
[Authorize(Roles="Application")]
[Route("Register")]
public async Task<IHttpActionResult> Register(UserModel userModel)
{
String userID = "";
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await _repo.RegisterUser(userModel);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
else
{
Task<IdentityUser> iu = _repo.FindUser(userModel.UserName, userModel.Password);
using (var context = new AuthContext())
{
var userStore = new UserStore<IdentityUser>(context);
var userManager = new UserManager<IdentityUser>(userStore);
userID = iu.Result.Id;
result = await userManager.AddToRoleAsync(userID, "Users");
errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
}
}
return Ok("userID:" + userID);
}
protected override void Dispose(bool disposing)
{
if (disposing)
_repo.Dispose();
base.Dispose(disposing);
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
return InternalServerError();
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
}
}
The 'call_web_api_other_method' code example:
[Authorize(Roles="Users")]
[Route("routinename")]
public IHttpActionResult getapplicationmethod(string param1, string param2)
{
//rest of code...
}
This is the one that is causing the Request.Path error. When I just go to the URL provided, without going first to validating the user authentication, everything bombs out instead of getting an unauthorized message. The url looks something similar to below and nothing within the URL looks to be something that would cause that error to be thrown:
http://hostname/application/api/data/getapplicationmethod?param1=param_value1¶m2=param_value2
.
Also when I go to this link directly via the browser, I get the Authorization has been denied for this request message that I should get without authenticating the request.
Putting [System.Web.Mvc.ValidateInput(false)]
on the given method still produces the same error as well. Even with that and the httpRuntime targetFramework="2.0"
the error still gets thrown. Obviously I wouldn't keep these changes in place they were just for testing purposes.
Handled exception message:
A potentially dangerous Request.Path value was detected from the client (:)
<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information
about the error and where it originated in the code. <br><br>
<b> Exception Details: </b>System.Web.HttpException: A potentially dangerous Request.Path value was detected from the client (:).<br><br>
<b>Source Error:</b> <br><br> An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location
of the exception can be identified using the exception stack trace below.<br> <b>Stack Trace:</b> <br><br>
[HttpException (0x80004005): A potentially dangerous Request.Path value was detected from the client (:).]
System.Web.HttpRequest.ValidateInputIfRequiredByConfig() +12715107 System.Web.PipelineStepManager.ValidateHelper(HttpContext context) +166 <br>
<b>Version Information:</b> Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.34237