Caching Claims in .net core 2.0 - c#

Looked up everywhere but looks like I am stuck right now. I am using Windows Active Directory in my application for authentication.
For authorization, I am using claims. After searching through the limited .net core documentation, this is how my code looks like.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IPrincipal>(
provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
}
ClaimsTransformer.cs
class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// call to database to get more claims based on user id ClaimsIdentity.Name
((ClaimsIdentity)principal.Identity).AddClaim(new Claim("now",DateTime.Now.ToString()));
return Task.FromResult(principal);
}
}
But the problem is, this code is called with every request and claims are loaded from the db every time which is absolutely wrong. Is there any way I can cache it? I was able to create a cookie of claims and use that cookie for any further calls in .net 4.0. I can't seem to find a way in the core. Any documentation I check, is incomplete or it does not cover my scenario. I am able to claims further in my application just how the documentation says here: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims
But there is no mention about caching the claims.
Anyone in the same boat? Or knows the way out of it?

You can inject the IMemoryCache service in your ClaimsTransformer constructor.
using Microsoft.Extensions.Caching.Memory;
public class ClaimsTransformer : IClaimsTransformation
{
private readonly IMemoryCache _cache;
public ClaimsTransformer(IMemoryCache cache)
{
_cache = cache;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var cacheKey = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (_cache.TryGetValue(cacheKey, out List<Claim> claims)
{
((ClaimsIdentity)principal.Identity).AddClaims(claims);
}
else
{
claims = new List<Claim>();
// call to database to get more claims based on user id ClaimsIdentity.Name
_cache.Set(cacheKey, claims);
}
return principal;
}
}

I am not doing the exact same thing, but I am using cookie Authentication/Authorization. Most of what I learned comes from this microsoft doc but as you said the documentation doesn't seem to take you all the way there. Here is what is working for me:
in startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication("tanushCookie")
.AddCookie("tanushCookie", options => {
options.AccessDeniedPath = "/api/Auth/Forbidden";
options.LoginPath = "/";
options.Cookie.Expiration = new TimeSpan(7,0,0,0);
});
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
...
app.UseAuthentication();
}
And then in your controller that handles authentication:
[HttpPost()]
[Route("api/[Controller]/[Action]/")]
public async Task<JsonResult> Login([FromBody]Dictionary<string, string> loginData)
{
try
{
var loggedIn = true;
if (loggedIn)
{
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, "tanush")
};
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaims(claims);
ClaimsPrincipal principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(
"tanushCookie",
principal,
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddDays(7)
});
}
return new JsonResult(logRtn);
}
catch (Exception ex)
{
return new JsonResult(ex.Message);
}
}
I am unsure if you can use cookies with windows authentication. However if you can authenticate and assign loggedIn the result of your authentication request, you should be able to store some sort of claim(s) in the cookie. You can then recall that claim in a controller that might be doing authorization/recalling values using the following:
[HttpGet("[Action]", Name = "GetSomething")]
[Route("[Action]")]
public JsonResult something()
{
try
{
var loggedInUser = HttpContext.User;
var claym = loggedInUser.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name);
if (claym != null)
{
return new JsonResult(claym.Value);
// returns "tanush"
}
else
{
return new JsonResult("");
}
}
catch (Exception ex)
{
return new JsonResult(ex.Message);
}
}

Related

Dependency Injection - There is no argument given that corresponds to the required parameter

