Blazor wasm get additional information and add to user claims - api

I am using identityserver4 for authentication and it's laid out something like this: identity server4 -> Web Api -> Blazor WASM Client(Standalone). everything is getting authenticated and working great. I get the authenticated user claims all the way to the wasm client.
I am now trying to add more claims which come directly from the database. I could have added the claims to the identityserver token but the token gets too big (> 2kb) and then identityserver stops working. apparently this is a known issue.
So iwant to build authorization and trying to keep the jwt token from identityserver small.
in the program.cs file i have a http client like so
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddOidcAuthentication(options =>// Configure your authentication provider options here.
// For more information, see https://aka.ms/blazor-standalone-auth
//builder.Configuration.Bind("Local", options.ProviderOptions);
... provider options
options.ProviderOptions.ResponseType = "code";
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<CustomAccountClaimsPrincipalFactory>();
await builder.Build().RunAsync();
in the file CustomAccountClaimsPrincipalFactory i have this
public class CustomAccountClaimsPrincipalFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
private const string Planet = "planet";
[Inject]
public HttpClient Http { get; set; }
public CustomAccountClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor)
: base(accessor) {
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var claims = identity.Claims.Where(a => a.Type == Planet);
if (!claims.Any())
{
identity.AddClaim(new Claim(Planet, "mars"));
}
//get user roles
//var url = $"/Identity/users/112b7de8-614f-40dc-a9e2-fa6e9d2bf85a/roles";
var dResources = await Http.GetFromJsonAsync<List<somemodel>>("/endpoint");
foreach (var item in dResources)
{
identity.AddClaim(new Claim(item.Name, item.DisplayName));
}
}
return user;
}
}
this is not working as the httpclient is not biolt when this is called and the http client uses the same builder which is building the base http client.
How do i get this to work?

