Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Joonas Westlin committed May 21, 2018
0 parents commit 8ee78f6
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#Ignore thumbnails created by Windows
Thumbs.db
#Ignore files built by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
.vs/
#Nuget packages folder
packages/
19 changes: 19 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Authorization/ScopeRequirement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Authorization;

namespace Joonasw.AzureAdApiSample.Api.Authorization
{
public class ScopeRequirement : IAuthorizationRequirement
{
public ScopeRequirement(string requiredScopeValue)
{
if (string.IsNullOrEmpty(requiredScopeValue))
{
throw new System.ArgumentException("message", nameof(requiredScopeValue));
}

RequiredScopeValue = requiredScopeValue;
}

public string RequiredScopeValue { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

namespace Joonasw.AzureAdApiSample.Api.Authorization
{
public class ScopeRequirementHandler : AuthorizationHandler<ScopeRequirement>
{
private const string ClaimScope = "http://schemas.microsoft.com/identity/claims/scope";

protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ScopeRequirement requirement)
{
string[] userScopes =
context.User.FindFirstValue(ClaimScope)?.Split(' ', StringSplitOptions.RemoveEmptyEntries) ??
new string[0];
if (userScopes.Contains(requirement.RequiredScopeValue))
{
context.Succeed(requirement);
}

return Task.CompletedTask;
}
}
}
87 changes: 87 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Controllers/TodosController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Joonasw.AzureAdApiSample.Api.Data;
using Microsoft.AspNetCore.Mvc;

namespace Joonasw.AzureAdApiSample.Api.Controllers
{
[Route("api/[controller]")]
public class TodosController : Controller
{
// In-memory data-store for testing.
private readonly List<TodoItem> _todoItems;

public TodosController()
{
_todoItems = new List<TodoItem>
{
new TodoItem
{
Id = Guid.NewGuid(),
Text = "Implement authentication",
IsDone = true
}
};
}

// GET api/todos
[HttpGet]
public IActionResult Get()
{
return Ok(_todoItems);
}

// GET api/todos/guid-value
[HttpGet("{id}")]
public IActionResult Get(Guid id)
{
var item = _todoItems.FirstOrDefault(i => i.Id == id);
if(item == null)
{
return NotFound();
}

return Ok(item);
}

// POST api/todos
[HttpPost]
public IActionResult Post([FromBody]TodoItem model)
{
model.Id = Guid.NewGuid();

_todoItems.Add(model);
return CreatedAtAction(nameof(Get), new{id = model.Id}, model);
}

// PUT api/todos/guid-value
[HttpPut("{id}")]
public IActionResult Put(Guid id, [FromBody]TodoItem model)
{
model.Id = id;

var item = _todoItems.FirstOrDefault(i => i.Id == id);
if(item == null)
{
return NotFound();
}

_todoItems.Remove(item);
_todoItems.Add(model);

return NoContent();
}

// DELETE api/todos/guid-value
[HttpDelete("{id}")]
public void Delete(Guid id)
{
var item = _todoItems.FirstOrDefault(i => i.Id == id);
if(item != null)
{
_todoItems.Remove(item);
}
}
}
}
11 changes: 11 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Data/TodoItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Joonasw.AzureAdApiSample.Api.Data
{
public class TodoItem
{
public Guid Id { get; set; }
public string Text { get; set; }
public bool IsDone { get; set; }
}
}
19 changes: 19 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Joonasw.AzureAdApiSample.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
</ItemGroup>

<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace Joonasw.AzureAdApiSample.Api
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
29 changes: 29 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2672/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Joonasw.AzureAdApiSample.Api": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:2673/"
}
}
}
69 changes: 69 additions & 0 deletions Joonasw.AzureAdApiSample.Api/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Collections.Generic;
using Joonasw.AzureAdApiSample.Api.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Joonasw.AzureAdApiSample.Api
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(o =>
{
o.Filters.Add(new AuthorizeFilter("default"));
});

services.AddAuthorization(o =>
{
o.AddPolicy("default", policy =>
{
policy.Requirements.Add(new ScopeRequirement("user_impersonation"));
});
});

services
.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.Authority = Configuration["Authentication:Authority"];
o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudiences = new List<string>
{
Configuration["Authentication:AppIdUri"],
Configuration["Authentication:ClientId"]
}
};
});
services.AddSingleton<IAuthorizationHandler, ScopeRequirementHandler>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseAuthentication();

app.UseMvc();
}
}
}
10 changes: 10 additions & 0 deletions Joonasw.AzureAdApiSample.Api/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
20 changes: 20 additions & 0 deletions Joonasw.AzureAdApiSample.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"Authentication": {
"Authority": "https://login.microsoftonline.com/joonasapps.onmicrosoft.com/",
"AppIdUri": "https://joonasapps.onmicrosoft.com/fa87d15c-fbc9-4fe5-95f5-0b36108eb305",
"ClientId": "6657d9d4-a9c1-4fb1-81b0-8a8d42b6a9cf"
}
}
25 changes: 25 additions & 0 deletions Joonasw.AzureAdApiSample.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27705.2000
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Joonasw.AzureAdApiSample.Api", "Joonasw.AzureAdApiSample.Api\Joonasw.AzureAdApiSample.Api.csproj", "{7F42DC02-1742-4592-B8A5-3F786AB842CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7F42DC02-1742-4592-B8A5-3F786AB842CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F42DC02-1742-4592-B8A5-3F786AB842CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F42DC02-1742-4592-B8A5-3F786AB842CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F42DC02-1742-4592-B8A5-3F786AB842CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {66829129-F9D9-4608-AE0D-E74277750666}
EndGlobalSection
EndGlobal

0 comments on commit 8ee78f6

Please sign in to comment.