Authorization using security token in WEB API without using Authentication - asp.net-web-api

How to secure WEB API with security token without using any login. We want to use this WEB API in windows service to get data from other db server. can't use user login or roles
We try [Authorize] attribute, but all in vain.
I try this
[MyAuthorize]
public class MasterDataController : ApiController
{
[HttpGet]
public string myMethod(string Name)
{
return Name;
}
}
MyAuthorize is
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext Context)
{
//Some logic to validate token...
}
}
WebApiConfig.cs is
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new AuthorizeAttribute());
config.Routes.MapHttpRoute(
name: "ActionGetPatientAndAppointmentInfo",
routeTemplate: "TestAPI/{controller}/{action}",
defaults: new
{
controller = "MasterData",
action = "myMethod"
}
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional}
);
}
}
When we test method in REST Client with Authorization header
But OnAuthorization method itself is not executing.
Response always show Unauthorized request.

this is the perfect scenario for OAuth2. You need to be able to generate a token and then to secure the API endpoints so only calls with this token in the authorization header will be fulfilled.
I suggest looking into using something like Owin which will give you everything you need.
This is application level authorization so you will have two keys, a ClientID and a ClientSecret which will be used to generate the token. This way you can even build multiple applications using the same API each identified through their own set of keys.
Here is a detailed article, albeit a bit older showing how to do it from scratch:
https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/

Related

ASP.NET Web Api 2 routing issue

I really can't understand why it does not work. I have the following code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
[RoutePrefix("api/Profile")]
[System.Web.Http.AuthorizeAttribute]
[IdentityBasicAuthenticationAttribute]
public class ProfileApiController : ApiController
{
[HttpPost]
[ValidateApiContentLength]
[ValidateApiMimeMultipart]
[Route("Upload")]
public async Task<HttpResponseMessage> UploadDocumentAsync(string description)
{
//....
}
}
}
but when I call: http://localhost:11015/api/profile/Upload
I get 404 error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:11015/api/profile/Upload'.",
"MessageDetail": "No action was found on the controller 'ProfileApi' that matches the request."
}
but insight says about error:
what is incorrect?
WebApi routing can't find your UploadDocumentAsync method. In your application you're using both the routing table (in the WebApiConfig class) and attribute routing. You don't need the latter.
You can leave the routing table in the WebApiConfig class as is and drop the Route and RoutePrefix attributes.
Change your action UploadDocumentAsync in the Profile controller to:
...
[HttpPost]
public async Task<HttpResponseMessage> UploadUploadDocumentAsync(string description)
{
...
just leaving the HttpPost attribute.
You can reach your your resource by calling (you can do it via Fiddler, for exampe):
POST http://localhost:11015/api/profile/
UPDATE:
Or if you would really like to have the "upload" part in your url, you can utilize the Route attribute for the action:
[Route("api/profile/upload")]
I have found a solution. Problem was not in the routing. Problem was in parameter of action. It should not be there for POST method. Other things leave as is
[HttpPost]
[ValidateApiContentLength]
[ValidateApiMimeMultipart]
[Route("upload")]
public async Task<HttpResponseMessage> UploadDocumentAsync()
{

Role based authorization in asp.net web api using ad access token

I need to implement role based authorization for asp .net web api
from native client application the access token will be sent in the header ,
so when i give [Authorize] attribute to my web api it is working fine,but when i give [Authorize(Role="Admin")] it is giving unauthorized error,
then whenever check for role in the claims it is always null.
My startup.cs is
public void Configuration(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
});
}
and i have applied authorize attribute for a method
[Authorize]
[HttpGet]
public async Task<UserDetails> TestAuthorization()
{
string upn = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
var role = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Role);
return null;
}
here the role value is always null
Please help me on this

Webapi method Get with string parameter not getting invoked

I am creating asp.net webapi with two get methods. One returns all the records while the other should be filtering based on a string parameter called countrycode. I am not sure for what reason the get method with string parameter doesnt get invoked.
I tried the following uri's
http://localhost:64389/api/team/'GB'
http://localhost:64389/api/team/GB
Following is my code
Web API
public HttpResponseMessage Get()
{
var teams = _teamServices.GetTeam();
if (teams != null)
{
var teamEntities = teams as List<TeamDto> ?? teams.ToList();
if (teamEntities.Any())
return Request.CreateResponse(HttpStatusCode.OK, teamEntities);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Team not found");
}
public HttpResponseMessage Get(string countryCode)
{
if (countryCode != null)
{
var team = _teamServices.GetTeamById(countryCode);
if (team != null)
return Request.CreateResponse(HttpStatusCode.OK, team);
}
throw new Exception();
}
WebAPIConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));
}
}
I think you are probably hitting the default 'Get()' method from your default API route.
I expect if you changed the parameter name to 'id' on your method like so, it would also work:
public HttpResponseMessage Get(string id)
This is because the optional parameter name in the default route is 'id'.
For attribute routing to work, you need to decorate your controller and methods with the values which were previously inferred by the route configuration.
So at the top of your controller, you would probably have:
[RoutePrefix("api/team")]
public class TeamController : ApiController
Then above your second get method:
[Route("{countryCode}")]
public HttpResponseMessage Get(string countryCode)
Since attribute routing, I haven't used the "old-style" routing.
Check out the ASP.NET page on attribute routing for more information.
Edit for comment:
If you have two routes which have the same parameters you need to differentiate them somehow in the route. So for your example of get by team name, I would probably do something like this:
[HttpGet()]
[Route("byTeamName/{teamName}")]
public HttpResponseMessage GetByTeamName(string teamName)
Your url would then be /api/team/byTeamName/...
Your other method name is "Get" and the default HTTP attribute routing looks for method names with the same as HTTP verbs. However you can name your methods anything you like and decorate them with the verbs instead.