I found a couple of sample code implementations of JWT authentication on the internet but I'm having difficulties in making these codes work together (since I got these codes from various sources).
I'm trying to add JWT authentication to the generated WeatherForecast API project (Web API) in visual studio.
Below are the changes I made to the default project:
1. Create a JWT Service class: Create a new class that will handle creating and validating JWTs. This class should have methods for creating a JWT given a set of claims, and for validating a JWT and returning the claims contained within it.
public class JwtService
{
private readonly SymmetricSecurityKey _signingKey;
public JwtService(string secretKey)
{
_signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
}
public string CreateToken(ClaimsIdentity claims)
{
var jwt = new JwtSecurityToken(
issuer: "app",
audience: "app",
claims: claims.Claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddDays(7),
signingCredentials: new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
public ClaimsPrincipal GetPrincipalFromToken(string token)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "app",
ValidateAudience = true,
ValidAudience = "app",
ValidateLifetime = true,
IssuerSigningKey = _signingKey
};
var handler = new JwtSecurityTokenHandler();
try
{
var principal = handler.ValidateToken(token, tokenValidationParameters, out var validatedToken);
return principal;
}
catch (SecurityTokenValidationException)
{
return null;
}
}
}
2. Create a JWT Authentication Service class: Create a new class that will handle authenticating users and returning a JWT. This class should have a method for authenticating a user given a username and password and returning a JWT if the authentication is successful.
public class JwtAuthenticationService
{
private readonly JwtService _jwtService;
public JwtAuthenticationService(JwtService jwtService)
{
_jwtService = jwtService;
}
public string Authenticate(string username, string password)
{
// authenticate user
var authenticated = username == "test" && password == "test";
if (!authenticated)
return null;
// create claims
var claims = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, "User")
});
// create token
return _jwtService.CreateToken(claims);
}
}
3. Create a JWT Authorization filter: Create a new class that will handle checking if the request contains a valid JWT and, if it does, adding the claims contained within the JWT to the current user's claims.
public class JwtAuthorizationFilter : AuthorizationFilterAttribute
{
private readonly JwtService _jwtService;
public JwtAuthorizationFilter(JwtService jwtService)
{
_jwtService = jwtService;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
// check if the request contains an Authorization header
var authHeader = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
if (authHeader == null || !authHeader.StartsWith("Bearer "))
{
context.Result = new UnauthorizedResult();
return;
}
// get the token from the header
var token = authHeader.Substring("Bearer ".Length).Trim();
// validate the token and get the claims
var claimsPrincipal = _jwtService.GetPrincipalFromToken(token);
if (claimsPrincipal == null)
{
context.Result = new UnauthorizedResult();
return;
}
// set the current user's claims
var identity = (ClaimsIdentity)claimsPrincipal.Identity;
var claims = identity.Claims.ToList();
var genericIdentity = new GenericIdentity(identity.Name);
genericIdentity.AddClaims(claims);
var genericPrincipal = new GenericPrincipal(genericIdentity, new string[] { identity.RoleClaimType });
context.HttpContext.User = genericPrincipal;
}
}
4. Add the filter to the WeatherForecastController: Apply the filter to the WeatherForecastController class using the [JwtAuthorizationFilter] attribute.
[ApiController]
[Route("api/[controller]")]
[JwtAuthorizationFilter]
public class WeatherForecastController : ControllerBase
{
private readonly IWeatherForecastService _weatherForecastService;
public WeatherForecastController(IWeatherForecastService weatherForecastService)
{
_weatherForecastService = weatherForecastService;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
// check if the user is authorized
if (!User.IsInRole("User"))
{
throw new UnauthorizedAccessException();
}
// return the weather forecast data
return _weatherForecastService.GetWeatherForecasts();
}
}
5. Add the JWT service and authentication service to the Dependency Injection container: In the Startup.cs class, add the JwtService and JwtAuthenticationService classes to the Dependency Injection container so that they can be injected into other classes as dependencies.**
services.AddSingleton<JwtService>(new JwtService("your_secret_key"));
services.AddSingleton<JwtAuthenticationService>();
6. Add the JWT filter to the Dependency Injection container: In the Startup.cs class, add the JwtAuthorizationFilter to the Dependency Injection container so that it can be applied to controllers as a filter.**
services.AddSingleton<JwtAuthorizationFilter>();
Here's the final Startup.cs after the changes:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<JwtService>(new JwtService("your_secret_key"));
services.AddSingleton<JwtAuthenticationService>();
services.AddSingleton<JwtAuthorizationFilter>();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WeatherForecast", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WeatherForecast v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
The Error:
There is no argument given that corresponds to the required parameter 'jwtService' of 'JwtAuthorizationFilter.JwtAuthorizationFilter(JwtService)'
The error is encountered at the line where I added the [JwtAuthorizationFilter] attribute on the WeatherForecastController class:
[ApiController]
[Route("[controller]")]
[JwtAuthorizationFilter] // <-- Error occurs at this line
public class WeatherForecastController : ControllerBase { ...
I understand that JwtAuthorizationFilter has a constructor that accepts an argument of JwtService type but I'm not sure how exactly to supply it in the controller or in the Startup.cs.
You can't use constructor DI like this for an attribute. Instead, get the services you require in inside the attribute. For example:
public class JwtAuthorizationFilter : AuthorizationFilterAttribute
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var jwtService = context.HttpContext.RequestServices
.GetRequiredService<JwtService>();
//etc
}
}

