Quellcode durchsuchen

Initial revision.

Andrew Klopper vor 8 Jahren
Commit
4ba833274e

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
1
+###############################################################################
2
+# Set default behavior to automatically normalize line endings.
3
+###############################################################################
4
+* text=auto
5
+
6
+###############################################################################
7
+# Set default behavior for command prompt diff.
8
+#
9
+# This is need for earlier builds of msysgit that does not have it on by
10
+# default for csharp files.
11
+# Note: This is only used by command line
12
+###############################################################################
13
+#*.cs     diff=csharp
14
+
15
+###############################################################################
16
+# Set the merge driver for project and solution files
17
+#
18
+# Merging from the command prompt will add diff markers to the files if there
19
+# are conflicts (Merging from VS is not affected by the settings below, in VS
20
+# the diff markers are never inserted). Diff markers may cause the following 
21
+# file extensions to fail to load in VS. An alternative would be to treat
22
+# these files as binary and thus will always conflict and require user
23
+# intervention with every merge. To do so, just uncomment the entries below
24
+###############################################################################
25
+#*.sln       merge=binary
26
+#*.csproj    merge=binary
27
+#*.vbproj    merge=binary
28
+#*.vcxproj   merge=binary
29
+#*.vcproj    merge=binary
30
+#*.dbproj    merge=binary
31
+#*.fsproj    merge=binary
32
+#*.lsproj    merge=binary
33
+#*.wixproj   merge=binary
34
+#*.modelproj merge=binary
35
+#*.sqlproj   merge=binary
36
+#*.wwaproj   merge=binary
37
+
38
+###############################################################################
39
+# behavior for image files
40
+#
41
+# image files are treated as binary by default.
42
+###############################################################################
43
+#*.jpg   binary
44
+#*.png   binary
45
+#*.gif   binary
46
+
47
+###############################################################################
48
+# diff behavior for common document formats
49
+# 
50
+# Convert binary document formats to text before diffing them. This feature
51
+# is only available from the command line. Turn it on by uncommenting the 
52
+# entries below.
53
+###############################################################################
54
+#*.doc   diff=astextplain
55
+#*.DOC   diff=astextplain
56
+#*.docx  diff=astextplain
57
+#*.DOCX  diff=astextplain
58
+#*.dot   diff=astextplain
59
+#*.DOT   diff=astextplain
60
+#*.pdf   diff=astextplain
61
+#*.PDF   diff=astextplain
62
+#*.rtf   diff=astextplain
63
+#*.RTF   diff=astextplain

+ 265 - 0
.gitignore

