Skip to content

Commit

Permalink
Added OpenIdConnect authentication and JWT token parsing to retrieve …
Browse files Browse the repository at this point in the history
…the user data.
  • Loading branch information
FelisiaM committed Oct 23, 2017
1 parent a9838ca commit f53f5bd
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 104 deletions.
13 changes: 13 additions & 0 deletions BMI/BMI/Authorisation/ITokenHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.IdentityModel.Tokens.Jwt;
using BMI.Models;

namespace BMI.Authorisation
{
public interface ITokenHandler
{
JwtSecurityToken GetJwtSecurityToken(string tokenId);
bool IsAuthorised(JwtSecurityToken jwtToken);
UserDetails GetUserDetailsFromClaims(JwtSecurityToken jwtToken);
string GetUserName(JwtSecurityToken jwtToken);
}
}
43 changes: 43 additions & 0 deletions BMI/BMI/Authorisation/TokenHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using BMI.Models;

namespace BMI.Authorisation
{
public class TokenHandler : ITokenHandler
{
public JwtSecurityToken GetJwtSecurityToken(string tokenId)
{
var handler = new JwtSecurityTokenHandler();
return handler.ReadToken(tokenId) as JwtSecurityToken;
}

public bool IsAuthorised(JwtSecurityToken jwtToken)
{
var access = GetClaim(jwtToken, "extension_Access");

return access.Equals("True");
}

public UserDetails GetUserDetailsFromClaims(JwtSecurityToken jwtToken)
{
return new UserDetails
{
Height = double.Parse(GetClaim(jwtToken, "extension_Height")),
Weight = double.Parse(GetClaim(jwtToken, "extension_Weight"))
};
}

public string GetUserName(JwtSecurityToken jwtToken)
{
return GetClaim(jwtToken, "family_name");
}

private static string GetClaim(
JwtSecurityToken jwtToken,
string claimType)
{
return jwtToken.Claims.First(claim => claim.Type == claimType).Value;
}
}
}
64 changes: 48 additions & 16 deletions BMI/BMI/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using BMI.Authorisation;
using Microsoft.AspNetCore.Mvc;
using BMI.Models;
using Microsoft.Extensions.Logging;
using BMI.Reporting;
using Microsoft.AspNetCore.Authorization;

namespace BMI.Controllers
{
public class HomeController : Controller
{
private readonly IBmiReport _bmiReport;
private readonly ICsvReader _csvReader;
private readonly ITokenHandler _tokenHandler;

public HomeController(
IBmiReport bmiReport,
ICsvReader csvReader)
ICsvReader csvReader,
ITokenHandler tokenHandler)
{
_bmiReport = bmiReport;
_csvReader = csvReader;
_tokenHandler = tokenHandler;
}


[Authorize]
public IActionResult Index()
{

return View();
}

[HttpPost]
public IActionResult Index(CancellationToken token)
{
try
{
Request.Form.TryGetValue("id_token", out var idToken);

var jwtToken = _tokenHandler.GetJwtSecurityToken(idToken);
if (!_tokenHandler.IsAuthorised(jwtToken))
{
return View("UserInput");
}

ViewData["UserName"] = _tokenHandler.GetUserName(jwtToken);
BuildBMIReport(
_tokenHandler.GetUserDetailsFromClaims(jwtToken));

return View();
}
catch (Exception ex)
{
Console.WriteLine("Failure happen during validating id_token.");
}

return View("UserInput");
}

public IActionResult GuestUser()
{
Expand All @@ -41,6 +73,13 @@ public IActionResult GuestUser(UserDetails details)
return View();
}

BuildBMIReport(details);

return View();
}

private void BuildBMIReport(UserDetails details)
{
var bmiIndex = _bmiReport.GetBmiIndex(details.Height, details.Weight);
var bmiCategory = _bmiReport.GetBmiCategory(bmiIndex);

Expand All @@ -57,18 +96,16 @@ public IActionResult GuestUser(UserDetails details)

ViewData["PopulationReport"] = report
.Select(o => new ReportModel
{
Category = o.Key,
Count = o.Value
})
{
Category = o.Key,
Count = o.Value
})
.ToList();

