ASP.NET Identity Token Methods accepts all HTTP methods - c#

I created pone webapi and implemented authentication. I have the token method to get the user token. All working fine.
Scenario:
I tested the token method with the postman. Here I noted that I can use any type of HTTP method to request for the token. I think /token method should support POST method only. But when I use DELETE method also I got token. Same as, I can also use PUT, PATH etc.
Is this expected? I assume that it should return Method Not Supported other than POST requests.

You can write your custom OAuthAuthorizationServerOptions.Provider. And use the context to accept Http Post request only
OAuthAuthorizationServerOptions is asp.net identity core class. which you can find under this namespace Microsoft.Owin.Security.OAuth.
Sample Code:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
if (context.Request.Method != "POST")
{
context.SetError("invalid_request", "Invalid request");
return;
}
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
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));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}

Related

How Owin Use OAuthAuthorizationServer?

I am trying to undesratnd owin and OAuthAuthorizationServer.
I know that Outh2 has 4 parts:
1- Resource Owner
2- Resource Server:
3- Client Applications:
4- Authorization Server:
I have implemnted owin and Authorization Server in a simple application.
The application is working fine.
I just want to learn more regading the Outh stuffs.
so I have in my srartp class :
public class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);//this is very important line cross orgin source(CORS)it is used to enable cross-site HTTP requests //For security reasons, browsers restrict cross-origin HTTP requests
var OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),//token expiration time
Provider = new OauthProvider()
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);//register the request
}
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
Then I created my OauthProvider
here is my class
public class OauthProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//First request will come here, this method will validate the request wheather it has crendtials(UserName and Password) if the request not contain username and
//password the request will reject from here not proceded any further
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//If the request has valid and it contain username and password than this method will check correct crenstials and than generate a valid token
var identity = new ClaimsIdentity(context.Options.AuthenticationType); //it will check the authenticate type
using (var db = new DataContext())
{
if (db != null)
{
var user = db.Users.Where(o => o.UserName == context.UserName && o.Password == context.Password).FirstOrDefault();
if (user != null)
{
//Store information againest the request
identity.AddClaim(new Claim("UserName", context.UserName));
identity.AddClaim(new Claim("LoggedOn", DateTime.Now.ToString()));
context.Validated(identity);
}
else
{
context.SetError("Wrong Crendtials", "Provided username and password is incorrect");
context.Rejected();
}
}
else
{
context.SetError("Wrong Crendtials", "Provided username and password is incorrect");
context.Rejected();
}
return;
}
}
}
So if I want to undersatnd the OAuth parts.
How can I define what I have done to each part ?
Notice That this is a web api project ?
Any useful informatuin is helpful.
Thanks

How to validate credentials with user created table and generate Token in web API

I am new to WEB API ,here I need to implement a token based authentication for a login page .
As of now I have completed the token generate functions by providing static values for learning purpose .
Now What I want to do is I want to validate each request with the table which I have created in my SQL SERVER (LOGIN_TABLE) and generate Token instead of validate with Identity tables in web API.
Columns of LOGIN_TABLE
FirstName,LastName,UserName,Email,Password,CreationDate
I don't know is it possible or not ,if possible please help me to do that .
I have created my project as Web API template without MVC and choosed No Authentication then I have added all the necessary packages and classes.
Here I have added the code I have used to generate token based on the static values.
My_Controller.cs
[Authorize]
[HttpGet]
[Route("api/data/authenticate")]
public IHttpActionResult GetForAuthenticate()
{
var identity = (ClaimsIdentity)User.Identity;
return Ok("Hello" + identity.Name);
}
MyAutorizationServerProvider.cs
public class MyAuthorizationServerProvider :OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
if (context.UserName == "user" && context.Password == "123")
{
identity.AddClaim(new Claim(ClaimTypes.Role, "USER"));
identity.AddClaim(new Claim("username", "user"));
identity.AddClaim(new Claim(ClaimTypes.Name, "Sakthi"));
context.Validated(identity);
}else
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
//This enable cors orgin requests
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var myProvider = new MyAuthorizationServerProvider();
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
Provider = myProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
}
}
AuthorizeAttribute.cs
public class AuthorizeAttribute :System.Web.Http.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actioncontext)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(actioncontext);
}else
{
actioncontext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
}
}
I am new to web API if I did any mistakes here please guide me to correct it .
Thanks .

"Message": "Authorization has been denied for this request." OWIN middleware

