Skip to content

Commit

Permalink
Fix for #47, Claims / Policies for Roles
Browse files Browse the repository at this point in the history
  • Loading branch information
enkodellc committed Oct 13, 2019
1 parent c332342 commit f3b361b
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 59 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ This project is licensed under the terms of the [MIT license](LICENSE).
- .NET Core 3.0.100 / Blazor 3.0.0-preview9.19457.4 update
- Known Issues:
- IAuditable Shadow Properties not getting UserId
- Authorization is broken / doesn't work. I need help sorting out IS4 / Asp.net Identity working together. Do

### 0.2.3 - .Net Core Authentication / Authorization (Stable Version)
- .NET Core 3.0.100 / Blazor 3.0.0-preview9.19457.4 update
Expand Down
27 changes: 4 additions & 23 deletions src/BlazorBoilerplate.Server/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace BlazorBoilerplate.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]

public class AccountController : ControllerBase
{
private static readonly UserInfoDto LoggedOutUser = new UserInfoDto { IsAuthenticated = false, Roles = new List<string>() };
Expand All @@ -33,7 +32,6 @@ public class AccountController : ControllerBase
private readonly IEmailService _emailService;
private readonly IConfiguration _configuration;
private readonly ApplicationDbContext _db;


public AccountController(UserManager<ApplicationUser> userManager, ApplicationDbContext db,
SignInManager<ApplicationUser> signInManager, ILogger<AccountController> logger,
Expand Down Expand Up @@ -94,17 +92,6 @@ public async Task<ApiResponse> Login(LoginDto parameters)
return new ApiResponse(401, "Login Failed");
}


// This is a policy test endpoint, feel free to delete it
[Authorize(Policies.IsAdmin)]
[HttpGet("amiadmin")]
public async Task<ApiResponse> Testing()
{
var claims = HttpContext.User.Claims.ToList();
var claimsResponse = claims.Distinct().Select(x=>(x.Type.ToString(), x.Value.ToString())).ToList();
return new ApiResponse(200, $"policy {Policies.IsAdmin} has allowed you through", claimsResponse);
}

[AllowAnonymous]
// POST: api/Account/Register
[HttpPost("Register")]
Expand Down Expand Up @@ -132,16 +119,15 @@ public async Task<ApiResponse> Register(RegisterDto parameters)
else
{
var claimsResult = _userManager.AddClaimsAsync(user, new Claim[]{
new Claim(Policies.IsUser,""),
new Claim(JwtClaimTypes.Name, parameters.UserName),
new Claim(JwtClaimTypes.Email, parameters.Email),
new Claim(JwtClaimTypes.EmailVerified, "false", ClaimValueTypes.Boolean)
}).Result;
}

//Role - Here we tie the new user to the "User" role
await _userManager.AddToRoleAsync(user, "User");
await _userManager.AddClaimAsync(user, new Claim(Policies.IsUser, "")); // Replacing roles with claims, if IsUser is present we interpret it as the equivalent of having the User role

await _userManager.AddToRoleAsync(user, "User");

if (Convert.ToBoolean(_configuration["BlazorBoilerplate:RequireConfirmedEmail"] ?? "false"))
{
Expand Down Expand Up @@ -439,18 +425,15 @@ public async Task<ApiResponse> Create(RegisterDto parameters)
else
{
var claimsResult = _userManager.AddClaimsAsync(user, new Claim[]{
new Claim(Policies.IsUser,""),
new Claim(JwtClaimTypes.Name, parameters.UserName),
new Claim(JwtClaimTypes.Email, parameters.Email),
new Claim(JwtClaimTypes.EmailVerified, "false", ClaimValueTypes.Boolean)
}).Result;
}

//Role - Here we tie the new user to the "User" role
await _userManager.AddToRoleAsync(user, "User");
await _userManager.AddClaimAsync(user, new Claim(Policies.IsUser, "")); // Replacing roles with claims, if IsUser is present we interpret it as the equivalent of having the User role



await _userManager.AddToRoleAsync(user, "User");

if (Convert.ToBoolean(_configuration["BlazorBoilerplate:RequireConfirmedEmail"] ?? "false"))
{
Expand Down Expand Up @@ -600,7 +583,6 @@ public async Task<ApiResponse> Get([FromQuery] int pageSize = 10, [FromQuery] in
public async Task<ApiResponse> ListRoles()
{
var roleList = _roleManager.Roles.Select(x => x.Name).ToList();

return new ApiResponse(200, "", roleList);
}

Expand Down Expand Up @@ -646,7 +628,6 @@ public async Task<ApiResponse> Update([FromBody] UserInfoDto userInfo)
rolesToAdd.Add(newUserRole);
}
}

await _userManager.AddToRolesAsync(appUser, rolesToAdd).ConfigureAwait(true);
//HACK to switch to claims auth
foreach (var role in rolesToAdd)
Expand Down
7 changes: 2 additions & 5 deletions src/BlazorBoilerplate.Server/Controllers/ToDoController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,8 @@ public async Task<ApiResponse> Put([FromBody] TodoDto todo)
}
return await _todoService.Update(todo);
}

