how to instantiate this object in Startup.cs - c#

I am using OAuth token based authentication in my web api based project.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
//At this line, I am getting Error Object reference not set.
if (_membershipService.ValidateUser(context.UserName.Trim(), context.Password.Trim()))
{
var user = _membershipService.GetUser(context.UserName);
/* db based authenication*/
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
identity.AddClaim(new Claim("sub", context.UserName));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
},
{
"userName", user.Email
},
{
"role", (user.Role).ToString()
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
else
{
context.Rejected();
}
}
While calling _membershipService.ValidateUser(), I am getting Object reference not set. Which is quite obvious.
So in order to fix this error, I defined the constructor as.
public SimpleAuthorizationServerProvider(IMembershipService membershipService)
{
_membershipService = membershipService;
}
And while calling the method, I am passing the reference.
Startup.cs
public void ConfigureOAuth(IAppBuilder app)
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//passing the membership object.
Provider = new SimpleAuthorizationServerProvider(_membershipService),
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
//Token Consumption
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
Object reference not set to an instance of an object.
So I tried to overload constructor of Startup.cs as below:
public Startup(IMembershipservice membership)
{
_membership = membership;
}
But this throws the below run time error
No parameterless constructor defined for this object.
Startup.cs
public Startup()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
RegisterIOC();
}
private void RegisterIOC()
{
container = new WindsorContainer();
container.Register(Component.For<SimpleAuthorizationServerProvider>().LifestyleTransient());
//rest of the stuff
}
How do I instanitate the Membership Class.
(Please note I am using Castle Windsor DI Container).
Any help/suggestion highly appreciated.
Thanks.

You say that you are using the Castle Windsor DI Container but there is no code that initializes container in the Startup.cs class.
If you use OWIN (Startup.cs class) then you don't need the application initialization in the Global.asax Application_Start method.
You should move the container initialization to the Startup.cs class and resolve the IMembershipservice instance after the initialization.
Something like this:
public void Configuration(IAppBuilder app)
{
var container = new WindsorContainer().Install(new WindsorInstaller());
container.Register(Component.For<IAppBuilder>().Instance(app));
var httpDependencyResolver = new WindsorHttpDependencyResolver(container);
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.DependencyResolver = httpDependencyResolver;
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorControllerActivator(container));
app.UseWebApi(config);
}
Then you can use the container to resolve the instance of your class.

Related

How to use or resolve a service(or dependency) in the Startup class

When using IdentityServerBearerTokenAuthentication middle-ware, I would like to have access to a service that is registered in my WebApi config. Specifically, I want to call a service to give me the default user id and add it to the Claims in the the request. See my TODO in the example code below in the OnValidateIdentity lambda.
//startup.cs
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = ConfigurationManager.AppSettings["Federation.IdentityServerPath"]
});
// azure functions will authenticate using Azure AD Tokens
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
Provider = new OAuthBearerAuthenticationProvider()
{
OnValidateIdentity = context =>
{
//add the account id claim if it's specified in the header
var accountIdString = context.Request.Headers["X-AccountId"];
if (!string.IsNullOrWhiteSpace(accountIdString) && Guid.TryParse(accountIdString, out var _))
{
context.Ticket.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, accountIdString));
}
else
{
//TODO: Need to pull the system user or admin user and jam that account id into NameIdentifier.
var systemDefaultId = "";
// How do I get a dependency from HttpContext or context.OwinContext?????
context.Ticket.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, systemDefaultId));
}
context.Ticket.Identity.AddClaim(new Claim("cl_aad_user", "true"));
return Task.FromResult<object>(null);
}
}
}
);
}
}
}
The application services are registered with the autofac builder pattern.
e.g.
builder.RegisterType<AccountInfoService>().As<IAccountInfoService>().InstancePerRequest(); in a static method that is called in a Global class (Global.asax).
// Global.asax.cs
...
private void Application_Start(object sender, EventArgs e)
{
// ... truncated code
// registers the services
GlobalConfiguration.Configure(WebApiConfig.Register);
}
I have tried grabbing a service from the HttpContext, but it always resolves to null. (i.e. var db = (IOutcomesContext)HttpContext.Current.Request.RequestContext.HttpContext.GetService(typeof(IAccountService));)
I have also checked this answer, but I am not using that middle ware.
This is how I register the dependencies.
// WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
RegisterIoc(config);
}
private static void RegisterIoc(HttpConfiguration config)
{
ContainerBuilder builder = GetIocContainerBuilder();
builder.RegisterWebApiFilterProvider(config);
//all the external dependencies
builder.RegisterType<InstitutionRequestContext>().As<IInstitutionRequestContext>().InstancePerRequest();
Autofac.IContainer container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
internal static ContainerBuilder GetIocContainerBuilder()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// ... truncated service list
builder.RegisterType<AccountInfoService>().As<IAccountInfoService>().InstancePerRequest();
return builder;
}
}
Thanks for the help.
I ended up solving the above problem by switching the application to use the app.UseAutofacMiddleware(container); middle ware as described in this answer.
For my particular use case, it only involved a few changes, specifically...
removing the autofac from the Global config file (e.g. Global.asax)
updating my WebApiConfig to return the Autofac.IContainer
adding 3 or so method calls to the Startup.Configure class as described in their documentation