I added Token based authentication to my OWIN middleware and can generate the token. But while using, the token for an API call with Authorize attribute I always get "Authorization has been denied for this request." It works fine though without Authorize attribute. Here is my startup.cs and controller method. Any thoughts , what is wrong?
startup.cs
public void Configuration(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["issuer"];
var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["secret"]);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new SimpleAuthProvider(),
AccessTokenFormat = new JwtFormat(issuer)
});
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { "*" },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
container = BuildDI();
var config = new HttpConfiguration();
config.Formatters.XmlFormatter.UseXmlSerializer = true;
config.MapHttpAttributeRoutes();
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ExternalBearer));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseCors(CorsOptions.AllowAll);
app.UseSerilogRequestContext("RequestId");
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
RegisterShutdownCallback(app, container);
}
public class SimpleAuthProvider: OAuthAuthorizationServerProvider
{
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.UserName != context.Password)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
context.Rejected();
return Task.FromResult<object>(null);
}
var ticket = new AuthenticationTicket(SetClaimsIdentity(context), new AuthenticationProperties());
context.Validated(ticket);
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ExternalBearer);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
return identity;
}
}
API Controller Method:
[HttpGet]
[Route("sampleroute")]
[Authorize]
public async Task<HttpResponseMessage> GetSamples(string search)
{
try
{
HttpResponseMessage response;
using (HttpClient client = new HttpClient(Common.CreateHttpClientHandler()))
{
response = await client.GetAsync("test url");
}
var result = response.Content.ReadAsStringAsync().Result;
Samples[] sampleArray = JsonConvert.DeserializeObject<Samples[]>(result);
var filteredSamples = sampleArray .ToList().Where(y => y.NY_SampleName.ToUpper().Contains(search.ToUpper())).Select(n=>n);
log.Information("<==========Ended==========>");
return Request.CreateResponse(HttpStatusCode.OK,filteredSamples);
}
catch (Exception ex)
{
log.Error($"Error occured while pulling the Samples: {ex.ToString()}");
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.ToString());
}
}
It's probably a problem with the allowed audiences.
Here
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
...
AllowedAudiences = new[] { "*" },
...
}
you set the allowed audiences. The tokens audclaim will be checked against the list of AllowedAudiences. But you never add any audience to the token.
In our project I used a CustomJwtFormat based on the code shown in http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
The token will be generated with a call to
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
the second parameter is responsible for the aud claim in the JWT:
From https://msdn.microsoft.com/en-us/library/dn451037(v=vs.114).aspx :
audience
Type: System.String
If this value is not null, a { aud, 'audience' } claim will be added.
After setting the aud claim in the token authorization should work fine.
From what I understood, you need to add the header: Authorization: Bearer "token".
If you have not modified the default implementation of the authorization request the steps are these:
Register user at the endpoint:
/api/Account/Register
Post to /token the following items:
grant_type: password
username: "the username you registered"
password: "the password you registered for the user"
You will receive a token in the Response
Copy that token and create a Request to the method you secured with the [Authorize] filter of type:
Authorization: Bearer "the_token_you_copied_earlier"
Needless to say, it could be pretty easy for you if you used Postman or Fiddler to make and receive Requests because it shows you how everything works.

token authorize web api 2 doesn't return userName

I'm using in my project asp.net web api 2, token authorize and when send request to /Token,I receive response
{
access_token: "u3XOCYV91f2P6odbceNIY_BnkfSpN7gQwzknsRi_.......0iRPlHYNMEES9",
token_type: "bearer",
expires_in: 1209599,
}
There is no argument UserName =( and when i send the request to the server with token on Authorize ActionResult,everything works well, but User.Identity.Name is null, User.Identity.isAuthenticated = true. Help pls.
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (AuthorizeRepository _repo = new AuthorizeRepository())
{
User user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
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));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
For User.Identity.Name to be automatically populated, you must add a ClaimTypes.Name claim in your access token:
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));

MVC-6 vs MVC-5 BearerAuthentication in Web API

I have a Web API project that use UseJwtBearerAuthentication to my identity server.
Config method in startup looks like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseJwtBearerAuthentication(options =>
{
options.AutomaticAuthentication = true;
options.Authority = "http://localhost:54540/";
options.Audience = "http://localhost:54540/";
});
// Configure the HTTP request pipeline.
app.UseStaticFiles();
// Add MVC to the request pipeline.
app.UseMvc();
}
This is working, and I want to do the same thing in an MVC5 project. I tried to do something like this:
Web api:
public class SecuredController : ApiController
{
[HttpGet]
[Authorize]
public IEnumerable<Tuple<string, string>> Get()
{
var claimsList = new List<Tuple<string, string>>();
var identity = (ClaimsIdentity)User.Identity;
foreach (var claim in identity.Claims)
{
claimsList.Add(new Tuple<string, string>(claim.Type, claim.Value));
}
claimsList.Add(new Tuple<string, string>("aaa", "bbb"));
return claimsList;
}
}
I can't call web api if is set attribute [authorized] (If I remove this than it is working)
I created Startup. This code is never called and I don't know what to change to make it work.
[assembly: OwinStartup(typeof(ProAuth.Mvc5WebApi.Startup))]
namespace ProAuth.Mvc5WebApi
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
Uri uri= new Uri("http://localhost:54540/");
PathString path= PathString.FromUriComponent(uri);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = path,
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
}
goal is to return claims from web api to client app. using Bearer Authentication.
Thanks for help.
TL;DR: you can't.
Authority refers to an OpenID Connect feature that has been added to the bearer middleware in ASP.NET 5: there's no such thing in the OWIN/Katana version.
Note: there's an app.UseJwtBearerAuthentication extension for Katana, but unlike its ASP.NET 5 equivalent, it doesn't use any OpenID Connect feature and must be configured manually: you'll have to provide the issuer name and the certificate used to verify tokens' signatures: https://github.com/jchannon/katanaproject/blob/master/src/Microsoft.Owin.Security.Jwt/JwtBearerAuthenticationExtensions.cs
You can get claims as:
IAuthenticationManager AuthenticationManager
{
get
{
return Request.GetOwinContext().Authentication;
}
}
public IHttpActionResult UserRoles()
{
return ok(AuthenticationManager.User.Claims.ToList());
}
This code should be in [Authorize] controller.

Categories