//Todo find out why this doesn't work!
//[Authorize(Roles = "User")]
[Authorize(Policy = Policies.IsUser)]
//[AllowAnonymous]

[Authorize(Policy = Policies.IsAdmin)]
// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<ApiResponse> Delete(long id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
using BlazorBoilerplate.Shared.Dto;
using BlazorBoilerplate.Server.Middleware.Wrappers;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using IdentityModel;

namespace BlazorBoilerplate.Server.Controllers
{
[Route("api/[controller]")]
[Authorize]
[ApiController]
[Authorize]
public class UserProfileController : ControllerBase
{
private readonly ILogger<UserProfileController> _logger;
Expand All @@ -29,8 +28,6 @@ public UserProfileController(IUserProfileService userProfileService, ILogger<Use
}

// GET: api/UserProfile
[Authorize]
[AllowAnonymous]
[HttpGet("Get")]
public async Task<ApiResponse> Get()
{
Expand Down
22 changes: 15 additions & 7 deletions src/BlazorBoilerplate.Server/Data/IdentityServerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public static IEnumerable<ApiResource> GetApiResources()
JwtClaimTypes.Email,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.Role,
ClaimConstants.Permission,
Policies.IsUser,
Policies.IsAdmin,
ClaimConstants.Permission
Policies.IsAdmin
}
}
};
Expand All @@ -56,11 +56,12 @@ public static IEnumerable<ApiResource> GetApiResources()
// http://docs.identityserver.io/en/release/reference/client.html.
new IdentityServer4.Models.Client
{
ClientId = IdentityServerConfig.AppClientID,
//AbsoluteRefreshTokenLifetime = 7200,
//AccessTokenLifetime = 900, // Lifetime of access token in seconds.
AccessTokenType = AccessTokenType.Jwt,
//AllowedCorsOrigin = "https://localhost:5003",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, // Resource Owner Password Credential grant.
AllowAccessTokensViaBrowser = true,
RequireClientSecret = false, // This client does not need a secret to request tokens from the token endpoint.

AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId, // For UserInfo endpoint.
IdentityServerConstants.StandardScopes.Profile,
Expand All @@ -69,11 +70,18 @@ public static IEnumerable<ApiResource> GetApiResources()
ScopeConstants.Roles,
ApiName
},
AllowRememberConsent = true,
AllowOfflineAccess = true, // For refresh token.
ClientId = IdentityServerConfig.AppClientID,
ClientName = IdentityServerConfig.ApiName,
//ClientUri = "https://localhost:5003",
ClientSecrets = new List<Secret> { new Secret { Value = "BlazorBoilerplate".Sha512() }},
Enabled = true,
//PostLogoutRedirectUris = new List<string> {"http://localhost:5436"},
RequireClientSecret = true, // This client does not need a secret to request tokens from the token endpoint.
//RedirectUris = new List<string> {"http://localhost:5436/account/oAuth2"},
RefreshTokenExpiration = TokenExpiration.Sliding,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
//AccessTokenLifetime = 900, // Lifetime of access token in seconds.
//AbsoluteRefreshTokenLifetime = 7200,
//SlidingRefreshTokenLifetime = 900,
},

