'Access Denied' on Web API with security Authorization - c#

I'm trying to create a dummy web api with authentication
by following this link : YouTube Video Tutorial Link
Controller Code :
MySecurityClient msc = new MySecurityClient();
ViewBag.result1 = msc.Demo()==null ?"Access Denied": msc.Demo();
return View();
In Model:
public class MySecurityClient
{
private string BASE_URL = "http://localhost:3513/api/MySecurity/";
private object convert;
public string Demo()
{
try
{
HttpClient Client = new HttpClient();
var authInfo = Convert.ToBase64String(Encoding.Default.GetBytes("acc1:123"));
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);
Client.BaseAddress = new Uri(BASE_URL);
HttpResponseMessage response = Client.GetAsync("Work2").Result;
if (response.IsSuccessStatusCode)
return response.Content.ReadAsStringAsync().Result;
return null;
}
catch (Exception ex)
{
return null;
}
}
}
Server Controller :
[HttpGet]
[Route("Work2")]
[MyAuthorize(Roles="SuperAdmin")]
public string Work2()
{
return "Work2";
}
Authorization Override:
public override void OnAuthorization(HttpActionContext actionContext)
{
try
{
AuthenticationHeaderValue authValue = actionContext.Request.Headers.Authorization;
if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter)
&& authValue.Scheme == BasicAuthResponseHeaderValue)
{
Credential parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
var MyPrincipal = new MyPrincipal(parsedCredentials.UserName);
if (!MyPrincipal.IsInRole(Roles))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK);
actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
//return;
}
}
}
catch (Exception ex)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK);
actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
}
response.IsSuccessStatusCode is true,
but ViewBag.result1 is empty if we use return response.Content.ReadAsAsync<string>().Result;
and Access Denied on return response.Content.ReadAsAsync<string>().Result;
Thanks in advance

Related

Getting content-type from HttpActionContext

I am trying to do an authorization of an endpoint based on a value passed in the body request. For example, a siteID is passed in the body of the request & I want to do authorization based on if the user has the appropriate permissions to that site.
I have this working if the body request is passed as json, but not if it's form urlencoded. And I can't figure out how to find that out beforehand. Here is a snippet of my code that works with json data, but fails if body request is urlencoded.
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.Request;
try
{
var content = actionContext.Request.Content.ReadAsStringAsync().Result;
var jsonResult = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
_siteId = jsonResult["siteID"].ToString();
actionContext.Response = UserWorker.UserValidation(_siteId, request) as HttpResponseMessage;
}
catch (Exception e)
{
actionContext.Response = request.CreateResponse(HttpStatusCode.BadRequest, e.Message);
}
You can get the content-type from the Request object. Try this:
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.Request;
try
{
var content = actionContext.Request.Content.ReadAsStringAsync().Result;
var contentType = request.Content.Headers.ContentType;
string _siteId = string.Empty;
if (contentType.MediaType == "application/json") //JSON case:
{
dynamic jsonResult = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
_siteId = jsonResult["siteID"].ToString();
}
else // form urlencode case:
{
_siteId = content.Split('=')[0] == "siteID" ? content.Split('=')[1] : string.Empty;
}
actionContext.Response = UserWorker.UserValidation(_siteId, request) as HttpResponseMessage;
}
catch (Exception e)
{
actionContext.Response = request.CreateResponse(HttpStatusCode.BadRequest, e.Message);
}
}

ASP.NET Core - getting a message from AuthenticateResult.Fail