How to retrieve ClaimsPrincipal from JWT in asp.net core

In my solution, I have two projects. 1) Web API and 2) MVC. I am using ASP.NET Core. API issues JWT token and MVC consumes it to get protected resources. I am using openiddict library to issue JWT. In MVC project, in AccountController Login method, I want to retrieve ClaimsPrincipal (using JwtSecurityTokenHandler ValidateToken method) and assign to HttpContext.User.Claims and HttpContext.User.Identity. I want to store the token in session and for each request after successful login, pass it in header to Web API. I can successfully, issue JWT and consume it in MVC project, but when I try to retrieve ClaimsPrincipal it throws me an error. First of all, I am not even sure whether this retrieving of ClaimsPrinciapal from JWT is a right approach or not. And if it is, what is the way forward.
WebAPI.Startup.CS
public class Startup
{
public static string SecretKey => "MySecretKey";
public static SymmetricSecurityKey SigningKey => new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IContainer ApplicationContainer { get; private set; }
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddCors();
services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver(); });
services.AddAutoMapper();
services.AddDbContext<MyDbContext>(options =>
{
options.UseMySql(Configuration.GetConnectionString("MyDbContext"));
options.UseOpenIddict();
});
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<TelescopeContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/Authorization/Token");
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
options.DisableHttpsRequirement();
options.UseJsonWebTokens();
options.AddEphemeralSigningKey();
options.SetAccessTokenLifetime(TimeSpan.FromMinutes(30));
});
var config = new MapperConfiguration(cfg => { cfg.AddProfile(new MappingProfile()); });
services.AddSingleton(sp => config.CreateMapper());
// Create the Autofac container builder.
var builder = new ContainerBuilder();
// Add any Autofac modules or registrations.
builder.RegisterModule(new AutofacModule());
// Populate the services.
builder.Populate(services);
// Build the container.
var container = builder.Build();
// Create and return the service provider.
return container.Resolve<IServiceProvider>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime applicationLifetime)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseCors(builder => builder.WithOrigins("http://localhost:9001/")
.AllowAnyOrigin());
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = "http://localhost:9001/",
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Audience = "http://localhost:9000/",
RequireHttpsMetadata = false,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = "http://localhost:9001/",
ValidateAudience = true,
ValidAudience = "http://localhost:9000",
ValidateLifetime = true,
IssuerSigningKey = SigningKey
}
});
app.UseOpenIddict();
app.UseMvcWithDefaultRoute();
applicationLifetime.ApplicationStopped.Register(() => this.ApplicationContainer.Dispose());
}
}
WebAPI.AuthorizationController.cs which issues JWT.
[Route("[controller]")]
public class AuthorizationController : Controller
{
private IUsersService UserService { get; set; }
public AuthorizationController(IUsersService userService)
{
UserService = userService;
}
[HttpPost("Token"), Produces("application/json")]
public async Task<IActionResult> Exchange(OpenIdConnectRequest request)
{
if (request.IsPasswordGrantType())
{
if (await UserService.AuthenticateUserAsync(new ViewModels.AuthenticateUserVm() { UserName = request.Username, Password = request.Password }) == false)
return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
var user = await UserService.FindByNameAsync(request.Username);
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme, OpenIdConnectConstants.Claims.Name, null);
identity.AddClaim(OpenIdConnectConstants.Claims.Subject, user.UserId.ToString(), OpenIdConnectConstants.Destinations.AccessToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Username, user.UserName, OpenIdConnectConstants.Destinations.AccessToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Email, user.EmailAddress, OpenIdConnectConstants.Destinations.IdentityToken);
identity.AddClaim(OpenIdConnectConstants.Claims.GivenName, user.FirstName, OpenIdConnectConstants.Destinations.IdentityToken);
identity.AddClaim(OpenIdConnectConstants.Claims.MiddleName, user.MiddleName, OpenIdConnectConstants.Destinations.IdentityToken);
identity.AddClaim(OpenIdConnectConstants.Claims.FamilyName, user.LastName, OpenIdConnectConstants.Destinations.IdentityToken);
identity.AddClaim(OpenIdConnectConstants.Claims.EmailVerified, user.IsEmailConfirmed.ToString(), OpenIdConnectConstants.Destinations.IdentityToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Audience, "http://localhost:9000", OpenIdConnectConstants.Destinations.AccessToken);
var principal = new ClaimsPrincipal(identity);
return SignIn(principal, OpenIdConnectServerDefaults.AuthenticationScheme);
}
throw new InvalidOperationException("The specified grant type is not supported.");
}
}
MVC.AccountController.cs contains Login, GetTokenAsync method.
public class AccountController : Controller
{
public static string SecretKey => "MySecretKey";
public static SymmetricSecurityKey SigningKey => new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginVm vm, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var token = await GetTokenAsync(vm);
SecurityToken validatedToken = null;
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = "http://localhost:9001/",
ValidateAudience = true,
ValidAudience = "http://localhost:9000",
ValidateLifetime = true,
IssuerSigningKey = SigningKey
};
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
try
{
ClaimsPrincipal principal = handler.ValidateToken(token.AccessToken, validationParameters, out validatedToken);
}
catch (Exception e)
{
throw;
}
}
return View(vm);
}
private async Task<TokenVm> GetTokenAsync(LoginVm vm)
{
using (var client = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:9001/Authorization/Token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["username"] = vm.EmailAddress,
["password"] = vm.Password
});
var response = await client.SendAsync(request, HttpCompletionOption.ResponseContentRead);
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadAsStringAsync();
//if (payload["error"] != null)
// throw new Exception("An error occurred while retriving an access tocken.");
return JsonConvert.DeserializeObject<TokenVm>(payload);
}
}
}
Error I am getting: "IDX10501: Signature validation failed. Unable to match 'kid': '0-AY7TPAUE2-ZVLUVQMMUJFJ54IMIB70E-XUSYIB', \ntoken: '{\"alg\":\"RS256\",\"typ\":\"JWT\",\"kid\":\"0-AY7TPAUE2-ZVLUVQMMUJFJ54IMIB70E-XUSYIB\"}.{\"sub\":\"10\",\"username\":\"...
See this thread because I was looking for the very same thing (not the exception though), and the accepted answer indeed helps the OP, however, it doesn't help me with : how to create ClaimsPrincipal from JWT Token.
After some research and digging, I've found a way to do it manually (it was my case, I had to do it manually in a specific case).
To do so, first, parse the token with JwtSecurityTokenHandler class :
var token = new JwtSecurityTokenHandler().ReadJwtToken(n.TokenEndpointResponse.AccessToken);
After that, you just ned to create a new ClaimsPrincipal :
var identity = new ClaimsPrincipal(new ClaimsIdentity(token.Claims));
In my specific case, I just have to update claims on my already authenticated user, so I use this code :
var identity = (ClaimsIdentity)User.Identity;
identity.AddClaims(token.Claims);
Hope it will help someone one day if looking after the answer for the title.
First of all, I am not even sure whether this retrieving of ClaimsPrinciapal from JWT is a right approach or not.
It's likely not the approach I'd personally use. Instead, I'd simply rely on the JWT middleware to extract the ClaimsPrincipal from the access token for me (no need to manually use JwtSecurityTokenHandler for that).
The exception thrown by IdentityModel is actually caused by a very simple root cause: you've configured OpenIddict to use an ephemeral RSA asymmetric signing key (via AddEphemeralSigningKey()) and registered a symmetric signing key in the JWT bearer options, a scenario that can't obviously work.
You have two options to fix that:
Register your symmetric signing key in the OpenIddict options using AddSigningKey(SigningKey) so OpenIddict can use it.
Use an asymmetric signing key (by calling AddEphemeralSigningKey(), or AddSigningCertificate()/AddSigningKey() on production) and let the JWT bearer middleware use it instead of your symmetric signing key. For that, remove the entire TokenValidationParameters configuration to allow IdentityModel to download the public signing key from OpenIddict's discovery endpoint.