How to get Windows logon in Provider class of Owin authentication in Web API?

I want to get Windows logon of the users in GrantResourceOwnerCredentials method of Provider class and validate them. I tried all the possible ways like below, but no luck.
System.Security.Principal.WindowsIdentity.GetCurrent().Name --> It is returning the server name
Request.LogonUserIdentity --> null (It cant be accessed before authentication)
HttpContext.Current.User --> null
From what I understand, if you're only using Windows Authentication, you don't need to worry about GrantResourceOwnerCredentials. Are you trying to use the token authentication as well as the Windows authentication? you should only use Windows Authentication for a Web Api that is going to run on your intranet.
Forgive me if I say things you already know, but from the research I've done, and my thanks go to Dominick Baier on pluralsight, you need to:
Install the Microsoft.Owin and Microsoft.Owin.Security.OAuth nuget packages
Set Windows Authentication to "Enabled" on the Project (F4 properties window) or in the config file
Make sure you have the [Authorize] attribute on your controller and inherit from the ApiController
Specifically implement the Owin middleware (you will need to create three classes and make sure they are configured in the startup.cs class) Have a look at the following code:
1st Middleware class: declare the function
public class ClaimsTransformationOptions
{
public Func<ClaimsPrincipal, Task<ClaimsPrincipal>> ClaimsTransformation { get; set; }
}
2nd Middleware class: this is where the Invoke method is
public class ClaimsTransformationMiddleware
{
readonly ClaimsTransformationOptions _options;
readonly Func<IDictionary<string, object>, Task> _next;
public ClaimsTransformationMiddleware(Func<IDictionary<string, object>, Task> next, ClaimsTransformationOptions options)
{
_next = next;
_options = options;
}
public async Task Invoke(IDictionary<string, object> env)
{
// use Katana OWIN abstractions (optional)
var context = new OwinContext(env);
if (context.Authentication != null &&
context.Authentication.User != null)
{
var transformedPrincipal = await _options.ClaimsTransformation(context.Authentication.User);
context.Authentication.User = new ClaimsPrincipal(transformedPrincipal);
}
await _next(env);
}
}
3rd Middleware class: this is an extension class
public static class ClaimsTransformationMiddlewareExtensions
{
public static IAppBuilder UseClaimsTransformation(this IAppBuilder app,
Func<ClaimsPrincipal, Task<ClaimsPrincipal>> transformation)
{
return app.UseClaimsTransformation(new ClaimsTransformationOptions
{
ClaimsTransformation = transformation
});
}
public static IAppBuilder UseClaimsTransformation(this IAppBuilder app, ClaimsTransformationOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
app.Use(typeof(ClaimsTransformationMiddleware), options);
return app;
}
}
In the startup class:
public void Configuration(IAppBuilder app)
{
app.UseClaimsTransformation(Transformation);
}
private async Task<ClaimsPrincipal> Transformation(ClaimsPrincipal incoming)
{
if (!incoming.Identity.IsAuthenticated)
{
return incoming;
}
var name = incoming.Identity.Name;
// go to a datastore - find the app specific claims
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, name),
new Claim(ClaimTypes.Role, "foo"),
new Claim(ClaimTypes.Email, "foo#foo.com")
};
var id = new ClaimsIdentity("Windows");
id.AddClaims(claims);
return new ClaimsPrincipal(id);
}
In the Controller (Make sure it has the [Authorize] attribute and inherits from ApiController
public IEnumerable<ViewClaim> Get()
{
var principal = User as ClaimsPrincipal;
return from c in principal.Claims
select new ViewClaim
{
Type = c.Type,
Value = c.Value
};
}

.Net Core Custom Authentication using API Keys with Identity Server 4

I have a .NET Core 2.2 Web API that authenticates with JWT tokens. Tokens are generated by Identity Server 4 on a separate API.
All the authentication and authorisation works as expected with JWT tokens. But I need to extend this to allow usage of API keys. If an API key is supplied, I want to load up the claims of that particular user, add it to the request and let Authorize attribute deal with the set policies.
Here is what I have done so far following suggestions from here. My error is exactly the same as the linked post and it works for me as well using GenericPrincipal with a set of roles but I am using AuthorisationPolicies and I always get 401 error with my current implementation, giving me errors similar to the link above.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
options.Filters.Add(new AuthorizeFilter());
options.Filters.Add(typeof(ValidateModelStateAttribute));
options.AllowEmptyInputInBodyModelBinding = true;
})
.AddAuthorization(options =>
{
options.AddPolicies();
})
.AddJsonFormatters();
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration["Authentication:Authority"];
options.RequireHttpsMetadata = true;
options.ApiName = Configuration["Authentication:ApiName"];
});
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors(policy =>
{
policy.AllowAnyHeader();
policy.AllowAnyMethod();
policy.AllowAnyOrigin();
});
app.UseHttpsRedirection();
app.UseMiddleware<ApiKeyMiddleware>();
app.UseAuthentication();
app.UseMvc();
}
AuthorizationPolicies.cs
public static class AuthorizationPolicies
{
public const string ReadUsersPolicy = "ReadUsers";
public const string EditUsersPolicy = "EditUsers";
public static void AddPolicies(this AuthorizationOptions options)
{
options.AddPolicy(ReadUsersPolicy, policy => policy.RequireClaim(Foo.Permission, Foo.CanReadUsers));
options.AddPolicy(EditUsersPolicy, policy => policy.RequireClaim(Foo.Permission, Foo.CanEditUsers));
}
}
ApiKeyMiddleware
public class ApiKeyMiddleware
{
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
private readonly RequestDelegate _next;
public async Task Invoke(HttpContext context)
{
if (context.Request.Path.StartsWithSegments(new PathString("/api")))
{
if (context.Request.Headers.Keys.Contains("ApiKey", StringComparer.InvariantCultureIgnoreCase))
{
var headerKey = context.Request.Headers["ApiKey"].FirstOrDefault();
await ValidateApiKey(context, _next, headerKey);
}
else
{
await _next.Invoke(context);
}
}
else
{
await _next.Invoke(context);
}
}
private async Task ValidateApiKey(HttpContext context, RequestDelegate next, string key)
{
var userClaimsService = context.RequestServices.GetService<IUserClaimsService>();
List<string> permissions = (await userClaimsService.GetAllPermissionsForApiKey(key))?.ToList();
if (permissions == null)
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await context.Response.WriteAsync("Invalid Api Key");
return;
}
ICollection<Claim> claims = permissions.Select(x => new Claim(FooClaimTypes.Permission, x)).ToList();
var identity = new ClaimsIdentity(claims);
var principal = new ClaimsPrincipal(identity);
context.User = principal;
await next.Invoke(context);
}
}
UsersController.cs
[Authorize(AuthorizationPolicies.EditUsersPolicy)]
public async Task<IActionResult> Put([FromBody] UserUpdateDto userUpdateDto)
{
...
}
Apparently, I had to set AuthenticationType to be Custom on the ClaimsIdentity as explained here.
var identity = new ClaimsIdentity(claims, "Custom");