Can not get an error message in HTTP response.
if (!string.IsNullOrWhiteSpace(checkTokenResponse.Error))
{
Logger.LogError(checkTokenResponse.Error);
return AuthenticateResult.Fail(checkTokenResponse.Error);
}
response
I suppose the error message should render into data response field
The same question ASP.NET Core - getting a message back from AuthenticationHandler
Update
code of custom Auth handler
public class AuthHandler : AuthenticationHandler<AuthOptions>
{
private readonly IPrimeApiProxy _primeApiProxy;
private readonly IPrimeProxy _primeProxy;
private readonly int _adminGroupId;
private static readonly string HeaderName = "Authorization";
private static readonly string ApiAuthScheme = "oauth ";
public AuthHandler(
IOptionsMonitor<AuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IPrimeApiProxy primeApiProxy,
IPrimeProxy primeProxy,
ApplicationSettingsProvider settings)
: base(options, logger, encoder, clock)
{
_primeApiProxy = primeApiProxy ?? throw new ArgumentNullException(nameof(primeApiProxy));
_primeProxy = primeProxy ?? throw new ArgumentNullException(nameof(primeProxy));
_adminGroupId = int.Parse((settings as dynamic).AdminGroupId as string);
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
Logger.LogTrace("HandleAuthenticateAsync");
if (!Request.Headers.ContainsKey("Authorization"))
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
try
{
var token = FetchToken(Request);
if (string.IsNullOrWhiteSpace(token.token) && token.userId < 1)
{
Logger.LogError("Invalid token");
return AuthenticateResult.Fail("Invalid token");
}
var checkTokenResponse = await _primeProxy.CheckToken(token.token);
if (!string.IsNullOrWhiteSpace(checkTokenResponse.Error))
{
Logger.LogError(checkTokenResponse.Error);
return AuthenticateResult.Fail(checkTokenResponse.Error);
}
var isValidInt = int.TryParse(checkTokenResponse.UserId, out var userId);
if (!isValidInt)
{
return AuthenticateResult.Fail("User Id is invalid");
}
if (token.userId != userId)
{
return AuthenticateResult.Fail("The token belongs to another user");
}
bool isUserAdminAndCustomGroupMember = false;
if (checkTokenResponse.UserRole == "admin")
{
isUserAdminAndCustomGroupMember = await _primeApiProxy.IsGroupMember(token.token, token.userId, _adminGroupId);
}
var claims = new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, token.userId.ToString()),
new Claim(ClaimTypes.Role, isUserAdminAndCustomGroupMember ? "Admin" : "Learner")
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
catch (Exception ex)
{
Logger.LogError(ex, "Auth exception");
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
private static (string token, int userId) FetchToken(HttpRequest request)
{
string authHeader = request.Headers[HeaderName];
if (authHeader != null && authHeader.StartsWith(ApiAuthScheme, StringComparison.OrdinalIgnoreCase))
{
string token = authHeader.Substring(ApiAuthScheme.Length).Trim();
string[] parts = token.Split(',', StringSplitOptions.RemoveEmptyEntries);
if (int.TryParse(parts[1], out int userId))
{
return (parts[0], userId);
}
}
return (null, 0);
}
}

Unable to get mvc webapi bearer token after hosting on server

I'm working on the securing the web API by OAuth bearer token as this working fine in local able to generate token, After hosting on server code is not working to generate token hosted on the server.
when am trying to the server sample Url "api.somedemo.com/token" showing the request responce as method not found ,
but in local "http://local:1234/token" same code working generated token.
I can't able find where am missing on the server to able generate bearer token.
here the code.
From Controller:
private BearerToken GetBearerToken(string userName, string password)
{
BearerToken token = null;
FormUrlEncodedContent bearerTokenContent = OAuthClientWrapper.CreateBearerToken(userName, password);
Uri tokenUri = new Uri("api.somedemo.com/token");
token = OAuthClientWrapper.GetJwtToken(tokenUri, bearerTokenContent);
return token;
}
OAuthClientWrapper Class:
public static FormUrlEncodedContent CreateBearerToken(string userName, string password)
{
var bearerTokenContent = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("grant_type", "password")
};
return new FormUrlEncodedContent(bearerTokenContent);
}
GetJwtToken method:
public static BearerToken GetJwtToken(Uri uri, FormUrlEncodedContent bearerTokenContent)
{
BearerToken token = null;
try
{
using (var httpClient = new HttpClient())
{
//Set the headers
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (HttpResponseMessage response = httpClient.PostAsync(uri, bearerTokenContent).Result)
{
if (response.IsSuccessStatusCode)
{
token = response.Content.ReadAsAsync<BearerToken>().Result;
}
else
{
var reasonPhrase = response.ReasonPhrase;
var result = response.Content.ReadAsStringAsync();
var errorMessage = string.Format("Error: {0} {1} for uri: {2}", reasonPhrase, result, uri.AbsoluteUri);
//Log the error message
token = null;
} //else
} //using
}//using
}//try
catch (AggregateException aex)
{
throw aex;
}//catch
return token;
}
As WebAPI Startup Class:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
ConfigureAuth(app);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseJwtBearerAuthentication(new MyJwtOptions());
}
}
Startupoverride :
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
int tokenExpiration = Convert.ToInt32(ConfigurationManager.AppSettings["TokenExpiration"]);
OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(),
//AccessTokenFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey)),
AccessTokenFormat = new MyJwtFormat(),
RefreshTokenProvider = new ApplicationRefreshTokenProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(tokenExpiration)
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Application OAuthProviderClass:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
IHttpClientWrapper _HttpClientWrapper = null;
private IEndPoints _ConfigsProviders = null;
public ApplicationOAuthProvider()
{
_HttpClientWrapper = new HttpClientWrapper();
_ConfigsProviders = new EndPoints();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
try
{
var isValidUser = false;
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var url = string.Format("{0}/{1}/{2}", "someAPIBaseUrl", context.UserName, context.Password);
//Getting user information if login is validated in json format.
var returnValue = _HttpClientWrapper.GetStringAsync(url);
var responseObject = JsonConvert.DeserializeObject<ResponseObject>(returnValue);
if (responseObject.Status==true)
{
isValidUser = true;
}
if (!isValidUser)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
context.Validated(identity);
}
catch (Exception ex)
{
throw ex;
}
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
public MyJwtFormat()
{
_tokenIssuer = ConfigurationManager.AppSettings["TokenIssuer"];
_tokenExpiration = Convert.ToInt32(ConfigurationManager.AppSettings["TokenExpiration"]);
}
ConfigurationManager.AppSettings["TokenIssuer"] given "localhost" in sever also.
Please help to fix this issue
Advance thanks you.

creating web api and calling asynchronous

I am creating web api. I want to call in bot messenger framework.
In web api controller i have method :
public async Task<HttpResponseMessage> Get()
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, DateTime.UtcNow.ToString());
return response;
}
In the bot framework i have this code :
public static async Task<List<EventModel>> Response(string uri)
{
//string escapeString = Uri.EscapeDataString(phrase);
string returnValue = string.Empty;
try
{
using (var client = new HttpClient())
{
var message = await client.GetAsync(uri);
if (message.IsSuccessStatusCode)
{
var jsonResponse = await message.Content.ReadAsStringAsync();
jsonResponse = jsonResponse.TrimStart('\"');
jsonResponse = jsonResponse.TrimEnd('\"');
jsonResponse = jsonResponse.Replace("\\", "");
var data = JsonConvert.DeserializeObject<List<EventModel>>(jsonResponse);
return data;
}
else return null;
}
}
catch (Exception exc)
{
return null;
}
}
the problem : client.GetAsync(uri) never ends.
Some help ?