You can create a IProfileService and customise it however you need:
var builder = services.AddIdentityServer(options =>
...
.AddProfileService<IdentityProfileService>();
public class IdentityProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
private readonly UserManager<ApplicationUser> _userManager;
public IdentityProfileService(IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, UserManager<ApplicationUser> userManager)
{
_claimsFactory = claimsFactory;
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
if (user == null)
{
throw new ArgumentException("");
}
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
//Add more claims like this
//claims.Add(new System.Security.Claims.Claim("MyProfileID", user.Id));
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}

Keep the access token small and only include the necessary claims to get past the JwtBearer authentication step.
Then in the API that receives an access token, you can simply create an authorization policy that do lookup the users additional claims and evaluate if he have access or not.
You can do that in the simple policy definitions or the more advanced authorization handlers like the code below:
public class CheckIfAccountantHandler : AuthorizationHandler<CanViewReportsRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
CanViewReportsRequirement requirement)
{
bool result = CallTheCheckIfAccountantService();
if(result)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
A sample requirement can be defined as:
public class CanViewReportsRequirement : IAuthorizationRequirement
{
public int StartHour { get; }
public int EndHour { get; }
public CanViewReportsRequirement(int startHour, int endHour)
{
StartHour = startHour;
EndHour = endHour;
}
}
The important thing is to keep the complexity of the application low and not try to make it harder than it has to be. Just to make the system easy to reason about!

Related

Get current logged in user in the Service in Blazor Server on Cookie based authentication and authorization

I use this repo to implement authentication and authorization with cookie on the Blazor Server.
Suppose that I'd like to retrieve the current logged-in user in the DeleteHotelRoomAsync method in HotelRoomService.cs to log the information of the user who deleted a room.
public async Task<int> DeleteHotelRoomAsync(int roomId)
{
var roomDetails = await _dbContext.HotelRooms.FindAsync(roomId);
if (roomDetails == null)
{
return 0;
}
_dbContext.HotelRooms.Remove(roomDetails);
//ToDo
//_dbContext.DbLog.Add(userId,roomId);
return await _dbContext.SaveChangesAsync();
}
I can't use of AuthenticationStateProvider as it is there or there, becuase of cookie based system and so the AuthenticationStateProvider is null in below code.
I used HttpContextAccessor, and I could retrieve the authenticated userId as below, however, I couldn't use HttpContextAccessor because of Microsoft recommendations.
public class GetUserId:IGetUserId
{
public IHttpContextAccessor _contextAccessor;
private readonly AuthenticationStateProvider _authenticationStateProvider;
public GetUserId(IHttpContextAccessor contextAccessor,AuthenticationStateProvider authenticationStateProvider)
{
_contextAccessor = contextAccessor;
_authenticationStateProvider = authenticationStateProvider;
}
public string Get()
{
var userId = _contextAccessor.HttpContext.User.Claims.First().Value;
return userId;
}
}
So is there any safe ways to retrieve authenticated user info (e.g. userId) in a .cs file to log it into database logs for user audit log?
First you should create a custom AuthenticationStateProvider
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
namespace BlazorServerTestDynamicAccess.Services;
public class CustomAuthenticationStateProvider : RevalidatingServerAuthenticationStateProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public CustomAuthenticationStateProvider(ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory)
: base(loggerFactory) =>
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
protected override TimeSpan RevalidationInterval { get; } = TimeSpan.FromMinutes(30);
protected override async Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState, CancellationToken cancellationToken)
{
// Get the user from a new scope to ensure it fetches fresh data
var scope = _scopeFactory.CreateScope();
try
{
var userManager = scope.ServiceProvider.GetRequiredService<IUsersService>();
return await ValidateUserAsync(userManager, authenticationState?.User);
}
finally
{
if (scope is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
else
{
scope.Dispose();
}
}
}
private async Task<bool> ValidateUserAsync(IUsersService userManager, ClaimsPrincipal? principal)
{
if (principal is null)
{
return false;
}
var userIdString = principal.FindFirst(ClaimTypes.UserData)?.Value;
if (!int.TryParse(userIdString, out var userId))
{
return false;
}
var user = await userManager.FindUserAsync(userId);
return user is not null;
}
}
Then register it:
services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
Now you can use it in your services. Here is an example of it:
public class UserInfoService
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public UserInfoService(AuthenticationStateProvider authenticationStateProvider) =>
_authenticationStateProvider = authenticationStateProvider ??
throw new ArgumentNullException(nameof(authenticationStateProvider));
public async Task<string?> GetUserIdAsync()
{
var authenticationState = await _authenticationStateProvider.GetAuthenticationStateAsync();
return authenticationState.User.Identity?.Name;
}
}
Well, if You don't want to use AuthenticationStateProvider, and the cookie is not working you need any other method to Authenticate and Authorize the User to Delete the reservation.
I would go to handle this by some email+password account managed during reservation, and then verification in this way, or just any "token".
Even if somebody doesn't want to register, when You make a reservation for Your client, you get his phone or e-mail. This way You can generate some random password and send it to the client with information that he needs to log in by phone/email and this password to manage the reservation.
Even more simple way is to generate some token as a parameter, that the user can use with deleteURL to be authenticated with it. Just store it in the database room reservation with that token. In example #page "/deleteRoom/{token}
Then You can use it this way
public async Task<int> DeleteHotelRoomAsync(string token)
{
var roomDetails = await _dbContext.HotelRooms.Where(n=>n.deleteToken == token).FirstOrDefaultAsync();
if (roomDetails == null)
{
return 0;
}
_dbContext.HotelRooms.Remove(roomDetails);
//ToDo
//_dbContext.DbLog.Add(userId,roomId);
return await _dbContext.SaveChangesAsync();
}
Just override OnInitialized method to get that token string as component parameter.

IdentityServer4 Reject Token Request If Custom Parameter Not Valid