Always getting the "Authorization has been denied for this request." message

I'm able to successfully retrieve token, but when trying to authenticate using the token I always get the Authorization has been denied for this request message.
My Startup.cs file contains the following methods
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
ConfigureOAuth(app);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter().First();
jsonFormatter.SerializerSettings
.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
private void ConfigureOAuth(IAppBuilder app)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new DefaultAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
The DefaultAuthorizationServerProvider.cs class contains the following
public class DefaultAuthorizationServerProvider : 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 identityManager = new IdentityManager();
var identity = identityManager.Get(context.UserName, context.Password,
new IpAddressProvider().Provide(IpAddressType.Forwarding));
if (identity == null)
{
context.SetError("invalid_grant", "Authentication failed. Please make sure you provided the correct username and password.");
}
else
{
identity.AddClaim(new Claim(ClaimTypes.Role, "User"));
context.Validated(identity);
}
}
}
And the IdentityManager.cs class have the following
public class IdentityManager : IIdentityManager
{
public virtual ClaimsIdentity Get
(
string username,
string password,
string ipAddress
)
{
var authenticateUserWorkflowOutput = new AuthenticateUserWorkflowHelper().Execute
(
new AuthenticateUserWorkflowInput
{
Username = username,
Password = password,
IpAddress = ipAddress
},
new AuthenticateUserWorkflowState()
);
if (authenticateUserWorkflowOutput.Message.Exception != null)
{
return null;
}
if (!authenticateUserWorkflowOutput.Authenticated)
{
return null;
}
return authenticateUserWorkflowOutput.User != null ? new Infrastructure.Identity(new[]
{
new Claim(ClaimTypes.Name, authenticateUserWorkflowOutput.MasterUser.EmailAddress),
}, "ApplicationCookie") : null;
}
}
Using Fiddler I can successfully retrieve a token
But when I try to authenticate using the token I get the following response
Ok, I found the problem in my Startup class. I was missing the following
[assembly: OwinStartup(typeof(Yugasat.System.ServiceLayer.Startup))]
namespace Yugasat.System.ServiceLayer
and the ConfigureOAuth(app);call needed to be moved to the top of the Configuration method. Below is my new Startup.cs class.
[assembly: OwinStartup(typeof(Yugasat.System.ServiceLayer.Startup))]
namespace Yugasat.System.ServiceLayer
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
private void ConfigureOAuth(IAppBuilder app)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new DefaultAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}