@@ -0,0 +1,265 @@
1
+## Ignore Visual Studio temporary files, build results, and
2
+## files generated by popular Visual Studio add-ons.
3
+
4
+# User-specific files
5
+*.suo
6
+*.user
7
+*.userosscache
8
+*.sln.docstates
9
+
10
+# User-specific files (MonoDevelop/Xamarin Studio)
11
+*.userprefs
12
+
13
+# Build results
14
+[Dd]ebug/
15
+[Dd]ebugPublic/
16
+[Rr]elease/
17
+[Rr]eleases/
18
+x64/
19
+x86/
20
+bld/
21
+[Bb]in/
22
+[Oo]bj/
23
+[Ll]og/
24
+
25
+# Visual Studio 2015 cache/options directory
26
+.vs/
27
+# Uncomment if you have tasks that create the project's static files in wwwroot
28
+#wwwroot/
29
+
30
+# MSTest test Results
31
+[Tt]est[Rr]esult*/
32
+[Bb]uild[Ll]og.*
33
+
34
+# NUNIT
35
+*.VisualState.xml
36
+TestResult.xml
37
+
38
+# Build Results of an ATL Project
39
+[Dd]ebugPS/
40
+[Rr]eleasePS/
41
+dlldata.c
42
+
43
+# DNX
44
+project.lock.json
45
+project.fragment.lock.json
46
+artifacts/
47
+
48
+*_i.c
49
+*_p.c
50
+*_i.h
51
+*.ilk
52
+*.meta
53
+*.obj
54
+*.pch
55
+*.pdb
56
+*.pgc
57
+*.pgd
58
+*.rsp
59
+*.sbr
60
+*.tlb
61
+*.tli
62
+*.tlh
63
+*.tmp
64
+*.tmp_proj
65
+*.log
66
+*.vspscc
67
+*.vssscc
68
+.builds
69
+*.pidb
70
+*.svclog
71
+*.scc
72
+
73
+# Chutzpah Test files
74
+_Chutzpah*
75
+
76
+# Visual C++ cache files
77
+ipch/
78
+*.aps
79
+*.ncb
80
+*.opendb
81
+*.opensdf
82
+*.sdf
83
+*.cachefile
84
+*.VC.db
85
+*.VC.VC.opendb
86
+
87
+# Visual Studio profiler
88
+*.psess
89
+*.vsp
90
+*.vspx
91
+*.sap
92
+
93
+# TFS 2012 Local Workspace
94
+$tf/
95
+
96
+# Guidance Automation Toolkit
97
+*.gpState
98
+
99
+# ReSharper is a .NET coding add-in
100
+_ReSharper*/
101
+*.[Rr]e[Ss]harper
102
+*.DotSettings.user
103
+
104
+# JustCode is a .NET coding add-in
105
+.JustCode
106
+
107
+# TeamCity is a build add-in
108
+_TeamCity*
109
+
110
+# DotCover is a Code Coverage Tool
111
+*.dotCover
112
+
113
+# NCrunch
114
+_NCrunch_*
115
+.*crunch*.local.xml
116
+nCrunchTemp_*
117
+
118
+# MightyMoose
119
+*.mm.*
120
+AutoTest.Net/
121
+
122
+# Web workbench (sass)
123
+.sass-cache/
124
+
125
+# Installshield output folder
126
+[Ee]xpress/
127
+
128
+# DocProject is a documentation generator add-in
129
+DocProject/buildhelp/
130
+DocProject/Help/*.HxT
131
+DocProject/Help/*.HxC
132
+DocProject/Help/*.hhc
133
+DocProject/Help/*.hhk
134
+DocProject/Help/*.hhp
135
+DocProject/Help/Html2
136
+DocProject/Help/html
137
+
138
+# Click-Once directory
139
+publish/
140
+
141
+# Publish Web Output
142
+*.[Pp]ublish.xml
143
+*.azurePubxml
144
+# TODO: Comment the next line if you want to checkin your web deploy settings
145
+# but database connection strings (with potential passwords) will be unencrypted
146
+#*.pubxml
147
+*.publishproj
148
+
149
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
150
+# checkin your Azure Web App publish settings, but sensitive information contained
151
+# in these scripts will be unencrypted
152
+PublishScripts/
153
+
154
+# NuGet Packages
155
+*.nupkg
156
+# The packages folder can be ignored because of Package Restore
157
+**/packages/*
158
+# except build/, which is used as an MSBuild target.
159
+!**/packages/build/
160
+# Uncomment if necessary however generally it will be regenerated when needed
161
+#!**/packages/repositories.config
162
+# NuGet v3's project.json files produces more ignoreable files
163
+*.nuget.props
164
+*.nuget.targets
165
+
166
+# Microsoft Azure Build Output
167
+csx/
168
+*.build.csdef
169
+
170
+# Microsoft Azure Emulator
171
+ecf/
172
+rcf/
173
+
174
+# Windows Store app package directories and files
175
+AppPackages/
176
+BundleArtifacts/
177
+Package.StoreAssociation.xml
178
+_pkginfo.txt
179
+
180
+# Visual Studio cache files
181
+# files ending in .cache can be ignored
182
+*.[Cc]ache
183
+# but keep track of directories ending in .cache
184
+!*.[Cc]ache/
185
+
186
+# Others
187
+ClientBin/
188
+~$*
189
+*~
190
+*.dbmdl
191
+*.dbproj.schemaview
192
+*.jfm
193
+*.pfx
194
+*.publishsettings
195
+node_modules/
196
+orleans.codegen.cs
197
+
198
+# Since there are multiple workflows, uncomment next line to ignore bower_components
199
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200
+#bower_components/
201
+
202
+# RIA/Silverlight projects
203
+Generated_Code/
204
+
205
+# Backup & report files from converting an old project file
206
+# to a newer Visual Studio version. Backup files are not needed,
207
+# because we have git ;-)
208
+_UpgradeReport_Files/
209
+Backup*/
210
+UpgradeLog*.XML
211
+UpgradeLog*.htm
212
+
213
+# SQL Server files
214
+*.mdf
215
+*.ldf
216
+
217
+# Business Intelligence projects
218
+*.rdl.data
219
+*.bim.layout
220
+*.bim_*.settings
221
+
222
+# Microsoft Fakes
223
+FakesAssemblies/
224
+
225
+# GhostDoc plugin setting file
226
+*.GhostDoc.xml
227
+
228
+# Node.js Tools for Visual Studio
229
+.ntvs_analysis.dat
230
+
231
+# Visual Studio 6 build log
232
+*.plg
233
+
234
+# Visual Studio 6 workspace options file
235
+*.opt
236
+
237
+# Visual Studio LightSwitch build output
238
+**/*.HTMLClient/GeneratedArtifacts
239
+**/*.DesktopClient/GeneratedArtifacts
240
+**/*.DesktopClient/ModelManifest.xml
241
+**/*.Server/GeneratedArtifacts
242
+**/*.Server/ModelManifest.xml
243
+_Pvt_Extensions
244
+
245
+# Paket dependency manager
246
+.paket/paket.exe
247
+paket-files/
248
+
249
+# FAKE - F# Make
250
+.fake/
251
+
252
+# JetBrains Rider
253
+.idea/
254
+*.sln.iml
255
+
256
+# CodeRush
257
+.cr/
258
+
259
+# Python Tools for Visual Studio (PTVS)
260
+__pycache__/
261
+*.pyc
262
+
263
+# Secrets
264
+secrets.json
265
+secrets.*.json

+ 22 - 0
BulkPrintingAPI.sln

@@ -0,0 +1,22 @@
1
+
2
+Microsoft Visual Studio Solution File, Format Version 12.00
3
+# Visual Studio 15
4
+VisualStudioVersion = 15.0.26430.13
5
+MinimumVisualStudioVersion = 10.0.40219.1
6
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BulkPrintingAPI", "BulkPrintingAPI\BulkPrintingAPI.csproj", "{92EEB85E-10FF-4902-9F73-BA4D58344824}"
7
+EndProject
8
+Global
9
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
10
+		Debug|Any CPU = Debug|Any CPU
11
+		Release|Any CPU = Release|Any CPU
12
+	EndGlobalSection
13
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
14
+		{92EEB85E-10FF-4902-9F73-BA4D58344824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15
+		{92EEB85E-10FF-4902-9F73-BA4D58344824}.Debug|Any CPU.Build.0 = Debug|Any CPU
16
+		{92EEB85E-10FF-4902-9F73-BA4D58344824}.Release|Any CPU.ActiveCfg = Release|Any CPU
17
+		{92EEB85E-10FF-4902-9F73-BA4D58344824}.Release|Any CPU.Build.0 = Release|Any CPU
18
+	EndGlobalSection
19
+	GlobalSection(SolutionProperties) = preSolution
20
+		HideSolutionNode = FALSE
21
+	EndGlobalSection
22
+EndGlobal

+ 134 - 0
BulkPrintingAPI/Authentication/TokenProviderMiddleware.cs

@@ -0,0 +1,134 @@
1
+using Microsoft.AspNetCore.Http;
2
+using Microsoft.Extensions.Options;
3
+using Newtonsoft.Json;
4
+using System;
5
+using System.IdentityModel.Tokens.Jwt;
6
+using System.Security.Claims;
7
+using System.Threading.Tasks;
8
+
9
+namespace BulkPrintingAPI.Authentication
10
+{
11
+    public class TokenProviderMiddleware
12
+    {
13
+        private readonly RequestDelegate _next;
14
+        private readonly TokenProviderOptions _options;
15
+        private readonly JsonSerializerSettings _serializerSettings;
16
+
17
+        public TokenProviderMiddleware(
18
+            RequestDelegate next,
19
+            IOptions<TokenProviderOptions> options)
20
+        {
21
+            _next = next;
22
+
23
+            _options = options.Value;
24
+            ThrowIfInvalidOptions(_options);
25
+
26
+            _serializerSettings = new JsonSerializerSettings
27
+            {
28
+                Formatting = Formatting.Indented
29
+            };
30
+        }
31
+
32
+        public Task Invoke(HttpContext context)
33
+        {
34
+            if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))
35
+            {
36
+                return _next(context);
37
+            }
38
+
39
+            if (!context.Request.Method.Equals("POST")
40
+               || !context.Request.HasFormContentType)
41
+            {
42
+                context.Response.StatusCode = 400;
43
+                return context.Response.WriteAsync("Bad request.");
44
+            }
45
+
46
+            return GenerateToken(context);
47
+        }
48
+
49
+        private async Task GenerateToken(HttpContext context)
50
+        {
51
+            var username = context.Request.Form["username"];
52
+            var password = context.Request.Form["password"];
53
+
54
+            var identity = await _options.IdentityResolver(username, password);
55
+            if (identity == null)
56
+            {
57
+                context.Response.StatusCode = 400;
58
+                await context.Response.WriteAsync("Invalid username or password.");
59
+                return;
60
+            }
61
+
62
+            var now = DateTime.UtcNow;
63
+
64
+            var claims = new Claim[]
65
+            {
66
+                new Claim(JwtRegisteredClaimNames.Sub, username),
67
+                new Claim(JwtRegisteredClaimNames.Jti, await _options.NonceGenerator())
68
+            };
69
+
70
+            var encodedJwt = new JwtSecurityTokenHandler().CreateEncodedJwt(
71
+                issuer: _options.Issuer,
72
+                audience: _options.Audience,
73
+                subject: new ClaimsIdentity(claims),
74
+                notBefore: now,
75
+                expires: now.Add(_options.Expiration),
76
+                issuedAt: now,
77
+                signingCredentials: _options.SigningCredentials,
78
+                encryptingCredentials: _options.EncryptingCredentials
79
+            );
80
+
81
+            var response = new
82
+            {
83
+                access_token = encodedJwt,
84
+                expires_in = (int)_options.Expiration.TotalSeconds
85
+            };
86
+
87
+            context.Response.ContentType = "application/json";
88
+            await context.Response.WriteAsync(JsonConvert.SerializeObject(response, _serializerSettings));
89
+        }
90
+
91
+        private static void ThrowIfInvalidOptions(TokenProviderOptions options)
92
+        {
93
+            if (string.IsNullOrEmpty(options.Path))
94
+            {
95
+                throw new ArgumentNullException(nameof(TokenProviderOptions.Path));
96
+            }
97
+
98
+            if (string.IsNullOrEmpty(options.Issuer))
99
+            {
100
+                throw new ArgumentNullException(nameof(TokenProviderOptions.Issuer));
101
+            }
102
+
103
+            if (string.IsNullOrEmpty(options.Audience))
104
+            {
105
+                throw new ArgumentNullException(nameof(TokenProviderOptions.Audience));
106
+            }
107
+
108
+            if (options.Expiration == TimeSpan.Zero)
109
+            {
110
+                throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(TokenProviderOptions.Expiration));
111
+            }
112
+
113
+            if (options.IdentityResolver == null)
114
+            {
115
+                throw new ArgumentNullException(nameof(TokenProviderOptions.IdentityResolver));
116
+            }
117
+
118
+            if (options.SigningCredentials == null)
119
+            {
120
+                throw new ArgumentNullException(nameof(TokenProviderOptions.SigningCredentials));
121
+            }
122
+
123
+            if (options.EncryptingCredentials == null)
124
+            {
125
+                throw new ArgumentNullException(nameof(TokenProviderOptions.EncryptingCredentials));
126
+            }
127
+
128
+            if (options.NonceGenerator == null)
129
+            {
130
+                throw new ArgumentNullException(nameof(TokenProviderOptions.NonceGenerator));
131
+            }
132
+        }
133
+    }
134
+}

+ 54 - 0
BulkPrintingAPI/Authentication/TokenProviderOptions.cs

@@ -0,0 +1,54 @@
1
+using Microsoft.IdentityModel.Tokens;
2
+using System;
3
+using System.Security.Claims;
4
+using System.Threading.Tasks;
5
+
6
+namespace BulkPrintingAPI.Authentication
7
+{
8
+    public class TokenProviderOptions
9
+    {
10
+        /// <summary>
11
+        /// The relative request path to listen on.
12
+        /// </summary>
13
+        /// <remarks>The default path is <c>/token</c>.</remarks>
14
+        public string Path { get; set; } = "/token";
15
+
16
+        /// <summary>
17
+        ///  The Issuer (iss) claim for generated tokens.
18
+        /// </summary>
19
+        public string Issuer { get; set; }
20
+
21
+        /// <summary>
22
+        /// The Audience (aud) claim for the generated tokens.
23
+        /// </summary>
24
+        public string Audience { get; set; }
25
+
26
+        /// <summary>
27
+        /// The expiration time for the generated tokens.
28
+        /// </summary>
29
+        /// <remarks>The default is five minutes (300 seconds).</remarks>
30
+        public TimeSpan Expiration { get; set; } = TimeSpan.FromDays(1);
31
+
32
+        /// <summary>
33
+        /// The signing key to use when generating tokens.
34
+        /// </summary>
35
+        public SigningCredentials SigningCredentials { get; set; }
36
+
37
+        /// <summary>
38
+        /// The encryption key to use when generating tokens.
39
+        /// </summary>
40
+        public EncryptingCredentials EncryptingCredentials { get; set; }
41
+
42
+        /// <summary>
43
+        /// Resolves a user identity given a username and password.
44
+        /// </summary>
45
+        public Func<string, string, Task<ClaimsIdentity>> IdentityResolver { get; set; }
46
+
47
+        /// <summary>
48
+        /// Generates a random value (nonce) for each generated token.
49
+        /// </summary>
50
+        /// <remarks>The default nonce is a random GUID.</remarks>
51
+        public Func<Task<string>> NonceGenerator { get; set; }
52
+            = () => Task.FromResult(Guid.NewGuid().ToString());
53
+    }
54
+}

+ 25 - 0
BulkPrintingAPI/BulkPrintingAPI.csproj

@@ -0,0 +1,25 @@
1
+<Project Sdk="Microsoft.NET.Sdk.Web">
2
+
3
+  <PropertyGroup>
4
+    <TargetFramework>netcoreapp1.1</TargetFramework>
5
+  </PropertyGroup>
6
+
7
+  <ItemGroup>
8
+    <Folder Include="MAX\" />
9
+    <Folder Include="wwwroot\" />
10
+  </ItemGroup>
11
+  <ItemGroup>
12
+    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
13
+    <PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
14
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.2" />
15
+    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
16
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
17
+  </ItemGroup>
18
+  <ItemGroup>
19
+    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />
20
+  </ItemGroup>
21
+  <ItemGroup>
22
+    <None Include="secrets.Development.json" />
23
+  </ItemGroup>
24
+
25
+</Project>

+ 43 - 0
BulkPrintingAPI/Controllers/ValuesController.cs

@@ -0,0 +1,43 @@
1
+using Microsoft.AspNetCore.Authorization;
2
+using Microsoft.AspNetCore.Mvc;
3
+using System.Collections.Generic;
4
+
5
+namespace BulkPrintingAPI.Controllers
6
+{
7
+    [Route("api/[controller]")]
8
+    public class ValuesController : Controller
9
+    {
10
+        // GET api/values
11
+        [HttpGet]
12
+        [Authorize]
13
+        public IEnumerable<string> Get()
14
+        {
15
+            return new string[] { "value1", "value2" };
16
+        }
17
+
18
+        // GET api/values/5
19
+        [HttpGet("{id}")]
20
+        public string Get(int id)
21
+        {
22
+            return "value";
23
+        }
24
+
25
+        // POST api/values
26
+        [HttpPost]
27
+        public void Post([FromBody]string value)
28
+        {
29
+        }
30
+
31
+        // PUT api/values/5
32
+        [HttpPut("{id}")]
33
+        public void Put(int id, [FromBody]string value)
34
+        {
35
+        }
36
+
37
+        // DELETE api/values/5
38
+        [HttpDelete("{id}")]
39
+        public void Delete(int id)
40
+        {
41
+        }
42
+    }
43
+}

+ 22 - 0
BulkPrintingAPI/Program.cs

@@ -0,0 +1,22 @@
1
+using Microsoft.AspNetCore.Builder;
2
+using Microsoft.AspNetCore.Hosting;
3
+using System.IO;
4
+
5
+namespace BulkPrintingAPI
6
+{
7
+    public class Program
8
+    {
9
+        public static void Main(string[] args)
10
+        {
11
+            var host = new WebHostBuilder()
12
+                .UseKestrel()
13
+                .UseContentRoot(Directory.GetCurrentDirectory())
14
+                .UseIISIntegration()
15
+                .UseStartup<Startup>()
16
+                .UseApplicationInsights()
17
+                .Build();
18
+
19
+            host.Run();
20
+        }
21
+    }
22
+}

+ 29 - 0
BulkPrintingAPI/Properties/launchSettings.json

@@ -0,0 +1,29 @@
1
+{
2
+  "iisSettings": {
3
+    "windowsAuthentication": false,
4
+    "anonymousAuthentication": true,
5
+    "iisExpress": {
6
+      "applicationUrl": "http://localhost:50069/",
7
+      "sslPort": 0
8
+    }
9
+  },
10
+  "profiles": {
11
+    "IIS Express": {
12
+      "commandName": "IISExpress",
13
+      "launchBrowser": true,
14
+      "launchUrl": "api/values",
15
+      "environmentVariables": {
16
+        "ASPNETCORE_ENVIRONMENT": "Development"
17
+      }
18
+    },
19
+    "BulkPrintingAPI": {
20
+      "commandName": "Project",
21
+      "launchBrowser": true,
22
+      "launchUrl": "api/values",
23
+      "environmentVariables": {
24
+        "ASPNETCORE_ENVIRONMENT": "Development"
25
+      },
26
+      "applicationUrl": "http://localhost:50070"
27
+    }
28
+  }
29
+}

+ 76 - 0
BulkPrintingAPI/Startup.Auth.cs

@@ -0,0 +1,76 @@
1
+using BulkPrintingAPI.Authentication;
2
+using Microsoft.AspNetCore.Builder;
3
+using Microsoft.Extensions.Options;
4
+using Microsoft.IdentityModel.Tokens;
5
+using System;
6
+using System.Security.Claims;
7
+using System.Security.Cryptography;
8
+using System.Security.Principal;
9
+using System.Text;
10
+using System.Threading.Tasks;
11
+
12
+namespace BulkPrintingAPI
13
+{
14
+    public partial class Startup
15
+    {
16
+        private void ConfigureAuth(IApplicationBuilder app)
17
+        {
18
+            var rawKey = new Rfc2898DeriveBytes(
19
+                    Encoding.ASCII.GetBytes(Configuration.GetSection("TokenAuthentication:SecretKey").Value),
20
+                    Encoding.ASCII.GetBytes(Configuration.GetSection("TokenAuthentication:Salt").Value),
21
+                    int.Parse(Configuration.GetSection("TokenAuthentication:Iterations").Value)
22
+                ).GetBytes(32);
23
+            var securityKey = new SymmetricSecurityKey(rawKey);
24
+
25
+            var tokenValidationParameters = new TokenValidationParameters
26
+            {
27
+                ValidateIssuerSigningKey = true,
28
+                IssuerSigningKey = securityKey,
29
+                TokenDecryptionKey = securityKey,
30
+                
31
+                ValidateIssuer = true,
32
+                ValidIssuer = Configuration.GetSection("TokenAuthentication:Issuer").Value,
33
+
34
+                ValidateAudience = true,
35
+                ValidAudience = Configuration.GetSection("TokenAuthentication:Audience").Value,
36
+
37
+                ValidateLifetime = true,
38
+                ClockSkew = TimeSpan.Zero
39
+            };
40
+
41
+            var bearerOptions = new JwtBearerOptions
42
+            {
43
+                AutomaticAuthenticate = true,
44
+                AutomaticChallenge = true,
45
+                SaveToken = true,
46
+                TokenValidationParameters = tokenValidationParameters
47
+            };
48
+
49
+            app.UseJwtBearerAuthentication(bearerOptions);
50
+
51
+            var tokenProviderOptions = new TokenProviderOptions
52
+            {
53
+                Path = Configuration.GetSection("TokenAuthentication:TokenPath").Value,
54
+                Audience = Configuration.GetSection("TokenAuthentication:Audience").Value,
55
+                Issuer = Configuration.GetSection("TokenAuthentication:Issuer").Value,
56
+                SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256),
57
+                EncryptingCredentials = new EncryptingCredentials(securityKey, "dir", SecurityAlgorithms.Aes128CbcHmacSha256),
58
+                IdentityResolver = GetIdentity
59
+            };
60
+
61
+            app.UseMiddleware<TokenProviderMiddleware>(Options.Create(tokenProviderOptions));
62
+        }
63
+
64
+        private Task<ClaimsIdentity> GetIdentity(string username, string password)
65
+        {
66
+            // Don't do this in production, obviously!
67
+            if (username == "TEST" && password == "TEST123")
68
+            {
69
+                return Task.FromResult(new ClaimsIdentity(new GenericIdentity(username, "Token"), new Claim[] { }));
70
+            }
71
+
72
+            // Credentials are invalid, or account doesn't exist
73
+            return Task.FromResult<ClaimsIdentity>(null);
74
+        }
75
+    }
76
+}

+ 43 - 0
BulkPrintingAPI/Startup.cs

@@ -0,0 +1,43 @@
1
+using Microsoft.AspNetCore.Builder;
2
+using Microsoft.AspNetCore.Hosting;
3
+using Microsoft.Extensions.Configuration;
4
+using Microsoft.Extensions.DependencyInjection;
5
+using Microsoft.Extensions.Logging;
6
+
7
+namespace BulkPrintingAPI
8
+{
9
+    public partial class Startup
10
+    {
11
+        public Startup(IHostingEnvironment env)
12
+        {
13
+            var builder = new ConfigurationBuilder()
14
+                .SetBasePath(env.ContentRootPath)
15
+                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
16
+                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
17
+                .AddJsonFile("secrets.json", optional: true, reloadOnChange: true)
18
+                .AddJsonFile($"secrets.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
19
+                .AddEnvironmentVariables();
20
+            Configuration = builder.Build();
21
+        }
22
+
23
+        public IConfigurationRoot Configuration { get; }
24
+
25
+        // This method gets called by the runtime. Use this method to add services to the container.
26
+        public void ConfigureServices(IServiceCollection services)
27
+        {
28
+            // Add framework services.
29
+            services.AddMvc();
30
+        }
31
+
32
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
33
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
34
+        {
35
+            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
36
+            loggerFactory.AddDebug();
37
+
38
+            ConfigureAuth(app);
39
+
40
+            app.UseMvc();
41
+        }
42
+    }
43
+}

+ 10 - 0
BulkPrintingAPI/appsettings.Development.json

@@ -0,0 +1,10 @@
1
+{
2
+  "Logging": {
3
+    "IncludeScopes": false,
4
+    "LogLevel": {
5
+      "Default": "Debug",
6
+      "System": "Information",
7
+      "Microsoft": "Information"
8
+    }
9
+  }
10
+}

+ 17 - 0
BulkPrintingAPI/appsettings.json

@@ -0,0 +1,17 @@
1
+{
2
+  "Logging": {
3
+    "IncludeScopes": false,
4
+    "LogLevel": {
5
+      "Default": "Warning"
6
+    }
7
+  },
8
+  "TokenAuthentication": {
9
+    "Audience": "bulk",
10
+    "Issuer": "bulk",
11
+    "SecretKey": "SET IN secrets.json",
12
+    "Salt": "SET IN secrets.json",
13
+    "Iterations": 4096,
14
+    "TokenPath": "/token",
15
+    "CookieName": "access_token"
16
+  }
17
+}