Expand Down
8 changes: 4 additions & 4 deletions src/BlazorBoilerplate.Server/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:53414/",
"sslPort": 53414
"applicationUrl": "http://localhost:53414/",
"sslPort": 0
}
},
"profiles": {
Expand All @@ -21,7 +21,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53416/;https://localhost:5001"
"applicationUrl": "http://localhost:53416/"
}
}
}
}
25 changes: 10 additions & 15 deletions src/BlazorBoilerplate.Server/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,12 @@ public void ConfigureServices(IServiceCollection services)
});

services.AddIdentity<ApplicationUser, IdentityRole<Guid>>()
// .AddRoles<IdentityRole<Guid>>()
.AddClaimsPrincipalFactory<AdditionalUserClaimsPrincipalFactory>()
.AddRoles<IdentityRole<Guid>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();

//services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>,
// AdditionalUserClaimsPrincipalFactory>();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>,
AdditionalUserClaimsPrincipalFactory>();

// Adds IdentityServer
var identityServerBuilder = services.AddIdentityServer(options =>
Expand All @@ -77,7 +76,7 @@ public void ConfigureServices(IServiceCollection services)
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder => {
Expand Down Expand Up @@ -106,13 +105,12 @@ public void ConfigureServices(IServiceCollection services)

// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
options.TokenCleanupInterval = 3600; //In Seconds 1 hour
})
.AddAspNetIdentity<ApplicationUser>();

X509Certificate2 cert = null;


if (_environment.IsDevelopment())
{
// The AddDeveloperSigningCredential extension creates temporary key material for signing tokens.
Expand All @@ -122,7 +120,7 @@ public void ConfigureServices(IServiceCollection services)
//.AddDeveloperSigningCredential(true, @"C:\tempkey.rsa")
identityServerBuilder.AddDeveloperSigningCredential();
}
else
else
{
// Works for IIS, finds cert by the thumbprint in appsettings.json
// Make sure Certificate is in the Web Hosting folder && installed to LocalMachine or update settings below
Expand Down Expand Up @@ -162,7 +160,7 @@ public void ConfigureServices(IServiceCollection services)
//var vaultConfigSection = Configuration.GetSection("Vault");
//var keyVaultService = new KeyVaultCertificateService(vaultConfigSection["Url"], vaultConfigSection["ClientId"], vaultConfigSection["ClientSecret"]);
////cert = keyVaultService.GetCertificateFromKeyVault(vaultConfigSection["CertificateName"]);

/// I was informed that this will work as a temp solution in Azure
cert = new X509Certificate2("AuthSample.pfx", "Admin123",
X509KeyStorageFlags.MachineKeySet |
Expand All @@ -172,7 +170,6 @@ public void ConfigureServices(IServiceCollection services)
identityServerBuilder.AddSigningCredential(cert);
}


services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
Expand All @@ -181,7 +178,6 @@ public void ConfigureServices(IServiceCollection services)
options.RequireHttpsMetadata = _environment.IsProduction() ? true : false;
options.ApiName = IdentityServerConfig.ApiName;
});


services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });

Expand Down Expand Up @@ -315,11 +311,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseDeveloperExceptionPage();
app.UseBlazorDebugging();
}
//else
//{
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(); //HSTS Middleware (UseHsts) to send HTTP Strict Transport Security Protocol (HSTS) headers to clients.
//}
}

//app.UseStaticFiles();
app.UseClientSideBlazorFiles<Client.Startup>();
Expand All @@ -328,7 +324,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseRouting();
//app.UseAuthentication();
app.UseIdentityServer();

app.UseAuthorization();

// NSwag
Expand Down

0 comments on commit f3b361b

Please sign in to comment.