Using Autofac with Web Api 2 and Owin

Im new to DI libraries and trying to use Autofac in a WebApi 2 project with Owin. This is my Owin Startup class,
[assembly: OwinStartup(typeof(FMIS.SIGMA.WebApi.Startup))]
namespace FMIS.SIGMA.WebApi
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
WebApiConfig.Register(config);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
ConfigureOAuth(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());
}
}
}
When I call a Api method I get this error
An error occurred when trying to create a controller of type
'MyController'. Make sure that the controller has a
parameterless public constructor.
What am I missing here?
MyController code is something like this
public class MyController : ApiController
{
ISomeCommandHandler someCommanHandler;
public MyController(ISomeCommandHandler SomeCommandHandler)
{
this.someCommanHandler = SomeCommandHandler;
}
// POST: api/My
public void Post([FromBody]string value)
{
someCommanHandler.Execute(new MyCommand() {
Name = "some value"
});
}
// GET: api/My
public IEnumerable<string> Get()
{
}
// GET: api/My/5
public string Get(int id)
{
}
}
You have set DependencyResolver to AutofacWebApiDependencyResolver, so Autofac comes into play and instantiates dependencies for you. Now you have to explicitly tell Autofac which concrete implementations should be used when an instance of interface is required.
Your controller requires an instance of ISomeCommandHandler:
MyController(ISomeCommandHandler SomeCommandHandler)
So you need to configure types that expose that interface:
builder.RegisterType<CommandHandler>.As<ISomeCommandHandler>();
Have a look at this documentation section for more examples about Autofac registration concepts.