Why does not MapHttpAttributeRoutes work in Stateless Web API in service fabric?

By default, VS 2015 templates for Web API in Service Fabric create a OWIN based hosting for Web API controllers. The default code in Startup.cs file for this service is:
public static void ConfigureApp(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
I replaced this code with following:
public static void ConfigureApp(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
appBuilder.UseWebApi(config);
}
and added
[RoutePrefix("mycontroller")]
public class ValuesController : ApiController
{
...
}
and try to navigate it by http://localhost:port/mycontroller.
It does not work.
The same code works fine when I create a web api controller with ASP.NET host project.
Am I doing something wrong here?
Attribute routing works just fine, it's the same ASP.NET whether it's hosted on Service Fabric or somewhere else. We use attribute routing in our Party Cluster sample. As Federico commented, make sure you have more than just the RoutePrefix on your controllers.

ODataController BearerToken Authorization denied

I'm trying to implement an Authentication Provider for my WebApi Services.
Im using this guide: http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
For testing purpose i've implemented two controllers in a separate webapi-project:
public class TestApiController : ApiController
{
[Authorize]
public string Get()
{
return "Secure";
}
public string Get(int id)
{
return "Not Secure";
}
}
public class TestODataController : ODataController
{
[Authorize]
[EnableQuery]
public HttpResponseMessage Get()
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
My Goal is to use the Odata Controller in the end.
When I call localhost:Port/api/TestApi and set the Bearer Token in the Header, everythings works fine. When i do the call localhost:Port/odata/TestOData and add the token i receive the Message :
Authorization has been denied for this request.
It doesn't matter if i set the token in header or not. If i remove the Authorize Attribute everything works fine.
I'm using Postman to call the methods, if this is of any interest.
At the moment i'm using iis-express from visual studio to host the controllers, but iis is alread configured but produces the same message.
My Startup.cs (the interesting part...)
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
ConfigureOAuth(app);
FilterConfig.Register(config);
ODataConfig.Register(config);
WebApiConfig.Register(config);
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
//Token consumption
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{});
}
OData and WebConfig :
public class ODataConfig
{
public static void Register(HttpConfiguration config)
{
ODataConventionModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<MyModel>("MyModel");
var conventions = ODataRoutingConventions.CreateDefault();
var route = config.Routes.MapODataRouteFixed(
routeName: "ODataRoute",
routePrefix: "odata",
model: modelBuilder.GetEdmModel(),
conventions: conventions) as Route;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
The Account-Controller to add new user is in another project. The database looks good and the token generation works, too. It's almost the same code as the example from bitoftech-demo.
I don't see the difference betweens these controllers. The Auhtorize attribute is recognized by the controller...but something else is wrong.
Any hints would be appreciated.
Update
After some research and the first answers i updated my startup values. The old options are only necessary for token generation and not token consumption. But still api controllers works and OdataController throws "Authorization denied".
Update2
It worked now. But i'm not quite sure why. I removed everything from my FilterConfig :
public class FilterConfig
{
public static void Register(HttpConfiguration config)
{
//config.SuppressDefaultHostAuthentication();
//config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
}
}
But i have no idea why it was working before with the api controller and not with the odata controller...
If you use one project for getting the token and another for webApi, both must have the same machine key in web.config.
In the next post of the same serial that you are following explains how to do it: Decouple OWIN Authorization Server from Resource Server
Example:
<system.web>
...
<machineKey validationKey="57B449BBA8F9E656087FF7848727E122C5F5966F65AC0FC25FB3532193B59CFCD13B370883FFC184C1F1500638F33E6F67B37CAED1D9BC65BBC6CFFB232BFD0B" decryptionKey="6D9FBE88D16B3FA5B5E6B37460BBE50DA85D5B4C482159006B5A337C58AA9E79" validation="SHA1" decryption="AES" />
...
</system.web>
Why you are using app.UseCookieAuthentication(new CookieAuthenticationOptions()); and app.UseOAuthAuthorizationServer(OAuthOptions); on the same time, I guess this is only API project with no MVC, right?
Remove the app.UseOAuthAuthorizationServer(OAuthOptions); and try again.
What is the value in response header (WWW-Authenticate) when you receive 401? Bearer or something else?
I had the similar problem and found this answer posted on Telerik web site and it worked for me. It required setting the dataType to "json".
transport: {
type: "odata",
read: {
url: "http://........",
dataType: "json",
beforeSend: function (xhr) {
var auth = 'Bearer ' + token;
xhr.setRequestHeader('Authorization', auth);
}
},
},
This is the url:
http://www.telerik.com/forums/odata-not-working-with-custom-authorization-header

Resources