I have this test client sending RequestToken:
var tokenResponse = await client.RequestTokenAsync(new TokenRequest
{
Address = disco.TokenEndpoint,
GrantType = "password",
ClientId = "My_Client",
ClientSecret = "mysecret",
Parameters =
{
{ "username", "user#entity.com" },
{ "password", "userpassword" },
{ "logged_entity_id", "143" },
{ "scope", "MyAPI" }
}
});
Now each user has a list of entity and I want to reject the token request if the value in the parameter "logged_entity_id" does not exist in the user's list of entity.
I was initially planning on checking it via IsActiveSync in my CustomProfileService but I can't seem to access the raw parameters in IsActiveSync method.
public class CustomProfileService : IProfileService
{
protected UserManager<User> _userManager;
public CustomProfileService(UserManager<User> userManager)
{
_userManager = userManager;
}
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var claims = new List<Claim>
{
new Claim("LoggedEntityId", context.ValidatedRequest.Raw["logged_entity_id"])
};
context.IssuedClaims.AddRange(claims);
return Task.FromResult(0);
}
public Task IsActiveAsync(IsActiveContext context)
{
var user = _userManager.GetUserAsync(context.Subject).Result;
// var entityId = Can't access logged_entity_id parameter here
context.IsActive = user != null && user.DeletingDate == null && user.entities.Contains(entityId);
return Task.FromResult(0);
}
}
I'm not really sure if this is where I should check and reject it.
In asp.net core you can register a dependency using the built-in dependency injection container. The dependency injection container supplies the IHttpContextAccessor to any classes that declare it as a dependency in their constructors:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpContextAccessor();
...
}
Then in your class ,for example , in the implement of IProfileService :
private readonly IHttpContextAccessor _httpContextAccessor;
public CustomProfileService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
Then in IsActiveAsync method get the value by :
var id = _httpContextAccessor.HttpContext.Request.Form["logged_entity_id"].ToString();
You can implement ICustomTokenValidator to validate token's request on your own way
You can run custom code as part of the token issuance pipeline at the token endpoint. This allows e.g. for
adding additional validation logic
changing certain parameters (e.g.token lifetime) dynamically
public class CustomValidator : ICustomTokenRequestValidator
{
public Task<TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result)
{
throw new NotImplementedException();
}
public Task<TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result)
{
throw new NotImplementedException();
}
}
and in your startup.cs:
services.AddIdentityServer(options =>
{
...
})
.AddCustomTokenRequestValidator<CustomValidator>();

ASP.NET Core 2.2 Create IdentityUser