Owin Bearer Token Not Working for WebApi

I have gone through loads of documentation on this, My google search shows that I've visited all the links on the first page
Problem
Token Generation works fine. I configured it with a custom provider as such:
public void ConfigureOAuth(IAppBuilder app)
{
var usermanager = NinjectContainer.Resolve<UserManager>();
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AppOAuthProvider(usermanager)
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
However when I call a protected URL and pass the bearer token, I always get:
How do I diagnose or fix the problem. If possible, how can I do the token validation myself
UPDATE
Here is my AppOAuthProvider. Both Methods are called when I'm trying to mint a token but not when I'm trying to access a protected resource
public class AppOAuthProvider : OAuthAuthorizationServerProvider
{
private UserManager _user;
public AppOAuthProvider(UserManager user)
{
_user = user;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//Get User Information
var getUser = _user.FindUser(context.UserName);
if (getUser.Status == StatusCode.Failed)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return Task.FromResult<object>(null);
}
var user = getUser.Result;
//Get Roles for User
var getRoles = _user.GetRoles(user.UserID);
if (getRoles.Status == StatusCode.Failed)
{
context.SetError("invalid_grant", "Could not determine Roles for the Specified User");
}
var roles = getRoles.Result;
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("UserID", user.UserID.ToString()));
identity.AddClaim(new Claim("UserName", user.UserName));
foreach (var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role));
}
context.Validated(identity);
return Task.FromResult<object>(null);
}
}
UPDATE 2:
Here is my Account Controller
[RoutePrefix("api/auth/account")]
public class AccountController : ApiController
{
private UserManager _user;
public AccountController(UserManager user)
{
_user = user;
}
[Authorize]
[HttpGet]
[Route("secret")]
public IHttpActionResult Secret()
{
return Ok("Yay! Achievement Unlocked");
}
}
UPDATE 3:
Here is my Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNinjectMiddleware(NinjectContainer.CreateKernel);
app.UseNinjectWebApi(GlobalConfiguration.Configuration);
GlobalConfiguration.Configure(WebApiConfig.Register);
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(GlobalConfiguration.Configuration);
app.UseWelcomePage();
}
}
You must configure the OAuth authorization server and OAuth bearer authentication before call UseWebApi on IAppBuilder. The following is from my program.
public void Configuration(IAppBuilder app)
{
app.UseFileServer(new FileServerOptions()
{
RequestPath = PathString.Empty,
FileSystem = new PhysicalFileSystem(#".\files")
});
// set the default page
app.UseWelcomePage(#"/index.html");
ConfigureAuth(app);
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute
(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.JsonFormatter.SerializerSettings =
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new YourApplicationOAuthProvider()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication
(
new OAuthBearerAuthenticationOptions
{
Provider = new OAuthBearerAuthenticationProvider()
}
);
}
HttpConfiguration config = new HttpConfiguration();
app.UseNinjectMiddleware(NinjectContainer.CreateKernel);
app.UseNinjectWebApi(GlobalConfiguration.Configuration);
ConfigureOAuth(app);
WebApiConfig.Register(config);
//GlobalConfiguration.Configure(WebApiConfig.Register);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// app.UseWebApi(GlobalConfiguration.Configuration);
app.UseWebApi(config);
app.UseWelcomePage();
I tried this with ur sample application on github and it worked
In your provider you have to:
public override ValidateClientAuthentication(OAuthClientAuthenticationContext context)
{
//test context.ClientId
//if you don't care about client id just validate the context
context.Validated();
}
The reason for this is that if you don't override ValidateClientAuthentication and validate the context, it is assumed as rejected and you'll always get that error.

Categories

Resources