var usersRanking = _bmiReport.GetUsersPercentile(population, bmiIndex);

ViewData["UsersRanking"] = usersRanking;
}

return View();
}

private List<UserDetails> TryParseCsv()
Expand All @@ -84,10 +121,5 @@ private List<UserDetails> TryParseCsv()
}
return population;
}

public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
11 changes: 0 additions & 11 deletions BMI/BMI/Models/ErrorViewModel.cs

This file was deleted.

11 changes: 2 additions & 9 deletions BMI/BMI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace BMI
{
Expand All @@ -20,7 +13,7 @@ public static void Main(string[] args)

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("https://localhost:44316")
.UseUrls("https://localhost:44316")
.UseStartup<Startup>()
.Build();
}
Expand Down
2 changes: 1 addition & 1 deletion BMI/BMI/BMIReport.cs → BMI/BMI/Reporting/BMIReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Linq;
using BMI.Models;

namespace BMI
namespace BMI.Reporting
{
public class BmiReport : IBmiReport
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace BMI
namespace BMI.Reporting
{
public class BmiCategory
{
Expand Down
2 changes: 1 addition & 1 deletion BMI/BMI/CsvReader.cs → BMI/BMI/Reporting/CsvReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.IO;
using BMI.Models;

namespace BMI
namespace BMI.Reporting
{
public class CsvReader : ICsvReader
{
Expand Down
2 changes: 1 addition & 1 deletion BMI/BMI/IBmiReport.cs → BMI/BMI/Reporting/IBmiReport.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using BMI.Models;

namespace BMI
namespace BMI.Reporting
{
public interface IBmiReport
{
Expand Down
2 changes: 1 addition & 1 deletion BMI/BMI/ICsvReader.cs → BMI/BMI/Reporting/ICsvReader.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using BMI.Models;

namespace BMI
namespace BMI.Reporting
{
public interface ICsvReader
{
Expand Down
50 changes: 38 additions & 12 deletions BMI/BMI/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite;
using System.IdentityModel.Tokens.Jwt;
using System.Threading.Tasks;
using BMI.Authorisation;
using BMI.Reporting;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;


namespace BMI
Expand All @@ -26,31 +31,50 @@ public Startup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();

// Add application services
services.AddTransient<IBmiReport, BmiReport>();
services.AddTransient<ICsvReader, CsvReader>();
services.AddTransient<ITokenHandler, TokenHandler>();

// enforce all requests to use ssl - global config
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});


// Add framework services
services.AddMvc();

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = Configuration["Authority"];
options.ClientId = Configuration["Client"];
options.CallbackPath = Configuration["CallbackPath"];

options.ResponseType = OpenIdConnectResponseType.IdToken;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.FormPost;

options.GetClaimsFromUserInfoEndpoint = true;
options.RequireHttpsMetadata = false;
options.MetadataAddress = Configuration["MetadataAddress"];

options.SaveTokens = true;
});
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();

Expand All @@ -62,9 +86,11 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
});

// Redirects all HTTP requests to HTTPS:
var options = new RewriteOptions()
.AddRedirectToHttps();
app.UseRewriter(options);
app.UseRewriter(
new RewriteOptions()
.AddRedirectToHttps());

app.UseAuthentication();
}
}
}
31 changes: 31 additions & 0 deletions BMI/BMI/Views/Home/BmiReport.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

<h4>@ViewData["Result"]</h4>

<h4>Population BMI Report</h4>
<br />
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>
Category
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@foreach (var item in (List<ReportModel>)ViewData["PopulationReport"])
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Category)
</td>
<td>
@Html.DisplayFor(modelItem => item.Count)
</td>
</tr>
}
</tbody>
</table>
<h4> You rank in @ViewData["UsersRanking"]% percentile of the population.</h4>
Loading

0 comments on commit f53f5bd

Please sign in to comment.