Simple token based authentication/authorization in asp.net core for Mongodb datastore

I need to implement pretty simple auth mechanizm with basically 2 roles: Owners and Users. And I think that having Enum for that will be enough. App itself is SPA with webapi implemented via Asp.net core. I saw article - how to implement it using EF Identity, but their models looks much more complex than I actually need and EF oriented to SQL db, and I using mongo. So my user will looks something like:
class UserModel{
Id,
Token,
Roles: ["Owners", "Users"],
...
}
So what interfaces I need to implement and add to DI to be able use
[Authorize] and [Authorize(Roles="Users")] attribute and they worked correctly based on token I send in header?
Let me clarify a little #Adem's answer. You need to to implement custom middleware in specific way. There is 3 abstract classes that need to be implemented to implementing this (answer is correct for asp.net core rc2btw):
Microsoft.AspNetCore.Builder.AuthenticationOptions
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware<TOptions>
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>
and then add this middleware to your startup class.
Code example:
public class TokenOptions : AuthenticationOptions
{
public TokenOptions() : base()
{
AuthenticationScheme = "Bearer";
AutomaticAuthenticate = true;
}
}
public class AuthMiddleware : AuthenticationMiddleware<TokenOptions>
{
protected override AuthenticationHandler<TokenOptions> CreateHandler()
{
return new AuthHandler(new TokenService());
}
public AuthMiddleware(RequestDelegate next, IOptions<TokenOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder) : base(next, options, loggerFactory, encoder)
{
}
}
public class AuthHandler : AuthenticationHandler<TokenOptions>
{
private ITokenService _tokenService;
public AuthHandler(ITokenService tokenService)
{
_tokenService = tokenService;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
string token = null;
AuthenticateResult result = null;
string token = Helper.GetTokenFromHEader(Request.Headers["Authorization"]);
// If no token found, no further work possible
if (string.IsNullOrEmpty(token))
{
result = AuthenticateResult.Skip();
}
else
{
bool isValid = await _tokenService.IsValidAsync(token);
if (isValid)
{
//assigning fake identity, just for illustration
ClaimsIdentity claimsIdentity = new ClaimsIdentity("Custom");
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, "admin"));
claims.Add(new Claim(ClaimTypes.NameIdentifier, "admin"));
claims.Add(new Claim(ClaimTypes.Role, "admin"));
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
result =
AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal,
new AuthenticationProperties(), Options.AuthenticationScheme));
}
else
{
result = AuthenticateResult.Skip();
}
}
return result;
}
}`
p.s. The code is just for illustration of idea. You will need to implement your own handler of course.
You can use custom middleware to authenticate user and set claims(name, roles etc.).
I will try to write a simple middleware:
First create a middlware class:
public class CustomMiddleware
{
private readonly RequestDelegate _next;
private readonly UserRepository _userRepository;
public CustomMiddleware(RequestDelegate next, UserRepository userRepository)
{
_next = next;
_userRepository = userRepository;
}
public async Task Invoke(HttpContext context)
{
string token = context.Request.Headers["Token"];
var user = _userRepository.Get(token);
ClaimsIdentity claimsIdentity = new ClaimsIdentity("Custom");
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, "admin"));
claims.Add(new Claim(ClaimTypes.NameIdentifier, "admin"));
foreach(var role in user.Roles)
{
claims.Add(ClaimTypes.Role, role);
}
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
context.User = claimsPrincipal;
await _next(context);
}
}
Then use middleware in Startup.cs like this:
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<CustomMiddleware>();
...
}
Finally use Authorize attribute:
[Authorize(Roles = "Users")]
public IActionResult Index()
{
}

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