Brand new to ASP.Net Core. Having to create an asp.net core 2.2 project with Identity (and have users seeded).
I can't find any documentation on how to do this exactly.
I was able to find the code to create Identity Roles (compiles anyway, haven't gotten to where I can run it yet:
private static async Task CreateUserTypes(ApplicationDbContext authContext, IServiceProvider serviceProvider)
{
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
string[] roleNames = { "Administrator", "Data Manager", "Interviewer", "Respondent" };
IdentityResult roleResult;
foreach (var roleName in roleNames)
{
var roleExist = await RoleManager.RoleExistsAsync(roleName);
if (!roleExist)
{
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}
}
Now, I need to create some users. But the with the weird microsoft syntax to do that I can't find (been googling for 2 days).
Here's what does not work:
private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
{
//Create the root ADMIN user for all things admin.
UserManager<ApplicationDbContext> userManager = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();
IdentityUser user = new IdentityUser()
{
UserName = "admin#admin.admin",
Email = "admin#admin.admin"
};
var NewAdmin = await userManager.CreateAsync(user, "password");
}
The error I see is:
Argument1: cannot convert from 'Microsoft.AspNetCore.Identity.IdentityUser' to 'ApplicationDbContext'
Does that mean? Obviously, I don't have the right userManager. But, how do I get the right one that takes a user as the 1st parameter and a string (password) for the 2nd?
In addition, the examples that come up in Google searches have an ApplicationUser object that I do not have (and don't need?). Not defined in the examples as to how I get it.
Owen
OK. Got past syntax error, but now I'm getting a runtime error:
NullReferenceException: Object reference not set to an instance of an object. on the call to CreateAsync. Here's the new code:
private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
{
//Create the root ADMIN user for all things admin.
var userStore = new UserStore<IdentityUser>(authContext);
UserManager<IdentityUser> userManager = new UserManager<IdentityUser>(userStore, null, null, null, null, null, null, serviceProvider, null);
// = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();
IdentityUser user = new IdentityUser()
{
UserName = "admin#admin.admin",
Email = "admin#admin.admin"
};
var result = await userManager.CreateAsync(user, "password");
}
Going to be looking into what the other parameters are to the create userManager and how to get them from the serviceProvider?
--Owen
Figured out how to do it. The key was finding the correct serviceprovider to pass in and the right syntax for creating the userManager. The other answers I've found through google all replace the IdentityUser with their own ApplicationUser that was muddying the water. Here's the working function (hope this helps someone):
private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
{
//Create the root ADMIN user for all things admin.
var userStore = new UserStore<IdentityUser>(authContext);
UserManager<IdentityUser> userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
//new UserManager<IdentityUser>(userStore, null, null, null, null, null, null, serviceProvider, null);
// = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();
IdentityUser user = new IdentityUser()
{
UserName = "admin#admin.admin",
Email = "admin#admin.admin"
};
var result = await userManager.CreateAsync(user, "password");
result = await userManager.AddToRoleAsync(user, "Administrator");
}
Your main issue seems to be dependency injection. Have a look at this link for more information. As long as you inject your DbContext and UserManager in the right way and the rest of the code should be fine.
Here is an example. You can set up a separate service for seeding to ensure you decouple your code from the rest.
public class UserSeeder
{
private readonly UserManager<IdentityUser> userManager;
private readonly ApplicationDbContext context;
public UserSeeder(UserManager<IdentityUser> userManager, ApplicationDbContext context)
{
this.userManager = userManager;
this.context = context;
}
public async Task `()
{
string username = "admin#admin.admin";
var users = context.Users;
if (!context.Users.Any(u => u.UserName == username))
{
var done = await userManager.CreateAsync(new IdentityUser
{
UserName = username,
Email = username
}, username);
}
}
}
You then have to add this class as a scoped (since your DbContext is scoped) by using services.AddScoped<UserSeeder>() in your startup. You can now simply inject your UserSeeder in any service (except singletons) and call your UserSeeder function. For instance, You can inject UserSeeder in the home controller and call it index action. This way the seeding is checked and added initially. However, this will only work IF you go to the home page first. Alternatively, you can set up a middleware like this in your startup class:
app.Use(async (context, next) => {
await context.RequestServices.GetService<UserSeeder>().SeedAsync();
await next();
});
Note that both of these ways, you are calling the database every time. You can plan on where to place it. You can also make sure this is only called once with the help of a boolean (could be in a singleton). But note that this would only run on application startup.
Here's how I seed my Admin user (learned from EF Core in Action book):
This is the User class:
public class User : IdentityUser<long>
{
//add your extra properties and relations
}
The long type specifies the primary key type. If you use the default IdentityUser class it's going to be string (uniqueidentifier in SQL).
This is the Role class:
public class Role : IdentityRole<long>
{
public static string Admin = "Admin";
}
It can be empty, I use static strings to avoid magic strings in my code.
This is the DbContext:
public class ApplicationDbContext : IdentityDbContext<User, Role, long>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
//your DbSets and configurations
//...
}
If you're going to use Identity, you need to use IdentityDbContext and specify your custom User and Role class and the type of primary key you're using.
This code adds Identity to the program:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddIdentity<User, Role>(options =>
{
//you can configure your password and user policy here
//for example:
options.Password.RequireDigit = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//...
}
This is an extension method to seed data:
public static class SeedData
{
public static IWebHost SeedAdminUser(this IWebHost webHost)
{
using (var scope = webHost.Services.CreateScope())
{
try
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.EnsureCreated();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<Role>>();
if (!userManager.Users.Any(u => u.Email == "admin#domain.com"))
{
roleManager.CreateAsync(new Role()
{
Name = Role.Admin
})
.Wait();
userManager.CreateAsync(new User
{
UserName = "Admin",
Email = "admin#domain.com"
}, "secret")
.Wait();
userManager.AddToRoleAsync(userManager.FindByEmailAsync("admin#domain.com").Result, Role.Admin).Wait();
}
}
catch (Exception ex)
{
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding user.");
//throw;
}
}
return webHost;
}
}
And finally use it in your Program.cs:
CreateWebHostBuilder(args)
.Build()
.SeedAdminUser()
.Run();

How to use/Implement OAuth2 with Owin in ASp.net Core?

Hello I am very beginner in whole web development , I got a task to make an API and for the good or bad of it I chose Asp.Core to do it .
The api connects a mobile client with a CRM system and there is an AD system (Not azure nor windows AD) it is called NetIQ. Any request to the api has to be from a user who is authenticated by Net IQ before then the API issues a token to the client.
Anyway I would like to have kind of authentication mechanism, and I have been told that OWIN can handle OAUTh2 stuff .
I have the exact code that I need , but it is with MVC 5.
Can someone help me with migrating this thing to MVC core ?
I searched for long time and could not find what I want . Maybe because i am still a bigenner in the web stuff area .
The code that I want to migrate is
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
Startup.Auth.cs
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(15),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
}
ApplicationOAuthProvider.cs
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private static string aadInstance = "https://login.microsoftonline.com/{0}";
private static string tenant = ConfigurationManager.AppSettings["AzureAD.Tenant"];
private static string clientId = ConfigurationManager.AppSettings["AzureAD.ClientId"];
private static string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
private static AuthenticationContext authContext = null;
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[] { "*" });
authContext = new AuthenticationContext(authority, new TokenCache());
var creds = new UserPasswordCredential(context.UserName, context.Password);
AuthenticationResult result;
try
{
result = await authContext.AcquireTokenAsync(clientId, clientId, creds);
}
catch (Exception ex)
{
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"));
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
context.Validated(identity);
}
}
So have anyone a sample how would I do that in ASP core ? because the whole startup thing is making me confused to be honest .

WebAPI : How to add the Account / Authentication logic to a self hosted WebAPI service

I just came across a great reference example of using authenticated WebAPI with AngularJS:
http://www.codeproject.com/Articles/742532/Using-Web-API-Individual-User-Account-plus-CORS-En?msg=4841205#xx4841205xx
An ideal solution for me would be to have such WebAPI service self hosted instead of running it as a Web application.
I just do not know where to place all of the authentication / authorization logic within a self hosted (OWIN / Topshelf) solution.
For example, in the Web app, we have these two files: Startup.Auth, and ApplicationOAuthProvider:
Startup.Auth:
public partial class Startup
{
static Startup()
{
PublicClientId = "self";
UserManagerFactory = () => new UserManager<IdentityUser>(new UserStore<IdentityUser>());
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static Func<UserManager<IdentityUser>> UserManagerFactory { get; set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
}
ApplicationOAuthProvider:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
private readonly Func<UserManager<IdentityUser>> _userManagerFactory;
public ApplicationOAuthProvider(string publicClientId, Func<UserManager<IdentityUser>> userManagerFactory)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
if (userManagerFactory == null)
{
throw new ArgumentNullException("userManagerFactory");
}
_publicClientId = publicClientId;
_userManagerFactory = userManagerFactory;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Add Access-Control-Allow-Origin header as Enabling the Web API CORS will not enable it for this provider request.
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (UserManager<IdentityUser> userManager = _userManagerFactory())
{
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await userManager.CreateIdentityAsync(user,
context.Options.AuthenticationType);
ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
}
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 ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
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);
}
}
I'm looking for a way to integrate these into my OWIN self hosted app, and have these authentication features. start upon application startup, and function as they do in the Web app version.