When I try use WebClient's DownloadString I response error (401) Unauthorized

I try understand how work with api (based on api.vk.com).
I have created ASP.NET MVC 4 empty project.
It part of Controller:
public ActionResult LoginVk()
{
vkProvider = new VKProvider();
vkProvider.Config = new VkAppConfig { AppKey = "5572789", AppSecret = "i2OpN7gj62ddwTqqRJrK" };
return Redirect(vkProvider.Authorize("http://localhost:56287/User/Access"));
}
public string Authorize(string redirectTo)
{
return string.Format(AuthorizeUri, Config.AppKey, redirectTo);
}
public ActionResult Access()
{
if (Request.Params.AllKeys.Contains("code"))
{
var code = Request.Params["code"];
if (ProcessVkCode(code))
{
return RedirectToAction("List");
}
}
return View("Error");
}
protected bool ProcessVkCode(string code)
{
if (vkProvider.GetAccessToken(code))
{
var jsonVkAccess = JsonConvert.SerializeObject(vkProvider.AccessToken);
var jObj = vkProvider.GetUserInfo();
var vkUser = new User
{
FirstName = jObj.ToString(),
LastName = jsonVkAccess.ToString()
};
repository.SaveUser(vkUser);
return true;
}
return false;
}
It's part of model VKProvider:
public static string AuthorizeUri =
"http://api.vkontakte.ru/oauth/authorize?client_id={0}&scope=photos,offline,wall,groups&redirect_uri={1}&response_type=code";
public static string GetTokenUri =
"https://api.vkontakte.ru/oauth/access_token?client_id={0}&client_secret={1}&code={2}";
public bool GetAccessToken(string Code)
{
try
{
string reqStr = string.Format(GetTokenUri, Config.AppKey, Config.AppSecret, Code);
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
WebClient webClient = new WebClient();
var response = webClient.DownloadString(reqStr);
AccessToken = JsonConvert.DeserializeObject<VkAccessToken>(response);
return true;
}
catch (WebException ex)
{
return false;
}
}
Application return error (401) Unauthorized when execute webClient.DownloadString(reqStr). What is wrong?

Categories

Resources