From 3d96327ecafbd68c979ca1a281db4c0758e3f5e3 Mon Sep 17 00:00:00 2001 From: Daniel Habenicht Date: Fri, 9 Aug 2019 09:42:22 +0200 Subject: [PATCH 01/23] Add Picture Service Code from Internal --- .../.gitignore | 329 ++++++++++++++++++ .../Phonebook.Backend.PictureService.sln | 25 ++ .../BackgroundTasks/PurgeTask.cs | 97 ++++++ .../Controllers/EmployeePicturesController.cs | 149 ++++++++ .../Controllers/UserController.cs | 70 ++++ .../Helpers/HelpersThing.cs | 72 ++++ .../Phonebook.Backend.PictureService.csproj | 30 ++ .../Program.cs | 24 ++ .../Properties/launchSettings.json | 29 ++ .../Startup.cs | 118 +++++++ .../appsettings.Development.json | 9 + .../appsettings.json | 36 ++ .../web.config | 19 + .../Readme.md | 21 ++ 14 files changed, 1028 insertions(+) create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Readme.md diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore new file mode 100644 index 000000000..df2a23e3f --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore @@ -0,0 +1,329 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln new file mode 100644 index 000000000..9c7b51aeb --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2035 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Phonebook.Backend.PictureService", "Phonebook.Backend.PictureService\Phonebook.Backend.PictureService.csproj", "{E5EB1B88-030D-4CED-90E2-CEABB7812F7D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E5EB1B88-030D-4CED-90E2-CEABB7812F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5EB1B88-030D-4CED-90E2-CEABB7812F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5EB1B88-030D-4CED-90E2-CEABB7812F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5EB1B88-030D-4CED-90E2-CEABB7812F7D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E575D074-EE97-4A69-AC86-2D40D72BAEAD} + EndGlobalSection +EndGlobal diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs new file mode 100644 index 000000000..28ee3d6a8 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs @@ -0,0 +1,97 @@ +using KK.AspNetCore.BackgroundTasks.Scheduled; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService.Controllers +{ + public class PurgeTask : IScheduledTask + { + + private readonly ILogger logger; + + public PurgeTask( + IScheduledTaskOptions options, + ILogger logger + ) + { + this.Options = options; + this.logger = logger; + } + + public IScheduledTaskOptions Options { get; } + + public async Task ExecuteAsync(CancellationToken stoppingToken) + { + // TODO: Add this to appsettings.json + string baseUrl = "https://demo-phonebook.me/api/persons"; + //The 'using' will help to prevent memory leaks. + //Create a new instance of HttpClient + using (HttpClient client = new HttpClient()) + + //Setting up the response... + + using (HttpResponseMessage res = await client.GetAsync(baseUrl)) + { + + if (!res.IsSuccessStatusCode) + { + this.logger.LogError("ERROR: Purging images failed: API request failed"); + } + + using (HttpContent content = res.Content) + { + string data = await content.ReadAsStringAsync(); + if (data == null) + { + this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); + } + Person[] persons = JsonConvert.DeserializeObject(data); + if (persons.Length == 0) + { + this.logger.LogError("ERROR: Purging images failed"); + } + + String[] files = Directory.GetFiles(Path.Combine( + Directory.GetCurrentDirectory(), "images")); + + + foreach (string file in files) + { + string fileName = Path.GetFileNameWithoutExtension(file); + IEnumerable matches = persons.Where(p => + { + return p.id.ToLower() == fileName.ToLower(); + }); + + if (matches.Count() == 0) + { + try + { + System.IO.File.Delete(file); + } + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed"); + }; + } + + }; + this.logger.LogInformation("Purged all images from users not in database."); + } + } + + } + } +} + +class Person +{ + public string id; +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs new file mode 100644 index 000000000..0cfaa26e7 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -0,0 +1,149 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Cors; +using Phonebook.Backend.PictureService.Helpers; + +namespace Phonebook.Backend.PictureService.Controllers +{ + /// + /// + /// + [Authorize] + [EnableCors("AllowDomainList")] + [Route("/")] + public class EmployeePictureController : Controller + { + /// + /// Upload an employee picture. + /// + /// Content has to be formatted as "image/jpeg" + /// See to get the currently logged in user. + /// The id of the user. + /// A "multipart" + /// + /// A status code indicating the success of the action. + /// + /// Everyone can access this method. + /// Ok + /// No Payload + /// Content malformated + /// User not authorized + /// Internal Server Error + [HttpPost("{id}")] + [RequestSizeLimit(2147483648)] + public async Task UploadPicture(string id, IFormFile file) + { + if (file == null || file.Length == 0) + { + return BadRequest("No Payload."); + } + var user = HttpContext.User; + if (user.Identity.Name.Split("\\")[1] != id) + { + return StatusCode(401, "User not authorized."); + } + if ( + // BMP + file.ContentType == "image/bmp" || + file.ContentType == "image/x-ms-bmp" || + file.ContentType == "image/x-bmp" || + // SVG + file.ContentType == "image/svg+xml" || + // WebP + file.ContentType == "image/webp" || + // GIF + file.ContentType == "image/gif" || + // JPEG 2000 + file.ContentType == "image/jp2" || + file.ContentType == "image/jpx" || + file.ContentType == "image/jpm" || + // JPEG + file.ContentType == "image/jpeg" || + // PNG + file.ContentType == "image/png" || + // PSD + file.ContentType == "image/vnd.adobe.photoshop" || + file.ContentType == "application/x-photoshop" || + file.ContentType == "application/photoshop" || + file.ContentType == "application/psd" || + file.ContentType == "image/psd" || + // SGI + file.ContentType == "image/sgi" || + // TGA + file.ContentType == "image/x-targa" || + file.ContentType == "image/x-tga" || + // TIFF + file.ContentType == "image/tiff" || + file.ContentType == "image/tiff-fx" + //// Last Resort + //file.ContentType == "application/octet-stream" + + ) + { + try + { + // Delete old File before writing the new one. + try + { + HelpersThing.DeleteFilesForUser(id); + } + catch (Exception err) + { + + } + + var path = Path.Combine( + Directory.GetCurrentDirectory(), "images", + id + Path.GetExtension(file.FileName)); + + using (var stream = new FileStream(path, FileMode.OpenOrCreate)) + { + await file.CopyToAsync(stream); + } + + } + catch (Exception err) + { + return StatusCode(500, "Internal Server Error"); + }; + + return Ok(); + } + else + { + return BadRequest("Content malformated. Server does only accept image/jpeg"); + } + + } + + /// + /// Delete a picture associated with a user id. + /// + /// The id of the user + /// A status code indicating the success of the action. + /// Ok + /// Ok, file not found + /// User not authorized + /// Internal Server Error + [HttpDelete("{id}")] + public IActionResult DeletePicture(string id) + { + var user = HttpContext.User; + if (user.Identity.Name.Split("\\")[1] != id) + { + return StatusCode(401, "User not authorized."); + } + try + { + return StatusCode(HelpersThing.DeleteFilesForUser(id)); + }catch (Exception err) + { + return StatusCode(500, "Internal Server Error"); + } + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs new file mode 100644 index 000000000..e27e501c0 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 + +namespace Phonebook.Backend.PictureService.Controllers +{ + /// + /// Controls User specific actions. + /// Until now only returns the username of the authenticated user. + /// + [Authorize] + [EnableCors("AllowDomainList")] + [Route("[controller]")] + public class UserController : Controller + { + private readonly ILogger logger; + + public UserController(ILogger logger) + { + this.logger = logger; + } + + /// + /// Displays the Username of the currently logged in User (via NTLM) + /// + /// Domain/Username + /// You have to be logged in via NTLM authentication + [HttpGet] + [Route("whoami")] + [ProducesResponseType(typeof(string), 200)] + public ActionResult WhoAmI([FromQuery] VersionQuery query) + { + var user = HttpContext.User; + logger.LogInformation($"Log user {user.Identity.Name}"); + + if(query.version == 2) + { + var returnValue = new WhoAmIReturnValue(user.Identity.Name, Helpers.HelpersThing.DoesFileExist(user.Identity.Name.Split("\\")[1])); + return returnValue; + } + return Json(user.Identity.Name); + } + } + + public class WhoAmIReturnValue + { + public string user { get; set; } + public Boolean hasPicture { get; set; } + + public WhoAmIReturnValue(string user, bool hasPicture) + { + this.user = user; + this.hasPicture = hasPicture; + } + } + + public class VersionQuery + { + public int? version { get; set; } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs new file mode 100644 index 000000000..d8137f229 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Phonebook.Backend.PictureService.Helpers +{ + public class HelpersThing + { + /// Why it's thrown. + public static int DeleteFilesForUser(string id) + { + + var generatedPath = Path.Combine( + Directory.GetCurrentDirectory(), "wwwroot", "generated", id); + + var uploadPath = Path.Combine( + Directory.GetCurrentDirectory(), "images"); + + try + { + // Delete the generated Images Folder + if (System.IO.Directory.Exists(generatedPath)) + { + System.IO.Directory.Delete(generatedPath, true); + }; + + // Delete the uploaded file, ignoring the file ending + IEnumerable files = Directory.EnumerateFiles(uploadPath, id + ".*"); + if (files.Count() == 0) + { + return 204; + } + + foreach (string file in files) + { + System.IO.File.Delete(file); + }; + + return 200; + } + catch (Exception err) + { + throw err; + }; + } + + public static Boolean DoesFileExist(string id) + { + var uploadPath = Path.Combine( + Directory.GetCurrentDirectory(), "images"); + + IEnumerable files = Directory.EnumerateFiles(uploadPath, id + ".*"); + + try + { + // File does not exist + if (files.Count() == 1) + { + return true; + } + return false; + } + catch (Exception err) + { + return false; + }; + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj new file mode 100644 index 000000000..65bee3b54 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj @@ -0,0 +1,30 @@ + + + + netcoreapp2.2 + + + + bin\Release\netcoreapp2.1\Phonebook.Backend.PictureService.xml + + + + bin\Debug\netcoreapp2.1\Phonebook.Backend.PictureService.xml + + + + + + + + + + + + + + + + + + diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs new file mode 100644 index 000000000..9f0ab97f8 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace Phonebook.Backend.PictureService +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json new file mode 100644 index 000000000..9ff8a44e2 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": true, + "anonymousAuthentication": false, + "iisExpress": { + "applicationUrl": "http://localhost:61992", + "sslPort": 44313 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Phonebook.Backend.PictureService": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs new file mode 100644 index 000000000..a803a7016 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using KK.AspNetCore.BackgroundTasks.Scheduled; +using KK.AspNetCore.Images.Processing; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Server.IISIntegration; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Phonebook.Backend.PictureService.Controllers; +using Swashbuckle.AspNetCore.Swagger; + +namespace Phonebook.Backend.PictureService +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + //Enable IIS Integration + services.AddAuthentication(IISDefaults.AuthenticationScheme); + services.Configure(options => + { + options.AutomaticAuthentication = true; + }); + services.AddCors(o => o.AddPolicy("AllowDomainList", builder => + { + // Add some CORS allowed origins here + // TODO: Refactor in appsettings.json + builder.WithOrigins("https://example.com", "https://localhost:8080", "http://localhost:4200", "https://localhost:4200").AllowAnyMethod().AllowAnyHeader().AllowCredentials(); + })); + + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + + services.AddImageProcessingSettings(Configuration); + + // Scheduled Tasks + services.AddSingleton>( + new ScheduledTaskOptions + { + // Once every day at startup -> May be exectuted multiple times a day depending on recycling + Schedule = "0 0 * * *", + } + ); + services.AddScheduledTask(); + services.AddHostedService(); + + + // Add Swagger + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new Info + { + Version = "v1", + Title = "Picture Service API", + Description = "API for management of Phonebook Pictures", + TermsOfService = "None", + // TODO: Put these settings into the appsettings.json + Contact = new Contact() { Name = "Phonebook Team", Email = "contact Address"} + }); + var basePath = AppContext.BaseDirectory; + var assemblyName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name; + var fileName = System.IO.Path.GetFileName(assemblyName + ".xml"); + c.IncludeXmlComments(System.IO.Path.Combine(basePath, fileName)); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + // Should stay on Top + app.UseCors("AllowDomainList"); + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseHsts(); + } + + app.UseAuthentication(); + + + // Show all Pictures in wwwroot + app.UseDirectoryBrowser(new DirectoryBrowserOptions + { + FileProvider = new PhysicalFileProvider( + Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")), + RequestPath = "" + }); + + // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), + // specifying the Swagger JSON endpoint. + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Picture Service API V1"); + }); + + // Image Processing Stuff + app.UseImageProcessing(); + app.UseStaticFiles(); + + app.UseHttpsRedirection(); + app.UseMvc(); + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json new file mode 100644 index 000000000..a2880cbf1 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json new file mode 100644 index 000000000..567463fcd --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json @@ -0,0 +1,36 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*", + "ImageProcessing": { + "TargetFolder": "generated", + "SourceFolder": "images", + "LosslessCompress": true, + "OutputFormats": [ + { + "FileEndings": [ "jpg", "jpeg" ] + } + ], + "Sizes": [ + { + "Width": 50, + "Quality": 80 + }, + { + "Width": 100, + "Quality": 80 + }, + { + "Width": 900, + "Quality": 95 + }, + { + "Width": 1800, + "Quality": 95 + } + ] + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config new file mode 100644 index 000000000..f79fb993a --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Readme.md b/Phonebook.Backend/Phonebook.Backend.PictureService/Readme.md new file mode 100644 index 000000000..f6d74b854 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Readme.md @@ -0,0 +1,21 @@ +# Picture Service API + +This project aims to host pictures. It also provides a self service for changing the pictures or deleting them. + +## Documentation + +The API is documented by Swagger. + +## Getting Started + +This is a DotNetCore2.1 project. Please install the [DotNetCore2.1-SDK](https://www.microsoft.com/net/download/windows). +The recommended IDE is [Visual Studio](https://visualstudio.microsoft.com/de/downloads/). + +## Development + +### Debugging with Postman (Authenticated) + +1. Configure Internet Options as shown [here](https://stackoverflow.com/a/44910453) and [here](https://stackoverflow.com/a/47749312) + - Use a Domain: `example.com` + - Use your PC name: for Example: `THISPCNAME` + - Fill in your AD Password and username: `username` (Your Windows account without the domain `DOMAIN\User`) From 82d3dbb741caff7077ada1573bfe268e167acbe3 Mon Sep 17 00:00:00 2001 From: Daniel Habenicht Date: Mon, 12 Aug 2019 13:45:12 +0200 Subject: [PATCH 02/23] Make settings configurable in appsettings --- .../BackgroundTasks/PurgeTask.cs | 100 +++++++++++------- .../Configuration/ContactInformation.cs | 21 ++++ .../PictureServiceConfiguration.cs | 46 ++++++++ .../Phonebook.Backend.PictureService.csproj | 1 + .../Properties/launchSettings.json | 6 +- .../Startup.cs | 37 +++++-- .../appsettings.Development.json | 8 +- .../appsettings.json | 13 ++- .../web.config | 5 + 9 files changed, 180 insertions(+), 57 deletions(-) create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/ContactInformation.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs index 28ee3d6a8..2f7916993 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs @@ -1,6 +1,7 @@ using KK.AspNetCore.BackgroundTasks.Scheduled; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Phonebook.Backend.PictureService.Configuration; using System; using System.Collections.Generic; using System.IO; @@ -15,75 +16,94 @@ public class PurgeTask : IScheduledTask { private readonly ILogger logger; + private readonly PictureServiceConfiguration configuration; public PurgeTask( IScheduledTaskOptions options, - ILogger logger + ILogger logger, + PictureServiceConfiguration configuration ) { this.Options = options; this.logger = logger; + this.configuration = configuration; } public IScheduledTaskOptions Options { get; } public async Task ExecuteAsync(CancellationToken stoppingToken) { - // TODO: Add this to appsettings.json - string baseUrl = "https://demo-phonebook.me/api/persons"; - //The 'using' will help to prevent memory leaks. - //Create a new instance of HttpClient - using (HttpClient client = new HttpClient()) + string baseUrl = this.configuration.PersonBackendUrl; - //Setting up the response... + HttpClientHandler clientHandler = new HttpClientHandler(); + // Ignore SSL Certificate Validity + if (this.configuration.IgnoreSSLValidity) + { + clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }; + } - using (HttpResponseMessage res = await client.GetAsync(baseUrl)) + //The 'using' will help to prevent memory leaks. + //Create a new instance of HttpClient + using (HttpClient client = new HttpClient(clientHandler)) { - if (!res.IsSuccessStatusCode) - { - this.logger.LogError("ERROR: Purging images failed: API request failed"); - } + client.Timeout = TimeSpan.FromSeconds(10); + //Setting up the response... - using (HttpContent content = res.Content) + try { - string data = await content.ReadAsStringAsync(); - if (data == null) - { - this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); - } - Person[] persons = JsonConvert.DeserializeObject(data); - if (persons.Length == 0) + using (HttpResponseMessage res = await client.GetAsync(baseUrl)) { - this.logger.LogError("ERROR: Purging images failed"); - } - - String[] files = Directory.GetFiles(Path.Combine( - Directory.GetCurrentDirectory(), "images")); - - foreach (string file in files) - { - string fileName = Path.GetFileNameWithoutExtension(file); - IEnumerable matches = persons.Where(p => + if (!res.IsSuccessStatusCode) { - return p.id.ToLower() == fileName.ToLower(); - }); + this.logger.LogError("ERROR: Purging images failed: API request failed"); + } - if (matches.Count() == 0) + using (HttpContent content = res.Content) { - try + string data = await content.ReadAsStringAsync(); + if (data == null) { - System.IO.File.Delete(file); + this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); } - catch (Exception err) + Person[] persons = JsonConvert.DeserializeObject(data); + if (persons.Length == 0) + { + this.logger.LogError("ERROR: Purging images failed (Malformated response)"); + } + + String[] files = Directory.GetFiles(Path.Combine( + Directory.GetCurrentDirectory(), "images")); + + + foreach (string file in files) { - this.logger.LogError("ERROR: Purging images failed"); + string fileName = Path.GetFileNameWithoutExtension(file); + IEnumerable matches = persons.Where(p => + { + return p.id.ToLower() == fileName.ToLower(); + }); + + if (matches.Count() == 0) + { + try + { + System.IO.File.Delete(file); + } + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (could not delete file)"); + }; + } }; + this.logger.LogInformation("Purged all images from users not in database."); } - - }; - this.logger.LogInformation("Purged all images from users not in database."); + } + } + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (might be a failed Request, maybe you should check the SSL Certificate)"); } } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/ContactInformation.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/ContactInformation.cs new file mode 100644 index 000000000..edc0fea08 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/ContactInformation.cs @@ -0,0 +1,21 @@ +using NetEscapades.Configuration.Validation; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService.Configuration +{ + public class ContactInformation : IValidatable + { + [Required] + public string Name { get; set; } + [Required] + public string Email { get; set; } + public void Validate() + { + Validator.ValidateObject(this, new ValidationContext(this), validateAllProperties: true); + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs new file mode 100644 index 000000000..72540061b --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs @@ -0,0 +1,46 @@ +using System.ComponentModel.DataAnnotations; +using NetEscapades.Configuration.Validation; + +namespace Phonebook.Backend.PictureService.Configuration +{ + + /// + /// The application configuration model that contains all configuration options of the application. + /// + public class PictureServiceConfiguration : IValidatable + { + /// + /// Gets or sets the configuration for the CORS Allowed Hosts. + /// + public string[] AllowedCORSDomains { get; set; } = { }; + + /// + /// The Schedule in which Pictures will get deleted if no user could be found. + /// + /// Default: Once every day at startup -> May be executed multiple times a day depending on recycling + public string PurgeSchedule { get; set; } = "0 0 * * *"; + /// + /// The Url to the Person Endpoint of the Phonebook + /// Required in order to delete pictures of users who are not listed anymore. + /// + [Required] + [Url] + public string PersonBackendUrl { get; set; } + + /// + /// Ignore the validity of the SSL Certificate for the Person Endpoint + /// + public bool IgnoreSSLValidity { get; set; } = false; + + /// + /// Contact Information displayed in the swagger API description. + /// + [Required] + public ContactInformation ContactInformation { get; set; } + + public void Validate() + { + Validator.ValidateObject(this, new ValidationContext(this), validateAllProperties: true); + } + } +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj index 65bee3b54..28b4de0bb 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj @@ -17,6 +17,7 @@ + diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json index 9ff8a44e2..98432e4a2 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json @@ -3,8 +3,8 @@ "windowsAuthentication": true, "anonymousAuthentication": false, "iisExpress": { - "applicationUrl": "http://localhost:61992", - "sslPort": 44313 + "applicationUrl": "http://localhost:5000", + "sslPort": 5001 } }, "$schema": "http://json.schemastore.org/launchsettings.json", @@ -19,7 +19,7 @@ "Phonebook.Backend.PictureService": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "/", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index a803a7016..4ef72d648 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -9,38 +9,56 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Phonebook.Backend.PictureService.Configuration; using Phonebook.Backend.PictureService.Controllers; using Swashbuckle.AspNetCore.Swagger; +using System.ComponentModel.DataAnnotations; namespace Phonebook.Backend.PictureService { + /// + /// Startup Class + /// public class Startup { + private IConfiguration Configuration { get; } + private PictureServiceConfiguration AppSettings { get; } + private const string CorsPolicy = "AllowDomainList"; + /// + /// Initializes a new instance of the class. + /// + /// public Startup(IConfiguration configuration) { - Configuration = configuration; + this.Configuration = configuration; + this.AppSettings = configuration.Get(); } - public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + // Validation of the appsettings on Startup + services.UseConfigurationValidation(); + services.ConfigureValidatableSetting(Configuration); + services.ConfigureValidatableSetting(Configuration.GetSection("ContactInformation")); + services.AddSingleton(AppSettings); + //Enable IIS Integration services.AddAuthentication(IISDefaults.AuthenticationScheme); services.Configure(options => { options.AutomaticAuthentication = true; }); - services.AddCors(o => o.AddPolicy("AllowDomainList", builder => + services.AddCors(o => o.AddPolicy(CorsPolicy, builder => { // Add some CORS allowed origins here - // TODO: Refactor in appsettings.json - builder.WithOrigins("https://example.com", "https://localhost:8080", "http://localhost:4200", "https://localhost:4200").AllowAnyMethod().AllowAnyHeader().AllowCredentials(); + builder.WithOrigins(this.AppSettings.AllowedCORSDomains).AllowAnyMethod().AllowAnyHeader().AllowCredentials(); })); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + + services.AddImageProcessingSettings(Configuration); // Scheduled Tasks @@ -48,7 +66,7 @@ public void ConfigureServices(IServiceCollection services) new ScheduledTaskOptions { // Once every day at startup -> May be exectuted multiple times a day depending on recycling - Schedule = "0 0 * * *", + Schedule = AppSettings.PurgeSchedule, } ); services.AddScheduledTask(); @@ -64,8 +82,7 @@ public void ConfigureServices(IServiceCollection services) Title = "Picture Service API", Description = "API for management of Phonebook Pictures", TermsOfService = "None", - // TODO: Put these settings into the appsettings.json - Contact = new Contact() { Name = "Phonebook Team", Email = "contact Address"} + Contact = new Swashbuckle.AspNetCore.Swagger.Contact() { Name = AppSettings.ContactInformation.Name, Email = AppSettings.ContactInformation.Email } }); var basePath = AppContext.BaseDirectory; var assemblyName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name; @@ -78,7 +95,7 @@ public void ConfigureServices(IServiceCollection services) public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // Should stay on Top - app.UseCors("AllowDomainList"); + app.UseCors(CorsPolicy); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json index a2880cbf1..0f1187ed0 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.Development.json @@ -5,5 +5,9 @@ "System": "Information", "Microsoft": "Information" } - } -} + }, + "IgnoreSSLValidity": true, + "AllowedCORSDomains": [ + "*" + ] +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json index 567463fcd..ecc89e8c9 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json @@ -5,13 +5,22 @@ } }, "AllowedHosts": "*", + "AllowedCORSDomains": [], + "ContactInformation": { + "Name": "Phonebook Team", + "Email": "some Email" + }, + "PersonBackendUrl": "https://demo-phonebook.me/api/persons", "ImageProcessing": { "TargetFolder": "generated", "SourceFolder": "images", "LosslessCompress": true, "OutputFormats": [ { - "FileEndings": [ "jpg", "jpeg" ] + "FileEndings": [ + "jpg", + "jpeg" + ] } ], "Sizes": [ @@ -33,4 +42,4 @@ } ] } -} +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config index f79fb993a..cadfad5c1 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config @@ -15,5 +15,10 @@ + + + + + \ No newline at end of file From 0b195533f0800c96c0c0854245dabe714d57bceb Mon Sep 17 00:00:00 2001 From: Christoph James Geisberger Date: Tue, 20 Aug 2019 10:05:52 +0200 Subject: [PATCH 03/23] add wwwroot to git history --- Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore | 2 +- .../Phonebook.Backend.PictureService/wwwroot/.gitkeep | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/wwwroot/.gitkeep diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore index df2a23e3f..e7fa74655 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore @@ -27,7 +27,7 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot -wwwroot/ +# wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/wwwroot/.gitkeep b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/wwwroot/.gitkeep new file mode 100644 index 000000000..e69de29bb From 75ea5a32d359397df35abb60dd36704a6d6528f8 Mon Sep 17 00:00:00 2001 From: Christoph James Geisberger Date: Tue, 20 Aug 2019 10:06:33 +0200 Subject: [PATCH 04/23] Add backend to the workspace folders. - and add spellchecker to recommended extensions --- phonebook.code-workspace | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/phonebook.code-workspace b/phonebook.code-workspace index 856731ffe..31e15ec8c 100644 --- a/phonebook.code-workspace +++ b/phonebook.code-workspace @@ -4,6 +4,10 @@ "name": "Frontend", "path": "./Phonebook.Frontend" }, + { + "name": "Backend", + "path": "./Phonebook.Backend" + }, { "name": "Source.PeopleSoft", "path": "./Phonebook.Source.PeopleSoft" @@ -31,7 +35,7 @@ { "name": "Azure Pipelines", "path": "./.azure/pipelines" - } + }, { "name": "root", "path": "." @@ -66,7 +70,8 @@ }, "extensions": { "recommendations": [ - "esbenp.prettier-vscode" + "esbenp.prettier-vscode", + "streetsidesoftware.code-spell-checker" ] } } \ No newline at end of file From 9b543ff09885a4bb535f6883b3fcbcf7509d746b Mon Sep 17 00:00:00 2001 From: GentleJames Date: Tue, 20 Aug 2019 16:39:50 +0200 Subject: [PATCH 05/23] Refactored PurgeTask Create method to get People from PersonBackend Create method to delete pictures of people who left --- .../BackgroundTasks/PurgeTask.cs | 117 ++++++++++-------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs index 2f7916993..502db72a0 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs @@ -33,80 +33,91 @@ PictureServiceConfiguration configuration public async Task ExecuteAsync(CancellationToken stoppingToken) { - string baseUrl = this.configuration.PersonBackendUrl; + try + { + var people = await GetPeople(); + var files = Directory.GetFiles(Path.Combine( + Directory.GetCurrentDirectory(), "images")); + + DeleteFilesOfNonMembers(files, people); + } + // Todo: check a more explicit error + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (might be a failed Request, maybe you should check the SSL Certificate)"); + } + } + /// + /// Delete all files of non existing members + /// + /// all files that exist + /// all person that are members + private void DeleteFilesOfNonMembers(string[] files, Person[] persons) + { + foreach (string file in files) + { + string fileName = Path.GetFileNameWithoutExtension(file); + IEnumerable matches = persons.Where(p => + { + return p.id.ToLower() == fileName.ToLower(); + }); + + if (matches.Count() == 0) + { + try + { + File.Delete(file); + } + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (could not delete file)"); + }; + } + }; + this.logger.LogInformation("Purged all images from users not in database."); + } + /// + /// Try Get People from the PersonBackendUrl + /// + /// Get all people that are members + private async Task GetPeople() + { HttpClientHandler clientHandler = new HttpClientHandler(); // Ignore SSL Certificate Validity if (this.configuration.IgnoreSSLValidity) { clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }; } - - //The 'using' will help to prevent memory leaks. - //Create a new instance of HttpClient + // The 'using' will help to prevent memory leaks. + // Create a new instance of HttpClient using (HttpClient client = new HttpClient(clientHandler)) { - client.Timeout = TimeSpan.FromSeconds(10); //Setting up the response... - - try + using (HttpResponseMessage res = await client.GetAsync(this.configuration.PersonBackendUrl)) { - using (HttpResponseMessage res = await client.GetAsync(baseUrl)) + if (!res.IsSuccessStatusCode) { + this.logger.LogError("ERROR: Purging images failed: API request failed"); + } - if (!res.IsSuccessStatusCode) + using (HttpContent content = res.Content) + { + string data = await content.ReadAsStringAsync(); + if (data == null) { - this.logger.LogError("ERROR: Purging images failed: API request failed"); + this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); } - - using (HttpContent content = res.Content) + Person[] persons = JsonConvert.DeserializeObject(data); + if (persons.Length == 0) { - string data = await content.ReadAsStringAsync(); - if (data == null) - { - this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); - } - Person[] persons = JsonConvert.DeserializeObject(data); - if (persons.Length == 0) - { - this.logger.LogError("ERROR: Purging images failed (Malformated response)"); - } - - String[] files = Directory.GetFiles(Path.Combine( - Directory.GetCurrentDirectory(), "images")); - - - foreach (string file in files) - { - string fileName = Path.GetFileNameWithoutExtension(file); - IEnumerable matches = persons.Where(p => - { - return p.id.ToLower() == fileName.ToLower(); - }); - - if (matches.Count() == 0) - { - try - { - System.IO.File.Delete(file); - } - catch (Exception err) - { - this.logger.LogError("ERROR: Purging images failed (could not delete file)"); - }; - } - }; - this.logger.LogInformation("Purged all images from users not in database."); + this.logger.LogError("ERROR: Purging images failed (Malformated response)"); } + return persons; } } - catch (Exception err) - { - this.logger.LogError("ERROR: Purging images failed (might be a failed Request, maybe you should check the SSL Certificate)"); - } } - } } } From 891d119dfba00aa0b8e8c419445649cc7761190f Mon Sep 17 00:00:00 2001 From: GentleJames Date: Tue, 20 Aug 2019 16:39:50 +0200 Subject: [PATCH 06/23] Refactored PurgeTask Create method to get People from PersonBackend Create method to delete pictures of people who left --- .../.gitignore | 3 +- .../Phonebook.Backend.PictureService.sln | 11 +- .../BackgroundTasks/PurgeTask.cs | 117 ++++++++++-------- .../ConfigureSwaggerOptions.cs | 66 ++++++++++ .../Controllers/EmployeePicturesController.cs | 29 +++-- .../Controllers/UserController.cs | 70 ----------- .../Controllers/V1/UserController.cs | 42 +++++++ .../Controllers/V2/UserController.cs | 43 +++++++ .../Helpers/HelpersThing.cs | 8 +- .../Models/Identity.cs | 18 +++ .../Phonebook.Backend.PictureService.csproj | 4 + .../Properties/launchSettings.json | 6 +- .../Startup.cs | 69 ++++++++--- .../SwaggerDefaultValues.cs | 54 ++++++++ .../web.config | 6 +- 15 files changed, 386 insertions(+), 160 deletions(-) create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs delete mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Models/Identity.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore index e7fa74655..2121e5df0 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/.gitignore @@ -27,7 +27,8 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot -# wwwroot/ +wwwroot/ +images/ # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln index 9c7b51aeb..69a563056 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.sln @@ -1,9 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2035 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.62 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Phonebook.Backend.PictureService", "Phonebook.Backend.PictureService\Phonebook.Backend.PictureService.csproj", "{E5EB1B88-030D-4CED-90E2-CEABB7812F7D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Phonebook.Backend.PictureService", "Phonebook.Backend.PictureService\Phonebook.Backend.PictureService.csproj", "{E5EB1B88-030D-4CED-90E2-CEABB7812F7D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3BB0B-64F3-4BC4-867F-937C99F1FAE4}" + ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs index 2f7916993..502db72a0 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/BackgroundTasks/PurgeTask.cs @@ -33,80 +33,91 @@ PictureServiceConfiguration configuration public async Task ExecuteAsync(CancellationToken stoppingToken) { - string baseUrl = this.configuration.PersonBackendUrl; + try + { + var people = await GetPeople(); + var files = Directory.GetFiles(Path.Combine( + Directory.GetCurrentDirectory(), "images")); + + DeleteFilesOfNonMembers(files, people); + } + // Todo: check a more explicit error + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (might be a failed Request, maybe you should check the SSL Certificate)"); + } + } + /// + /// Delete all files of non existing members + /// + /// all files that exist + /// all person that are members + private void DeleteFilesOfNonMembers(string[] files, Person[] persons) + { + foreach (string file in files) + { + string fileName = Path.GetFileNameWithoutExtension(file); + IEnumerable matches = persons.Where(p => + { + return p.id.ToLower() == fileName.ToLower(); + }); + + if (matches.Count() == 0) + { + try + { + File.Delete(file); + } + catch (Exception err) + { + this.logger.LogError("ERROR: Purging images failed (could not delete file)"); + }; + } + }; + this.logger.LogInformation("Purged all images from users not in database."); + } + /// + /// Try Get People from the PersonBackendUrl + /// + /// Get all people that are members + private async Task GetPeople() + { HttpClientHandler clientHandler = new HttpClientHandler(); // Ignore SSL Certificate Validity if (this.configuration.IgnoreSSLValidity) { clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }; } - - //The 'using' will help to prevent memory leaks. - //Create a new instance of HttpClient + // The 'using' will help to prevent memory leaks. + // Create a new instance of HttpClient using (HttpClient client = new HttpClient(clientHandler)) { - client.Timeout = TimeSpan.FromSeconds(10); //Setting up the response... - - try + using (HttpResponseMessage res = await client.GetAsync(this.configuration.PersonBackendUrl)) { - using (HttpResponseMessage res = await client.GetAsync(baseUrl)) + if (!res.IsSuccessStatusCode) { + this.logger.LogError("ERROR: Purging images failed: API request failed"); + } - if (!res.IsSuccessStatusCode) + using (HttpContent content = res.Content) + { + string data = await content.ReadAsStringAsync(); + if (data == null) { - this.logger.LogError("ERROR: Purging images failed: API request failed"); + this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); } - - using (HttpContent content = res.Content) + Person[] persons = JsonConvert.DeserializeObject(data); + if (persons.Length == 0) { - string data = await content.ReadAsStringAsync(); - if (data == null) - { - this.logger.LogError("ERROR: Purging images failed: No Users in API Response"); - } - Person[] persons = JsonConvert.DeserializeObject(data); - if (persons.Length == 0) - { - this.logger.LogError("ERROR: Purging images failed (Malformated response)"); - } - - String[] files = Directory.GetFiles(Path.Combine( - Directory.GetCurrentDirectory(), "images")); - - - foreach (string file in files) - { - string fileName = Path.GetFileNameWithoutExtension(file); - IEnumerable matches = persons.Where(p => - { - return p.id.ToLower() == fileName.ToLower(); - }); - - if (matches.Count() == 0) - { - try - { - System.IO.File.Delete(file); - } - catch (Exception err) - { - this.logger.LogError("ERROR: Purging images failed (could not delete file)"); - }; - } - }; - this.logger.LogInformation("Purged all images from users not in database."); + this.logger.LogError("ERROR: Purging images failed (Malformated response)"); } + return persons; } } - catch (Exception err) - { - this.logger.LogError("ERROR: Purging images failed (might be a failed Request, maybe you should check the SSL Certificate)"); - } } - } } } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs new file mode 100644 index 000000000..07c747238 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Phonebook.Backend.PictureService.Configuration; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService +{ + /// + /// Configures the Swagger generation options. + /// + /// This allows API versioning to define a Swagger document per API version after the + /// service has been resolved from the service container. + public class ConfigureSwaggerOptions : IConfigureOptions + { + readonly IApiVersionDescriptionProvider provider; + private readonly PictureServiceConfiguration configuration; + + /// + /// Initializes a new instance of the class. + /// + /// The provider used to generate Swagger documents. + public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, PictureServiceConfiguration configuration) + { + this.provider = provider; + this.configuration = configuration; + } + + /// + public void Configure(SwaggerGenOptions options) + { + // add a swagger document for each discovered API version + // note: you might choose to skip or document deprecated API versions differently + foreach (var description in provider.ApiVersionDescriptions) + { + options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); + } + } + + private Info CreateInfoForApiVersion(ApiVersionDescription description) + { + var info = new Info() + { + Title = "Picture Service API", + Version = description.ApiVersion.ToString(), + Description = "API for management of Phonebook Pictures", + Contact = new Contact() { Name = configuration.ContactInformation.Name, Email = configuration.ContactInformation.Email }, + TermsOfService = "None", + License = new License() { Name = "MIT", Url = "https://opensource.org/licenses/MIT" } + }; + + if (description.IsDeprecated) + { + info.Description += " This API version has been deprecated."; + } + + return info; + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index 0cfaa26e7..820785bed 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Cors; using Phonebook.Backend.PictureService.Helpers; +using Microsoft.Extensions.Logging; namespace Phonebook.Backend.PictureService.Controllers { @@ -15,8 +16,17 @@ namespace Phonebook.Backend.PictureService.Controllers [Authorize] [EnableCors("AllowDomainList")] [Route("/")] - public class EmployeePictureController : Controller + [ApiVersion("2.0")] + [ApiVersion("1.0")] + [ApiController] + public class EmployeePictureController : ControllerBase { + private readonly ILogger logger; + + public EmployeePictureController(ILogger logger) + { + this.logger = logger; + } /// /// Upload an employee picture. /// @@ -87,19 +97,15 @@ public async Task UploadPicture(string id, IFormFile file) try { // Delete old File before writing the new one. - try - { - HelpersThing.DeleteFilesForUser(id); - } - catch (Exception err) - { - - } + HelpersThing.DeleteFilesForUser(id); var path = Path.Combine( Directory.GetCurrentDirectory(), "images", id + Path.GetExtension(file.FileName)); - + if(!Directory.Exists(Path.GetDirectoryName(path))) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + } using (var stream = new FileStream(path, FileMode.OpenOrCreate)) { await file.CopyToAsync(stream); @@ -108,6 +114,7 @@ public async Task UploadPicture(string id, IFormFile file) } catch (Exception err) { + this.logger.LogError(err, err.Message); return StatusCode(500, "Internal Server Error"); }; @@ -115,6 +122,7 @@ public async Task UploadPicture(string id, IFormFile file) } else { + // TODO: that is wrong! Maybe we should send a a list of supported mime types. return BadRequest("Content malformated. Server does only accept image/jpeg"); } @@ -142,6 +150,7 @@ public IActionResult DeletePicture(string id) return StatusCode(HelpersThing.DeleteFilesForUser(id)); }catch (Exception err) { + this.logger.LogError(err, err.Message); return StatusCode(500, "Internal Server Error"); } } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs deleted file mode 100644 index e27e501c0..000000000 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/UserController.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Principal; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Cors; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; - -// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 - -namespace Phonebook.Backend.PictureService.Controllers -{ - /// - /// Controls User specific actions. - /// Until now only returns the username of the authenticated user. - /// - [Authorize] - [EnableCors("AllowDomainList")] - [Route("[controller]")] - public class UserController : Controller - { - private readonly ILogger logger; - - public UserController(ILogger logger) - { - this.logger = logger; - } - - /// - /// Displays the Username of the currently logged in User (via NTLM) - /// - /// Domain/Username - /// You have to be logged in via NTLM authentication - [HttpGet] - [Route("whoami")] - [ProducesResponseType(typeof(string), 200)] - public ActionResult WhoAmI([FromQuery] VersionQuery query) - { - var user = HttpContext.User; - logger.LogInformation($"Log user {user.Identity.Name}"); - - if(query.version == 2) - { - var returnValue = new WhoAmIReturnValue(user.Identity.Name, Helpers.HelpersThing.DoesFileExist(user.Identity.Name.Split("\\")[1])); - return returnValue; - } - return Json(user.Identity.Name); - } - } - - public class WhoAmIReturnValue - { - public string user { get; set; } - public Boolean hasPicture { get; set; } - - public WhoAmIReturnValue(string user, bool hasPicture) - { - this.user = user; - this.hasPicture = hasPicture; - } - } - - public class VersionQuery - { - public int? version { get; set; } - } -} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs new file mode 100644 index 000000000..a9d02f1db --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace Phonebook.Backend.PictureService.Controllers.V1 +{ + [Route("[controller]")] + [ApiController] + [Authorize] + [EnableCors("AllowDomainList")] + [ApiVersion("1.0")] + public class UserController : ControllerBase + { + private readonly ILogger logger; + + public UserController(ILogger logger) + { + this.logger = logger; + } + /// + /// Displays the Username of the currently logged in User (via NTLM) + /// + /// Domain/Username + /// You have to be logged in via NTLM authentication + [HttpGet] + [Route("whoami")] + [ProducesResponseType(typeof(string), 200)] + public string WhoAmI() + { + var user = HttpContext.User; + logger.LogInformation($"Log user {user.Identity.Name}"); + return '"' + user.Identity.Name + '"'; + } + + } +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs new file mode 100644 index 000000000..aafa5e173 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Phonebook.Backend.PictureService.Models; + +namespace Phonebook.Backend.PictureService.Controllers.V2 +{ + + [Route("[controller]")] + [ApiController] + [Authorize] + [EnableCors("AllowDomainList")] + [ApiVersion("2.0")] + public class UserController : ControllerBase + { + private readonly ILogger logger; + + public UserController(ILogger logger) + { + this.logger = logger; + } + /// + /// Displays the Username of the currently logged in User (via NTLM) + /// + /// Domain/Username + /// You have to be logged in via NTLM authentication + [HttpGet] + [Route("whoami")] + public Identity WhoAmI() + { + var user = HttpContext.User; + logger.LogInformation($"Log user {user.Identity.Name}"); + var returnValue = new Identity(user.Identity.Name, Helpers.HelpersThing.DoesFileExist(user.Identity.Name.Split("\\")[1])); + return returnValue; + } + } +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs index d8137f229..6543c2bb8 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs @@ -7,7 +7,7 @@ namespace Phonebook.Backend.PictureService.Helpers { - public class HelpersThing + public static class HelpersThing { /// Why it's thrown. public static int DeleteFilesForUser(string id) @@ -22,9 +22,9 @@ public static int DeleteFilesForUser(string id) try { // Delete the generated Images Folder - if (System.IO.Directory.Exists(generatedPath)) + if (Directory.Exists(generatedPath)) { - System.IO.Directory.Delete(generatedPath, true); + Directory.Delete(generatedPath, true); }; // Delete the uploaded file, ignoring the file ending @@ -36,7 +36,7 @@ public static int DeleteFilesForUser(string id) foreach (string file in files) { - System.IO.File.Delete(file); + File.Delete(file); }; return 200; diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Models/Identity.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Models/Identity.cs new file mode 100644 index 000000000..72625cff1 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Models/Identity.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService.Models +{ + public class Identity + { + public string user { get; set; } + public bool hasPicture { get; set; } + public Identity(string user, bool hasPicture) + { + this.user = user; + this.hasPicture = hasPicture; + } + } +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj index 28b4de0bb..cab7abbb6 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj @@ -17,6 +17,10 @@ + + + + diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json index 98432e4a2..f208402d2 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json @@ -3,8 +3,8 @@ "windowsAuthentication": true, "anonymousAuthentication": false, "iisExpress": { - "applicationUrl": "http://localhost:5000", - "sslPort": 5001 + "applicationUrl": "http://localhost:5000/", + "sslPort": 44300 } }, "$schema": "http://json.schemastore.org/launchsettings.json", @@ -23,7 +23,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" + "applicationUrl": "https://localhost:44300;http://localhost:5000" } } } \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index 4ef72d648..62a52d80a 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -13,6 +13,11 @@ using Phonebook.Backend.PictureService.Controllers; using Swashbuckle.AspNetCore.Swagger; using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Swashbuckle.AspNetCore.SwaggerGen; +using Microsoft.Extensions.PlatformAbstractions; +using System.Reflection; namespace Phonebook.Backend.PictureService { @@ -38,11 +43,31 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { // Validation of the appsettings on Startup + services.AddSingleton(AppSettings); services.UseConfigurationValidation(); services.ConfigureValidatableSetting(Configuration); services.ConfigureValidatableSetting(Configuration.GetSection("ContactInformation")); services.AddSingleton(AppSettings); + // Add Api Versioning Logic + services.AddApiVersioning(o => + { + o.ReportApiVersions = true; + o.AssumeDefaultVersionWhenUnspecified = true; + o.DefaultApiVersion = new ApiVersion(1, 0); + + }); + + services.AddVersionedApiExplorer(options => + { + // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service + // note: the specified format code will format the version as "'v'major[.minor][-status]" + options.GroupNameFormat = "'v'VVV"; + // note: this option is only necessary when versioning by url segment. the SubstitutionFormat + // can also be used to control the format of the API version in route templates + options.SubstituteApiVersionInUrl = true; + }); + //Enable IIS Integration services.AddAuthentication(IISDefaults.AuthenticationScheme); services.Configure(options => @@ -66,7 +91,7 @@ public void ConfigureServices(IServiceCollection services) new ScheduledTaskOptions { // Once every day at startup -> May be exectuted multiple times a day depending on recycling - Schedule = AppSettings.PurgeSchedule, + Schedule = AppSettings.PurgeSchedule } ); services.AddScheduledTask(); @@ -74,25 +99,26 @@ public void ConfigureServices(IServiceCollection services) // Add Swagger + services.AddTransient, ConfigureSwaggerOptions>(); services.AddSwaggerGen(c => { - c.SwaggerDoc("v1", new Info - { - Version = "v1", - Title = "Picture Service API", - Description = "API for management of Phonebook Pictures", - TermsOfService = "None", - Contact = new Swashbuckle.AspNetCore.Swagger.Contact() { Name = AppSettings.ContactInformation.Name, Email = AppSettings.ContactInformation.Email } - }); - var basePath = AppContext.BaseDirectory; - var assemblyName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name; - var fileName = System.IO.Path.GetFileName(assemblyName + ".xml"); - c.IncludeXmlComments(System.IO.Path.Combine(basePath, fileName)); + // add a custom operation filter which sets default values + c.OperationFilter(); + + //c.SwaggerDoc("v1", new Info + //{ + // Version = "v1", + // Title = "Picture Service API", + // Description = "API for management of Phonebook Pictures", + // TermsOfService = "None", + // Contact = new Swashbuckle.AspNetCore.Swagger.Contact() { Name = AppSettings.ContactInformation.Name, Email = AppSettings.ContactInformation.Email } + //}); + c.IncludeXmlComments(XmlCommentsFilePath); }); } // 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, IApiVersionDescriptionProvider provider) { // Should stay on Top app.UseCors(CorsPolicy); @@ -121,7 +147,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseSwagger(); app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "Picture Service API V1"); + foreach (var description in provider.ApiVersionDescriptions) + { + c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); + } }); // Image Processing Stuff @@ -131,5 +160,15 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseHttpsRedirection(); app.UseMvc(); } + + static string XmlCommentsFilePath + { + get + { + var basePath = PlatformServices.Default.Application.ApplicationBasePath; + var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; + return Path.Combine(basePath, fileName); + } + } } } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs new file mode 100644 index 000000000..04ebe219a --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService +{ + /// + /// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter. + /// + /// This is only required due to bugs in the . + /// Once they are fixed and published, this class can be removed. + public class SwaggerDefaultValues : IOperationFilter + { + /// + /// Applies the filter to the specified operation using the given context. + /// + /// The operation to apply the filter to. + /// The current operation filter context. + public void Apply(Operation operation, OperationFilterContext context) + { + var apiDescription = context.ApiDescription; + + operation.Deprecated |= apiDescription.IsDeprecated(); + + if (operation.Parameters == null) + { + return; + } + + // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412 + // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413 + foreach (var parameter in operation.Parameters.OfType()) + { + var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); + + if (parameter.Description == null) + { + parameter.Description = description.ModelMetadata?.Description; + } + + if (parameter.Default == null) + { + parameter.Default = description.DefaultValue; + } + + parameter.Required |= description.IsRequired; + } + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config index cadfad5c1..0db39d2d5 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config @@ -8,7 +8,11 @@ - + + + + + From 81ddcc75b6fc47d23cb0638d822d386e055ddbaa Mon Sep 17 00:00:00 2001 From: GentleJames Date: Thu, 22 Aug 2019 10:41:46 +0200 Subject: [PATCH 07/23] Created List for valid content types and refactored a bit --- .../Controllers/EmployeePicturesController.cs | 94 ++++++++++--------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index 820785bed..49e1f01c8 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Cors; using Phonebook.Backend.PictureService.Helpers; using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; namespace Phonebook.Backend.PictureService.Controllers { @@ -21,6 +23,42 @@ namespace Phonebook.Backend.PictureService.Controllers [ApiController] public class EmployeePictureController : ControllerBase { + private static readonly string[] validContentTypes = new string[] + { + // BMP + "image/bmp", + "image/x-ms-bmp", + "image/x-bmp", + // SVG + "image/svg+xml", + // WebP + "image/webp", + // GIF + "image/gif", + // JPEG 2000 + "image/jp2", + "image/jpx", + "image/jpm", + // JPEG + "image/jpeg", + // PNG + "image/png", + // PSD + "image/vnd.adobe.photoshop", + "application/x-photoshop", + "application/photoshop", + "application/psd", + "image/psd", + // SGI + "image/sgi", + // TGA + "image/x-targa", + "image/x-tga", + // TIFF + "image/tiff", + "image/tiff-fx" + }; + private readonly ILogger logger; public EmployeePictureController(ILogger logger) @@ -47,52 +85,16 @@ public EmployeePictureController(ILogger logger) [RequestSizeLimit(2147483648)] public async Task UploadPicture(string id, IFormFile file) { - if (file == null || file.Length == 0) + if(file == null || file.Length == 0) { return BadRequest("No Payload."); } var user = HttpContext.User; - if (user.Identity.Name.Split("\\")[1] != id) + if(user.Identity.Name.Split("\\")[1] != id) { return StatusCode(401, "User not authorized."); } - if ( - // BMP - file.ContentType == "image/bmp" || - file.ContentType == "image/x-ms-bmp" || - file.ContentType == "image/x-bmp" || - // SVG - file.ContentType == "image/svg+xml" || - // WebP - file.ContentType == "image/webp" || - // GIF - file.ContentType == "image/gif" || - // JPEG 2000 - file.ContentType == "image/jp2" || - file.ContentType == "image/jpx" || - file.ContentType == "image/jpm" || - // JPEG - file.ContentType == "image/jpeg" || - // PNG - file.ContentType == "image/png" || - // PSD - file.ContentType == "image/vnd.adobe.photoshop" || - file.ContentType == "application/x-photoshop" || - file.ContentType == "application/photoshop" || - file.ContentType == "application/psd" || - file.ContentType == "image/psd" || - // SGI - file.ContentType == "image/sgi" || - // TGA - file.ContentType == "image/x-targa" || - file.ContentType == "image/x-tga" || - // TIFF - file.ContentType == "image/tiff" || - file.ContentType == "image/tiff-fx" - //// Last Resort - //file.ContentType == "application/octet-stream" - - ) + if(IsAValidContentType(file.ContentType)) { try { @@ -106,13 +108,13 @@ public async Task UploadPicture(string id, IFormFile file) { Directory.CreateDirectory(Path.GetDirectoryName(path)); } - using (var stream = new FileStream(path, FileMode.OpenOrCreate)) + using(var stream = new FileStream(path, FileMode.OpenOrCreate)) { await file.CopyToAsync(stream); } } - catch (Exception err) + catch(Exception err) { this.logger.LogError(err, err.Message); return StatusCode(500, "Internal Server Error"); @@ -125,7 +127,6 @@ public async Task UploadPicture(string id, IFormFile file) // TODO: that is wrong! Maybe we should send a a list of supported mime types. return BadRequest("Content malformated. Server does only accept image/jpeg"); } - } /// @@ -141,18 +142,23 @@ public async Task UploadPicture(string id, IFormFile file) public IActionResult DeletePicture(string id) { var user = HttpContext.User; - if (user.Identity.Name.Split("\\")[1] != id) + if(user.Identity.Name.Split("\\")[1] != id) { return StatusCode(401, "User not authorized."); } try { return StatusCode(HelpersThing.DeleteFilesForUser(id)); - }catch (Exception err) + } + catch(Exception err) { this.logger.LogError(err, err.Message); return StatusCode(500, "Internal Server Error"); } } + private bool IsAValidContentType(string ContentType) + { + return validContentTypes.Any(d => d == ContentType); + } } } From 4350bd065194f6c48f48f6bc4ee4ab1d420a08bf Mon Sep 17 00:00:00 2001 From: GentleJames Date: Thu, 22 Aug 2019 11:23:36 +0200 Subject: [PATCH 08/23] Lists all support mime types now in the error message --- .../Controllers/EmployeePicturesController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index 49e1f01c8..eb167e236 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -125,7 +125,8 @@ public async Task UploadPicture(string id, IFormFile file) else { // TODO: that is wrong! Maybe we should send a a list of supported mime types. - return BadRequest("Content malformated. Server does only accept image/jpeg"); + var AcceptableContentTypes = String.Join(",", validContentTypes); + return BadRequest($"Content malformated. Server does only accept {AcceptableContentTypes}"); } } From 15a6dc52f65dae20eaf24d51d1312ded7f571219 Mon Sep 17 00:00:00 2001 From: GentleJames <53565550+GentleJames@users.noreply.github.com> Date: Mon, 26 Aug 2019 15:37:01 +0200 Subject: [PATCH 09/23] Build definition for PictureService --- .../pr/Phonebook.Backend.PictureService.pr.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml diff --git a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml new file mode 100644 index 000000000..8fa7e5502 --- /dev/null +++ b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml @@ -0,0 +1,16 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +trigger: +- master + +pool: + vmImage: 'ubuntu-latest' + +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + projects: '**/Phonebook.Backend.PictureService/*.csproj' From 93121cca246f7276885098dffc35ab77965f1ac8 Mon Sep 17 00:00:00 2001 From: GentleJames Date: Wed, 28 Aug 2019 10:37:20 +0200 Subject: [PATCH 10/23] Changed license link, listed more common content types first in the list of valid content types, removed unnecessary comments in startup and added trigger paths to the backend build --- .../pr/Phonebook.Backend.PictureService.pr.yml | 11 +++++++++-- .../ConfigureSwaggerOptions.cs | 2 +- .../Controllers/EmployeePicturesController.cs | 10 +++++----- .../Phonebook.Backend.PictureService/Startup.cs | 9 +-------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml index 8fa7e5502..6b4358729 100644 --- a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml +++ b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml @@ -3,8 +3,15 @@ # Add steps that build, run tests, deploy, and more: # https://aka.ms/yaml -trigger: -- master +trigger: none +pr: + branches: + include: + - master + paths: + include: + - /Phonebook.Frontend/* + pool: vmImage: 'ubuntu-latest' diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs index 07c747238..b64f5af3a 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs @@ -52,7 +52,7 @@ private Info CreateInfoForApiVersion(ApiVersionDescription description) Description = "API for management of Phonebook Pictures", Contact = new Contact() { Name = configuration.ContactInformation.Name, Email = configuration.ContactInformation.Email }, TermsOfService = "None", - License = new License() { Name = "MIT", Url = "https://opensource.org/licenses/MIT" } + License = new License() { Name = "MIT", Url = "https://github.com/T-Systems-MMS/phonebook/blob/master/LICENSE" } }; if (description.IsDeprecated) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index eb167e236..f2a4101b6 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -25,6 +25,10 @@ public class EmployeePictureController : ControllerBase { private static readonly string[] validContentTypes = new string[] { + // JPEG + "image/jpeg", + // PNG + "image/png", // BMP "image/bmp", "image/x-ms-bmp", @@ -38,11 +42,7 @@ public class EmployeePictureController : ControllerBase // JPEG 2000 "image/jp2", "image/jpx", - "image/jpm", - // JPEG - "image/jpeg", - // PNG - "image/png", + "image/jpm", // PSD "image/vnd.adobe.photoshop", "application/x-photoshop", diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index 62a52d80a..ddc1dcee9 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -105,14 +105,7 @@ public void ConfigureServices(IServiceCollection services) // add a custom operation filter which sets default values c.OperationFilter(); - //c.SwaggerDoc("v1", new Info - //{ - // Version = "v1", - // Title = "Picture Service API", - // Description = "API for management of Phonebook Pictures", - // TermsOfService = "None", - // Contact = new Swashbuckle.AspNetCore.Swagger.Contact() { Name = AppSettings.ContactInformation.Name, Email = AppSettings.ContactInformation.Email } - //}); + c.IncludeXmlComments(XmlCommentsFilePath); }); } From 3d7b94fb1b92f73a0c4247f1d6a7d1c1f952e5f7 Mon Sep 17 00:00:00 2001 From: GentleJames Date: Wed, 28 Aug 2019 10:52:57 +0200 Subject: [PATCH 11/23] Replaced a comment to a more fitting place --- .../Configuration/PictureServiceConfiguration.cs | 1 + .../Phonebook.Backend.PictureService/Startup.cs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs index 72540061b..324d5f415 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs @@ -16,6 +16,7 @@ public class PictureServiceConfiguration : IValidatable /// /// The Schedule in which Pictures will get deleted if no user could be found. + /// Once every day at startup -> May be exectuted multiple times a day depending on recycling /// /// Default: Once every day at startup -> May be executed multiple times a day depending on recycling public string PurgeSchedule { get; set; } = "0 0 * * *"; diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index ddc1dcee9..035886a7e 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -89,8 +89,7 @@ public void ConfigureServices(IServiceCollection services) // Scheduled Tasks services.AddSingleton>( new ScheduledTaskOptions - { - // Once every day at startup -> May be exectuted multiple times a day depending on recycling + { Schedule = AppSettings.PurgeSchedule } ); From 6e6af4bc0a88bf1bfe903d5b3682313566fc798a Mon Sep 17 00:00:00 2001 From: GentleJames Date: Thu, 29 Aug 2019 13:13:28 +0200 Subject: [PATCH 12/23] Replaced wrong name --- .../Phonebook.Backend.PictureService.pr.yml | 2 +- Phonebook.Backend/.vscode/launch.json | 36 ++++++++++++++++ Phonebook.Backend/.vscode/tasks.json | 42 +++++++++++++++++++ .../Helpers/HelpersThing.cs | 2 +- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 Phonebook.Backend/.vscode/launch.json create mode 100644 Phonebook.Backend/.vscode/tasks.json diff --git a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml index 6b4358729..5883af4d2 100644 --- a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml +++ b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml @@ -10,7 +10,7 @@ pr: - master paths: include: - - /Phonebook.Frontend/* + - /Phonebook.Phonebook.Backend.PictureService/* pool: diff --git a/Phonebook.Backend/.vscode/launch.json b/Phonebook.Backend/.vscode/launch.json new file mode 100644 index 000000000..811b91a40 --- /dev/null +++ b/Phonebook.Backend/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/bin/Debug/netcoreapp2.2/Phonebook.Backend.PictureService.dll", + "args": [], + "cwd": "${workspaceFolder}/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService", + "stopAtEntry": false, + // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser + "serverReadyAction": { + "action": "openExternally", + "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/Phonebook.Backend/.vscode/tasks.json b/Phonebook.Backend/.vscode/tasks.json new file mode 100644 index 000000000..aadef8d8c --- /dev/null +++ b/Phonebook.Backend/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs index 6543c2bb8..401a36475 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs @@ -25,7 +25,7 @@ public static int DeleteFilesForUser(string id) if (Directory.Exists(generatedPath)) { Directory.Delete(generatedPath, true); - }; + }; // Delete the uploaded file, ignoring the file ending IEnumerable files = Directory.EnumerateFiles(uploadPath, id + ".*"); From e594714ebbfbe7a4690ccf674596fb9b2a1cc0b3 Mon Sep 17 00:00:00 2001 From: GentleJames <53565550+GentleJames@users.noreply.github.com> Date: Thu, 29 Aug 2019 13:16:31 +0200 Subject: [PATCH 13/23] Unnecessary comment Co-Authored-By: DanielHabenicht --- .../Configuration/PictureServiceConfiguration.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs index 324d5f415..1afd4db5c 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Configuration/PictureServiceConfiguration.cs @@ -16,7 +16,6 @@ public class PictureServiceConfiguration : IValidatable /// /// The Schedule in which Pictures will get deleted if no user could be found. - /// Once every day at startup -> May be exectuted multiple times a day depending on recycling /// /// Default: Once every day at startup -> May be executed multiple times a day depending on recycling public string PurgeSchedule { get; set; } = "0 0 * * *"; @@ -44,4 +43,4 @@ public void Validate() Validator.ValidateObject(this, new ValidationContext(this), validateAllProperties: true); } } -} \ No newline at end of file +} From ec1d6c1641628e62a86a96d1034f1bc0375f045b Mon Sep 17 00:00:00 2001 From: Paul Jeschke Date: Sun, 1 Sep 2019 17:23:26 +0200 Subject: [PATCH 14/23] refactor helperthings - rename to ImageHelperFuncitons - add documentation about the functionalitiy - centralize some logic. --- .../Controllers/EmployeePicturesController.cs | 4 +- .../Controllers/V2/UserController.cs | 2 +- .../Helpers/HelpersThing.cs | 72 ------------- .../Helpers/ImageHelperFunctions.cs | 102 ++++++++++++++++++ 4 files changed, 105 insertions(+), 75 deletions(-) delete mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/ImageHelperFunctions.cs diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index f2a4101b6..83a56a895 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -99,7 +99,7 @@ public async Task UploadPicture(string id, IFormFile file) try { // Delete old File before writing the new one. - HelpersThing.DeleteFilesForUser(id); + ImageHelperFunctions.DeleteFilesForUser(id); var path = Path.Combine( Directory.GetCurrentDirectory(), "images", @@ -149,7 +149,7 @@ public IActionResult DeletePicture(string id) } try { - return StatusCode(HelpersThing.DeleteFilesForUser(id)); + return StatusCode((int)ImageHelperFunctions.DeleteFilesForUser(id)); } catch(Exception err) { diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs index aafa5e173..52580da09 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs @@ -36,7 +36,7 @@ public Identity WhoAmI() { var user = HttpContext.User; logger.LogInformation($"Log user {user.Identity.Name}"); - var returnValue = new Identity(user.Identity.Name, Helpers.HelpersThing.DoesFileExist(user.Identity.Name.Split("\\")[1])); + var returnValue = new Identity(user.Identity.Name, Helpers.ImageHelperFunctions.DoesFileExist(user.Identity.Name.Split("\\")[1])); return returnValue; } } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs deleted file mode 100644 index 401a36475..000000000 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/HelpersThing.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Phonebook.Backend.PictureService.Helpers -{ - public static class HelpersThing - { - /// Why it's thrown. - public static int DeleteFilesForUser(string id) - { - - var generatedPath = Path.Combine( - Directory.GetCurrentDirectory(), "wwwroot", "generated", id); - - var uploadPath = Path.Combine( - Directory.GetCurrentDirectory(), "images"); - - try - { - // Delete the generated Images Folder - if (Directory.Exists(generatedPath)) - { - Directory.Delete(generatedPath, true); - }; - - // Delete the uploaded file, ignoring the file ending - IEnumerable files = Directory.EnumerateFiles(uploadPath, id + ".*"); - if (files.Count() == 0) - { - return 204; - } - - foreach (string file in files) - { - File.Delete(file); - }; - - return 200; - } - catch (Exception err) - { - throw err; - }; - } - - public static Boolean DoesFileExist(string id) - { - var uploadPath = Path.Combine( - Directory.GetCurrentDirectory(), "images"); - - IEnumerable files = Directory.EnumerateFiles(uploadPath, id + ".*"); - - try - { - // File does not exist - if (files.Count() == 1) - { - return true; - } - return false; - } - catch (Exception err) - { - return false; - }; - } - } -} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/ImageHelperFunctions.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/ImageHelperFunctions.cs new file mode 100644 index 000000000..7a5de6908 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/ImageHelperFunctions.cs @@ -0,0 +1,102 @@ +using System.Net; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Phonebook.Backend.PictureService.Helpers +{ + /// + /// Contains functions to help with accessing and manage the images of the phonebook. + /// + public static class ImageHelperFunctions + { + /// + /// The default storage for the original images. + /// + private static string originalImagesFolder = Path.Combine(Directory.GetCurrentDirectory(), "images"); + + /// + /// Get all original images of the user from the storage. + /// + /// The user id. That is not the database id. It is more a unique shortname of a user. + private static Func> allOriginalUserImages = (userId) => Directory.EnumerateFiles(originalImagesFolder, userId + ".*"); + + /// + /// The folder for the generated images per user. + /// + /// The user id. That is not the database id. It is more a unique shortname of a user. + private static Func generatedImagesFolder = (userId) => Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "generated", userId); + + + + /// + /// + /// + /// The user id. That is not the database id. It is more a unique shortname of a user. + /// Why it's thrown. + /// If the user hasn't pictures uploaded yet you get an error. + /// + public static HttpStatusCode DeleteFilesForUser(string userId) + { + + if(DoesFileExist(userId) == false){ + throw new ArgumentException($"The user {userId} doesn't has a picture. Please check first if a user has pictures!"); + } + + var generatedPath = generatedImagesFolder(userId); + try + { + // Delete the generated Images Folder + if (Directory.Exists(generatedPath)) + { + Directory.Delete(generatedPath, true); + }; + + // Delete the uploaded file, ignoring the file ending + var files = allOriginalUserImages(userId); + if (files.Count() == 0) + { + return HttpStatusCode.NoContent; + } + + foreach (string file in files) + { + File.Delete(file); + }; + + return HttpStatusCode.NoContent; + } + catch (Exception err) + { + throw err; + }; + } + /// + /// Check if a picture exits in the storage. + /// + /// The user id. That is not the database id. It is more a unique shortname of a user. + /// True if the file exists. + public static Boolean DoesFileExist(string userId) + { + var uploadPath = Path.Combine( + Directory.GetCurrentDirectory(), "images"); + var files = allOriginalUserImages(userId); + try + { + // File does not exist + if (files.Count() == 1) + { + return true; + } + return false; + } + catch (Exception err) + { + return false; + }; + } + } +} From 93cf6a5d89f4e77e36b051618d2f746aeec81faa Mon Sep 17 00:00:00 2001 From: paule96 Date: Thu, 12 Sep 2019 19:20:41 +0200 Subject: [PATCH 15/23] add IIS errors and IIS support --- .../Program.cs | 8 ++++++- .../Properties/launchSettings.json | 13 ++++++++++- .../Phonebook.Source.PeopleSoft.csproj | 2 +- .../Phonebook.Source.PeopleSoft/Program.cs | 10 +++++++-- .../Properties/launchSettings.json | 22 +++++++++++++++---- 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs index 9f0ab97f8..d1f24f04a 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs @@ -14,7 +14,13 @@ public class Program { public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + var builder = CreateWebHostBuilder(args).Build(); + if (builder.ServerFeatures.Count() > 0) + { + // Here we are know we are not in an IIS + throw new ApplicationException("This web app must run in an IIS. You are currently not running in a IIS."); + } + builder.Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json index f208402d2..819465aa9 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json @@ -1,7 +1,11 @@ { "iisSettings": { "windowsAuthentication": true, - "anonymousAuthentication": false, + "anonymousAuthentication": true, + "iis": { + "applicationUrl": "http://localhost/Phonebook.Backend.PictureService", + "sslPort": 0 + }, "iisExpress": { "applicationUrl": "http://localhost:5000/", "sslPort": 44300 @@ -24,6 +28,13 @@ "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:44300;http://localhost:5000" + }, + "IIS": { + "commandName": "IIS", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } } } } \ No newline at end of file diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Phonebook.Source.PeopleSoft.csproj b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Phonebook.Source.PeopleSoft.csproj index 77df3d23b..0a163b0b2 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Phonebook.Source.PeopleSoft.csproj +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Phonebook.Source.PeopleSoft.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2 diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs index bace14d6a..9e162d342 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs @@ -14,11 +14,17 @@ public class Program { public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + var builder = CreateWebHostBuilder(args).Build(); + if(builder.ServerFeatures.Count() > 0) + { + // Here we are know we are not in an IIS + throw new ApplicationException("This web app must run in an IIS. You are currently not running in a IIS."); + } + builder.Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) + WebHost.CreateDefaultBuilder(args) .UseStartup(); } } diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json index a7804460c..58c6d2327 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json @@ -1,13 +1,17 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", +{ "iisSettings": { - "windowsAuthentication": false, + "windowsAuthentication": true, "anonymousAuthentication": true, + "iis": { + "applicationUrl": "http://localhost/Phonebook.Source.PeopleSoft", + "sslPort": 0 + }, "iisExpress": { "applicationUrl": "http://localhost:22913", "sslPort": 44390 } }, + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "IIS Express": { "commandName": "IISExpress", @@ -21,7 +25,17 @@ "commandName": "Project", "launchBrowser": true, "launchUrl": "api/values", - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + }, + "Azure Dev Spaces": { + "commandName": "AzureDevSpaces", + "launchBrowser": true + }, + "IIS": { + "commandName": "IIS", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From b64324394bf44cecb16ce2cfa83269f98698dc10 Mon Sep 17 00:00:00 2001 From: DanielHabenicht Date: Mon, 9 Mar 2020 20:50:18 +0100 Subject: [PATCH 16/23] Update .azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml --- .azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml index 5883af4d2..c93fece9e 100644 --- a/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml +++ b/.azure/pipelines/pr/Phonebook.Backend.PictureService.pr.yml @@ -10,7 +10,7 @@ pr: - master paths: include: - - /Phonebook.Phonebook.Backend.PictureService/* + - /Phonebook.Backend/Phonebook.Backend.PictureService/* pool: From d270b9182c0b5922f793f1ce324263c5ee6799a1 Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:18:09 +0200 Subject: [PATCH 17/23] update to 3.1 dotnet and dependencies - also remove auth for now - also remove IIS integration for ever --- .../ConfigureSwaggerOptions.cs | 11 ++-- .../Controllers/V1/UserController.cs | 3 +- .../Controllers/V2/UserController.cs | 3 +- .../Phonebook.Backend.PictureService.csproj | 16 +++--- .../Program.cs | 7 +-- .../Properties/launchSettings.json | 2 +- .../Startup.cs | 57 +++++++++++-------- .../SwaggerDefaultValues.cs | 11 ++-- .../web.config | 2 +- 9 files changed, 59 insertions(+), 53 deletions(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs index b64f5af3a..c27243bc0 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/ConfigureSwaggerOptions.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; using Phonebook.Backend.PictureService.Configuration; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; @@ -43,16 +44,16 @@ public void Configure(SwaggerGenOptions options) } } - private Info CreateInfoForApiVersion(ApiVersionDescription description) + private OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) { - var info = new Info() + var info = new OpenApiInfo() { Title = "Picture Service API", Version = description.ApiVersion.ToString(), Description = "API for management of Phonebook Pictures", - Contact = new Contact() { Name = configuration.ContactInformation.Name, Email = configuration.ContactInformation.Email }, - TermsOfService = "None", - License = new License() { Name = "MIT", Url = "https://github.com/T-Systems-MMS/phonebook/blob/master/LICENSE" } + Contact = new OpenApiContact() { Name = configuration.ContactInformation.Name, Email = configuration.ContactInformation.Email }, + TermsOfService = new Uri("https://example.org/"), + License = new OpenApiLicense() { Name = "MIT", Url = new Uri("https://github.com/T-Systems-MMS/phonebook/blob/master/LICENSE") } }; if (description.IsDeprecated) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs index a9d02f1db..eb9b01dbb 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs @@ -12,8 +12,7 @@ namespace Phonebook.Backend.PictureService.Controllers.V1 { [Route("[controller]")] [ApiController] - [Authorize] - [EnableCors("AllowDomainList")] + //[Authorize] [ApiVersion("1.0")] public class UserController : ControllerBase { diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs index 52580da09..5d341e6f1 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs @@ -14,8 +14,7 @@ namespace Phonebook.Backend.PictureService.Controllers.V2 [Route("[controller]")] [ApiController] - [Authorize] - [EnableCors("AllowDomainList")] + //[Authorize] [ApiVersion("2.0")] public class UserController : ControllerBase { diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj index cab7abbb6..1a0c6fdbf 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + netcoreapp3.1 @@ -15,14 +15,14 @@ - - - - + + + - - - + + + + diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs index d1f24f04a..0e2583feb 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Program.cs @@ -14,12 +14,7 @@ public class Program { public static void Main(string[] args) { - var builder = CreateWebHostBuilder(args).Build(); - if (builder.ServerFeatures.Count() > 0) - { - // Here we are know we are not in an IIS - throw new ApplicationException("This web app must run in an IIS. You are currently not running in a IIS."); - } + var builder = CreateWebHostBuilder(args).Build(); builder.Run(); } diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json index 819465aa9..b95970d0c 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Properties/launchSettings.json @@ -23,7 +23,7 @@ "Phonebook.Backend.PictureService": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "/", + "launchUrl": "swagger/index.html", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index 035886a7e..459212fe7 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -39,9 +39,12 @@ public Startup(IConfiguration configuration) this.AppSettings = configuration.Get(); } - // This method gets called by the runtime. Use this method to add services to the container. + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// public void ConfigureServices(IServiceCollection services) { + services.AddControllers(); // Validation of the appsettings on Startup services.AddSingleton(AppSettings); services.UseConfigurationValidation(); @@ -69,18 +72,18 @@ public void ConfigureServices(IServiceCollection services) }); //Enable IIS Integration - services.AddAuthentication(IISDefaults.AuthenticationScheme); - services.Configure(options => - { - options.AutomaticAuthentication = true; - }); - services.AddCors(o => o.AddPolicy(CorsPolicy, builder => - { - // Add some CORS allowed origins here - builder.WithOrigins(this.AppSettings.AllowedCORSDomains).AllowAnyMethod().AllowAnyHeader().AllowCredentials(); - })); + //services.AddAuthentication(IISDefaults.AuthenticationScheme); + //services.Configure(options => + //{ + // options.AutomaticAuthentication = true; + //}); + //services.AddCors(o => o.AddPolicy(CorsPolicy, builder => + //{ + // // Add some CORS allowed origins here + // builder.WithOrigins(this.AppSettings.AllowedCORSDomains).AllowAnyMethod().AllowAnyHeader().AllowCredentials(); + //})); - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); @@ -89,7 +92,7 @@ public void ConfigureServices(IServiceCollection services) // Scheduled Tasks services.AddSingleton>( new ScheduledTaskOptions - { + { Schedule = AppSettings.PurgeSchedule } ); @@ -103,17 +106,19 @@ public void ConfigureServices(IServiceCollection services) { // add a custom operation filter which sets default values c.OperationFilter(); - + c.IncludeXmlComments(XmlCommentsFilePath); }); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + /// + ///This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + ///The order should be like this: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1#middleware-order + /// public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider) { - // Should stay on Top - app.UseCors(CorsPolicy); + //Should stay on Top if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -123,8 +128,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVers app.UseHsts(); } - app.UseAuthentication(); - + app.UseHttpsRedirection(); // Show all Pictures in wwwroot app.UseDirectoryBrowser(new DirectoryBrowserOptions @@ -133,6 +137,16 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVers Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")), RequestPath = "" }); + // Image Processing Stuff + app.UseImageProcessing(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), // specifying the Swagger JSON endpoint. @@ -145,12 +159,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVers } }); - // Image Processing Stuff - app.UseImageProcessing(); - app.UseStaticFiles(); - app.UseHttpsRedirection(); - app.UseMvc(); } static string XmlCommentsFilePath diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs index 04ebe219a..723fe2bd2 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/SwaggerDefaultValues.cs @@ -1,9 +1,12 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using System.Threading.Tasks; namespace Phonebook.Backend.PictureService @@ -20,7 +23,7 @@ public class SwaggerDefaultValues : IOperationFilter /// /// The operation to apply the filter to. /// The current operation filter context. - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { var apiDescription = context.ApiDescription; @@ -33,7 +36,7 @@ public void Apply(Operation operation, OperationFilterContext context) // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412 // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413 - foreach (var parameter in operation.Parameters.OfType()) + foreach (var parameter in operation.Parameters) { var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); @@ -42,9 +45,9 @@ public void Apply(Operation operation, OperationFilterContext context) parameter.Description = description.ModelMetadata?.Description; } - if (parameter.Default == null) + if (parameter.Schema.Default == null && description.DefaultValue != null) { - parameter.Default = description.DefaultValue; + parameter.Schema.Default = new OpenApiString(description.DefaultValue.ToString()); } parameter.Required |= description.IsRequired; diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config index 0db39d2d5..6c2fac719 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/web.config @@ -7,7 +7,7 @@ - + From 0b03465779dd05e4bce2015b3d5563a7e04a2160 Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:25:16 +0200 Subject: [PATCH 18/23] remove the iis check from peoplesoft! --- .../src/Phonebook.Source.PeopleSoft/Program.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs index 8a3e42fb7..174bafbdb 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs @@ -8,11 +8,6 @@ public static class Program public static void Main(string[] args) { var builder = CreateWebHostBuilder(args).Build(); - if(builder.ServerFeatures.Count() > 0) - { - // Here we are know we are not in an IIS - throw new ApplicationException("This web app must run in an IIS. You are currently not running in a IIS."); - } builder.Run(); } From bd446728bf6945a82a5189a055fb66b15918afdb Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:34:51 +0200 Subject: [PATCH 19/23] use authorization again --- .../Controllers/EmployeePicturesController.cs | 3 - .../Controllers/V1/UserController.cs | 2 +- .../Controllers/V2/UserController.cs | 2 +- .../Helpers/AdfsHelper.cs | 91 +++++++++++++++++++ .../Startup.cs | 25 ++--- .../appsettings.json | 5 + 6 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/AdfsHelper.cs diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs index 83a56a895..fc12f043f 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/EmployeePicturesController.cs @@ -12,9 +12,6 @@ namespace Phonebook.Backend.PictureService.Controllers { - /// - /// - /// [Authorize] [EnableCors("AllowDomainList")] [Route("/")] diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs index eb9b01dbb..bb30d899c 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V1/UserController.cs @@ -12,7 +12,7 @@ namespace Phonebook.Backend.PictureService.Controllers.V1 { [Route("[controller]")] [ApiController] - //[Authorize] + [Authorize] [ApiVersion("1.0")] public class UserController : ControllerBase { diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs index 5d341e6f1..bcd2ccba4 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Controllers/V2/UserController.cs @@ -14,7 +14,7 @@ namespace Phonebook.Backend.PictureService.Controllers.V2 [Route("[controller]")] [ApiController] - //[Authorize] + [Authorize] [ApiVersion("2.0")] public class UserController : ControllerBase { diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/AdfsHelper.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/AdfsHelper.cs new file mode 100644 index 000000000..5972b6e94 --- /dev/null +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Helpers/AdfsHelper.cs @@ -0,0 +1,91 @@ +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.WsFederation; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace Phonebook.Backend.PictureService.Helpers +{ + internal static class AdfsHelper + { + internal static void AddWsFederation(IServiceCollection services, IConfiguration configuration) + { + services.AddAuthentication(sharedOptions => + { + sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; + + }) + .AddWsFederation(options => + { + // MetadataAddress represents the Active Directory instance used to authenticate users. + options.MetadataAddress = configuration.GetValue("WsFederationConfig:MetadataAddress"); ; + + var appId = configuration.GetValue("WsFederationConfig:ApplicationId"); + + + // Wtrealm is the app's identifier in the Active Directory instance. + // For ADFS, use the relying party's identifier, its WS-Federation Passive protocol URL: + options.Wtrealm = $"{appId}"; + + // maybe the following is requiered for azure. check this alter. + //options.Wtrealm = $"spn:{appId}"; + options.AllowUnsolicitedLogins = true; + // https://stackoverflow.com/questions/28627061/owin-ws-federation-setting-up-token-sliding-expiration + options.UseTokenLifetime = false; + + options.ClaimsIssuer = configuration.GetValue("WsFederationConfig:ClaimsIssuer"); + options.Events.OnRedirectToIdentityProvider = (c) => + { + var hostname = string.Empty; + if (string.IsNullOrWhiteSpace(c.Request.Headers["Referer"]) == false) + { + var uri = new Uri(c.Request.Headers["Referer"]); + hostname = $"{uri.Host}:{uri.Port}"; + } + else + { + hostname = c.Request.Host.ToString(); + } + c.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + c.ProtocolMessage.Wreply = $"https://{hostname}/signin-wsfed"; + c.Properties.RedirectUri = $"{c.Request.Headers["Referer"]}"; + c.Response.Headers.Add(new KeyValuePair("Location", new StringValues(c.ProtocolMessage.CreateSignInUrl()))); + c.HandleResponse(); + return Task.CompletedTask; + }; + + options.Events.OnAuthenticationFailed = (c) => + { + var hostname = string.Empty; + if (string.IsNullOrWhiteSpace(c.Request.Headers["Referer"]) == false) + { + var uri = new Uri(c.Request.Headers["Referer"]); + hostname = $"{uri.Host}:{uri.Port}"; + } + else + { + hostname = c.Request.Host.ToString(); + } + c.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + c.ProtocolMessage.Wreply = $"https://{hostname}/signin-wsfed"; + c.Properties.RedirectUri = $"{c.Request.Headers["Referer"]}"; + c.Response.Headers.Add(new KeyValuePair("Location", new StringValues(c.ProtocolMessage.CreateSignInUrl()))); + c.HandleResponse(); + return Task.CompletedTask; + }; + + // For AAD, use the App ID URI from the app registration's Properties blade: + //options.Wtrealm = "https://wsfedsample.onmicrosoft.com/63e4796f-9e4e-40f1-928b-d4efd0642d0d"; + + }) + .AddCookie(); + } + } +} diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs index 459212fe7..8131d3470 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Startup.cs @@ -18,6 +18,7 @@ using Swashbuckle.AspNetCore.SwaggerGen; using Microsoft.Extensions.PlatformAbstractions; using System.Reflection; +using static Phonebook.Backend.PictureService.Helpers.AdfsHelper; namespace Phonebook.Backend.PictureService { @@ -71,21 +72,12 @@ public void ConfigureServices(IServiceCollection services) options.SubstituteApiVersionInUrl = true; }); - //Enable IIS Integration - //services.AddAuthentication(IISDefaults.AuthenticationScheme); - //services.Configure(options => - //{ - // options.AutomaticAuthentication = true; - //}); - //services.AddCors(o => o.AddPolicy(CorsPolicy, builder => - //{ - // // Add some CORS allowed origins here - // builder.WithOrigins(this.AppSettings.AllowedCORSDomains).AllowAnyMethod().AllowAnyHeader().AllowCredentials(); - //})); - - //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - + // Auth +#if DEBUG + Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; +#endif + AddWsFederation(services, Configuration); services.AddImageProcessingSettings(Configuration); @@ -142,7 +134,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVers app.UseStaticFiles(); app.UseRouting(); - + + app.UseAuthentication(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json index ecc89e8c9..741e3c8de 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/appsettings.json @@ -41,5 +41,10 @@ "Quality": 95 } ] + }, + "WsFederationConfig": { + "MetadataAddress": "https://login.microsoftonline.com/2f5af4bb-2ab0-4b54-87a0-9ce3ca95a9d0/federationmetadata/2007-06/federationmetadata.xml", + "ApplicationId": "63e4796f-9e4e-40f1-928b-d4efd0642d0d", + "ClaimsIssuer": "https://sts.windows.net/2f5af4bb-2ab0-4b54-87a0-9ce3ca95a9d0/" } } \ No newline at end of file From 86fc60facc8efd4a0640af12a218a2216480bbbf Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:36:35 +0200 Subject: [PATCH 20/23] revert old changes --- .../src/Phonebook.Source.PeopleSoft/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs index 174bafbdb..7b4e4ea2b 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Program.cs @@ -7,8 +7,7 @@ public static class Program { public static void Main(string[] args) { - var builder = CreateWebHostBuilder(args).Build(); - builder.Run(); + CreateWebHostBuilder(args).Build().Run(); } public static IHostBuilder CreateWebHostBuilder(string[] args) => From 72a772756b60753bdd766a28124b257e1511812e Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:38:27 +0200 Subject: [PATCH 21/23] revert old changes --- .../Properties/launchSettings.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json index 9f2c61a2d..80c55e273 100644 --- a/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json +++ b/Phonebook.Source.PeopleSoft/src/Phonebook.Source.PeopleSoft/Properties/launchSettings.json @@ -1,11 +1,7 @@ { "iisSettings": { - "windowsAuthentication": true, + "windowsAuthentication": false, "anonymousAuthentication": true, - "iis": { - "applicationUrl": "http://localhost/Phonebook.Source.PeopleSoft", - "sslPort": 0 - }, "iisExpress": { "applicationUrl": "http://localhost:22913", "sslPort": 44390 @@ -38,4 +34,4 @@ "useSSL": true } } -} \ No newline at end of file +} From 4588904b53afe67054315adba529b73d9f3ae033 Mon Sep 17 00:00:00 2001 From: paule96 Date: Sat, 11 Apr 2020 21:42:03 +0200 Subject: [PATCH 22/23] remove old work --- phonebook.code-workspace | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/phonebook.code-workspace b/phonebook.code-workspace index 6f0dca184..1ba1b76e8 100644 --- a/phonebook.code-workspace +++ b/phonebook.code-workspace @@ -55,11 +55,8 @@ "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "extensions": { - "recommendations": [ - "esbenp.prettier-vscode", - "streetsidesoftware.code-spell-checker" - ] + "files.associations": { + "**/assets/js/search-data.json": "plaintext" } }, "extensions": { From 5789240acd2e244699d2e7be1801fc0f76a315e7 Mon Sep 17 00:00:00 2001 From: paule96 Date: Sun, 12 Apr 2020 14:19:48 +0200 Subject: [PATCH 23/23] =?UTF-8?q?add=20ws=20federation=20as=20nuget=20ref?= =?UTF-8?q?=20=F0=9F=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hit always save! --- .../Phonebook.Backend.PictureService.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj index 1a0c6fdbf..54f2514e3 100644 --- a/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj +++ b/Phonebook.Backend/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService/Phonebook.Backend.PictureService.csproj @@ -15,7 +15,8 @@ - + +